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 @@
-