Implement environment record for class constructors (#4207)

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2020-10-12 13:13:38 +02:00
committed by GitHub
parent d317124650
commit 3c2a3f5dd9
11 changed files with 220 additions and 95 deletions
+37 -13
View File
@@ -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);
+13
View File
@@ -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.
@@ -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) */
+60 -49
View File
@@ -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) */
/**
+6 -13
View File
@@ -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) */
/**
+2 -2
View File
@@ -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;
+2 -2
View File
@@ -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."));
+12 -12
View File
@@ -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;
+87
View File
@@ -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)
}
-1
View File
@@ -244,7 +244,6 @@
<test id="language/asi/S7.9_A5.7_T1.js"><reason></reason></test>
<test id="language/block-scope/syntax/redeclaration-in-block/attempt-to-redeclare-function-declaration-with-function-declaration.js"><reason>No longer a SyntaxError in ES11</reason></test>
<test id="language/default-parameters/function-length.js"><reason></reason></test>
<test id="language/expressions/arrow-function/lexical-super-call-from-within-constructor.js"><reason></reason></test>
<test id="language/expressions/assignment/S11.13.1_A5_T1.js"><reason></reason></test>
<test id="language/expressions/assignment/S11.13.1_A5_T2.js"><reason></reason></test>
<test id="language/expressions/assignment/S11.13.1_A5_T3.js"><reason></reason></test>
-2
View File
@@ -2897,7 +2897,6 @@
<test id="language/expressions/arrow-function/dstr/obj-ptrn-rest-val-obj.js"><reason></reason></test>
<test id="language/expressions/arrow-function/eval-var-scope-syntax-err.js"><reason></reason></test>
<test id="language/expressions/arrow-function/length-dflt.js"><reason></reason></test>
<test id="language/expressions/arrow-function/lexical-super-call-from-within-constructor.js"><reason></reason></test>
<test id="language/expressions/arrow-function/name.js"><reason></reason></test>
<test id="language/expressions/arrow-function/param-dflt-yield-expr.js"><reason></reason></test>
<test id="language/expressions/assignment/S11.13.1_A5_T1.js"><reason></reason></test>
@@ -5982,7 +5981,6 @@
<test id="language/expressions/class/elements/direct-eval-err-contains-newtarget.js"><reason></reason></test>
<test id="language/expressions/class/elements/fields-anonymous-function-length.js"><reason></reason></test>
<test id="language/expressions/class/elements/fields-multiple-definitions-static-private-methods-proxy.js"><reason></reason></test>
<test id="language/expressions/class/elements/fields-run-once-on-double-super.js"><reason></reason></test>
<test id="language/expressions/class/elements/gen-private-method-static/yield-spread-arr-multiple.js"><reason></reason></test>
<test id="language/expressions/class/elements/gen-private-method-static/yield-spread-arr-single.js"><reason></reason></test>
<test id="language/expressions/class/elements/gen-private-method-static/yield-spread-obj.js"><reason></reason></test>