diff --git a/jerry-core/ecma/base/ecma-gc.c b/jerry-core/ecma/base/ecma-gc.c index 3b6df8ca0..c5687cda6 100644 --- a/jerry-core/ecma/base/ecma-gc.c +++ b/jerry-core/ecma/base/ecma-gc.c @@ -197,9 +197,7 @@ ecma_gc_mark_properties (ecma_property_pair_t *property_pair_p) /**< property pa if (ecma_is_value_object (value)) { - ecma_object_t *value_obj_p = ecma_get_object_from_value (value); - - ecma_gc_set_object_visited (value_obj_p); + ecma_gc_set_object_visited (ecma_get_object_from_value (value)); } break; } @@ -225,6 +223,24 @@ ecma_gc_mark_properties (ecma_property_pair_t *property_pair_p) /**< property pa JERRY_ASSERT (ECMA_PROPERTY_GET_NAME_TYPE (property) == ECMA_DIRECT_STRING_MAGIC && property_pair_p->names_cp[index] >= LIT_INTERNAL_MAGIC_STRING_FIRST_DATA && property_pair_p->names_cp[index] < LIT_MAGIC_STRING__COUNT); + +#if ENABLED (JERRY_ESNEXT) + if (property_pair_p->names_cp[index] == LIT_INTERNAL_MAGIC_STRING_ENVIRONMENT_RECORD) + { + ecma_environment_record_t *environment_record_p; + environment_record_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_environment_record_t, + property_pair_p->values[index].value); + + if (environment_record_p->this_binding != ECMA_VALUE_UNINITIALIZED) + { + JERRY_ASSERT (ecma_is_value_object (environment_record_p->this_binding)); + ecma_gc_set_object_visited (ecma_get_object_from_value (environment_record_p->this_binding)); + } + + JERRY_ASSERT (ecma_is_value_object (environment_record_p->function_object)); + ecma_gc_set_object_visited (ecma_get_object_from_value (environment_record_p->function_object)); + } +#endif /* ENABLED (JERRY_ESNEXT) */ break; } default: @@ -1166,6 +1182,24 @@ ecma_gc_free_properties (ecma_object_t *object_p) /**< object */ /* Call the native's free callback. */ switch (name_cp) { +#if ENABLED (JERRY_ESNEXT) + case LIT_INTERNAL_MAGIC_STRING_ENVIRONMENT_RECORD: + { + ecma_environment_record_t *environment_record_p; + environment_record_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_environment_record_t, + prop_pair_p->values[i].value); + jmem_heap_free_block (environment_record_p, sizeof (ecma_environment_record_t)); + break; + } + case LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED: + { + ecma_value_t *compact_collection_p; + compact_collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_value_t, + prop_pair_p->values[i].value); + ecma_compact_collection_free (compact_collection_p); + break; + } +#endif /* ENABLED (JERRY_ESNEXT) */ #if ENABLED (JERRY_BUILTIN_WEAKMAP) || ENABLED (JERRY_BUILTIN_WEAKSET) case LIT_INTERNAL_MAGIC_STRING_WEAK_REFS: { @@ -1187,16 +1221,6 @@ ecma_gc_free_properties (ecma_object_t *object_p) /**< object */ break; } #endif /* ENABLED (JERRY_BUILTIN_WEAKMAP) || ENABLED (JERRY_BUILTIN_WEAKSET) */ -#if ENABLED (JERRY_ESNEXT) - case LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED: - { - ecma_value_t *compact_collection_p; - compact_collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_value_t, - prop_pair_p->values[i].value); - ecma_compact_collection_free (compact_collection_p); - break; - } -#endif /* ENABLED (JERRY_ESNEXT) */ default: { JERRY_ASSERT (name_cp == LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER); diff --git a/jerry-core/ecma/base/ecma-globals.h b/jerry-core/ecma/base/ecma-globals.h index e5a127f82..9ee1d9b23 100644 --- a/jerry-core/ecma/base/ecma-globals.h +++ b/jerry-core/ecma/base/ecma-globals.h @@ -319,6 +319,19 @@ typedef struct ecma_native_pointer_t struct ecma_native_pointer_t *next_p; /**< points to the next ecma_native_pointer_t element */ } ecma_native_pointer_t; +#if ENABLED (JERRY_ESNEXT) + +/** + * Representation for class constructor environment record. + */ +typedef struct +{ + ecma_value_t this_binding; /**< this binding */ + ecma_value_t function_object; /**< function object */ +} ecma_environment_record_t; + +#endif /* ENABLED (JERRY_ESNEXT) */ + /** * Property list: * The property list of an object is a chain list of various items. diff --git a/jerry-core/ecma/operations/ecma-function-object.c b/jerry-core/ecma/operations/ecma-function-object.c index 864ed56da..08f6e4cbd 100644 --- a/jerry-core/ecma/operations/ecma-function-object.c +++ b/jerry-core/ecma/operations/ecma-function-object.c @@ -972,7 +972,7 @@ ecma_op_function_call_simple (ecma_object_t *func_obj_p, /**< Function object */ lexical_this = ECMA_VALUE_UNINITIALIZED; } - ecma_op_init_this_binding (scope_p, lexical_this); + ecma_op_create_environment_record (scope_p, lexical_this, func_obj_p); } #endif /* ENABLED (JERRY_ESNEXT) */ diff --git a/jerry-core/ecma/operations/ecma-lex-env.c b/jerry-core/ecma/operations/ecma-lex-env.c index d2676b5c0..45ed0a0c8 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.c +++ b/jerry-core/ecma/operations/ecma-lex-env.c @@ -464,19 +464,29 @@ ecma_op_initialize_binding (ecma_object_t *lex_env_p, /**< lexical environment * * See also: ECMA-262 v6, 8.1.1.3.1 */ void -ecma_op_init_this_binding (ecma_object_t *lex_env_p, /**< lexical environment */ - ecma_value_t this_binding) /**< this binding value */ +ecma_op_create_environment_record (ecma_object_t *lex_env_p, /**< lexical environment */ + ecma_value_t this_binding, /**< this binding value */ + ecma_object_t *func_obj_p) /**< function object */ { JERRY_ASSERT (lex_env_p != NULL); JERRY_ASSERT (ecma_is_value_object (this_binding) || this_binding == ECMA_VALUE_UNINITIALIZED); - ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE); + ecma_environment_record_t *environment_record_p; + environment_record_p = (ecma_environment_record_t *) jmem_heap_alloc_block (sizeof (ecma_environment_record_t)); + + environment_record_p->this_binding = this_binding; + environment_record_p->function_object = ecma_make_object_value (func_obj_p); + + ecma_string_t *property_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ENVIRONMENT_RECORD); + + ecma_property_t *property_p; ecma_property_value_t *prop_value_p = ecma_create_named_data_property (lex_env_p, - prop_name_p, + property_name_p, ECMA_PROPERTY_FIXED, - NULL); - prop_value_p->value = this_binding; -} /* ecma_op_init_this_binding */ + &property_p); + ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p); + ECMA_SET_INTERNAL_VALUE_POINTER (prop_value_p->value, environment_record_p); +} /* ecma_op_create_environment_record */ /** * GetThisEnvironment operation. @@ -485,28 +495,61 @@ ecma_op_init_this_binding (ecma_object_t *lex_env_p, /**< lexical environment */ * * @return property pointer for the internal [[ThisBindingValue]] property */ -ecma_property_t * -ecma_op_get_this_property (ecma_object_t *lex_env_p) /**< lexical environment */ +ecma_environment_record_t * +ecma_op_get_environment_record (ecma_object_t *lex_env_p) /**< lexical environment */ { JERRY_ASSERT (lex_env_p != NULL); - ecma_string_t *prop_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE); + ecma_string_t *property_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_ENVIRONMENT_RECORD); while (true) { if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE) { - ecma_property_t *prop_p = ecma_find_named_property (lex_env_p, prop_name_p); + ecma_property_t *property_p = ecma_find_named_property (lex_env_p, property_name_p); - if (prop_p != NULL) + if (property_p != NULL) { - return prop_p; + ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p); + return ECMA_GET_INTERNAL_VALUE_POINTER (ecma_environment_record_t, property_value_p->value); } } JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL); lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp); } -} /* ecma_op_get_this_property */ +} /* ecma_op_get_environment_record */ + +/** + * Get the environment record [[ThisBindingStatus]] internal property. + * + * See also: ECMA-262 v6, 8.1.1.3 + * + * @return true - if the status is "initialzed" + * false - otherwise + */ +bool +ecma_op_this_binding_is_initialized (ecma_environment_record_t *environment_record_p) /**< environment record */ +{ + JERRY_ASSERT (environment_record_p != NULL); + + return environment_record_p->this_binding != ECMA_VALUE_UNINITIALIZED; +} /* ecma_op_this_binding_is_initialized */ + +/** + * BindThisValue operation. + * + * See also: ECMA-262 v6, 8.1.1.3.1 + */ +void +ecma_op_bind_this_value (ecma_environment_record_t *environment_record_p, /**< environment record */ + ecma_value_t this_binding) /**< this binding value */ +{ + JERRY_ASSERT (environment_record_p != NULL); + JERRY_ASSERT (ecma_is_value_object (this_binding)); + JERRY_ASSERT (!ecma_op_this_binding_is_initialized (environment_record_p)); + + environment_record_p->this_binding = this_binding; +} /* ecma_op_bind_this_value */ /** * GetThisBinding operation. @@ -521,10 +564,10 @@ ecma_op_get_this_binding (ecma_object_t *lex_env_p) /**< lexical environment */ { JERRY_ASSERT (lex_env_p != NULL); - ecma_property_t *prop_p = ecma_op_get_this_property (lex_env_p); - JERRY_ASSERT (prop_p != NULL); + ecma_environment_record_t *environment_record_p = ecma_op_get_environment_record (lex_env_p); + JERRY_ASSERT (environment_record_p != NULL); - ecma_value_t this_value = ECMA_PROPERTY_VALUE_PTR (prop_p)->value; + ecma_value_t this_value = environment_record_p->this_binding; if (this_value == ECMA_VALUE_UNINITIALIZED) { @@ -537,38 +580,6 @@ ecma_op_get_this_binding (ecma_object_t *lex_env_p) /**< lexical environment */ return this_value; } /* ecma_op_get_this_binding */ -/** - * BindThisValue operation. - * - * See also: ECMA-262 v6, 8.1.1.3.1 - */ -void -ecma_op_bind_this_value (ecma_property_t *prop_p, /**< [[ThisBindingValue]] internal property */ - ecma_value_t this_binding) /**< this binding value */ -{ - JERRY_ASSERT (prop_p != NULL); - JERRY_ASSERT (ecma_is_value_object (this_binding)); - JERRY_ASSERT (!ecma_op_this_binding_is_initialized (prop_p)); - - ECMA_PROPERTY_VALUE_PTR (prop_p)->value = this_binding; -} /* ecma_op_bind_this_value */ - -/** - * Get the environment record [[ThisBindingStatus]] internal property. - * - * See also: ECMA-262 v6, 8.1.1.3 - * - * @return true - if the status is "initialzed" - * false - otherwise - */ -bool -ecma_op_this_binding_is_initialized (ecma_property_t *prop_p) /**< [[ThisBindingValue]] internal property */ -{ - JERRY_ASSERT (prop_p != NULL); - - return ECMA_PROPERTY_VALUE_PTR (prop_p)->value != ECMA_VALUE_UNINITIALIZED; -} /* ecma_op_this_binding_is_initialized */ - #endif /* ENABLED (JERRY_ESNEXT) */ /** diff --git a/jerry-core/ecma/operations/ecma-lex-env.h b/jerry-core/ecma/operations/ecma-lex-env.h index d7618c1ec..f83540a8f 100644 --- a/jerry-core/ecma/operations/ecma-lex-env.h +++ b/jerry-core/ecma/operations/ecma-lex-env.h @@ -69,20 +69,13 @@ void ecma_op_create_immutable_binding (ecma_object_t *lex_env_p, ecma_string_t * #if ENABLED (JERRY_ESNEXT) void ecma_op_initialize_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, ecma_value_t value); -void -ecma_op_init_this_binding (ecma_object_t *lex_env_p, ecma_value_t this_binding); +void ecma_op_create_environment_record (ecma_object_t *lex_env_p, ecma_value_t this_binding, + ecma_object_t *func_obj_p); +ecma_environment_record_t *ecma_op_get_environment_record (ecma_object_t *lex_env_p); -ecma_property_t * -ecma_op_get_this_property (ecma_object_t *lex_env_p); - -bool -ecma_op_this_binding_is_initialized (ecma_property_t *prop_p); - -ecma_value_t -ecma_op_get_this_binding (ecma_object_t *lex_env_p); - -void -ecma_op_bind_this_value (ecma_property_t *prop_p, ecma_value_t this_binding); +bool ecma_op_this_binding_is_initialized (ecma_environment_record_t *environment_record_p); +void ecma_op_bind_this_value (ecma_environment_record_t *environment_record_p, ecma_value_t this_binding); +ecma_value_t ecma_op_get_this_binding (ecma_object_t *lex_env_p); #endif /* ENABLED (JERRY_ESNEXT) */ /** diff --git a/jerry-core/lit/lit-magic-strings.h b/jerry-core/lit/lit-magic-strings.h index c4c19c9fd..670263c8e 100644 --- a/jerry-core/lit/lit-magic-strings.h +++ b/jerry-core/lit/lit-magic-strings.h @@ -40,7 +40,6 @@ typedef enum LIT_INTERNAL_MAGIC_STRING_TYPEDARRAY_PROTOTYPE_VALUES, /**< %TypedArray%.prototype values and [@@iterator] routine */ LIT_INTERNAL_MAGIC_STRING_SET_PROTOTYPE_VALUES, /**< Set.prototype values, keys and [@@iterator] routines */ LIT_INTERNAL_MAGIC_STRING_MAP_PROTOTYPE_ENTRIES, /**< Map.prototype entries and [@@iterator] routines */ - LIT_INTERNAL_MAGIC_THIS_BINDING_VALUE, /**< FunctionEnvironmentRecord [[ThisBindingValue]] internal slot */ LIT_INTERNAL_MAGIC_PROMISE_CAPABILITY, /**< PromiseCapability record */ /* List of well known symbols */ LIT_GLOBAL_SYMBOL_HAS_INSTANCE, /**< @@hasInstance well known symbol */ @@ -65,8 +64,9 @@ typedef enum LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< native pointer info associated with an object */ LIT_INTERNAL_MAGIC_STRING_FIRST_DATA = LIT_INTERNAL_MAGIC_STRING_NATIVE_POINTER, /**< first index of special * data properties */ - LIT_INTERNAL_MAGIC_STRING_WEAK_REFS, /**< Weak references to the current object */ + LIT_INTERNAL_MAGIC_STRING_ENVIRONMENT_RECORD, /**< dynamic environment record needed by class constructors */ LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED, /**< computed class field name list */ + LIT_INTERNAL_MAGIC_STRING_WEAK_REFS, /**< Weak references to the current object */ LIT_MAGIC_STRING__COUNT /**< number of magic strings */ } lit_magic_string_id_t; diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index 854c5cdb1..13d14c1be 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -1557,9 +1557,9 @@ opfunc_form_super_reference (ecma_value_t **vm_stack_top_p, /**< current vm stac { if (CBC_FUNCTION_GET_TYPE (frame_ctx_p->shared_p->bytecode_header_p->status_flags) == CBC_FUNCTION_CONSTRUCTOR) { - ecma_property_t *prop_p = ecma_op_get_this_property (frame_ctx_p->lex_env_p); + ecma_environment_record_t *environment_record_p = ecma_op_get_environment_record (frame_ctx_p->lex_env_p); - if (!ecma_op_this_binding_is_initialized (prop_p)) + if (!ecma_op_this_binding_is_initialized (environment_record_p)) { return ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class before " "accessing 'this' or returning from it.")); diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 2eb7284eb..d6b7f67c5 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -528,17 +528,17 @@ static const uint8_t vm_error_byte_code_p[] = static ecma_object_t * vm_get_class_function (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ { - while (true) + JERRY_ASSERT (frame_ctx_p != NULL); + + if (frame_ctx_p->shared_p->status_flags & VM_FRAME_CTX_SHARED_NON_ARROW_FUNC) { - JERRY_ASSERT (frame_ctx_p != NULL); - - if (frame_ctx_p->shared_p->status_flags & VM_FRAME_CTX_SHARED_NON_ARROW_FUNC) - { - return VM_FRAME_CTX_GET_FUNCTION_OBJECT (frame_ctx_p); - } - - frame_ctx_p = frame_ctx_p->prev_context_p; + return VM_FRAME_CTX_GET_FUNCTION_OBJECT (frame_ctx_p); } + + ecma_environment_record_t *environment_record_p = ecma_op_get_environment_record (frame_ctx_p->lex_env_p); + + JERRY_ASSERT (environment_record_p != NULL); + return ecma_get_object_from_value (environment_record_p->function_object); } /* vm_get_class_function */ /** @@ -575,7 +575,7 @@ vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_value_t func_value = *(--frame_ctx_p->stack_top_p); ecma_value_t completion_value; - ecma_property_t *prop_p = ecma_op_get_this_property (frame_ctx_p->lex_env_p); + ecma_environment_record_t *environment_record_p = ecma_op_get_environment_record (frame_ctx_p->lex_env_p); if (!ecma_is_constructor (func_value)) { @@ -606,7 +606,7 @@ vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_free_value (proto_value); } - if (!ECMA_IS_VALUE_ERROR (completion_value) && ecma_op_this_binding_is_initialized (prop_p)) + if (!ECMA_IS_VALUE_ERROR (completion_value) && ecma_op_this_binding_is_initialized (environment_record_p)) { ecma_free_value (completion_value); completion_value = ecma_raise_reference_error (ECMA_ERR_MSG ("Super constructor may only be called once")); @@ -647,7 +647,7 @@ vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ } else { - ecma_op_bind_this_value (prop_p, completion_value); + ecma_op_bind_this_value (environment_record_p, completion_value); frame_ctx_p->this_binding = completion_value; frame_ctx_p->byte_code_p = byte_code_p; diff --git a/tests/jerry/es.next/class-fields5.js b/tests/jerry/es.next/class-fields5.js new file mode 100644 index 000000000..e11349971 --- /dev/null +++ b/tests/jerry/es.next/class-fields5.js @@ -0,0 +1,87 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +var count = 0 + +class C1 { + constructor() { + assert(++count === 3) + } + + a = (assert(++count === 2), 1.1) +} + +class C2 extends C1 { + constructor() { + var s = () => super() + + function g() { + assert(++count === 1) + eval("s()"); + } + + g(); + assert(++count === 5) + } + + b = (assert(++count === 4), "prop") +} + +var c = new C2 +assert(count === 5) +assert(c.a === 1.1) +assert(c.b === "prop") + +var o = {} +count = 0 + +class C3 extends C1 { + constructor() { + var s = () => () => eval("() => eval('super()')") + + function g() { + assert(++count === 1) + s()()() + } + + g(); + assert(++count === 5) + } + + b = (assert(++count === 4), o) +} + +c = new C3 +assert(count === 5) +assert(c.a === 1.1) +assert(c.b === o) + +var f +class C4 extends Array { + a = 6.6 + + constructor() { + f = () => super() + super() + } +} +c = new C4 +assert(c.a === 6.6) + +try { + f() + assert(false) +} catch(e) { + assert(e instanceof ReferenceError) +} diff --git a/tests/test262-es6-excludelist.xml b/tests/test262-es6-excludelist.xml index 03e3dc209..f77fa1980 100644 --- a/tests/test262-es6-excludelist.xml +++ b/tests/test262-es6-excludelist.xml @@ -244,7 +244,6 @@ No longer a SyntaxError in ES11 - diff --git a/tests/test262-esnext-excludelist.xml b/tests/test262-esnext-excludelist.xml index 63b488dec..4b81afec7 100644 --- a/tests/test262-esnext-excludelist.xml +++ b/tests/test262-esnext-excludelist.xml @@ -2897,7 +2897,6 @@ - @@ -5982,7 +5981,6 @@ -