@ -1,8 +1,8 @@
@@ -1,8 +1,8 @@
/*
* QuickJS Javascript Engine
*
* Copyright ( c ) 2017 - 2020 Fabrice Bellard
* Copyright ( c ) 2017 - 2020 Charlie Gordon
* Copyright ( c ) 2017 - 2021 Fabrice Bellard
* Copyright ( c ) 2017 - 2021 Charlie Gordon
*
* Permission is hereby granted , free of charge , to any person obtaining a copy
* of this software and associated documentation files ( the " Software " ) , to deal
@ -36,6 +36,8 @@
@@ -36,6 +36,8 @@
# include <malloc/malloc.h>
# elif defined(__linux__)
# include <malloc.h>
# elif defined(__FreeBSD__)
# include <malloc_np.h>
# endif
# include "cutils.h"
@ -265,9 +267,10 @@ struct JSRuntime {
@@ -265,9 +267,10 @@ struct JSRuntime {
struct list_head string_list ; /* list of JSString.link */
# endif
/* stack limitation */
const uint8_t * stack_top ;
size_t stack_size ; /* in bytes */
uintptr_t stack_size ; /* in bytes, 0 if no limit */
uintptr_t stack_top ;
uintptr_t stack_limit ; /* lower stack limit */
JSValue current_exception ;
/* true if inside an out of memory error, to avoid recursing */
BOOL in_out_of_memory : 8 ;
@ -1569,9 +1572,9 @@ static void set_dummy_numeric_ops(JSNumericOperations *ops)
@@ -1569,9 +1572,9 @@ static void set_dummy_numeric_ops(JSNumericOperations *ops)
# if !defined(CONFIG_STACK_CHECK)
/* no stack limitation */
static inline uint8_t * js_get_stack_pointer ( void )
static inline uintptr_t js_get_stack_pointer ( void )
{
return NULL ;
return 0 ;
}
static inline BOOL js_check_stack_overflow ( JSRuntime * rt , size_t alloca_size )
@ -1580,16 +1583,16 @@ static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
@@ -1580,16 +1583,16 @@ static inline BOOL js_check_stack_overflow(JSRuntime *rt, size_t alloca_size)
}
# else
/* Note: OS and CPU dependent */
static inline uint8_t * js_get_stack_pointer ( void )
static inline uintptr_t js_get_stack_pointer ( void )
{
return __builtin_frame_address ( 0 ) ;
return ( uintptr_t ) __builtin_frame_address ( 0 ) ;
}
static inline BOOL js_check_stack_overflow ( JSRuntime * rt , size_t alloca_size )
{
size_t size ;
size = rt - > stack_top - js_get_stack_pointer ( ) ;
return unlikely ( ( size + alloca_size ) > rt - > stack_size ) ;
uintptr_t sp ;
sp = js_get_stack_pointer ( ) - alloca_size ;
return unlikely ( sp < rt - > stack_limit ) ;
}
# endif
@ -1649,8 +1652,9 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
@@ -1649,8 +1652,9 @@ JSRuntime *JS_NewRuntime2(const JSMallocFunctions *mf, void *opaque)
if ( init_shape_hash ( rt ) )
goto fail ;
rt - > stack_top = js_get_stack_pointer ( ) ;
rt - > stack_size = JS_DEFAULT_STACK_SIZE ;
JS_UpdateStackTop ( rt ) ;
rt - > current_exception = JS_NULL ;
return rt ;
@ -2338,9 +2342,25 @@ JSRuntime *JS_GetRuntime(JSContext *ctx)
@@ -2338,9 +2342,25 @@ JSRuntime *JS_GetRuntime(JSContext *ctx)
return ctx - > rt ;
}
static void update_stack_limit ( JSRuntime * rt )
{
if ( rt - > stack_size = = 0 ) {
rt - > stack_limit = 0 ; /* no limit */
} else {
rt - > stack_limit = rt - > stack_top - rt - > stack_size ;
}
}
void JS_SetMaxStackSize ( JSRuntime * rt , size_t stack_size )
{
rt - > stack_size = stack_size ;
update_stack_limit ( rt ) ;
}
void JS_UpdateStackTop ( JSRuntime * rt )
{
rt - > stack_top = js_get_stack_pointer ( ) ;
update_stack_limit ( rt ) ;
}
static inline BOOL is_strict_mode ( JSContext * ctx )
@ -3377,6 +3397,8 @@ static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
@@ -3377,6 +3397,8 @@ static int JS_NewClass1(JSRuntime *rt, JSClassID class_id,
JSClass * cl , * new_class_array ;
struct list_head * el ;
if ( class_id > = ( 1 < < 16 ) )
return - 1 ;
if ( class_id < rt - > class_count & &
rt - > class_array [ class_id ] . class_id ! = 0 )
return - 1 ;
@ -8231,6 +8253,23 @@ static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
@@ -8231,6 +8253,23 @@ static int set_array_length(JSContext *ctx, JSObject *p, JSValue val,
return TRUE ;
}
/* return -1 if exception */
static int expand_fast_array ( JSContext * ctx , JSObject * p , uint32_t new_len )
{
uint32_t new_size ;
size_t slack ;
JSValue * new_array_prop ;
/* XXX: potential arithmetic overflow */
new_size = max_int ( new_len , p - > u . array . u1 . size * 3 / 2 ) ;
new_array_prop = js_realloc2 ( ctx , p - > u . array . u . values , sizeof ( JSValue ) * new_size , & slack ) ;
if ( ! new_array_prop )
return - 1 ;
new_size + = slack / sizeof ( * new_array_prop ) ;
p - > u . array . u . values = new_array_prop ;
p - > u . array . u1 . size = new_size ;
return 0 ;
}
/* Preconditions: 'p' must be of class JS_CLASS_ARRAY, p->fast_array =
TRUE and p - > extensible = TRUE */
static int add_fast_array_element ( JSContext * ctx , JSObject * p ,
@ -8253,19 +8292,10 @@ static int add_fast_array_element(JSContext *ctx, JSObject *p,
@@ -8253,19 +8292,10 @@ static int add_fast_array_element(JSContext *ctx, JSObject *p,
}
}
if ( unlikely ( new_len > p - > u . array . u1 . size ) ) {
uint32_t new_size ;
size_t slack ;
JSValue * new_array_prop ;
/* XXX: potential arithmetic overflow */
new_size = max_int ( new_len , p - > u . array . u1 . size * 3 / 2 ) ;
new_array_prop = js_realloc2 ( ctx , p - > u . array . u . values , sizeof ( JSValue ) * new_size , & slack ) ;
if ( ! new_array_prop ) {
if ( expand_fast_array ( ctx , p , new_len ) ) {
JS_FreeValue ( ctx , val ) ;
return - 1 ;
}
new_size + = slack / sizeof ( * new_array_prop ) ;
p - > u . array . u . values = new_array_prop ;
p - > u . array . u1 . size = new_size ;
}
p - > u . array . u . values [ new_len - 1 ] = val ;
p - > u . array . count = new_len ;
@ -8279,22 +8309,24 @@ static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
@@ -8279,22 +8309,24 @@ static void js_free_desc(JSContext *ctx, JSPropertyDescriptor *desc)
JS_FreeValue ( ctx , desc - > value ) ;
}
/* generic (and slower) version of JS_SetProperty() for Reflect.set() */
/* generic (and slower) version of JS_SetProperty() for
* Reflect . set ( ) . ' obj ' must be an object . */
static int JS_SetPropertyGeneric ( JSContext * ctx ,
JSObject * p , JSAtom prop ,
JSValueConst obj , JSAtom prop ,
JSValue val , JSValueConst this_obj ,
int flags )
{
int ret ;
JSPropertyDescriptor desc ;
while ( p ! = NULL ) {
JSValue obj1 ;
JSObject * p ;
obj1 = JS_DupValue ( ctx , obj ) ;
for ( ; ; ) {
p = JS_VALUE_GET_OBJ ( obj1 ) ;
if ( p - > is_exotic ) {
const JSClassExoticMethods * em = ctx - > rt - > class_array [ p - > class_id ] . exotic ;
if ( em & & em - > set_property ) {
JSValue obj1 ;
/* set_property can free the prototype */
obj1 = JS_DupValue ( ctx , JS_MKPTR ( JS_TAG_OBJECT , p ) ) ;
ret = em - > set_property ( ctx , obj1 , prop ,
val , this_obj , flags ) ;
JS_FreeValue ( ctx , obj1 ) ;
@ -8304,8 +8336,11 @@ static int JS_SetPropertyGeneric(JSContext *ctx,
@@ -8304,8 +8336,11 @@ static int JS_SetPropertyGeneric(JSContext *ctx,
}
ret = JS_GetOwnPropertyInternal ( ctx , & desc , p , prop ) ;
if ( ret < 0 )
if ( ret < 0 ) {
JS_FreeValue ( ctx , obj1 ) ;
JS_FreeValue ( ctx , val ) ;
return ret ;
}
if ( ret ) {
if ( desc . flags & JS_PROP_GETSET ) {
JSObject * setter ;
@ -8316,27 +8351,38 @@ static int JS_SetPropertyGeneric(JSContext *ctx,
@@ -8316,27 +8351,38 @@ static int JS_SetPropertyGeneric(JSContext *ctx,
ret = call_setter ( ctx , setter , this_obj , val , flags ) ;
JS_FreeValue ( ctx , desc . getter ) ;
JS_FreeValue ( ctx , desc . setter ) ;
JS_FreeValue ( ctx , obj1 ) ;
return ret ;
} else {
JS_FreeValue ( ctx , desc . value ) ;
if ( ! ( desc . flags & JS_PROP_WRITABLE ) ) {
JS_FreeValue ( ctx , obj1 ) ;
goto read_only_error ;
}
}
break ;
}
p = p - > shape - > proto ;
/* Note: at this point 'obj1' cannot be a proxy. XXX: may have
to check recursion */
obj1 = JS_GetPrototypeFree ( ctx , obj1 ) ;
if ( JS_IsNull ( obj1 ) )
break ;
}
JS_FreeValue ( ctx , obj1 ) ;
if ( ! JS_IsObject ( this_obj ) )
if ( ! JS_IsObject ( this_obj ) ) {
JS_FreeValue ( ctx , val ) ;
return JS_ThrowTypeErrorOrFalse ( ctx , flags , " receiver is not an object " ) ;
}
p = JS_VALUE_GET_OBJ ( this_obj ) ;
/* modify the property in this_obj if it already exists */
ret = JS_GetOwnPropertyInternal ( ctx , & desc , p , prop ) ;
if ( ret < 0 )
if ( ret < 0 ) {
JS_FreeValue ( ctx , val ) ;
return ret ;
}
if ( ret ) {
if ( desc . flags & JS_PROP_GETSET ) {
JS_FreeValue ( ctx , desc . getter ) ;
@ -15022,10 +15068,10 @@ static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *
@@ -15022,10 +15068,10 @@ static JSValue js_build_rest(JSContext *ctx, int first, int argc, JSValueConst *
static JSValue build_for_in_iterator ( JSContext * ctx , JSValue obj )
{
JSObject * p , * p1 ;
JSObject * p ;
JSPropertyEnum * tab_atom ;
int i ;
JSValue enum_obj ;
JSValue enum_obj , obj1 ;
JSForInIterator * it ;
uint32_t tag , tab_atom_count ;
@ -15054,20 +15100,34 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
@@ -15054,20 +15100,34 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
if ( tag = = JS_TAG_NULL | | tag = = JS_TAG_UNDEFINED )
return enum_obj ;
p = JS_VALUE_GET_OBJ ( obj ) ;
/* fast path: assume no enumerable properties in the prototype chain */
p1 = p - > shape - > proto ;
while ( p1 ! = NULL ) {
if ( JS_GetOwnPropertyNamesInternal ( ctx , & tab_atom , & tab_atom_count , p1 ,
JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY ) )
obj1 = JS_DupValue ( ctx , obj ) ;
for ( ; ; ) {
obj1 = JS_GetPrototypeFree ( ctx , obj1 ) ;
if ( JS_IsNull ( obj1 ) )
break ;
if ( JS_IsException ( obj1 ) )
goto fail ;
if ( JS_GetOwnPropertyNamesInternal ( ctx , & tab_atom , & tab_atom_count ,
JS_VALUE_GET_OBJ ( obj1 ) ,
JS_GPN_STRING_MASK | JS_GPN_ENUM_ONLY ) ) {
JS_FreeValue ( ctx , obj1 ) ;
goto fail ;
}
js_free_prop_enum ( ctx , tab_atom , tab_atom_count ) ;
if ( tab_atom_count ! = 0 ) {
JS_FreeValue ( ctx , obj1 ) ;
goto slow_path ;
}
p1 = p1 - > shape - > proto ;
/* must check for timeout to avoid infinite loop */
if ( js_poll_interrupts ( ctx ) ) {
JS_FreeValue ( ctx , obj1 ) ;
goto fail ;
}
}
p = JS_VALUE_GET_OBJ ( obj ) ;
if ( p - > fast_array ) {
JSShape * sh ;
JSShapeProperty * prs ;
@ -15095,17 +15155,30 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
@@ -15095,17 +15155,30 @@ static JSValue build_for_in_iterator(JSContext *ctx, JSValue obj)
slow_path :
/* non enumerable properties hide the enumerables ones in the
prototype chain */
while ( p ! = NULL ) {
if ( JS_GetOwnPropertyNamesInternal ( ctx , & tab_atom , & tab_atom_count , p ,
JS_GPN_STRING_MASK | JS_GPN_SET_ENUM ) )
obj1 = JS_DupValue ( ctx , obj ) ;
for ( ; ; ) {
if ( JS_GetOwnPropertyNamesInternal ( ctx , & tab_atom , & tab_atom_count ,
JS_VALUE_GET_OBJ ( obj1 ) ,
JS_GPN_STRING_MASK | JS_GPN_SET_ENUM ) ) {
JS_FreeValue ( ctx , obj1 ) ;
goto fail ;
}
for ( i = 0 ; i < tab_atom_count ; i + + ) {
JS_DefinePropertyValue ( ctx , enum_obj , tab_atom [ i ] . atom , JS_NULL ,
( tab_atom [ i ] . is_enumerable ?
JS_PROP_ENUMERABLE : 0 ) ) ;
}
js_free_prop_enum ( ctx , tab_atom , tab_atom_count ) ;
p = p - > shape - > proto ;
obj1 = JS_GetPrototypeFree ( ctx , obj1 ) ;
if ( JS_IsNull ( obj1 ) )
break ;
if ( JS_IsException ( obj1 ) )
goto fail ;
/* must check for timeout to avoid infinite loop */
if ( js_poll_interrupts ( ctx ) ) {
JS_FreeValue ( ctx , obj1 ) ;
goto fail ;
}
}
return enum_obj ;
@ -15572,8 +15645,10 @@ static __exception int JS_CopyDataProperties(JSContext *ctx,
@@ -15572,8 +15645,10 @@ static __exception int JS_CopyDataProperties(JSContext *ctx,
uint32_t i , tab_atom_count ;
JSObject * p ;
JSObject * pexcl = NULL ;
int ret = 0 , flags ;
int ret , gpn_flags ;
JSPropertyDescriptor desc ;
BOOL is_enumerable ;
if ( JS_VALUE_GET_TAG ( source ) ! = JS_TAG_OBJECT )
return 0 ;
@ -15581,37 +15656,57 @@ static __exception int JS_CopyDataProperties(JSContext *ctx,
@@ -15581,37 +15656,57 @@ static __exception int JS_CopyDataProperties(JSContext *ctx,
pexcl = JS_VALUE_GET_OBJ ( excluded ) ;
p = JS_VALUE_GET_OBJ ( source ) ;
gpn_flags = JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK | JS_GPN_ENUM_ONLY ;
if ( p - > is_exotic ) {
const JSClassExoticMethods * em = ctx - > rt - > class_array [ p - > class_id ] . exotic ;
/* cannot use JS_GPN_ENUM_ONLY with e.g. proxies because it
introduces a visible change */
if ( em & & em - > get_own_property_names ) {
gpn_flags & = ~ JS_GPN_ENUM_ONLY ;
}
}
if ( JS_GetOwnPropertyNamesInternal ( ctx , & tab_atom , & tab_atom_count , p ,
JS_GPN_STRING_MASK | JS_GPN_SYMBOL_MASK |
JS_GPN_ENUM_ONLY ) )
gpn_flags ) )
return - 1 ;
flags = JS_PROP_C_W_E ;
for ( i = 0 ; i < tab_atom_count ; i + + ) {
if ( pexcl ) {
ret = JS_GetOwnPropertyInternal ( ctx , NULL , pexcl , tab_atom [ i ] . atom ) ;
if ( ret ) {
if ( ret < 0 )
break ;
ret = 0 ;
goto exception ;
continue ;
}
}
ret = - 1 ;
if ( ! ( gpn_flags & JS_GPN_ENUM_ONLY ) ) {
/* test if the property is enumerable */
ret = JS_GetOwnPropertyInternal ( ctx , & desc , p , tab_atom [ i ] . atom ) ;
if ( ret < 0 )
goto exception ;
if ( ! ret )
continue ;
is_enumerable = ( desc . flags & JS_PROP_ENUMERABLE ) ! = 0 ;
js_free_desc ( ctx , & desc ) ;
if ( ! is_enumerable )
continue ;
}
val = JS_GetProperty ( ctx , source , tab_atom [ i ] . atom ) ;
if ( JS_IsException ( val ) )
break ;
goto exception ;
if ( setprop )
ret = JS_SetProperty ( ctx , target , tab_atom [ i ] . atom , val ) ;
else
ret = JS_DefinePropertyValue ( ctx , target , tab_atom [ i ] . atom , val , flags ) ;
ret = JS_DefinePropertyValue ( ctx , target , tab_atom [ i ] . atom , val ,
JS_PROP_C_W_E ) ;
if ( ret < 0 )
break ;
ret = 0 ;
goto exception ;
}
js_free_prop_enum ( ctx , tab_atom , tab_atom_count ) ;
return ret ;
return 0 ;
exception :
js_free_prop_enum ( ctx , tab_atom , tab_atom_count ) ;
return - 1 ;
}
/* only valid inside C functions */
@ -16654,7 +16749,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
@@ -16654,7 +16749,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
BREAK ;
CASE ( OP_check_ctor ) :
if ( JS_IsUndefined ( new_target ) ) {
JS_ThrowTypeError ( caller_c tx , " class constructors must be invoked with 'new' " ) ;
JS_ThrowTypeError ( ctx , " class constructors must be invoked with 'new' " ) ;
goto exception ;
}
BREAK ;
@ -17770,8 +17865,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
@@ -17770,8 +17865,7 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj,
atom = JS_ValueToAtom ( ctx , sp [ - 2 ] ) ;
if ( unlikely ( atom = = JS_ATOM_NULL ) )
goto exception ;
ret = JS_SetPropertyGeneric ( ctx , JS_VALUE_GET_OBJ ( sp [ - 3 ] ) ,
atom , sp [ - 1 ] , sp [ - 4 ] ,
ret = JS_SetPropertyGeneric ( ctx , sp [ - 3 ] , atom , sp [ - 1 ] , sp [ - 4 ] ,
JS_PROP_THROW_STRICT ) ;
JS_FreeAtom ( ctx , atom ) ;
JS_FreeValue ( ctx , sp [ - 4 ] ) ;
@ -22678,7 +22772,7 @@ static __exception int js_parse_left_hand_side_expr(JSParseState *s)
@@ -22678,7 +22772,7 @@ static __exception int js_parse_left_hand_side_expr(JSParseState *s)
return js_parse_postfix_expr ( s , PF_POSTFIX_CALL ) ;
}
/* XXX: is there is nicer solution ? */
/* XXX: could generate specific bytecode */
static __exception int js_parse_class_default_ctor ( JSParseState * s ,
BOOL has_super ,
JSFunctionDef * * pfd )
@ -22691,7 +22785,8 @@ static __exception int js_parse_class_default_ctor(JSParseState *s,
@@ -22691,7 +22785,8 @@ static __exception int js_parse_class_default_ctor(JSParseState *s,
js_parse_get_pos ( s , & pos ) ;
if ( has_super ) {
str = " (...a){super(...a);} " ;
/* spec change: no argument evaluation */
str = " (){super(...arguments);} " ;
func_type = JS_PARSE_FUNC_DERIVED_CLASS_CONSTRUCTOR ;
} else {
str = " (){} " ;
@ -34227,6 +34322,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
@@ -34227,6 +34322,7 @@ static int JS_WriteFunctionTag(BCWriterState *s, JSValueConst obj)
bc_put_leb128 ( s , b - > cpool_count ) ;
bc_put_leb128 ( s , b - > byte_code_len ) ;
if ( b - > vardefs ) {
/* XXX: this field is redundant */
bc_put_leb128 ( s , b - > arg_count + b - > var_count ) ;
for ( i = 0 ; i < b - > arg_count + b - > var_count ; i + + ) {
JSVarDef * vd = & b - > vardefs [ i ] ;
@ -35196,6 +35292,16 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
@@ -35196,6 +35292,16 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
memcpy ( b , & bc , offsetof ( JSFunctionBytecode , debug ) ) ;
b - > header . ref_count = 1 ;
if ( local_count ! = 0 ) {
b - > vardefs = ( void * ) ( ( uint8_t * ) b + vardefs_offset ) ;
}
if ( b - > closure_var_count ! = 0 ) {
b - > closure_var = ( void * ) ( ( uint8_t * ) b + closure_var_offset ) ;
}
if ( b - > cpool_count ! = 0 ) {
b - > cpool = ( void * ) ( ( uint8_t * ) b + cpool_offset ) ;
}
add_gc_object ( ctx - > rt , & b - > header , JS_GC_OBJ_TYPE_FUNCTION_BYTECODE ) ;
obj = JS_MKPTR ( JS_TAG_FUNCTION_BYTECODE , b ) ;
@ -35211,7 +35317,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
@@ -35211,7 +35317,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
if ( local_count ! = 0 ) {
bc_read_trace ( s , " vars { \n " ) ;
b - > vardefs = ( void * ) ( ( uint8_t * ) b + vardefs_offset ) ;
for ( i = 0 ; i < local_count ; i + + ) {
JSVarDef * vd = & b - > vardefs [ i ] ;
if ( bc_get_atom ( s , & vd - > var_name ) )
@ -35236,7 +35341,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
@@ -35236,7 +35341,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
}
if ( b - > closure_var_count ! = 0 ) {
bc_read_trace ( s , " closure vars { \n " ) ;
b - > closure_var = ( void * ) ( ( uint8_t * ) b + closure_var_offset ) ;
for ( i = 0 ; i < b - > closure_var_count ; i + + ) {
JSClosureVar * cv = & b - > closure_var [ i ] ;
int var_idx ;
@ -35288,7 +35392,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
@@ -35288,7 +35392,6 @@ static JSValue JS_ReadFunctionTag(BCReaderState *s)
}
if ( b - > cpool_count ! = 0 ) {
bc_read_trace ( s , " cpool { \n " ) ;
b - > cpool = ( void * ) ( ( uint8_t * ) b + cpool_offset ) ;
for ( i = 0 ; i < b - > cpool_count ; i + + ) {
JSValue val ;
val = JS_ReadObjectRec ( s ) ;
@ -37493,6 +37596,10 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
@@ -37493,6 +37596,10 @@ static JSValue *build_arg_list(JSContext *ctx, uint32_t *plen,
}
if ( js_get_length32 ( ctx , & len , array_arg ) )
return NULL ;
if ( len > JS_MAX_LOCAL_VARS ) {
JS_ThrowInternalError ( ctx , " too many arguments " ) ;
return NULL ;
}
/* avoid allocating 0 bytes */
tab = js_mallocz ( ctx , sizeof ( tab [ 0 ] ) * max_uint32 ( 1 , len ) ) ;
if ( ! tab )
@ -38293,9 +38400,16 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val,
@@ -38293,9 +38400,16 @@ static JSValue js_array_every(JSContext *ctx, JSValueConst this_val,
n = 0 ;
for ( k = 0 ; k < len ; k + + ) {
present = JS_TryGetPropertyInt64 ( ctx , obj , k , & val ) ;
if ( present < 0 )
goto exception ;
if ( special & special_TA ) {
val = JS_GetPropertyInt64 ( ctx , obj , k ) ;
if ( JS_IsException ( val ) )
goto exception ;
present = TRUE ;
} else {
present = JS_TryGetPropertyInt64 ( ctx , obj , k , & val ) ;
if ( present < 0 )
goto exception ;
}
if ( present ) {
index_val = JS_NewInt64 ( ctx , k ) ;
if ( JS_IsException ( index_val ) )
@ -38413,18 +38527,32 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val,
@@ -38413,18 +38527,32 @@ static JSValue js_array_reduce(JSContext *ctx, JSValueConst this_val,
}
k1 = ( special & special_reduceRight ) ? len - k - 1 : k ;
k + + ;
present = JS_TryGetPropertyInt64 ( ctx , obj , k1 , & acc ) ;
if ( present < 0 )
goto exception ;
if ( present )
if ( special & special_TA ) {
acc = JS_GetPropertyInt64 ( ctx , obj , k1 ) ;
if ( JS_IsException ( acc ) )
goto exception ;
break ;
} else {
present = JS_TryGetPropertyInt64 ( ctx , obj , k1 , & acc ) ;
if ( present < 0 )
goto exception ;
if ( present )
break ;
}
}
}
for ( ; k < len ; k + + ) {
k1 = ( special & special_reduceRight ) ? len - k - 1 : k ;
present = JS_TryGetPropertyInt64 ( ctx , obj , k1 , & val ) ;
if ( present < 0 )
goto exception ;
if ( special & special_TA ) {
val = JS_GetPropertyInt64 ( ctx , obj , k1 ) ;
if ( JS_IsException ( val ) )
goto exception ;
present = TRUE ;
} else {
present = JS_TryGetPropertyInt64 ( ctx , obj , k1 , & val ) ;
if ( present < 0 )
goto exception ;
}
if ( present ) {
index_val = JS_NewInt64 ( ctx , k1 ) ;
if ( JS_IsException ( index_val ) )
@ -38829,27 +38957,64 @@ static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
@@ -38829,27 +38957,64 @@ static JSValue js_array_push(JSContext *ctx, JSValueConst this_val,
int64_t len , from , newLen ;
obj = JS_ToObject ( ctx , this_val ) ;
if ( js_get_length64 ( ctx , & len , obj ) )
goto exception ;
newLen = len + argc ;
if ( newLen > MAX_SAFE_INTEGER ) {
JS_ThrowTypeError ( ctx , " Array loo long " ) ;
goto exception ;
}
from = len ;
if ( unshift & & argc > 0 ) {
if ( JS_CopySubArray ( ctx , obj , argc , 0 , len , - 1 ) )
if ( JS_VALUE_GET_TAG ( obj ) = = JS_TAG_OBJECT ) {
JSObject * p = JS_VALUE_GET_OBJ ( obj ) ;
if ( p - > class_id ! = JS_CLASS_ARRAY | |
! p - > fast_array | | ! p - > extensible )
goto generic_case ;
/* length must be writable */
if ( unlikely ( ! ( get_shape_prop ( p - > shape ) - > flags & JS_PROP_WRITABLE ) ) )
goto generic_case ;
/* check the length */
if ( unlikely ( JS_VALUE_GET_TAG ( p - > prop [ 0 ] . u . value ) ! = JS_TAG_INT ) )
goto generic_case ;
len = JS_VALUE_GET_INT ( p - > prop [ 0 ] . u . value ) ;
/* we don't support holes */
if ( unlikely ( len ! = p - > u . array . count ) )
goto generic_case ;
newLen = len + argc ;
if ( unlikely ( newLen > INT32_MAX ) )
goto generic_case ;
if ( newLen > p - > u . array . u1 . size ) {
if ( expand_fast_array ( ctx , p , newLen ) )
goto exception ;
}
if ( unshift & & argc > 0 ) {
memmove ( p - > u . array . u . values + argc , p - > u . array . u . values ,
len * sizeof ( p - > u . array . u . values [ 0 ] ) ) ;
from = 0 ;
} else {
from = len ;
}
for ( i = 0 ; i < argc ; i + + ) {
p - > u . array . u . values [ from + i ] = JS_DupValue ( ctx , argv [ i ] ) ;
}
p - > u . array . count = newLen ;
p - > prop [ 0 ] . u . value = JS_NewInt32 ( ctx , newLen ) ;
} else {
generic_case :
if ( js_get_length64 ( ctx , & len , obj ) )
goto exception ;
from = 0 ;
}
for ( i = 0 ; i < argc ; i + + ) {
if ( JS_SetPropertyInt64 ( ctx , obj , from + i ,
JS_DupValue ( ctx , argv [ i ] ) ) < 0 )
newLen = len + argc ;
if ( newLen > MAX_SAFE_INTEGER ) {
JS_ThrowTypeError ( ctx , " Array loo long " ) ;
goto exception ;
}
from = len ;
if ( unshift & & argc > 0 ) {
if ( JS_CopySubArray ( ctx , obj , argc , 0 , len , - 1 ) )
goto exception ;
from = 0 ;
}
for ( i = 0 ; i < argc ; i + + ) {
if ( JS_SetPropertyInt64 ( ctx , obj , from + i ,
JS_DupValue ( ctx , argv [ i ] ) ) < 0 )
goto exception ;
}
if ( JS_SetProperty ( ctx , obj , JS_ATOM_length , JS_NewInt64 ( ctx , newLen ) ) < 0 )
goto exception ;
}
if ( JS_SetProperty ( ctx , obj , JS_ATOM_length , JS_NewInt64 ( ctx , newLen ) ) < 0 )
goto exception ;
JS_FreeValue ( ctx , obj ) ;
return JS_NewInt64 ( ctx , newLen ) ;
@ -39079,6 +39244,11 @@ static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
@@ -39079,6 +39244,11 @@ static int64_t JS_FlattenIntoArray(JSContext *ctx, JSValueConst target,
int64_t sourceIndex , elementLen ;
int present , is_array ;
if ( js_check_stack_overflow ( ctx - > rt , 0 ) ) {
JS_ThrowStackOverflow ( ctx ) ;
return - 1 ;
}
for ( sourceIndex = 0 ; sourceIndex < sourceLen ; sourceIndex + + ) {
present = JS_TryGetPropertyInt64 ( ctx , source , sourceIndex , & element ) ;
if ( present < 0 )
@ -41816,7 +41986,7 @@ static JSValue js___date_clock(JSContext *ctx, JSValueConst this_val,
@@ -41816,7 +41986,7 @@ static JSValue js___date_clock(JSContext *ctx, JSValueConst this_val,
}
/* OS dependent. d = argv[0] is in ms from 1970. Return the difference
between local time and UTC time ' d ' in minutes */
between UTC time and local time ' d ' in minutes */
static int getTimezoneOffset ( int64_t time ) {
# if defined(_WIN32)
/* XXX: TODO */
@ -44165,7 +44335,7 @@ static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
@@ -44165,7 +44335,7 @@ static JSValue js_reflect_set(JSContext *ctx, JSValueConst this_val,
atom = JS_ValueToAtom ( ctx , prop ) ;
if ( unlikely ( atom = = JS_ATOM_NULL ) )
return JS_EXCEPTION ;
ret = JS_SetPropertyGeneric ( ctx , JS_VALUE_GET_OBJ ( obj ) , atom ,
ret = JS_SetPropertyGeneric ( ctx , obj , atom ,
JS_DupValue ( ctx , val ) , receiver , 0 ) ;
JS_FreeAtom ( ctx , atom ) ;
if ( ret < 0 )
@ -44513,7 +44683,7 @@ static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
@@ -44513,7 +44683,7 @@ static int js_proxy_set(JSContext *ctx, JSValueConst obj, JSAtom atom,
if ( ! s )
return - 1 ;
if ( JS_IsUndefined ( method ) ) {
return JS_SetPropertyGeneric ( ctx , JS_VALUE_GET_OBJ ( s - > target ) , atom ,
return JS_SetPropertyGeneric ( ctx , s - > target , atom ,
JS_DupValue ( ctx , value ) , receiver ,
flags ) ;
}
@ -48134,24 +48304,22 @@ static void string_skip_non_spaces(JSString *sp, int *pp) {
@@ -48134,24 +48304,22 @@ static void string_skip_non_spaces(JSString *sp, int *pp) {
* pp + = 1 ;
}
/* parse a numeric field */
static int string_get_field ( JSString * sp , int * pp , int64_t * pval ) {
/* parse a numeric field with an optional sign if accept_sign is TRUE */
static int string_get_digits ( JSString * sp , int * pp , int64_t * pval ) {
int64_t v = 0 ;
int c , p = * pp ;
/* skip non digits, should only skip spaces? */
while ( p < sp - > len ) {
c = string_get ( sp , p ) ;
if ( c > = ' 0 ' & & c < = ' 9 ' )
break ;
p + + ;
}
int c , p = * pp , p_start ;
if ( p > = sp - > len )
return - 1 ;
p_start = p ;
while ( p < sp - > len ) {
c = string_get ( sp , p ) ;
if ( ! ( c > = ' 0 ' & & c < = ' 9 ' ) )
break ;
if ( ! ( c > = ' 0 ' & & c < = ' 9 ' ) ) {
if ( p = = p_start )
return - 1 ;
else
break ;
}
v = v * 10 + c - ' 0 ' ;
p + + ;
}
@ -48160,8 +48328,25 @@ static int string_get_field(JSString *sp, int *pp, int64_t *pval) {
@@ -48160,8 +48328,25 @@ static int string_get_field(JSString *sp, int *pp, int64_t *pval) {
return 0 ;
}
static int string_get_signed_digits ( JSString * sp , int * pp , int64_t * pval ) {
int res , sgn , p = * pp ;
if ( p > = sp - > len )
return - 1 ;
sgn = string_get ( sp , p ) ;
if ( sgn = = ' - ' | | sgn = = ' + ' )
p + + ;
res = string_get_digits ( sp , & p , pval ) ;
if ( res = = 0 & & sgn = = ' - ' )
* pval = - * pval ;
* pp = p ;
return res ;
}
/* parse a fixed width numeric field */
static int string_get_digits ( JSString * sp , int * pp , int n , int64_t * pval ) {
static int string_get_fixed_width_ digits ( JSString * sp , int * pp , int n , int64_t * pval ) {
int64_t v = 0 ;
int i , c , p = * pp ;
@ -48179,23 +48364,32 @@ static int string_get_digits(JSString *sp, int *pp, int n, int64_t *pval) {
@@ -48179,23 +48364,32 @@ static int string_get_digits(JSString *sp, int *pp, int n, int64_t *pval) {
return 0 ;
}
/* parse a signed numeric field */
static int string_get_signed_field ( JSString * sp , int * pp , int64_t * pval ) {
int sgn , res ;
if ( * p p > = sp - > len )
static int string_get_milliseconds ( JSString * sp , int * pp , int64_t * pval ) {
/* parse milliseconds as a fractional part, round to nearest */
/* XXX: the spec does not indicate which rounding should be used */
int mul = 1000 , ms = 0 , p = * pp , c , p_start ;
if ( p > = sp - > len )
return - 1 ;
sgn = string_get ( sp , * pp ) ;
if ( sgn = = ' - ' | | sgn = = ' + ' )
* pp + = 1 ;
res = string_get_field ( sp , pp , pval ) ;
if ( res = = 0 & & sgn = = ' - ' )
* pval = - * pval ;
return res ;
p_start = p ;
while ( p < sp - > len ) {
c = string_get ( sp , p ) ;
if ( ! ( c > = ' 0 ' & & c < = ' 9 ' ) ) {
if ( p = = p_start )
return - 1 ;
else
break ;
}
if ( mul = = 1 & & c > = ' 5 ' )
ms + = 1 ;
ms + = ( c - ' 0 ' ) * ( mul / = 10 ) ;
p + + ;
}
* pval = ms ;
* pp = p ;
return 0 ;
}
static int find_abbrev ( JSString * sp , int p , const char * list , int count ) {
int n , i ;
@ -48234,7 +48428,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
@@ -48234,7 +48428,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
double fields1 [ 7 ] ;
int64_t tz , hh , mm ;
double d ;
int p , i , c , sgn ;
int p , i , c , sgn , l ;
JSString * sp ;
BOOL is_local ;
@ -48249,50 +48443,74 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
@@ -48249,50 +48443,74 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
if ( p < sp - > len & & ( ( ( c = string_get ( sp , p ) ) > = ' 0 ' & & c < = ' 9 ' ) | | c = = ' + ' | | c = = ' - ' ) ) {
/* ISO format */
/* year field can be negative */
/* XXX: could be stricter */
if ( string_get_signed_field ( sp , & p , & fields [ 0 ] ) )
if ( string_get_signed_digits ( sp , & p , & fields [ 0 ] ) )
goto done ;
is_local = TRUE ;
for ( i = 1 ; i < 6 ; i + + ) {
if ( string_get_field ( sp , & p , & fields [ i ] ) )
for ( i = 1 ; i < 7 ; i + + ) {
if ( p > = sp - > len )
break ;
}
if ( i < = 3 ) {
/* no time: UTC by default */
is_local = FALSE ;
} else if ( i = = 6 & & p < sp - > len & & string_get ( sp , p ) = = ' . ' ) {
/* parse milliseconds as a fractional part, round to nearest */
/* XXX: the spec does not indicate which rounding should be used */
int mul = 1000 , ms = 0 ;
while ( + + p < sp - > len ) {
int c = string_get ( sp , p ) ;
if ( ! ( c > = ' 0 ' & & c < = ' 9 ' ) )
break ;
if ( mul = = 1 & & c > = ' 5 ' )
ms + = 1 ;
ms + = ( c - ' 0 ' ) * ( mul / = 10 ) ;
switch ( i ) {
case 1 :
case 2 :
c = ' - ' ;
break ;
case 3 :
c = ' T ' ;
break ;
case 4 :
case 5 :
c = ' : ' ;
break ;
case 6 :
c = ' . ' ;
break ;
}
if ( string_get ( sp , p ) ! = c )
break ;
p + + ;
if ( i = = 6 ) {
if ( string_get_milliseconds ( sp , & p , & fields [ i ] ) )
goto done ;
} else {
if ( string_get_digits ( sp , & p , & fields [ i ] ) )
goto done ;
}
fields [ 6 ] = ms ;
}
/* no time: UTC by default */
is_local = ( i > 3 ) ;
fields [ 1 ] - = 1 ;
/* parse the time zone offset if present: [+-]HH:mm */
/* parse the time zone offset if present: [+-]HH:mm or [+-]HHmm */
tz = 0 ;
if ( p < sp - > len ) {
sgn = string_get ( sp , p ) ;
if ( sgn = = ' + ' | | sgn = = ' - ' ) {
if ( string_get_field ( sp , & p , & hh ) )
p + + ;
l = sp - > len - p ;
if ( l ! = 4 & & l ! = 5 )
goto done ;
if ( string_get_fixed_width_digits ( sp , & p , 2 , & hh ) )
goto done ;
if ( string_get_field ( sp , & p , & mm ) )
if ( l = = 5 ) {
if ( string_get ( sp , p ) ! = ' : ' )
goto done ;
p + + ;
}
if ( string_get_fixed_width_digits ( sp , & p , 2 , & mm ) )
goto done ;
tz = hh * 60 + mm ;
if ( sgn = = ' - ' )
tz = - tz ;
is_local = FALSE ;
} else if ( sgn = = ' Z ' ) {
p + + ;
is_local = FALSE ;
} else {
goto done ;
}
/* error if extraneous characters */
if ( p ! = sp - > len )
goto done ;
}
} else {
/* toString or toUTCString format */
@ -48304,7 +48522,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
@@ -48304,7 +48522,7 @@ static JSValue js_Date_parse(JSContext *ctx, JSValueConst this_val,
c = string_get ( sp , p ) ;
if ( c > = ' 0 ' & & c < = ' 9 ' ) {
/* day of month first */
if ( string_get_field ( sp , & p , & fields [ 2 ] ) )
if ( string_get_digits ( sp , & p , & fields [ 2 ] ) )
goto done ;
if ( string_get_month ( sp , & p , & fields [ 1 ] ) )
goto done ;