| @@ -825,8 +825,8 @@ typedef struct JSShapeProperty { · 824 unmodified lines |
| 825 | 825 | } JSShapeProperty; |
| 826 | 826 | |
| 827 | 827 | struct JSShape { |
| 828 | | − uint32_t prop_hash_end[0]; /* hash table of size hash_mask + 1 |
| 829 | | − before the start of the structure. */ |
| 828 | + /* hash table of size hash_mask + 1 before the start of the |
| 829 | + structure (see prop_hash_end()). */ |
| 830 | 830 | JSGCObjectHeader header; |
| 831 | 831 | /* true if the shape is inserted in the shape hash table. If not, |
| 832 | 832 | JSShape.hash is not valid */ |
| @@ -859,6 +859,7 @@ struct JSObject { · 26 unmodified lines |
| 859 | 859 | uint8_t is_constructor : 1; /* TRUE if object is a constructor function */ |
| 860 | 860 | uint8_t is_uncatchable_error : 1; /* if TRUE, error is not catchable */ |
| 861 | 861 | uint8_t tmp_mark : 1; /* used in JS_WriteObjectRec() */ |
| 862 | + uint8_t is_HTMLDDA : 1; /* specific annex B IsHtmlDDA behavior */ |
| 862 | 863 | uint16_t class_id; /* see JS_CLASS_x */ |
| 863 | 864 | }; |
| 864 | 865 | }; |
| @@ -931,7 +932,7 @@ struct JSObject { · 66 unmodified lines |
| 931 | 932 | /* byte sizes: 40/48/72 */ |
| 932 | 933 | }; |
| 933 | 934 | enum { |
| 934 | | − JS_ATOM_NULL, |
| 935 | + __JS_ATOM_NULL = JS_ATOM_NULL, |
| 935 | 936 | #define DEF(name, str) JS_ATOM_ ## name, |
| 936 | 937 | #include "quickjs-atom.h" |
| 937 | 938 | #undef DEF |
| @@ -4198,9 +4199,14 @@ static inline JSShape *get_shape_from_alloc(void *sh_alloc, size_t hash_size) · 3260 unmodified lines |
| 4198 | 4199 | return (JSShape *)(void *)((uint32_t *)sh_alloc + hash_size); |
| 4199 | 4200 | } |
| 4200 | 4201 | |
| 4202 | +static inline uint32_t *prop_hash_end(JSShape *sh) |
| 4203 | +{ |
| 4204 | + return (uint32_t *)sh; |
| 4205 | +} |
| 4206 | + |
| 4201 | 4207 | static inline void *get_alloc_from_shape(JSShape *sh) |
| 4202 | 4208 | { |
| 4203 | | − return sh->prop_hash_end - ((intptr_t)sh->prop_hash_mask + 1); |
| 4209 | + return prop_hash_end(sh) - ((intptr_t)sh->prop_hash_mask + 1); |
| 4204 | 4210 | } |
| 4205 | 4211 | |
| 4206 | 4212 | static inline JSShapeProperty *get_shape_prop(JSShape *sh) |
| @@ -4311,7 +4317,7 @@ static no_inline JSShape *js_new_shape2(JSContext *ctx, JSObject *proto, · 104 unmodified lines |
| 4311 | 4317 | if (proto) |
| 4312 | 4318 | JS_DupValue(ctx, JS_MKPTR(JS_TAG_OBJECT, proto)); |
| 4313 | 4319 | sh->proto = proto; |
| 4314 | | − memset(sh->prop_hash_end - hash_size, 0, sizeof(sh->prop_hash_end[0]) * |
| 4320 | + memset(prop_hash_end(sh) - hash_size, 0, sizeof(prop_hash_end(sh)[0]) * |
| 4315 | 4321 | hash_size); |
| 4316 | 4322 | sh->prop_hash_mask = hash_size - 1; |
| 4317 | 4323 | sh->prop_size = prop_size; |
| @@ -4440,13 +4446,13 @@ static no_inline int resize_properties(JSContext *ctx, JSShape **psh, · 122 unmodified lines |
| 4440 | 4446 | list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); |
| 4441 | 4447 | new_hash_mask = new_hash_size - 1; |
| 4442 | 4448 | sh->prop_hash_mask = new_hash_mask; |
| 4443 | | − memset(sh->prop_hash_end - new_hash_size, 0, |
| 4444 | | − sizeof(sh->prop_hash_end[0]) * new_hash_size); |
| 4449 | + memset(prop_hash_end(sh) - new_hash_size, 0, |
| 4450 | + sizeof(prop_hash_end(sh)[0]) * new_hash_size); |
| 4445 | 4451 | for(i = 0, pr = sh->prop; i < sh->prop_count; i++, pr++) { |
| 4446 | 4452 | if (pr->atom != JS_ATOM_NULL) { |
| 4447 | 4453 | h = ((uintptr_t)pr->atom & new_hash_mask); |
| 4448 | | − pr->hash_next = sh->prop_hash_end[-h - 1]; |
| 4449 | | − sh->prop_hash_end[-h - 1] = i + 1; |
| 4454 | + pr->hash_next = prop_hash_end(sh)[-h - 1]; |
| 4455 | + prop_hash_end(sh)[-h - 1] = i + 1; |
| 4450 | 4456 | } |
| 4451 | 4457 | } |
| 4452 | 4458 | js_free(ctx, get_alloc_from_shape(old_sh)); |
| @@ -4500,8 +4506,8 @@ static int compact_properties(JSContext *ctx, JSObject *p) · 47 unmodified lines |
| 4500 | 4506 | memcpy(sh, old_sh, sizeof(JSShape)); |
| 4501 | 4507 | list_add_tail(&sh->header.link, &ctx->rt->gc_obj_list); |
| 4502 | 4508 | |
| 4503 | | − memset(sh->prop_hash_end - new_hash_size, 0, |
| 4504 | | − sizeof(sh->prop_hash_end[0]) * new_hash_size); |
| 4509 | + memset(prop_hash_end(sh) - new_hash_size, 0, |
| 4510 | + sizeof(prop_hash_end(sh)[0]) * new_hash_size); |
| 4505 | 4511 | |
| 4506 | 4512 | j = 0; |
| 4507 | 4513 | old_pr = old_sh->prop; |
| @@ -4512,8 +4518,8 @@ static int compact_properties(JSContext *ctx, JSObject *p) · 4 unmodified lines |
| 4512 | 4518 | pr->atom = old_pr->atom; |
| 4513 | 4519 | pr->flags = old_pr->flags; |
| 4514 | 4520 | h = ((uintptr_t)old_pr->atom & new_hash_mask); |
| 4515 | | − pr->hash_next = sh->prop_hash_end[-h - 1]; |
| 4516 | | − sh->prop_hash_end[-h - 1] = j + 1; |
| 4521 | + pr->hash_next = prop_hash_end(sh)[-h - 1]; |
| 4522 | + prop_hash_end(sh)[-h - 1] = j + 1; |
| 4517 | 4523 | prop[j] = prop[i]; |
| 4518 | 4524 | j++; |
| 4519 | 4525 | pr++; |
| @@ -4575,8 +4581,8 @@ static int add_shape_property(JSContext *ctx, JSShape **psh, · 55 unmodified lines |
| 4575 | 4581 | /* add in hash table */ |
| 4576 | 4582 | hash_mask = sh->prop_hash_mask; |
| 4577 | 4583 | h = atom & hash_mask; |
| 4578 | | − pr->hash_next = sh->prop_hash_end[-h - 1]; |
| 4579 | | − sh->prop_hash_end[-h - 1] = sh->prop_count; |
| 4584 | + pr->hash_next = prop_hash_end(sh)[-h - 1]; |
| 4585 | + prop_hash_end(sh)[-h - 1] = sh->prop_count; |
| 4580 | 4586 | return 0; |
| 4581 | 4587 | } |
| 4582 | 4588 | |
| @@ -4693,6 +4699,7 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas · 110 unmodified lines |
| 4693 | 4699 | p->is_constructor = 0; |
| 4694 | 4700 | p->is_uncatchable_error = 0; |
| 4695 | 4701 | p->tmp_mark = 0; |
| 4702 | + p->is_HTMLDDA = 0; |
| 4696 | 4703 | p->first_weak_ref = NULL; |
| 4697 | 4704 | p->u.opaque = NULL; |
| 4698 | 4705 | p->shape = sh; |
| @@ -4731,7 +4738,19 @@ static JSValue JS_NewObjectFromShape(JSContext *ctx, JSShape *sh, JSClassID clas · 32 unmodified lines |
| 4731 | 4738 | p->prop[0].u.value = JS_UNDEFINED; |
| 4732 | 4739 | break; |
| 4733 | 4740 | case JS_CLASS_ARGUMENTS: |
| 4734 | | − case JS_CLASS_UINT8C_ARRAY ... JS_CLASS_FLOAT64_ARRAY: |
| 4741 | + case JS_CLASS_UINT8C_ARRAY: |
| 4742 | + case JS_CLASS_INT8_ARRAY: |
| 4743 | + case JS_CLASS_UINT8_ARRAY: |
| 4744 | + case JS_CLASS_INT16_ARRAY: |
| 4745 | + case JS_CLASS_UINT16_ARRAY: |
| 4746 | + case JS_CLASS_INT32_ARRAY: |
| 4747 | + case JS_CLASS_UINT32_ARRAY: |
| 4748 | +#ifdef CONFIG_BIGNUM |
| 4749 | + case JS_CLASS_BIG_INT64_ARRAY: |
| 4750 | + case JS_CLASS_BIG_UINT64_ARRAY: |
| 4751 | +#endif |
| 4752 | + case JS_CLASS_FLOAT32_ARRAY: |
| 4753 | + case JS_CLASS_FLOAT64_ARRAY: |
| 4735 | 4754 | p->is_exotic = 1; |
| 4736 | 4755 | p->fast_array = 1; |
| 4737 | 4756 | p->u.array.u.ptr = NULL; |
| @@ -5133,7 +5152,7 @@ static force_inline JSShapeProperty *find_own_property1(JSObject *p, · 395 unmodified lines |
| 5133 | 5152 | intptr_t h; |
| 5134 | 5153 | sh = p->shape; |
| 5135 | 5154 | h = (uintptr_t)atom & sh->prop_hash_mask; |
| 5136 | | − h = sh->prop_hash_end[-h - 1]; |
| 5155 | + h = prop_hash_end(sh)[-h - 1]; |
| 5137 | 5156 | prop = get_shape_prop(sh); |
| 5138 | 5157 | while (h) { |
| 5139 | 5158 | pr = &prop[h - 1]; |
| @@ -5154,7 +5173,7 @@ static force_inline JSShapeProperty *find_own_property(JSProperty **ppr, · 14 unmodified lines |
| 5154 | 5173 | intptr_t h; |
| 5155 | 5174 | sh = p->shape; |
| 5156 | 5175 | h = (uintptr_t)atom & sh->prop_hash_mask; |
| 5157 | | − h = sh->prop_hash_end[-h - 1]; |
| 5176 | + h = prop_hash_end(sh)[-h - 1]; |
| 5158 | 5177 | prop = get_shape_prop(sh); |
| 5159 | 5178 | while (h) { |
| 5160 | 5179 | pr = &prop[h - 1]; |
| @@ -7994,7 +8013,7 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) · 2833 unmodified lines |
| 7994 | 8013 | redo: |
| 7995 | 8014 | sh = p->shape; |
| 7996 | 8015 | h1 = atom & sh->prop_hash_mask; |
| 7997 | | − h = sh->prop_hash_end[-h1 - 1]; |
| 8016 | + h = prop_hash_end(sh)[-h1 - 1]; |
| 7998 | 8017 | prop = get_shape_prop(sh); |
| 7999 | 8018 | lpr = NULL; |
| 8000 | 8019 | lpr_idx = 0; /* prevent warning */ |
| @@ -8015,7 +8034,7 @@ static int delete_property(JSContext *ctx, JSObject *p, JSAtom atom) · 14 unmodified lines |
| 8015 | 8034 | lpr = get_shape_prop(sh) + lpr_idx; |
| 8016 | 8035 | lpr->hash_next = pr->hash_next; |
| 8017 | 8036 | } else { |
| 8018 | | − sh->prop_hash_end[-h1 - 1] = pr->hash_next; |
| 8037 | + prop_hash_end(sh)[-h1 - 1] = pr->hash_next; |
| 8019 | 8038 | } |
| 8020 | 8039 | sh->deleted_prop_count++; |
| 8021 | 8040 | /* free the entry */ |
| @@ -8095,15 +8114,16 @@ static int call_setter(JSContext *ctx, JSObject *setter, · 73 unmodified lines |
| 8095 | 8114 | } |
| 8096 | 8115 | |
| 8097 | 8116 | /* set the array length and remove the array elements if necessary. */ |
| 8098 | | −static int set_array_length(JSContext *ctx, JSObject *p, JSProperty *prop, |
| 8099 | | − JSValue val, int flags) |
| 8117 | +static int set_array_length(JSContext *ctx, JSObject *p, JSValue val, int flags) |
| 8100 | 8118 | { |
| 8101 | 8119 | uint32_t len, idx, cur_len; |
| 8102 | 8120 | int i, ret; |
| 8103 | 8121 | |
| 8122 | + /* Note: this call can reallocate the properties of 'p' */ |
| 8104 | 8123 | ret = JS_ToArrayLengthFree(ctx, &len, val); |
| 8105 | 8124 | if (ret) |
| 8106 | 8125 | return -1; |
| 8126 | + |
| 8107 | 8127 | if (likely(p->fast_array)) { |
| 8108 | 8128 | uint32_t old_len = p->u.array.count; |
| 8109 | 8129 | if (len < old_len) { |
| @@ -8112,11 +8132,11 @@ static int set_array_length(JSContext *ctx, JSObject *p, JSProperty *prop, · 2 unmodified lines |
| 8112 | 8132 | } |
| 8113 | 8133 | p->u.array.count = len; |
| 8114 | 8134 | } |
| 8115 | | − prop->u.value = JS_NewUint32(ctx, len); |
| 8135 | + p->prop[0].u.value = JS_NewUint32(ctx, len); |
| 8116 | 8136 | } else { |
| 8117 | 8137 | /* Note: length is always a uint32 because the object is an |
| 8118 | 8138 | array */ |
| 8119 | | − JS_ToUint32(ctx, &cur_len, prop->u.value); |
| 8139 | + JS_ToUint32(ctx, &cur_len, p->prop[0].u.value); |
| 8120 | 8140 | if (len < cur_len) { |
| 8121 | 8141 | uint32_t d; |
| 8122 | 8142 | JSShape *sh; |
| @@ -8366,7 +8386,7 @@ retry: · 243 unmodified lines |
| 8366 | 8386 | (JS_PROP_LENGTH | JS_PROP_WRITABLE)) { |
| 8367 | 8387 | assert(p->class_id == JS_CLASS_ARRAY); |
| 8368 | 8388 | assert(prop == JS_ATOM_length); |
| 8369 | | − return set_array_length(ctx, p, pr, val, flags); |
| 8389 | + return set_array_length(ctx, p, val, flags); |
| 8370 | 8390 | } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_GETSET) { |
| 8371 | 8391 | return call_setter(ctx, pr->u.getset.setter, this_obj, val, flags); |
| 8372 | 8392 | } else if ((prs->flags & JS_PROP_TMASK) == JS_PROP_VARREF) { |
| @@ -9047,7 +9067,7 @@ int JS_DefineProperty(JSContext *ctx, JSValueConst this_obj, · 674 unmodified lines |
| 9047 | 9067 | } |
| 9048 | 9068 | if (prs->flags & JS_PROP_LENGTH) { |
| 9049 | 9069 | if (flags & JS_PROP_HAS_VALUE) { |
| 9050 | | − res = set_array_length(ctx, p, pr, JS_DupValue(ctx, val), |
| 9070 | + res = set_array_length(ctx, p, JS_DupValue(ctx, val), |
| 9051 | 9071 | flags); |
| 9052 | 9072 | } else { |
| 9053 | 9073 | res = TRUE; |
| @@ -9806,6 +9826,24 @@ static JSValue JS_ToPrimitive(JSContext *ctx, JSValueConst val, int hint) · 752 unmodified lines |
| 9806 | 9826 | return JS_ToPrimitiveFree(ctx, JS_DupValue(ctx, val), hint); |
| 9807 | 9827 | } |
| 9808 | 9828 | |
| 9829 | +void JS_SetIsHTMLDDA(JSContext *ctx, JSValueConst obj) |
| 9830 | +{ |
| 9831 | + JSObject *p; |
| 9832 | + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) |
| 9833 | + return; |
| 9834 | + p = JS_VALUE_GET_OBJ(obj); |
| 9835 | + p->is_HTMLDDA = TRUE; |
| 9836 | +} |
| 9837 | + |
| 9838 | +static inline BOOL JS_IsHTMLDDA(JSContext *ctx, JSValueConst obj) |
| 9839 | +{ |
| 9840 | + JSObject *p; |
| 9841 | + if (JS_VALUE_GET_TAG(obj) != JS_TAG_OBJECT) |
| 9842 | + return FALSE; |
| 9843 | + p = JS_VALUE_GET_OBJ(obj); |
| 9844 | + return p->is_HTMLDDA; |
| 9845 | +} |
| 9846 | + |
| 9809 | 9847 | static int JS_ToBoolFree(JSContext *ctx, JSValue val) |
| 9810 | 9848 | { |
| 9811 | 9849 | uint32_t tag = JS_VALUE_GET_TAG(val); |
| @@ -9843,6 +9881,15 @@ static int JS_ToBoolFree(JSContext *ctx, JSValue val) · 31 unmodified lines |
| 9843 | 9881 | return ret; |
| 9844 | 9882 | } |
| 9845 | 9883 | #endif |
| 9884 | + case JS_TAG_OBJECT: |
| 9885 | + { |
| 9886 | + JSObject *p = JS_VALUE_GET_OBJ(val); |
| 9887 | + BOOL ret; |
| 9888 | + ret = !p->is_HTMLDDA; |
| 9889 | + JS_FreeValue(ctx, val); |
| 9890 | + return ret; |
| 9891 | + } |
| 9892 | + break; |
| 9846 | 9893 | default: |
| 9847 | 9894 | if (JS_TAG_IS_FLOAT64(tag)) { |
| 9848 | 9895 | double d = JS_VALUE_GET_FLOAT64(val); |
| @@ -11602,7 +11649,19 @@ static __maybe_unused void JS_DumpObject(JSRuntime *rt, JSObject *p) · 1753 unmodified lines |
| 11602 | 11649 | case JS_CLASS_ARGUMENTS: |
| 11603 | 11650 | JS_DumpValueShort(rt, p->u.array.u.values[i]); |
| 11604 | 11651 | break; |
| 11605 | | − case JS_CLASS_UINT8C_ARRAY ... JS_CLASS_FLOAT64_ARRAY: |
| 11652 | + case JS_CLASS_UINT8C_ARRAY: |
| 11653 | + case JS_CLASS_INT8_ARRAY: |
| 11654 | + case JS_CLASS_UINT8_ARRAY: |
| 11655 | + case JS_CLASS_INT16_ARRAY: |
| 11656 | + case JS_CLASS_UINT16_ARRAY: |
| 11657 | + case JS_CLASS_INT32_ARRAY: |
| 11658 | + case JS_CLASS_UINT32_ARRAY: |
| 11659 | +#ifdef CONFIG_BIGNUM |
| 11660 | + case JS_CLASS_BIG_INT64_ARRAY: |
| 11661 | + case JS_CLASS_BIG_UINT64_ARRAY: |
| 11662 | +#endif |
| 11663 | + case JS_CLASS_FLOAT32_ARRAY: |
| 11664 | + case JS_CLASS_FLOAT64_ARRAY: |
| 11606 | 11665 | { |
| 11607 | 11666 | int size = 1 << typed_array_size_log2(p->class_id); |
| 11608 | 11667 | const uint8_t *b = p->u.array.u.uint8_ptr + i * size; |
| @@ -13668,33 +13727,8 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, · 2059 unmodified lines |
| 13668 | 13727 | JS_FreeValue(ctx, op2); |
| 13669 | 13728 | } else if ((tag1 <= JS_TAG_NULL || tag1 == JS_TAG_FLOAT64) && |
| 13670 | 13729 | (tag2 <= JS_TAG_NULL || tag2 == JS_TAG_FLOAT64)) { |
| 13671 | | − /* can use floating point comparison */ |
| 13672 | | − double d1, d2; |
| 13673 | | − if (tag1 == JS_TAG_FLOAT64) { |
| 13674 | | − d1 = JS_VALUE_GET_FLOAT64(op1); |
| 13675 | | − } else { |
| 13676 | | − d1 = JS_VALUE_GET_INT(op1); |
| 13677 | | − } |
| 13678 | | − if (tag2 == JS_TAG_FLOAT64) { |
| 13679 | | − d2 = JS_VALUE_GET_FLOAT64(op2); |
| 13680 | | − } else { |
| 13681 | | − d2 = JS_VALUE_GET_INT(op2); |
| 13682 | | − } |
| 13683 | | − switch(op) { |
| 13684 | | − case OP_lt: |
| 13685 | | − res = (d1 < d2); /* if NaN return false */ |
| 13686 | | − break; |
| 13687 | | − case OP_lte: |
| 13688 | | − res = (d1 <= d2); /* if NaN return false */ |
| 13689 | | − break; |
| 13690 | | − case OP_gt: |
| 13691 | | − res = (d1 > d2); /* if NaN return false */ |
| 13692 | | − break; |
| 13693 | | − default: |
| 13694 | | − case OP_gte: |
| 13695 | | − res = (d1 >= d2); /* if NaN return false */ |
| 13696 | | − break; |
| 13697 | | − } |
| 13730 | + /* fast path for float64/int */ |
| 13731 | + goto float64_compare; |
| 13698 | 13732 | } else { |
| 13699 | 13733 | if (((tag1 == JS_TAG_BIG_INT && tag2 == JS_TAG_STRING) || |
| 13700 | 13734 | (tag2 == JS_TAG_BIG_INT && tag1 == JS_TAG_STRING)) && |
| @@ -13727,20 +13761,51 @@ static no_inline int js_relational_slow(JSContext *ctx, JSValue *sp, · 26 unmodified lines |
| 13727 | 13761 | } |
| 13728 | 13762 | } |
| 13729 | 13763 | |
| 13730 | | − if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_DECIMAL || |
| 13731 | | − JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_DECIMAL) { |
| 13764 | + tag1 = JS_VALUE_GET_NORM_TAG(op1); |
| 13765 | + tag2 = JS_VALUE_GET_NORM_TAG(op2); |
| 13766 | + |
| 13767 | + if (tag1 == JS_TAG_BIG_DECIMAL || tag2 == JS_TAG_BIG_DECIMAL) { |
| 13732 | 13768 | res = ctx->rt->bigdecimal_ops.compare(ctx, op, op1, op2); |
| 13733 | 13769 | if (res < 0) |
| 13734 | 13770 | goto exception; |
| 13735 | | − } else if (JS_VALUE_GET_TAG(op1) == JS_TAG_BIG_FLOAT || |
| 13736 | | − JS_VALUE_GET_TAG(op2) == JS_TAG_BIG_FLOAT) { |
| 13771 | + } else if (tag1 == JS_TAG_BIG_FLOAT || tag2 == JS_TAG_BIG_FLOAT) { |
| 13737 | 13772 | res = ctx->rt->bigfloat_ops.compare(ctx, op, op1, op2); |
| 13738 | 13773 | if (res < 0) |
| 13739 | 13774 | goto exception; |
| 13740 | | − } else { |
| 13775 | + } else if (tag1 == JS_TAG_BIG_INT || tag2 == JS_TAG_BIG_INT) { |
| 13741 | 13776 | res = ctx->rt->bigint_ops.compare(ctx, op, op1, op2); |
| 13742 | 13777 | if (res < 0) |
| 13743 | 13778 | goto exception; |
| 13779 | + } else { |
| 13780 | + double d1, d2; |
| 13781 | + |
| 13782 | + float64_compare: |
| 13783 | + /* can use floating point comparison */ |
| 13784 | + if (tag1 == JS_TAG_FLOAT64) { |
| 13785 | + d1 = JS_VALUE_GET_FLOAT64(op1); |
| 13786 | + } else { |
| 13787 | + d1 = JS_VALUE_GET_INT(op1); |
| 13788 | + } |
| 13789 | + if (tag2 == JS_TAG_FLOAT64) { |
| 13790 | + d2 = JS_VALUE_GET_FLOAT64(op2); |
| 13791 | + } else { |
| 13792 | + d2 = JS_VALUE_GET_INT(op2); |
| 13793 | + } |
| 13794 | + switch(op) { |
| 13795 | + case OP_lt: |
| 13796 | + res = (d1 < d2); /* if NaN return false */ |
| 13797 | + break; |
| 13798 | + case OP_lte: |
| 13799 | + res = (d1 <= d2); /* if NaN return false */ |
| 13800 | + break; |
| 13801 | + case OP_gt: |
| 13802 | + res = (d1 > d2); /* if NaN return false */ |
| 13803 | + break; |
| 13804 | + default: |
| 13805 | + case OP_gte: |
| 13806 | + res = (d1 >= d2); /* if NaN return false */ |
| 13807 | + break; |
| 13808 | + } |
| 13744 | 13809 | } |
| 13745 | 13810 | } |
| 13746 | 13811 | done: |
| @@ -13895,9 +13960,17 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, · 148 unmodified lines |
| 13895 | 13960 | } |
| 13896 | 13961 | goto redo; |
| 13897 | 13962 | } else { |
| 13963 | + /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */ |
| 13964 | + if ((JS_IsHTMLDDA(ctx, op1) && |
| 13965 | + (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) || |
| 13966 | + (JS_IsHTMLDDA(ctx, op2) && |
| 13967 | + (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) { |
| 13968 | + res = TRUE; |
| 13969 | + } else { |
| 13970 | + res = FALSE; |
| 13971 | + } |
| 13898 | 13972 | JS_FreeValue(ctx, op1); |
| 13899 | 13973 | JS_FreeValue(ctx, op2); |
| 13900 | | − res = FALSE; |
| 13901 | 13974 | } |
| 13902 | 13975 | done: |
| 13903 | 13976 | sp[-2] = JS_NewBool(ctx, res ^ is_neq); |
| @@ -14348,9 +14421,17 @@ static no_inline __exception int js_eq_slow(JSContext *ctx, JSValue *sp, · 444 unmodified lines |
| 14348 | 14421 | } |
| 14349 | 14422 | goto redo; |
| 14350 | 14423 | } else { |
| 14424 | + /* IsHTMLDDA object is equivalent to undefined for '==' and '!=' */ |
| 14425 | + if ((JS_IsHTMLDDA(ctx, op1) && |
| 14426 | + (tag2 == JS_TAG_NULL || tag2 == JS_TAG_UNDEFINED)) || |
| 14427 | + (JS_IsHTMLDDA(ctx, op2) && |
| 14428 | + (tag1 == JS_TAG_NULL || tag1 == JS_TAG_UNDEFINED))) { |
| 14429 | + res = TRUE; |
| 14430 | + } else { |
| 14431 | + res = FALSE; |
| 14432 | + } |
| 14351 | 14433 | JS_FreeValue(ctx, op1); |
| 14352 | 14434 | JS_FreeValue(ctx, op2); |
| 14353 | | − res = FALSE; |
| 14354 | 14435 | } |
| 14355 | 14436 | sp[-2] = JS_NewBool(ctx, res ^ is_neq); |
| 14356 | 14437 | return 0; |
| @@ -14631,7 +14712,7 @@ static __exception int js_operator_instanceof(JSContext *ctx, JSValue *sp) · 274 unmodified lines |
| 14631 | 14712 | return 0; |
| 14632 | 14713 | } |
| 14633 | 14714 | |
| 14634 | | −static __exception int js_operator_typeof(JSContext *ctx, JSValue op1) |
| 14715 | +static __exception int js_operator_typeof(JSContext *ctx, JSValueConst op1) |
| 14635 | 14716 | { |
| 14636 | 14717 | JSAtom atom; |
| 14637 | 14718 | uint32_t tag; |
| @@ -14663,10 +14744,16 @@ static __exception int js_operator_typeof(JSContext *ctx, JSValue op1) · 25 unmodified lines |
| 14663 | 14744 | atom = JS_ATOM_string; |
| 14664 | 14745 | break; |
| 14665 | 14746 | case JS_TAG_OBJECT: |
| 14666 | | − if (JS_IsFunction(ctx, op1)) |
| 14667 | | − atom = JS_ATOM_function; |
| 14668 | | − else |
| 14669 | | − goto obj_type; |
| 14747 | + { |
| 14748 | + JSObject *p; |
| 14749 | + p = JS_VALUE_GET_OBJ(op1); |
| 14750 | + if (unlikely(p->is_HTMLDDA)) |
| 14751 | + atom = JS_ATOM_undefined; |
| 14752 | + else if (JS_IsFunction(ctx, op1)) |
| 14753 | + atom = JS_ATOM_function; |
| 14754 | + else |
| 14755 | + goto obj_type; |
| 14756 | + } |
| 14670 | 14757 | break; |
| 14671 | 14758 | case JS_TAG_NULL: |
| 14672 | 14759 | obj_type: |
| @@ -15231,7 +15318,10 @@ static __exception int js_for_of_start(JSContext *ctx, JSValue *sp, · 558 unmodified lines |
| 15231 | 15318 | return 0; |
| 15232 | 15319 | } |
| 15233 | 15320 | |
| 15234 | | −/* enum_rec -> enum_rec value done */ |
| 15321 | +/* enum_rec [objs] -> enum_rec [objs] value done. There are 'offset' |
| 15322 | + objs. If 'done' is true or in case of exception, 'enum_rec' is set |
| 15323 | + to undefined. If 'done' is true, 'value' is always set to |
| 15324 | + undefined. */ |
| 15235 | 15325 | static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset) |
| 15236 | 15326 | { |
| 15237 | 15327 | JSValue value = JS_UNDEFINED; |
| @@ -15246,8 +15336,12 @@ static __exception int js_for_of_next(JSContext *ctx, JSValue *sp, int offset) · 8 unmodified lines |
| 15246 | 15336 | /* replace the iteration object with undefined */ |
| 15247 | 15337 | JS_FreeValue(ctx, sp[offset]); |
| 15248 | 15338 | sp[offset] = JS_UNDEFINED; |
| 15249 | | − if (done < 0) |
| 15339 | + if (done < 0) { |
| 15250 | 15340 | return -1; |
| 15341 | + } else { |
| 15342 | + JS_FreeValue(ctx, value); |
| 15343 | + value = JS_UNDEFINED; |
| 15344 | + } |
| 15251 | 15345 | } |
| 15252 | 15346 | } |
| 15253 | 15347 | sp[0] = value; |
| @@ -15363,10 +15457,10 @@ static BOOL js_get_fast_array(JSContext *ctx, JSValueConst obj, · 109 unmodified lines |
| 15363 | 15457 | static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) |
| 15364 | 15458 | { |
| 15365 | 15459 | JSValue iterator, enumobj, method, value; |
| 15366 | | − int pos, is_array_iterator; |
| 15460 | + int is_array_iterator; |
| 15367 | 15461 | JSValue *arrp; |
| 15368 | | − uint32_t i, count32; |
| 15369 | | − |
| 15462 | + uint32_t i, count32, pos; |
| 15463 | + |
| 15370 | 15464 | if (JS_VALUE_GET_TAG(sp[-2]) != JS_TAG_INT) { |
| 15371 | 15465 | JS_ThrowInternalError(ctx, "invalid index for append"); |
| 15372 | 15466 | return -1; |
| @@ -15399,24 +15493,21 @@ static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) · 26 unmodified lines |
| 15399 | 15493 | if (is_array_iterator |
| 15400 | 15494 | && JS_IsCFunction(ctx, method, (JSCFunction *)js_array_iterator_next, 0) |
| 15401 | 15495 | && js_get_fast_array(ctx, sp[-1], &arrp, &count32)) { |
| 15402 | | − int64_t len; |
| 15403 | | − /* Handle fast arrays explicitly */ |
| 15404 | | − if (js_get_length64(ctx, &len, sp[-1])) |
| 15496 | + uint32_t len; |
| 15497 | + if (js_get_length32(ctx, &len, sp[-1])) |
| 15405 | 15498 | goto exception; |
| 15499 | + /* if len > count32, the elements >= count32 might be read in |
| 15500 | + the prototypes and might have side effects */ |
| 15501 | + if (len != count32) |
| 15502 | + goto general_case; |
| 15503 | + /* Handle fast arrays explicitly */ |
| 15406 | 15504 | for (i = 0; i < count32; i++) { |
| 15407 | 15505 | if (JS_DefinePropertyValueUint32(ctx, sp[-3], pos++, |
| 15408 | 15506 | JS_DupValue(ctx, arrp[i]), JS_PROP_C_W_E) < 0) |
| 15409 | 15507 | goto exception; |
| 15410 | 15508 | } |
| 15411 | | − if (len > count32) { |
| 15412 | | − /* This is not strictly correct because the trailing elements are |
| 15413 | | − empty instead of undefined. Append undefined entries instead. |
| 15414 | | − */ |
| 15415 | | − pos += len - count32; |
| 15416 | | − if (JS_SetProperty(ctx, sp[-3], JS_ATOM_length, JS_NewUint32(ctx, pos)) < 0) |
| 15417 | | − goto exception; |
| 15418 | | − } |
| 15419 | 15509 | } else { |
| 15510 | + general_case: |
| 15420 | 15511 | for (;;) { |
| 15421 | 15512 | BOOL done; |
| 15422 | 15513 | value = JS_IteratorNext(ctx, enumobj, method, 0, NULL, &done); |
| @@ -15430,6 +15521,7 @@ static __exception int js_append_enumerate(JSContext *ctx, JSValue *sp) · 7 unmodified lines |
| 15430 | 15521 | goto exception; |
| 15431 | 15522 | } |
| 15432 | 15523 | } |
| 15524 | + /* Note: could raise an error if too many elements */ |
| 15433 | 15525 | sp[-2] = JS_NewInt32(ctx, pos); |
| 15434 | 15526 | JS_FreeValue(ctx, enumobj); |
| 15435 | 15527 | JS_FreeValue(ctx, method); |
| @@ -17742,47 +17834,42 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, · 2306 unmodified lines |
| 17742 | 17834 | BREAK; |
| 17743 | 17835 | CASE(OP_add_loc): |
| 17744 | 17836 | { |
| 17745 | | − JSValue ops[2]; |
| 17837 | + JSValue *pv; |
| 17746 | 17838 | int idx; |
| 17747 | 17839 | idx = *pc; |
| 17748 | 17840 | pc += 1; |
| 17749 | 17841 | |
| 17750 | | − ops[0] = var_buf[idx]; |
| 17751 | | − ops[1] = sp[-1]; |
| 17752 | | − if (likely(JS_VALUE_IS_BOTH_INT(ops[0], ops[1]))) { |
| 17842 | + pv = &var_buf[idx]; |
| 17843 | + if (likely(JS_VALUE_IS_BOTH_INT(*pv, sp[-1]))) { |
| 17753 | 17844 | int64_t r; |
| 17754 | | − r = (int64_t)JS_VALUE_GET_INT(ops[0]) + JS_VALUE_GET_INT(ops[1]); |
| 17845 | + r = (int64_t)JS_VALUE_GET_INT(*pv) + |
| 17846 | + JS_VALUE_GET_INT(sp[-1]); |
| 17755 | 17847 | if (unlikely((int)r != r)) |
| 17756 | 17848 | goto add_loc_slow; |
| 17757 | | − var_buf[idx] = JS_NewInt32(ctx, r); |
| 17849 | + *pv = JS_NewInt32(ctx, r); |
| 17758 | 17850 | sp--; |
| 17759 | | − } else if (JS_VALUE_GET_TAG(ops[0]) == JS_TAG_STRING) { |
| 17851 | + } else if (JS_VALUE_GET_TAG(*pv) == JS_TAG_STRING) { |
| 17852 | + JSValue op1; |
| 17853 | + op1 = sp[-1]; |
| 17760 | 17854 | sp--; |
| 17761 | | − ops[1] = JS_ToPrimitiveFree(ctx, ops[1], HINT_NONE); |
| 17762 | | − if (JS_IsException(ops[1])) { |
| 17855 | + op1 = JS_ToPrimitiveFree(ctx, op1, HINT_NONE); |
| 17856 | + if (JS_IsException(op1)) |
| 17763 | 17857 | goto exception; |
| 17764 | | − } |
| 17765 | | − /* XXX: should not modify the variable in case of |
| 17766 | | − exception */ |
| 17767 | | − ops[0] = JS_ConcatString(ctx, ops[0], ops[1]); |
| 17768 | | − if (JS_IsException(ops[0])) { |
| 17769 | | − var_buf[idx] = JS_UNDEFINED; |
| 17858 | + op1 = JS_ConcatString(ctx, JS_DupValue(ctx, *pv), op1); |
| 17859 | + if (JS_IsException(op1)) |
| 17770 | 17860 | goto exception; |
| 17771 | | − } |
| 17772 | | − var_buf[idx] = ops[0]; |
| 17861 | + set_value(ctx, pv, op1); |
| 17773 | 17862 | } else { |
| 17863 | + JSValue ops[2]; |
| 17774 | 17864 | add_loc_slow: |
| 17775 | | − /* XXX: should not modify the variable in case of |
| 17776 | | − exception */ |
| 17777 | | − sp--; |
| 17778 | 17865 | /* In case of exception, js_add_slow frees ops[0] |
| 17779 | | − and ops[1]. */ |
| 17780 | | − /* XXX: change API */ |
| 17781 | | − if (js_add_slow(ctx, ops + 2)) { |
| 17782 | | − var_buf[idx] = JS_UNDEFINED; |
| 17866 | + and ops[1], so we must duplicate *pv */ |
| 17867 | + ops[0] = JS_DupValue(ctx, *pv); |
| 17868 | + ops[1] = sp[-1]; |
| 17869 | + sp--; |
| 17870 | + if (js_add_slow(ctx, ops + 2)) |
| 17783 | 17871 | goto exception; |
| 17784 | | − } |
| 17785 | | − var_buf[idx] = ops[0]; |
| 17872 | + set_value(ctx, pv, ops[0]); |
| 17786 | 17873 | } |
| 17787 | 17874 | } |
| 17788 | 17875 | BREAK; |
| @@ -18427,7 +18514,15 @@ static JSValue JS_CallInternal(JSContext *caller_ctx, JSValueConst func_obj, · 638 unmodified lines |
| 18427 | 18514 | } else { |
| 18428 | 18515 | goto free_and_set_false; |
| 18429 | 18516 | } |
| 18430 | | − CASE(OP_is_function): |
| 18517 | + /* XXX: could merge to a single opcode */ |
| 18518 | + CASE(OP_typeof_is_undefined): |
| 18519 | + /* different from OP_is_undefined because of isHTMLDDA */ |
| 18520 | + if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_undefined) { |
| 18521 | + goto free_and_set_true; |
| 18522 | + } else { |
| 18523 | + goto free_and_set_false; |
| 18524 | + } |
| 18525 | + CASE(OP_typeof_is_function): |
| 18431 | 18526 | if (js_operator_typeof(ctx, sp[-1]) == JS_ATOM_function) { |
| 18432 | 18527 | goto free_and_set_true; |
| 18433 | 18528 | } else { |
| @@ -19656,6 +19751,9 @@ enum { · 1222 unmodified lines |
| 19656 | 19751 | TOK_MATH_POW_ASSIGN, |
| 19657 | 19752 | #endif |
| 19658 | 19753 | TOK_POW_ASSIGN, |
| 19754 | + TOK_LAND_ASSIGN, |
| 19755 | + TOK_LOR_ASSIGN, |
| 19756 | + TOK_DOUBLE_QUESTION_MARK_ASSIGN, |
| 19659 | 19757 | TOK_DEC, |
| 19660 | 19758 | TOK_INC, |
| 19661 | 19759 | TOK_SHL, |
| @@ -20015,11 +20113,14 @@ static void free_token(JSParseState *s, JSToken *token) · 353 unmodified lines |
| 20015 | 20113 | JS_FreeValue(s->ctx, token->u.regexp.flags); |
| 20016 | 20114 | break; |
| 20017 | 20115 | case TOK_IDENT: |
| 20018 | | − case TOK_FIRST_KEYWORD ... TOK_LAST_KEYWORD: |
| 20019 | 20116 | case TOK_PRIVATE_NAME: |
| 20020 | 20117 | JS_FreeAtom(s->ctx, token->u.ident.atom); |
| 20021 | 20118 | break; |
| 20022 | 20119 | default: |
| 20120 | + if (token->val >= TOK_FIRST_KEYWORD && |
| 20121 | + token->val <= TOK_LAST_KEYWORD) { |
| 20122 | + JS_FreeAtom(s->ctx, token->u.ident.atom); |
| 20123 | + } |
| 20023 | 20124 | break; |
| 20024 | 20125 | } |
| 20025 | 20126 | } |
| @@ -20233,6 +20334,8 @@ static __exception int js_parse_string(JSParseState *s, int sep, · 207 unmodified lines |
| 20233 | 20334 | } |
| 20234 | 20335 | if (c == '\\') { |
| 20235 | 20336 | c = *p; |
| 20337 | + /* XXX: need a specific JSON case to avoid |
| 20338 | + accepting invalid escapes */ |
| 20236 | 20339 | switch(c) { |
| 20237 | 20340 | case '\0': |
| 20238 | 20341 | if (p >= s->buf_end) |
| @@ -20256,18 +20359,23 @@ static __exception int js_parse_string(JSParseState *s, int sep, · 17 unmodified lines |
| 20256 | 20359 | s->line_num++; |
| 20257 | 20360 | continue; |
| 20258 | 20361 | default: |
| 20259 | | − if (c >= '0' && c <= '7') { |
| 20362 | + if (c >= '0' && c <= '9') { |
| 20260 | 20363 | if (!s->cur_func) |
| 20261 | | − goto invalid_octal; /* JSON case */ |
| 20364 | + goto invalid_escape; /* JSON case */ |
| 20262 | 20365 | if (!(s->cur_func->js_mode & JS_MODE_STRICT) && sep != '`') |
| 20263 | 20366 | goto parse_escape; |
| 20264 | 20367 | if (c == '0' && !(p[1] >= '0' && p[1] <= '9')) { |
| 20265 | 20368 | p++; |
| 20266 | 20369 | c = '\0'; |
| 20267 | 20370 | } else { |
| 20268 | | − invalid_octal: |
| 20269 | | − if (do_throw) |
| 20270 | | − js_parse_error(s, "invalid octal syntax in strict mode"); |
| 20371 | + if (c >= '8' || sep == '`') { |
| 20372 | + /* Note: according to ES2021, \8 and \9 are not |
| 20373 | + accepted in strict mode or in templates. */ |
| 20374 | + goto invalid_escape; |
| 20375 | + } else { |
| 20376 | + if (do_throw) |
| 20377 | + js_parse_error(s, "octal escape sequences are not allowed in strict mode"); |
| 20378 | + } |
| 20271 | 20379 | goto fail; |
| 20272 | 20380 | } |
| 20273 | 20381 | } else if (c >= 0x80) { |
| @@ -20284,6 +20392,7 @@ static __exception int js_parse_string(JSParseState *s, int sep, · 10 unmodified lines |
| 20284 | 20392 | parse_escape: |
| 20285 | 20393 | ret = lre_parse_escape(&p, TRUE); |
| 20286 | 20394 | if (ret == -1) { |
| 20395 | + invalid_escape: |
| 20287 | 20396 | if (do_throw) |
| 20288 | 20397 | js_parse_error(s, "malformed escape sequence in string literal"); |
| 20289 | 20398 | goto fail; |
| @@ -20634,8 +20743,20 @@ static __exception int next_token(JSParseState *s) · 344 unmodified lines |
| 20634 | 20743 | } |
| 20635 | 20744 | } |
| 20636 | 20745 | goto def_token; |
| 20637 | | − case 'a' ... 'z': |
| 20638 | | − case 'A' ... 'Z': |
| 20746 | + case 'a': case 'b': case 'c': case 'd': |
| 20747 | + case 'e': case 'f': case 'g': case 'h': |
| 20748 | + case 'i': case 'j': case 'k': case 'l': |
| 20749 | + case 'm': case 'n': case 'o': case 'p': |
| 20750 | + case 'q': case 'r': case 's': case 't': |
| 20751 | + case 'u': case 'v': case 'w': case 'x': |
| 20752 | + case 'y': case 'z': |
| 20753 | + case 'A': case 'B': case 'C': case 'D': |
| 20754 | + case 'E': case 'F': case 'G': case 'H': |
| 20755 | + case 'I': case 'J': case 'K': case 'L': |
| 20756 | + case 'M': case 'N': case 'O': case 'P': |
| 20757 | + case 'Q': case 'R': case 'S': case 'T': |
| 20758 | + case 'U': case 'V': case 'W': case 'X': |
| 20759 | + case 'Y': case 'Z': |
| 20639 | 20760 | case '_': |
| 20640 | 20761 | case '$': |
| 20641 | 20762 | /* identifier */ |
| @@ -20717,7 +20838,9 @@ static __exception int next_token(JSParseState *s) · 75 unmodified lines |
| 20717 | 20838 | goto fail; |
| 20718 | 20839 | } |
| 20719 | 20840 | goto parse_number; |
| 20720 | | − case '1' ... '9': |
| 20841 | + case '1': case '2': case '3': case '4': |
| 20842 | + case '5': case '6': case '7': case '8': |
| 20843 | + case '9': |
| 20721 | 20844 | /* number */ |
| 20722 | 20845 | parse_number: |
| 20723 | 20846 | { |
| @@ -20887,8 +21010,13 @@ static __exception int next_token(JSParseState *s) · 163 unmodified lines |
| 20887 | 21010 | p += 2; |
| 20888 | 21011 | s->token.val = TOK_AND_ASSIGN; |
| 20889 | 21012 | } else if (p[1] == '&') { |
| 20890 | | − p += 2; |
| 20891 | | − s->token.val = TOK_LAND; |
| 21013 | + if (p[2] == '=') { |
| 21014 | + p += 3; |
| 21015 | + s->token.val = TOK_LAND_ASSIGN; |
| 21016 | + } else { |
| 21017 | + p += 2; |
| 21018 | + s->token.val = TOK_LAND; |
| 21019 | + } |
| 20892 | 21020 | } else { |
| 20893 | 21021 | goto def_token; |
| 20894 | 21022 | } |
| @@ -20934,16 +21062,26 @@ static __exception int next_token(JSParseState *s) · 39 unmodified lines |
| 20934 | 21062 | p += 2; |
| 20935 | 21063 | s->token.val = TOK_OR_ASSIGN; |
| 20936 | 21064 | } else if (p[1] == '|') { |
| 20937 | | − p += 2; |
| 20938 | | − s->token.val = TOK_LOR; |
| 21065 | + if (p[2] == '=') { |
| 21066 | + p += 3; |
| 21067 | + s->token.val = TOK_LOR_ASSIGN; |
| 21068 | + } else { |
| 21069 | + p += 2; |
| 21070 | + s->token.val = TOK_LOR; |
| 21071 | + } |
| 20939 | 21072 | } else { |
| 20940 | 21073 | goto def_token; |
| 20941 | 21074 | } |
| 20942 | 21075 | break; |
| 20943 | 21076 | case '?': |
| 20944 | 21077 | if (p[1] == '?') { |
| 20945 | | − p += 2; |
| 20946 | | − s->token.val = TOK_DOUBLE_QUESTION_MARK; |
| 21078 | + if (p[2] == '=') { |
| 21079 | + p += 3; |
| 21080 | + s->token.val = TOK_DOUBLE_QUESTION_MARK_ASSIGN; |
| 21081 | + } else { |
| 21082 | + p += 2; |
| 21083 | + s->token.val = TOK_DOUBLE_QUESTION_MARK; |
| 21084 | + } |
| 20947 | 21085 | } else if (p[1] == '.' && !(p[2] >= '0' && p[2] <= '9')) { |
| 20948 | 21086 | p += 2; |
| 20949 | 21087 | s->token.val = TOK_QUESTION_MARK_DOT; |
| @@ -21135,8 +21273,20 @@ static __exception int json_next_token(JSParseState *s) · 185 unmodified lines |
| 21135 | 21273 | goto def_token; |
| 21136 | 21274 | } |
| 21137 | 21275 | break; |
| 21138 | | − case 'a' ... 'z': |
| 21139 | | − case 'A' ... 'Z': |
| 21276 | + case 'a': case 'b': case 'c': case 'd': |
| 21277 | + case 'e': case 'f': case 'g': case 'h': |
| 21278 | + case 'i': case 'j': case 'k': case 'l': |
| 21279 | + case 'm': case 'n': case 'o': case 'p': |
| 21280 | + case 'q': case 'r': case 's': case 't': |
| 21281 | + case 'u': case 'v': case 'w': case 'x': |
| 21282 | + case 'y': case 'z': |
| 21283 | + case 'A': case 'B': case 'C': case 'D': |
| 21284 | + case 'E': case 'F': case 'G': case 'H': |
| 21285 | + case 'I': case 'J': case 'K': case 'L': |
| 21286 | + case 'M': case 'N': case 'O': case 'P': |
| 21287 | + case 'Q': case 'R': case 'S': case 'T': |
| 21288 | + case 'U': case 'V': case 'W': case 'X': |
| 21289 | + case 'Y': case 'Z': |
| 21140 | 21290 | case '_': |
| 21141 | 21291 | case '$': |
| 21142 | 21292 | /* identifier : only pure ascii characters are accepted */ |
| @@ -21161,7 +21311,9 @@ static __exception int json_next_token(JSParseState *s) · 18 unmodified lines |
| 21161 | 21311 | if (!is_digit(p[1])) |
| 21162 | 21312 | goto def_token; |
| 21163 | 21313 | goto parse_number; |
| 21164 | | − case '1' ... '9': |
| 21314 | + case '1': case '2': case '3': case '4': |
| 21315 | + case '5': case '6': case '7': case '8': |
| 21316 | + case '9': |
| 21165 | 21317 | /* number */ |
| 21166 | 21318 | parse_number: |
| 21167 | 21319 | { |
| @@ -23267,15 +23419,6 @@ static BOOL has_with_scope(JSFunctionDef *s, int scope_level) · 2099 unmodified lines |
| 23267 | 23419 | return FALSE; |
| 23268 | 23420 | } |
| 23269 | 23421 | |
| 23270 | | −typedef struct JSLValue { |
| 23271 | | − int opcode; |
| 23272 | | − int scope; |
| 23273 | | − int label; |
| 23274 | | − int depth; |
| 23275 | | − int tok; |
| 23276 | | − JSAtom name; |
| 23277 | | −} JSLValue; |
| 23278 | | − |
| 23279 | 23422 | static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope, |
| 23280 | 23423 | JSAtom *pname, int *plabel, int *pdepth, BOOL keep, |
| 23281 | 23424 | int tok) |
| @@ -23400,84 +23543,112 @@ static __exception int get_lvalue(JSParseState *s, int *popcode, int *pscope, · 118 unmodified lines |
| 23400 | 23543 | return 0; |
| 23401 | 23544 | } |
| 23402 | 23545 | |
| 23403 | | −/* if special = TRUE: specific post inc/dec case */ |
| 23404 | | −/* name has a live reference */ |
| 23546 | +typedef enum { |
| 23547 | + PUT_LVALUE_NOKEEP, /* [depth] v -> */ |
| 23548 | + PUT_LVALUE_NOKEEP_DEPTH, /* [depth] v -> , keep depth (currently |
| 23549 | + just disable optimizations) */ |
| 23550 | + PUT_LVALUE_KEEP_TOP, /* [depth] v -> v */ |
| 23551 | + PUT_LVALUE_KEEP_SECOND, /* [depth] v0 v -> v0 */ |
| 23552 | + PUT_LVALUE_NOKEEP_BOTTOM, /* v [depth] -> */ |
| 23553 | +} PutLValueEnum; |
| 23554 | + |
| 23555 | +/* name has a live reference. 'is_let' is only used with opcode = |
| 23556 | + OP_scope_get_var which is never generated by get_lvalue(). */ |
| 23405 | 23557 | static void put_lvalue(JSParseState *s, int opcode, int scope, |
| 23406 | | − JSAtom name, int label, BOOL special) |
| 23558 | + JSAtom name, int label, PutLValueEnum special, |
| 23559 | + BOOL is_let) |
| 23407 | 23560 | { |
| 23408 | 23561 | switch(opcode) { |
| 23409 | 23562 | case OP_get_field: |
| 23410 | | − if (!special) |
| 23411 | | − emit_op(s, OP_insert2); /* obj v -> v obj v */ |
| 23412 | | − else |
| 23413 | | − emit_op(s, OP_perm3); /* obj v0 v -> v0 obj v */ |
| 23414 | | − emit_op(s, OP_put_field); |
| 23415 | | − emit_u32(s, name); /* name has refcount */ |
| 23416 | | − break; |
| 23417 | 23563 | case OP_scope_get_private_field: |
| 23418 | | − if (!special) |
| 23564 | + /* depth = 1 */ |
| 23565 | + switch(special) { |
| 23566 | + case PUT_LVALUE_NOKEEP: |
| 23567 | + case PUT_LVALUE_NOKEEP_DEPTH: |
| 23568 | + break; |
| 23569 | + case PUT_LVALUE_KEEP_TOP: |
| 23419 | 23570 | emit_op(s, OP_insert2); /* obj v -> v obj v */ |
| 23420 | | − else |
| 23571 | + break; |
| 23572 | + case PUT_LVALUE_KEEP_SECOND: |
| 23421 | 23573 | emit_op(s, OP_perm3); /* obj v0 v -> v0 obj v */ |
| 23422 | | − emit_op(s, OP_scope_put_private_field); |
| 23423 | | − emit_u32(s, name); /* name has refcount */ |
| 23424 | | − emit_u16(s, scope); |
| 23574 | + break; |
| 23575 | + case PUT_LVALUE_NOKEEP_BOTTOM: |
| 23576 | + emit_op(s, OP_swap); |
| 23577 | + break; |
| 23578 | + default: |
| 23579 | + abort(); |
| 23580 | + } |
| 23425 | 23581 | break; |
| 23426 | 23582 | case OP_get_array_el: |
| 23427 | | − if (!special) |
| 23428 | | − emit_op(s, OP_insert3); /* obj prop v -> v obj prop v */ |
| 23429 | | − else |
| 23430 | | − emit_op(s, OP_perm4); /* obj prop v0 v -> v0 obj prop v */ |
| 23431 | | − emit_op(s, OP_put_array_el); |
| 23432 | | − break; |
| 23433 | 23583 | case OP_get_ref_value: |
| 23434 | | − JS_FreeAtom(s->ctx, name); |
| 23435 | | − emit_label(s, label); |
| 23436 | | − if (!special) |
| 23584 | + /* depth = 2 */ |
| 23585 | + if (opcode == OP_get_ref_value) { |
| 23586 | + JS_FreeAtom(s->ctx, name); |
| 23587 | + emit_label(s, label); |
| 23588 | + } |
| 23589 | + switch(special) { |
| 23590 | + case PUT_LVALUE_NOKEEP: |
| 23591 | + emit_op(s, OP_nop); /* will trigger optimization */ |
| 23592 | + break; |
| 23593 | + case PUT_LVALUE_NOKEEP_DEPTH: |
| 23594 | + break; |
| 23595 | + case PUT_LVALUE_KEEP_TOP: |
| 23437 | 23596 | emit_op(s, OP_insert3); /* obj prop v -> v obj prop v */ |
| 23438 | | − else |
| 23597 | + break; |
| 23598 | + case PUT_LVALUE_KEEP_SECOND: |
| 23439 | 23599 | emit_op(s, OP_perm4); /* obj prop v0 v -> v0 obj prop v */ |
| 23440 | | − emit_op(s, OP_put_ref_value); |
| 23600 | + break; |
| 23601 | + case PUT_LVALUE_NOKEEP_BOTTOM: |
| 23602 | + emit_op(s, OP_rot3l); |
| 23603 | + break; |
| 23604 | + default: |
| 23605 | + abort(); |
| 23606 | + } |
| 23441 | 23607 | break; |
| 23442 | 23608 | case OP_get_super_value: |
| 23443 | | − if (!special) |
| 23609 | + /* depth = 3 */ |
| 23610 | + switch(special) { |
| 23611 | + case PUT_LVALUE_NOKEEP: |
| 23612 | + case PUT_LVALUE_NOKEEP_DEPTH: |
| 23613 | + break; |
| 23614 | + case PUT_LVALUE_KEEP_TOP: |
| 23444 | 23615 | emit_op(s, OP_insert4); /* this obj prop v -> v this obj prop v */ |
| 23445 | | − else |
| 23616 | + break; |
| 23617 | + case PUT_LVALUE_KEEP_SECOND: |
| 23446 | 23618 | emit_op(s, OP_perm5); /* this obj prop v0 v -> v0 this obj prop v */ |
| 23447 | | − emit_op(s, OP_put_super_value); |
| 23619 | + break; |
| 23620 | + case PUT_LVALUE_NOKEEP_BOTTOM: |
| 23621 | + emit_op(s, OP_rot4l); |
| 23622 | + break; |
| 23623 | + default: |
| 23624 | + abort(); |
| 23625 | + } |
| 23448 | 23626 | break; |
| 23449 | 23627 | default: |
| 23450 | | − abort(); |
| 23628 | + break; |
| 23451 | 23629 | } |
| 23452 | | −} |
| 23453 | | − |
| 23454 | | −static void put_lvalue_nokeep(JSParseState *s, int opcode, int scope, |
| 23455 | | − JSAtom name, int label, int var_tok) |
| 23456 | | −{ |
| 23630 | + |
| 23457 | 23631 | switch(opcode) { |
| 23458 | 23632 | case OP_scope_get_var: /* val -- */ |
| 23459 | | − emit_op(s, (var_tok == TOK_CONST || var_tok == TOK_LET) ? |
| 23460 | | − OP_scope_put_var_init : OP_scope_put_var); |
| 23633 | + assert(special == PUT_LVALUE_NOKEEP || |
| 23634 | + special == PUT_LVALUE_NOKEEP_DEPTH); |
| 23635 | + emit_op(s, is_let ? OP_scope_put_var_init : OP_scope_put_var); |
| 23461 | 23636 | emit_u32(s, name); /* has refcount */ |
| 23462 | 23637 | emit_u16(s, scope); |
| 23463 | 23638 | break; |
| 23464 | | − case OP_get_field: /* obj val -- */ |
| 23639 | + case OP_get_field: |
| 23465 | 23640 | emit_op(s, OP_put_field); |
| 23466 | | − emit_u32(s, name); /* has refcount */ |
| 23641 | + emit_u32(s, name); /* name has refcount */ |
| 23467 | 23642 | break; |
| 23468 | 23643 | case OP_scope_get_private_field: |
| 23469 | 23644 | emit_op(s, OP_scope_put_private_field); |
| 23470 | | − emit_u32(s, name); /* has refcount */ |
| 23645 | + emit_u32(s, name); /* name has refcount */ |
| 23471 | 23646 | emit_u16(s, scope); |
| 23472 | 23647 | break; |
| 23473 | | − case OP_get_array_el: /* obj prop val -- */ |
| 23648 | + case OP_get_array_el: |
| 23474 | 23649 | emit_op(s, OP_put_array_el); |
| 23475 | 23650 | break; |
| 23476 | | − case OP_get_ref_value: /* obj prop val -- */ |
| 23477 | | − /* XXX: currently this reference is never optimized */ |
| 23478 | | − JS_FreeAtom(s->ctx, name); |
| 23479 | | − emit_label(s, label); |
| 23480 | | − //emit_op(s, OP_nop); /* emit 2 bytes for optimizer */ |
| 23651 | + case OP_get_ref_value: |
| 23481 | 23652 | emit_op(s, OP_put_ref_value); |
| 23482 | 23653 | break; |
| 23483 | 23654 | case OP_get_super_value: |
| @@ -23869,7 +24040,9 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, · 385 unmodified lines |
| 23869 | 24040 | emit_label(s, label_hasval); |
| 23870 | 24041 | } |
| 23871 | 24042 | /* store value into lvalue object */ |
| 23872 | | − put_lvalue_nokeep(s, opcode, scope, var_name, label_lvalue, tok); |
| 24043 | + put_lvalue(s, opcode, scope, var_name, label_lvalue, |
| 24044 | + PUT_LVALUE_NOKEEP_DEPTH, |
| 24045 | + (tok == TOK_CONST || tok == TOK_LET)); |
| 23873 | 24046 | if (s->token.val == '}') |
| 23874 | 24047 | break; |
| 23875 | 24048 | /* accept a trailing comma before the '}' */ |
| @@ -23969,8 +24142,9 @@ static int js_parse_destructuring_element(JSParseState *s, int tok, int is_arg, · 93 unmodified lines |
| 23969 | 24142 | emit_label(s, label_hasval); |
| 23970 | 24143 | } |
| 23971 | 24144 | /* store value into lvalue object */ |
| 23972 | | − put_lvalue_nokeep(s, opcode, scope, var_name, |
| 23973 | | − label_lvalue, tok); |
| 24145 | + put_lvalue(s, opcode, scope, var_name, |
| 24146 | + label_lvalue, PUT_LVALUE_NOKEEP_DEPTH, |
| 24147 | + (tok == TOK_CONST || tok == TOK_LET)); |
| 23974 | 24148 | } |
| 23975 | 24149 | if (s->token.val == ']') |
| 23976 | 24150 | break; |
| @@ -24786,7 +24960,8 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) · 809 unmodified lines |
| 24786 | 24960 | if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op)) |
| 24787 | 24961 | return -1; |
| 24788 | 24962 | emit_op(s, OP_dec + op - TOK_DEC); |
| 24789 | | − put_lvalue(s, opcode, scope, name, label, FALSE); |
| 24963 | + put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, |
| 24964 | + FALSE); |
| 24790 | 24965 | } |
| 24791 | 24966 | break; |
| 24792 | 24967 | case TOK_TYPEOF: |
| @@ -24834,7 +25009,8 @@ static __exception int js_parse_unary(JSParseState *s, int exponentiation_flag) · 41 unmodified lines |
| 24834 | 25009 | if (get_lvalue(s, &opcode, &scope, &name, &label, NULL, TRUE, op)) |
| 24835 | 25010 | return -1; |
| 24836 | 25011 | emit_op(s, OP_post_dec + op - TOK_DEC); |
| 24837 | | − put_lvalue(s, opcode, scope, name, label, TRUE); |
| 25012 | + put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_SECOND, |
| 25013 | + FALSE); |
| 24838 | 25014 | if (next_token(s)) |
| 24839 | 25015 | return -1; |
| 24840 | 25016 | } |
| @@ -25298,7 +25474,61 @@ static __exception int js_parse_assign_expr(JSParseState *s, BOOL in_accepted) · 457 unmodified lines |
| 25298 | 25474 | #endif |
| 25299 | 25475 | emit_op(s, op); |
| 25300 | 25476 | } |
| 25301 | | − put_lvalue(s, opcode, scope, name, label, FALSE); |
| 25477 | + put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_KEEP_TOP, FALSE); |
| 25478 | + } else if (op >= TOK_LAND_ASSIGN && op <= TOK_DOUBLE_QUESTION_MARK_ASSIGN) { |
| 25479 | + int label, label1, depth_lvalue, label2; |
| 25480 | + |
| 25481 | + if (next_token(s)) |
| 25482 | + return -1; |
| 25483 | + if (get_lvalue(s, &opcode, &scope, &name, &label, |
| 25484 | + &depth_lvalue, TRUE, op) < 0) |
| 25485 | + return -1; |
| 25486 | + |
| 25487 | + emit_op(s, OP_dup); |
| 25488 | + if (op == TOK_DOUBLE_QUESTION_MARK_ASSIGN) |
| 25489 | + emit_op(s, OP_is_undefined_or_null); |
| 25490 | + label1 = emit_goto(s, op == TOK_LOR_ASSIGN ? OP_if_true : OP_if_false, |
| 25491 | + -1); |
| 25492 | + emit_op(s, OP_drop); |
| 25493 | + |
| 25494 | + if (js_parse_assign_expr(s, in_accepted)) { |
| 25495 | + JS_FreeAtom(s->ctx, name); |
| 25496 | + return -1; |
| 25497 | + } |
| 25498 | + |
| 25499 | + if (opcode == OP_get_ref_value && name == name0) { |
| 25500 | + set_object_name(s, name); |
| 25501 | + } |
| 25502 | + |
| 25503 | + switch(depth_lvalue) { |
| 25504 | + case 1: |
| 25505 | + emit_op(s, OP_insert2); |
| 25506 | + break; |
| 25507 | + case 2: |
| 25508 | + emit_op(s, OP_insert3); |
| 25509 | + break; |
| 25510 | + case 3: |
| 25511 | + emit_op(s, OP_insert4); |
| 25512 | + break; |
| 25513 | + default: |
| 25514 | + abort(); |
| 25515 | + } |
| 25516 | + |
| 25517 | + /* XXX: we disable the OP_put_ref_value optimization by not |
| 25518 | + using put_lvalue() otherwise depth_lvalue is not correct */ |
| 25519 | + put_lvalue(s, opcode, scope, name, label, PUT_LVALUE_NOKEEP_DEPTH, |
| 25520 | + FALSE); |
| 25521 | + label2 = emit_goto(s, OP_goto, -1); |
| 25522 | + |
| 25523 | + emit_label(s, label1); |
| 25524 | + |
| 25525 | + /* remove the lvalue stack entries */ |
| 25526 | + while (depth_lvalue != 0) { |
| 25527 | + emit_op(s, OP_nip); |
| 25528 | + depth_lvalue--; |
| 25529 | + } |
| 25530 | + |
| 25531 | + emit_label(s, label2); |
| 25302 | 25532 | } |
| 25303 | 25533 | return 0; |
| 25304 | 25534 | } |
| @@ -25563,8 +25793,8 @@ static __exception int js_parse_var(JSParseState *s, BOOL in_accepted, int tok, · 258 unmodified lines |
| 25563 | 25793 | goto var_error; |
| 25564 | 25794 | } |
| 25565 | 25795 | set_object_name(s, name); |
| 25566 | | − put_lvalue(s, opcode, scope, name1, label, FALSE); |
| 25567 | | − emit_op(s, OP_drop); |
| 25796 | + put_lvalue(s, opcode, scope, name1, label, |
| 25797 | + PUT_LVALUE_NOKEEP, FALSE); |
| 25568 | 25798 | } else { |
| 25569 | 25799 | if (js_parse_assign_expr(s, in_accepted)) |
| 25570 | 25800 | goto var_error; |
| @@ -25751,29 +25981,14 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name, · 180 unmodified lines |
| 25751 | 25981 | if (js_parse_destructuring_element(s, 0, 0, TRUE, skip_bits & SKIP_HAS_ELLIPSIS, TRUE)) |
| 25752 | 25982 | return -1; |
| 25753 | 25983 | } else { |
| 25754 | | − int lvalue_label, depth; |
| 25984 | + int lvalue_label; |
| 25755 | 25985 | if (js_parse_postfix_expr(s, TRUE)) |
| 25756 | 25986 | return -1; |
| 25757 | 25987 | if (get_lvalue(s, &opcode, &scope, &var_name, &lvalue_label, |
| 25758 | | − &depth, FALSE, TOK_FOR)) |
| 25988 | + NULL, FALSE, TOK_FOR)) |
| 25759 | 25989 | return -1; |
| 25760 | | − /* swap value and lvalue object and store it into lvalue object */ |
| 25761 | | − /* enum_rec val [depth] -- enum_rec */ |
| 25762 | | − switch(depth) { |
| 25763 | | − case 1: |
| 25764 | | − emit_op(s, OP_swap); |
| 25765 | | − break; |
| 25766 | | − case 2: |
| 25767 | | − emit_op(s, OP_rot3l); |
| 25768 | | − break; |
| 25769 | | − case 3: |
| 25770 | | − emit_op(s, OP_rot4l); |
| 25771 | | − break; |
| 25772 | | − default: |
| 25773 | | − abort(); |
| 25774 | | − } |
| 25775 | | − put_lvalue_nokeep(s, opcode, scope, var_name, lvalue_label, |
| 25776 | | − TOK_FOR /* not used */); |
| 25990 | + put_lvalue(s, opcode, scope, var_name, lvalue_label, |
| 25991 | + PUT_LVALUE_NOKEEP_BOTTOM, FALSE); |
| 25777 | 25992 | } |
| 25778 | 25993 | var_name = JS_ATOM_NULL; |
| 25779 | 25994 | } |
| @@ -26933,32 +27148,20 @@ static JSModuleDef *js_find_loaded_module(JSContext *ctx, JSAtom name) · 1153 unmodified lines |
| 26933 | 27148 | |
| 26934 | 27149 | /* return NULL in case of exception (e.g. module could not be loaded) */ |
| 26935 | 27150 | static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx, |
| 26936 | | − JSAtom base_module_name, |
| 26937 | | − JSAtom module_name1) |
| 27151 | + const char *base_cname, |
| 27152 | + const char *cname1) |
| 26938 | 27153 | { |
| 26939 | 27154 | JSRuntime *rt = ctx->rt; |
| 26940 | 27155 | JSModuleDef *m; |
| 26941 | 27156 | char *cname; |
| 26942 | | − const char *base_cname, *cname1; |
| 26943 | 27157 | JSAtom module_name; |
| 26944 | 27158 | |
| 26945 | | − base_cname = JS_AtomToCString(ctx, base_module_name); |
| 26946 | | − if (!base_cname) |
| 26947 | | − return NULL; |
| 26948 | | − cname1 = JS_AtomToCString(ctx, module_name1); |
| 26949 | | − if (!cname1) { |
| 26950 | | − JS_FreeCString(ctx, base_cname); |
| 26951 | | − return NULL; |
| 26952 | | − } |
| 26953 | | − |
| 26954 | 27159 | if (!rt->module_normalize_func) { |
| 26955 | 27160 | cname = js_default_module_normalize_name(ctx, base_cname, cname1); |
| 26956 | 27161 | } else { |
| 26957 | 27162 | cname = rt->module_normalize_func(ctx, base_cname, cname1, |
| 26958 | 27163 | rt->module_loader_opaque); |
| 26959 | 27164 | } |
| 26960 | | − JS_FreeCString(ctx, base_cname); |
| 26961 | | − JS_FreeCString(ctx, cname1); |
| 26962 | 27165 | if (!cname) |
| 26963 | 27166 | return NULL; |
| 26964 | 27167 | |
| @@ -26992,6 +27195,27 @@ static JSModuleDef *js_host_resolve_imported_module(JSContext *ctx, · 27 unmodified lines |
| 26992 | 27195 | return m; |
| 26993 | 27196 | } |
| 26994 | 27197 | |
| 27198 | +static JSModuleDef *js_host_resolve_imported_module_atom(JSContext *ctx, |
| 27199 | + JSAtom base_module_name, |
| 27200 | + JSAtom module_name1) |
| 27201 | +{ |
| 27202 | + const char *base_cname, *cname; |
| 27203 | + JSModuleDef *m; |
| 27204 | + |
| 27205 | + base_cname = JS_AtomToCString(ctx, base_module_name); |
| 27206 | + if (!base_cname) |
| 27207 | + return NULL; |
| 27208 | + cname = JS_AtomToCString(ctx, module_name1); |
| 27209 | + if (!cname) { |
| 27210 | + JS_FreeCString(ctx, base_cname); |
| 27211 | + return NULL; |
| 27212 | + } |
| 27213 | + m = js_host_resolve_imported_module(ctx, base_cname, cname); |
| 27214 | + JS_FreeCString(ctx, base_cname); |
| 27215 | + JS_FreeCString(ctx, cname); |
| 27216 | + return m; |
| 27217 | +} |
| 27218 | + |
| 26995 | 27219 | typedef struct JSResolveEntry { |
| 26996 | 27220 | JSModuleDef *module; |
| 26997 | 27221 | JSAtom name; |
| @@ -27435,8 +27659,8 @@ static int js_resolve_module(JSContext *ctx, JSModuleDef *m) · 437 unmodified lines |
| 27435 | 27659 | /* resolve each requested module */ |
| 27436 | 27660 | for(i = 0; i < m->req_module_entries_count; i++) { |
| 27437 | 27661 | JSReqModuleEntry *rme = &m->req_module_entries[i]; |
| 27438 | | − m1 = js_host_resolve_imported_module(ctx, m->module_name, |
| 27439 | | − rme->module_name); |
| 27662 | + m1 = js_host_resolve_imported_module_atom(ctx, m->module_name, |
| 27663 | + rme->module_name); |
| 27440 | 27664 | if (!m1) |
| 27441 | 27665 | return -1; |
| 27442 | 27666 | rme->module = m1; |
| @@ -27711,8 +27935,9 @@ static int js_instantiate_module(JSContext *ctx, JSModuleDef *m) · 268 unmodified lines |
| 27711 | 27935 | return -1; |
| 27712 | 27936 | } |
| 27713 | 27937 | |
| 27714 | | −/* warning: the returned atom is not allocated */ |
| 27715 | | −static JSAtom js_get_script_or_module_name(JSContext *ctx) |
| 27938 | +/* return JS_ATOM_NULL if the name cannot be found. Only works with |
| 27939 | + not striped bytecode functions. */ |
| 27940 | +JSAtom JS_GetScriptOrModuleName(JSContext *ctx, int n_stack_levels) |
| 27716 | 27941 | { |
| 27717 | 27942 | JSStackFrame *sf; |
| 27718 | 27943 | JSFunctionBytecode *b; |
| @@ -27721,14 +27946,22 @@ static JSAtom js_get_script_or_module_name(JSContext *ctx) · 2 unmodified lines |
| 27721 | 27946 | function. It does not work for eval(). Need to add a |
| 27722 | 27947 | ScriptOrModule info in JSFunctionBytecode */ |
| 27723 | 27948 | sf = ctx->rt->current_stack_frame; |
| 27724 | | − assert(sf != NULL); |
| 27725 | | − assert(JS_VALUE_GET_TAG(sf->cur_func) == JS_TAG_OBJECT); |
| 27949 | + if (!sf) |
| 27950 | + return JS_ATOM_NULL; |
| 27951 | + while (n_stack_levels-- > 0) { |
| 27952 | + sf = sf->prev_frame; |
| 27953 | + if (!sf) |
| 27954 | + return JS_ATOM_NULL; |
| 27955 | + } |
| 27956 | + if (JS_VALUE_GET_TAG(sf->cur_func) != JS_TAG_OBJECT) |
| 27957 | + return JS_ATOM_NULL; |
| 27726 | 27958 | p = JS_VALUE_GET_OBJ(sf->cur_func); |
| 27727 | | − assert(js_class_has_bytecode(p->class_id)); |
| 27959 | + if (!js_class_has_bytecode(p->class_id)) |
| 27960 | + return JS_ATOM_NULL; |
| 27728 | 27961 | b = p->u.func.function_bytecode; |
| 27729 | 27962 | if (!b->has_debug) |
| 27730 | 27963 | return JS_ATOM_NULL; |
| 27731 | | − return b->debug.filename; |
| 27964 | + return JS_DupAtom(ctx, b->debug.filename); |
| 27732 | 27965 | } |
| 27733 | 27966 | |
| 27734 | 27967 | JSAtom JS_GetModuleName(JSContext *ctx, JSModuleDef *m) |
| @@ -27755,13 +27988,14 @@ static JSValue js_import_meta(JSContext *ctx) · 20 unmodified lines |
| 27755 | 27988 | JSAtom filename; |
| 27756 | 27989 | JSModuleDef *m; |
| 27757 | 27990 | |
| 27758 | | − filename = js_get_script_or_module_name(ctx); |
| 27991 | + filename = JS_GetScriptOrModuleName(ctx, 0); |
| 27759 | 27992 | if (filename == JS_ATOM_NULL) |
| 27760 | 27993 | goto fail; |
| 27761 | 27994 | |
| 27762 | 27995 | /* XXX: inefficient, need to add a module or script pointer in |
| 27763 | 27996 | JSFunctionBytecode */ |
| 27764 | 27997 | m = js_find_loaded_module(ctx, filename); |
| 27998 | + JS_FreeAtom(ctx, filename); |
| 27765 | 27999 | if (!m) { |
| 27766 | 28000 | fail: |
| 27767 | 28001 | JS_ThrowTypeError(ctx, "import.meta not supported in this context"); |
| @@ -27770,6 +28004,31 @@ static JSValue js_import_meta(JSContext *ctx) · 2 unmodified lines |
| 27770 | 28004 | return JS_GetImportMeta(ctx, m); |
| 27771 | 28005 | } |
| 27772 | 28006 | |
| 28007 | +/* used by os.Worker() and import() */ |
| 28008 | +JSModuleDef *JS_RunModule(JSContext *ctx, const char *basename, |
| 28009 | + const char *filename) |
| 28010 | +{ |
| 28011 | + JSModuleDef *m; |
| 28012 | + JSValue ret, func_obj; |
| 28013 | + |
| 28014 | + m = js_host_resolve_imported_module(ctx, basename, filename); |
| 28015 | + if (!m) |
| 28016 | + return NULL; |
| 28017 | + |
| 28018 | + if (js_resolve_module(ctx, m) < 0) { |
| 28019 | + js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED); |
| 28020 | + return NULL; |
| 28021 | + } |
| 28022 | + |
| 28023 | + /* Evaluate the module code */ |
| 28024 | + func_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); |
| 28025 | + ret = JS_EvalFunction(ctx, func_obj); |
| 28026 | + if (JS_IsException(ret)) |
| 28027 | + return NULL; |
| 28028 | + JS_FreeValue(ctx, ret); |
| 28029 | + return m; |
| 28030 | +} |
| 28031 | + |
| 27773 | 28032 | static JSValue js_dynamic_import_job(JSContext *ctx, |
| 27774 | 28033 | int argc, JSValueConst *argv) |
| 27775 | 28034 | { |
| @@ -27777,53 +28036,36 @@ static JSValue js_dynamic_import_job(JSContext *ctx, · 1 unmodified line |
| 27777 | 28036 | JSValueConst basename_val = argv[2]; |
| 27778 | 28037 | JSValueConst specifier = argv[3]; |
| 27779 | 28038 | JSModuleDef *m; |
| 27780 | | − JSAtom basename = JS_ATOM_NULL, filename; |
| 27781 | | − JSValue specifierString, ret, func_obj, err, ns; |
| 28039 | + const char *basename = NULL, *filename; |
| 28040 | + JSValue ret, err, ns; |
| 27782 | 28041 | |
| 27783 | 28042 | if (!JS_IsString(basename_val)) { |
| 27784 | 28043 | JS_ThrowTypeError(ctx, "no function filename for import()"); |
| 27785 | 28044 | goto exception; |
| 27786 | 28045 | } |
| 27787 | | − basename = JS_ValueToAtom(ctx, basename_val); |
| 27788 | | − if (basename == JS_ATOM_NULL) |
| 28046 | + basename = JS_ToCString(ctx, basename_val); |
| 28047 | + if (!basename) |
| 27789 | 28048 | goto exception; |
| 27790 | 28049 | |
| 27791 | | − specifierString = JS_ToString(ctx, specifier); |
| 27792 | | − if (JS_IsException(specifierString)) |
| 27793 | | − goto exception; |
| 27794 | | − filename = JS_ValueToAtom(ctx, specifierString); |
| 27795 | | − JS_FreeValue(ctx, specifierString); |
| 27796 | | − if (filename == JS_ATOM_NULL) |
| 28050 | + filename = JS_ToCString(ctx, specifier); |
| 28051 | + if (!filename) |
| 27797 | 28052 | goto exception; |
| 27798 | 28053 | |
| 27799 | | − m = js_host_resolve_imported_module(ctx, basename, filename); |
| 27800 | | − JS_FreeAtom(ctx, filename); |
| 27801 | | − if (!m) { |
| 27802 | | − goto exception; |
| 27803 | | − } |
| 27804 | | − |
| 27805 | | − if (js_resolve_module(ctx, m) < 0) { |
| 27806 | | − js_free_modules(ctx, JS_FREE_MODULE_NOT_RESOLVED); |
| 27807 | | − goto exception; |
| 27808 | | − } |
| 27809 | | − |
| 27810 | | − /* Evaluate the module code */ |
| 27811 | | − func_obj = JS_DupValue(ctx, JS_MKPTR(JS_TAG_MODULE, m)); |
| 27812 | | − ret = JS_EvalFunction(ctx, func_obj); |
| 27813 | | − if (JS_IsException(ret)) |
| 28054 | + m = JS_RunModule(ctx, basename, filename); |
| 28055 | + JS_FreeCString(ctx, filename); |
| 28056 | + if (!m) |
| 27814 | 28057 | goto exception; |
| 27815 | | − JS_FreeValue(ctx, ret); |
| 27816 | 28058 | |
| 27817 | 28059 | /* return the module namespace */ |
| 27818 | 28060 | ns = js_get_module_ns(ctx, m); |
| 27819 | | − if (JS_IsException(ret)) |
| 28061 | + if (JS_IsException(ns)) |
| 27820 | 28062 | goto exception; |
| 27821 | 28063 | |
| 27822 | 28064 | ret = JS_Call(ctx, resolving_funcs[0], JS_UNDEFINED, |
| 27823 | 28065 | 1, (JSValueConst *)&ns); |
| 27824 | 28066 | JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */ |
| 27825 | 28067 | JS_FreeValue(ctx, ns); |
| 27826 | | − JS_FreeAtom(ctx, basename); |
| 28068 | + JS_FreeCString(ctx, basename); |
| 27827 | 28069 | return JS_UNDEFINED; |
| 27828 | 28070 | exception: |
| 27829 | 28071 | |
| @@ -27832,7 +28074,7 @@ static JSValue js_dynamic_import_job(JSContext *ctx, · 2 unmodified lines |
| 27832 | 28074 | 1, (JSValueConst *)&err); |
| 27833 | 28075 | JS_FreeValue(ctx, ret); /* XXX: what to do if exception ? */ |
| 27834 | 28076 | JS_FreeValue(ctx, err); |
| 27835 | | − JS_FreeAtom(ctx, basename); |
| 28077 | + JS_FreeCString(ctx, basename); |
| 27836 | 28078 | return JS_UNDEFINED; |
| 27837 | 28079 | } |
| 27838 | 28080 | |
| @@ -27842,11 +28084,12 @@ static JSValue js_dynamic_import(JSContext *ctx, JSValueConst specifier) · 3 unmodified lines |
| 27842 | 28084 | JSValue promise, resolving_funcs[2], basename_val; |
| 27843 | 28085 | JSValueConst args[4]; |
| 27844 | 28086 | |
| 27845 | | − basename = js_get_script_or_module_name(ctx); |
| 28087 | + basename = JS_GetScriptOrModuleName(ctx, 0); |
| 27846 | 28088 | if (basename == JS_ATOM_NULL) |
| 27847 | 28089 | basename_val = JS_NULL; |
| 27848 | 28090 | else |
| 27849 | 28091 | basename_val = JS_AtomToValue(ctx, basename); |
| 28092 | + JS_FreeAtom(ctx, basename); |
| 27850 | 28093 | if (JS_IsException(basename_val)) |
| 27851 | 28094 | return basename_val; |
| 27852 | 28095 | |
| @@ -28957,7 +29200,7 @@ static BOOL can_opt_put_ref_value(const uint8_t *bc_buf, int pos) · 1104 unmodified lines |
| 28957 | 29200 | return (bc_buf[pos + 1] == OP_put_ref_value && |
| 28958 | 29201 | (opcode == OP_insert3 || |
| 28959 | 29202 | opcode == OP_perm4 || |
| 28960 | | − //opcode == OP_nop || |
| 29203 | + opcode == OP_nop || |
| 28961 | 29204 | opcode == OP_rot3l)); |
| 28962 | 29205 | } |
| 28963 | 29206 | |
| @@ -28967,7 +29210,7 @@ static BOOL can_opt_put_global_ref_value(const uint8_t *bc_buf, int pos) · 3 unmodified lines |
| 28967 | 29210 | return (bc_buf[pos + 1] == OP_put_ref_value && |
| 28968 | 29211 | (opcode == OP_insert3 || |
| 28969 | 29212 | opcode == OP_perm4 || |
| 28970 | | − //opcode == OP_nop || |
| 29213 | + opcode == OP_nop || |
| 28971 | 29214 | opcode == OP_rot3l)); |
| 28972 | 29215 | } |
| 28973 | 29216 | |
| @@ -29049,20 +29292,22 @@ static int optimize_scope_make_global_ref(JSContext *ctx, JSFunctionDef *s, · 75 unmodified lines |
| 29049 | 29292 | end_pos = label_pos + 2; |
| 29050 | 29293 | op = bc_buf[label_pos]; |
| 29051 | 29294 | if (is_strict) { |
| 29052 | | − switch(op) { |
| 29053 | | − case OP_insert3: |
| 29054 | | − op = OP_insert2; |
| 29055 | | − break; |
| 29056 | | − case OP_perm4: |
| 29057 | | − op = OP_perm3; |
| 29058 | | − break; |
| 29059 | | − case OP_rot3l: |
| 29060 | | − op = OP_swap; |
| 29061 | | − break; |
| 29062 | | − default: |
| 29063 | | − abort(); |
| 29295 | + if (op != OP_nop) { |
| 29296 | + switch(op) { |
| 29297 | + case OP_insert3: |
| 29298 | + op = OP_insert2; |
| 29299 | + break; |
| 29300 | + case OP_perm4: |
| 29301 | + op = OP_perm3; |
| 29302 | + break; |
| 29303 | + case OP_rot3l: |
| 29304 | + op = OP_swap; |
| 29305 | + break; |
| 29306 | + default: |
| 29307 | + abort(); |
| 29308 | + } |
| 29309 | + bc_buf[pos++] = op; |
| 29064 | 29310 | } |
| 29065 | | − bc_buf[pos++] = op; |
| 29066 | 29311 | } else { |
| 29067 | 29312 | if (op == OP_insert3) |
| 29068 | 29313 | bc_buf[pos++] = OP_dup; |
| @@ -31567,20 +31812,20 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) · 2498 unmodified lines |
| 31567 | 31812 | } |
| 31568 | 31813 | goto no_change; |
| 31569 | 31814 | |
| 31815 | +#if SHORT_OPCODES |
| 31570 | 31816 | case OP_typeof: |
| 31571 | 31817 | if (OPTIMIZE) { |
| 31572 | 31818 | /* simplify typeof tests */ |
| 31573 | 31819 | if (code_match(&cc, pos_next, OP_push_atom_value, M4(OP_strict_eq, OP_strict_neq, OP_eq, OP_neq), -1)) { |
| 31574 | 31820 | if (cc.line_num >= 0) line_num = cc.line_num; |
| 31575 | 31821 | int op1 = (cc.op == OP_strict_eq || cc.op == OP_eq) ? OP_strict_eq : OP_strict_neq; |
| 31576 | | −#if SHORT_OPCODES |
| 31577 | 31822 | int op2 = -1; |
| 31578 | 31823 | switch (cc.atom) { |
| 31579 | 31824 | case JS_ATOM_undefined: |
| 31580 | | − op2 = OP_is_undefined; |
| 31825 | + op2 = OP_typeof_is_undefined; |
| 31581 | 31826 | break; |
| 31582 | 31827 | case JS_ATOM_function: |
| 31583 | | − op2 = OP_is_function; |
| 31828 | + op2 = OP_typeof_is_function; |
| 31584 | 31829 | break; |
| 31585 | 31830 | } |
| 31586 | 31831 | if (op2 >= 0) { |
| @@ -31604,19 +31849,10 @@ static __exception int resolve_labels(JSContext *ctx, JSFunctionDef *s) · 17 unmodified lines |
| 31604 | 31849 | goto has_label; |
| 31605 | 31850 | } |
| 31606 | 31851 | } |
| 31607 | | −#endif |
| 31608 | | − if (cc.atom == JS_ATOM_undefined) { |
| 31609 | | − /* transform typeof(s) == "undefined" into s === void 0 */ |
| 31610 | | − add_pc2line_info(s, bc_out.size, line_num); |
| 31611 | | − dbuf_putc(&bc_out, OP_undefined); |
| 31612 | | − dbuf_putc(&bc_out, op1); |
| 31613 | | − JS_FreeAtom(ctx, cc.atom); |
| 31614 | | − pos_next = cc.pos; |
| 31615 | | − break; |
| 31616 | | − } |
| 31617 | 31852 | } |
| 31618 | 31853 | } |
| 31619 | 31854 | goto no_change; |
| 31855 | +#endif |
| 31620 | 31856 | |
| 31621 | 31857 | default: |
| 31622 | 31858 | no_change: |
| @@ -37067,10 +37303,9 @@ static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val, · 5444 unmodified lines |
| 37067 | 37303 | int argc, JSValueConst *argv) |
| 37068 | 37304 | { |
| 37069 | 37305 | JSBoundFunction *bf; |
| 37070 | | − JSValue func_obj, name1; |
| 37306 | + JSValue func_obj, name1, len_val; |
| 37071 | 37307 | JSObject *p; |
| 37072 | | − int arg_count, i; |
| 37073 | | − uint32_t len1; |
| 37308 | + int arg_count, i, ret; |
| 37074 | 37309 | |
| 37075 | 37310 | if (check_function(ctx, this_val)) |
| 37076 | 37311 | return JS_EXCEPTION; |
| @@ -37093,6 +37328,44 @@ static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val, · 16 unmodified lines |
| 37093 | 37328 | } |
| 37094 | 37329 | p->u.bound_function = bf; |
| 37095 | 37330 | |
| 37331 | + /* XXX: the spec could be simpler by only using GetOwnProperty */ |
| 37332 | + ret = JS_GetOwnProperty(ctx, NULL, this_val, JS_ATOM_length); |
| 37333 | + if (ret < 0) |
| 37334 | + goto exception; |
| 37335 | + if (!ret) { |
| 37336 | + len_val = JS_NewInt32(ctx, 0); |
| 37337 | + } else { |
| 37338 | + len_val = JS_GetProperty(ctx, this_val, JS_ATOM_length); |
| 37339 | + if (JS_IsException(len_val)) |
| 37340 | + goto exception; |
| 37341 | + if (JS_VALUE_GET_TAG(len_val) == JS_TAG_INT) { |
| 37342 | + /* most common case */ |
| 37343 | + int len1 = JS_VALUE_GET_INT(len_val); |
| 37344 | + if (len1 <= arg_count) |
| 37345 | + len1 = 0; |
| 37346 | + else |
| 37347 | + len1 -= arg_count; |
| 37348 | + len_val = JS_NewInt32(ctx, len1); |
| 37349 | + } else if (JS_VALUE_GET_NORM_TAG(len_val) == JS_TAG_FLOAT64) { |
| 37350 | + double d = JS_VALUE_GET_FLOAT64(len_val); |
| 37351 | + if (isnan(d)) { |
| 37352 | + d = 0.0; |
| 37353 | + } else { |
| 37354 | + d = trunc(d); |
| 37355 | + if (d <= (double)arg_count) |
| 37356 | + d = 0.0; |
| 37357 | + else |
| 37358 | + d -= (double)arg_count; /* also converts -0 to +0 */ |
| 37359 | + } |
| 37360 | + len_val = JS_NewFloat64(ctx, d); |
| 37361 | + } else { |
| 37362 | + JS_FreeValue(ctx, len_val); |
| 37363 | + len_val = JS_NewInt32(ctx, 0); |
| 37364 | + } |
| 37365 | + } |
| 37366 | + JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, |
| 37367 | + len_val, JS_PROP_CONFIGURABLE); |
| 37368 | + |
| 37096 | 37369 | name1 = JS_GetProperty(ctx, this_val, JS_ATOM_name); |
| 37097 | 37370 | if (JS_IsException(name1)) |
| 37098 | 37371 | goto exception; |
| @@ -37105,15 +37378,6 @@ static JSValue js_function_bind(JSContext *ctx, JSValueConst this_val, · 6 unmodified lines |
| 37105 | 37378 | goto exception; |
| 37106 | 37379 | JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_name, name1, |
| 37107 | 37380 | JS_PROP_CONFIGURABLE); |
| 37108 | | − if (js_get_length32(ctx, &len1, this_val)) |
| 37109 | | − goto exception; |
| 37110 | | − if (len1 <= (uint32_t)arg_count) |
| 37111 | | − len1 = 0; |
| 37112 | | − else |
| 37113 | | − len1 -= arg_count; |
| 37114 | | − JS_DefinePropertyValue(ctx, func_obj, JS_ATOM_length, |
| 37115 | | − JS_NewUint32(ctx, len1), |
| 37116 | | − JS_PROP_CONFIGURABLE); |
| 37117 | 37381 | return func_obj; |
| 37118 | 37382 | exception: |
| 37119 | 37383 | JS_FreeValue(ctx, func_obj); |
| @@ -40455,10 +40719,6 @@ static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val, · 3335 unmodified lines |
| 40455 | 40719 | len = p->len; |
| 40456 | 40720 | if (len >= n) |
| 40457 | 40721 | return str; |
| 40458 | | − if (n > JS_STRING_LEN_MAX) { |
| 40459 | | − JS_ThrowInternalError(ctx, "string too long"); |
| 40460 | | − goto fail2; |
| 40461 | | − } |
| 40462 | 40722 | if (argc > 1 && !JS_IsUndefined(argv[1])) { |
| 40463 | 40723 | v = JS_ToString(ctx, argv[1]); |
| 40464 | 40724 | if (JS_IsException(v)) |
| @@ -40473,6 +40733,10 @@ static JSValue js_string_pad(JSContext *ctx, JSValueConst this_val, · 8 unmodified lines |
| 40473 | 40733 | p1 = NULL; |
| 40474 | 40734 | } |
| 40475 | 40735 | } |
| 40736 | + if (n > JS_STRING_LEN_MAX) { |
| 40737 | + JS_ThrowInternalError(ctx, "string too long"); |
| 40738 | + goto fail2; |
| 40739 | + } |
| 40476 | 40740 | if (string_buffer_init(ctx, b, n)) |
| 40477 | 40741 | goto fail3; |
| 40478 | 40742 | n -= len; |
| @@ -41932,14 +42196,11 @@ static JSValue js_regexp_exec(JSContext *ctx, JSValueConst this_val, · 1453 unmodified lines |
| 41932 | 42196 | if (JS_IsException(obj)) |
| 41933 | 42197 | goto fail; |
| 41934 | 42198 | prop_flags = JS_PROP_C_W_E | JS_PROP_THROW; |
| 41935 | | − group_name_ptr = NULL; |
| 41936 | | − if (re_flags & LRE_FLAG_NAMED_GROUPS) { |
| 41937 | | − uint32_t re_bytecode_len; |
| 42199 | + group_name_ptr = lre_get_groupnames(re_bytecode); |
| 42200 | + if (group_name_ptr) { |
| 41938 | 42201 | groups = JS_NewObjectProto(ctx, JS_NULL); |
| 41939 | 42202 | if (JS_IsException(groups)) |
| 41940 | 42203 | goto fail; |
| 41941 | | − re_bytecode_len = get_u32(re_bytecode + 3); |
| 41942 | | − group_name_ptr = (char *)(re_bytecode + 7 + re_bytecode_len); |
| 41943 | 42204 | } |
| 41944 | 42205 | |
| 41945 | 42206 | for(i = 0; i < capture_count; i++) { |
| @@ -43724,6 +43985,7 @@ static const JSCFunctionListEntry js_reflect_funcs[] = { · 1778 unmodified lines |
| 43724 | 43985 | JS_CFUNC_MAGIC_DEF("preventExtensions", 1, js_object_preventExtensions, 1 ), |
| 43725 | 43986 | JS_CFUNC_DEF("set", 3, js_reflect_set ), |
| 43726 | 43987 | JS_CFUNC_DEF("setPrototypeOf", 2, js_reflect_setPrototypeOf ), |
| 43988 | + JS_PROP_STRING_DEF("[Symbol.toStringTag]", "Reflect", JS_PROP_CONFIGURABLE ), |
| 43727 | 43989 | }; |
| 43728 | 43990 | |
| 43729 | 43991 | static const JSCFunctionListEntry js_reflect_obj[] = { |