Rework the core of class parsing/runtime semantic (#3598)

Changes:
 - Use the pre-scanner to provide information for the parser about the existence of the class constructor
 - The allocation of the super declarative environment is no longer needed
 - The VM frame context holds the information about the this binding status
 - Reduce the number of class related VM/CBC instructions
 - Improve ecma_op_function_{construct, call} to properly set new.target

JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
This commit is contained in:
Robert Fancsik
2020-03-16 14:37:47 +01:00
committed by GitHub
parent 56b9f098ab
commit bfd2639634
49 changed files with 1671 additions and 1490 deletions
@@ -73,7 +73,7 @@ ecma_op_new_array_object (ecma_length_t length) /**< length of the new array */
ecma_object_t *array_prototype_object_p = ecma_builtin_get (ECMA_BUILTIN_ID_ARRAY_PROTOTYPE);
#else /* !ENABLED (JERRY_BUILTIN_ARRAY) */
ecma_object_t *array_prototype_object_p = ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE);
#endif /* (ENABLED (JERRY_BUILTIN_ARRAY)) */
#endif /* ENABLED (JERRY_BUILTIN_ARRAY) */
ecma_object_t *object_p = ecma_create_object (array_prototype_object_p,
sizeof (ecma_extended_object_t),
@@ -733,7 +733,7 @@ ecma_op_array_species_create (ecma_object_t *original_array_p, /**< The object f
ecma_value_t len_val = ecma_make_uint32_value (length);
ecma_object_t *ctor_object_p = ecma_get_object_from_value (constructor);
ecma_value_t ret_val = ecma_op_function_construct (ctor_object_p,
ECMA_VALUE_UNDEFINED,
ctor_object_p,
&len_val,
1);
+1 -1
View File
@@ -98,7 +98,7 @@ ecma_op_eval_chars_buffer (const lit_utf8_byte_t *code_p, /**< code characters b
#endif /* ENABLED (JERRY_LINE_INFO) || ENABLED (JERRY_ERROR_MESSAGES) */
#if ENABLED (JERRY_ES2015)
ECMA_CLEAR_SUPER_EVAL_PARSER_OPTS ();
ECMA_CLEAR_LOCAL_PARSE_OPTS ();
/* If a direct eval is used inside the function the info should be propagated. */
if (JERRY_CONTEXT (current_new_target) != JERRY_CONTEXT_INVALID_NEW_TARGET
File diff suppressed because it is too large Load Diff
@@ -51,29 +51,8 @@ ecma_op_create_dynamic_function (const ecma_value_t *arguments_list_p,
ecma_parse_opts_t opts);
#if ENABLED (JERRY_ES2015)
void
ecma_op_set_super_called (ecma_object_t *lex_env_p);
bool
ecma_op_is_super_called (ecma_object_t *lex_env_p);
void
ecma_op_set_class_this_binding (ecma_object_t *lex_env_p, ecma_value_t this_binding);
ecma_value_t
ecma_op_get_class_this_binding (ecma_object_t *lex_env_p);
ecma_value_t
ecma_op_function_implicit_constructor_handler_cb (const ecma_value_t function_obj,
const ecma_value_t this_val,
const ecma_value_t args_p[],
const ecma_length_t args_count);
void
ecma_op_set_class_prototype (ecma_value_t completion_value, ecma_value_t this_arg);
ecma_object_t *
ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, ecma_builtin_id_t default_proto_id);
ecma_op_function_get_super_constructor (ecma_object_t *func_obj_p);
ecma_object_t *
ecma_op_create_generator_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p);
@@ -81,9 +60,13 @@ ecma_op_create_generator_function_object (ecma_object_t *scope_p, const ecma_com
ecma_object_t *
ecma_op_create_arrow_function_object (ecma_object_t *scope_p, const ecma_compiled_code_t *bytecode_data_p,
ecma_value_t this_binding);
bool
ecma_op_function_is_generator (ecma_object_t *func_obj_p);
#endif /* ENABLED (JERRY_ES2015) */
ecma_object_t *
ecma_op_get_prototype_from_constructor (ecma_object_t *ctor_obj_p, ecma_builtin_id_t default_proto_id);
ecma_value_t
ecma_op_function_has_instance (ecma_object_t *func_obj_p, ecma_value_t value);
@@ -92,7 +75,7 @@ ecma_op_function_call (ecma_object_t *func_obj_p, ecma_value_t this_arg_value,
const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len);
ecma_value_t
ecma_op_function_construct (ecma_object_t *func_obj_p, ecma_value_t this_arg_value,
ecma_op_function_construct (ecma_object_t *func_obj_p, ecma_object_t *new_target_p,
const ecma_value_t *arguments_list_p, ecma_length_t arguments_list_len);
ecma_property_t *
@@ -77,7 +77,7 @@ ecma_op_get_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environme
break;
}
#if ENABLED (JERRY_ES2015)
case ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND:
case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND:
{
break;
}
@@ -266,7 +266,7 @@ ecma_op_put_value_lex_env_base (ecma_object_t *lex_env_p, /**< lexical environme
break;
}
#if ENABLED (JERRY_ES2015)
case ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND:
case ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND:
{
break;
}
+138
View File
@@ -427,6 +427,144 @@ ecma_op_create_immutable_binding (ecma_object_t *lex_env_p, /**< lexical environ
prop_value_p->value = ecma_copy_value_if_not_object (value);
} /* ecma_op_create_immutable_binding */
#if ENABLED (JERRY_ES2015)
/**
* InitializeBinding operation.
*
* See also: ECMA-262 v6, 8.1.1.1.4
*/
void
ecma_op_initialize_binding (ecma_object_t *lex_env_p, /**< lexical environment */
ecma_string_t *name_p, /**< argument N */
ecma_value_t value) /**< argument V */
{
JERRY_ASSERT (lex_env_p != NULL
&& ecma_is_lexical_environment (lex_env_p));
JERRY_ASSERT (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_DECLARATIVE);
ecma_property_t *prop_p = ecma_find_named_property (lex_env_p, name_p);
JERRY_ASSERT (prop_p != NULL);
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (*prop_p) == ECMA_PROPERTY_TYPE_NAMEDDATA);
ecma_property_value_t *prop_value_p = ECMA_PROPERTY_VALUE_PTR (prop_p);
JERRY_ASSERT (prop_value_p->value == ECMA_VALUE_UNINITIALIZED);
prop_value_p->value = ecma_copy_value_if_not_object (value);
} /* ecma_op_initialize_binding */
/**
* BindThisValue operation for an empty 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 */
{
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_property_value_t *prop_value_p = ecma_create_named_data_property (lex_env_p,
prop_name_p,
ECMA_PROPERTY_FIXED,
NULL);
prop_value_p->value = this_binding;
} /* ecma_op_init_this_binding */
/**
* GetThisEnvironment operation.
*
* See also: ECMA-262 v6, 8.3.2
*
* @return property pointer for the internal [[ThisBindingValue]] property
*/
ecma_property_t *
ecma_op_get_this_property (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);
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);
if (prop_p != NULL)
{
return prop_p;
}
}
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 */
/**
* GetThisBinding operation.
*
* See also: ECMA-262 v6, 8.1.1.3.4
*
* @return ECMA_VALUE_ERROR - if the operation fails
* ecma-object - otherwise
*/
ecma_value_t
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_value_t this_value = ECMA_PROPERTY_VALUE_PTR (prop_p)->value;
if (this_value == ECMA_VALUE_UNINITIALIZED)
{
return ecma_raise_reference_error (ECMA_ERR_MSG ("Must call super constructor in derived class before "
"accessing 'this' or returning from it."));
}
ecma_ref_object (ecma_get_object_from_value (this_value));
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_ES2015) */
/**
* @}
* @}
+19
View File
@@ -66,6 +66,25 @@ ecma_value_t ecma_op_implicit_this_value (ecma_object_t *lex_env_p);
/* ECMA-262 v5, Table 18. Additional methods of Declarative Environment Records */
void ecma_op_create_immutable_binding (ecma_object_t *lex_env_p, ecma_string_t *name_p, ecma_value_t value);
#if ENABLED (JERRY_ES2015)
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);
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);
#endif /* ENABLED (JERRY_ES2015) */
/**
* @}
* @}
@@ -679,7 +679,7 @@ ecma_promise_new_capability (ecma_value_t constructor)
/* 6. */
ecma_value_t promise = ecma_op_function_construct (constructor_obj_p,
ECMA_VALUE_UNDEFINED,
constructor_obj_p,
&executor,
1);
ecma_deref_object (executor_p);
@@ -849,12 +849,12 @@ ecma_proxy_object_call (ecma_object_t *obj_p, /**< proxy object */
*/
ecma_value_t
ecma_proxy_object_construct (ecma_object_t *obj_p, /**< proxy object */
ecma_object_t *new_target_p, /**< new target */
const ecma_value_t *args_p, /**< argument list */
ecma_length_t argc, /**< number of arguments */
ecma_value_t new_target) /**< this argument to invoke the function */
ecma_length_t argc) /**< number of arguments */
{
JERRY_ASSERT (ECMA_OBJECT_IS_PROXY (obj_p));
JERRY_UNUSED_4 (obj_p, args_p, argc, new_target);
JERRY_UNUSED_4 (obj_p, new_target_p, args_p, argc);
return ecma_raise_type_error (ECMA_ERR_MSG ("UNIMPLEMENTED: Proxy.[[Construct]]"));
} /* ecma_proxy_object_construct */
@@ -106,9 +106,9 @@ ecma_proxy_object_call (ecma_object_t *obj_p,
ecma_value_t
ecma_proxy_object_construct (ecma_object_t *obj_p,
ecma_object_t *new_target_p,
const ecma_value_t *args_p,
ecma_length_t argc,
ecma_value_t new_target);
ecma_length_t argc);
#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
+41 -12
View File
@@ -21,6 +21,7 @@
#include "ecma-lcache.h"
#include "ecma-lex-env.h"
#include "ecma-objects.h"
#include "ecma-proxy-object.h"
#include "ecma-reference.h"
#include "jrt.h"
@@ -47,7 +48,7 @@ ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical
while (true)
{
#if ENABLED (JERRY_ES2015)
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND)
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND)
{
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);
@@ -79,27 +80,55 @@ ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, /**< starting lexical
#if ENABLED (JERRY_ES2015)
/**
* Resolve super reference.
* Perform GetThisEnvironment and GetSuperBase operations
*
* @return value of the reference
* See also: ECMAScript v6, 8.1.1.3.5
*
* @return ECMA_VALUE_ERROR - if the operation fails
* ECMA_VALUE_UNDEFINED - if the home object is null
* value of the [[HomeObject]].[[Prototype]] internal slot - otherwise
*/
ecma_object_t *
ecma_op_resolve_super_reference_value (ecma_object_t *lex_env_p) /**< starting lexical environment */
ecma_value_t
ecma_op_resolve_super_base (ecma_object_t *lex_env_p) /**< starting lexical environment */
{
JERRY_ASSERT (lex_env_p != NULL);
while (true)
{
JERRY_ASSERT (lex_env_p != NULL);
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND)
if (ecma_get_lex_env_type (lex_env_p) == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND)
{
return ecma_get_lex_env_binding_object (lex_env_p);
ecma_object_t *home_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u1.home_object_cp);
#if ENABLED (JERRY_ES2015_BUILTIN_PROXY)
if (ECMA_OBJECT_IS_PROXY (home_p))
{
return ecma_proxy_object_get_prototype_of (home_p);
}
#endif /* ENABLED (JERRY_ES2015_BUILTIN_PROXY) */
jmem_cpointer_t proto_cp = ecma_op_ordinary_object_get_prototype_of (home_p);
if (proto_cp == JMEM_CP_NULL)
{
return ECMA_VALUE_NULL;
}
ecma_object_t *proto_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, proto_cp);
ecma_ref_object (proto_p);
return ecma_make_object_value (proto_p);
}
JERRY_ASSERT (lex_env_p->u2.outer_reference_cp != JMEM_CP_NULL);
if (lex_env_p->u2.outer_reference_cp == JMEM_CP_NULL)
{
break;
}
lex_env_p = ECMA_GET_NON_NULL_POINTER (ecma_object_t, lex_env_p->u2.outer_reference_cp);
}
} /* ecma_op_resolve_super_reference_value */
return ECMA_VALUE_UNDEFINED;
} /* ecma_op_resolve_super_base */
/**
* Helper method for HasBindig operation
@@ -262,7 +291,7 @@ ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, /**< starting lexical
else
{
#if ENABLED (JERRY_ES2015)
JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_SUPER_OBJECT_BOUND);
JERRY_ASSERT (lex_env_type == ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND);
#else /* !ENABLED (JERRY_ES2015) */
JERRY_UNREACHABLE ();
#endif /* ENABLED (JERRY_ES2015) */
+1 -1
View File
@@ -29,7 +29,7 @@
ecma_object_t *ecma_op_resolve_reference_base (ecma_object_t *lex_env_p, ecma_string_t *name_p);
ecma_value_t ecma_op_resolve_reference_value (ecma_object_t *lex_env_p, ecma_string_t *name_p);
#if ENABLED (JERRY_ES2015)
ecma_object_t *ecma_op_resolve_super_reference_value (ecma_object_t *lex_env_p);
ecma_value_t ecma_op_resolve_super_base (ecma_object_t *lex_env_p);
ecma_value_t ecma_op_is_prop_unscopable (ecma_object_t *lex_env_p, ecma_string_t *prop_name_p);
#endif /* ENABLED (JERRY_ES2015) */
@@ -1696,7 +1696,7 @@ ecma_regexp_split_helper (ecma_value_t this_arg, /**< this value */
/* 13-14. */
ecma_value_t arguments[] = { this_arg, ecma_make_string_value (flags_str_p) };
ecma_value_t splitter = ecma_op_function_construct (constructor_obj_p, ECMA_VALUE_UNDEFINED, arguments, 2);
ecma_value_t splitter = ecma_op_function_construct (constructor_obj_p, constructor_obj_p, arguments, 2);
ecma_deref_ecma_string (flags_str_p);
ecma_deref_object (constructor_obj_p);
@@ -536,7 +536,7 @@ ecma_typedarray_create_object_with_length (ecma_length_t array_length, /**< leng
ecma_value_t byte_length_val = ecma_make_uint32_value (byte_length);
ecma_value_t new_arraybuffer = ecma_op_function_construct (ctor_proto_p,
ECMA_VALUE_UNDEFINED,
ctor_proto_p,
&byte_length_val,
1);
ecma_deref_object (ctor_proto_p);