Initial implementation of class fields (#4191)

Missing features:
 - this binding in static fields are not supported
 - static field evaluation order is wrong
 - function names are not supported

JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com
This commit is contained in:
Zoltan Herczeg
2020-09-17 15:22:55 +02:00
committed by GitHub
parent 7345c83af7
commit d9653823ca
30 changed files with 1666 additions and 581 deletions
+119 -10
View File
@@ -959,6 +959,105 @@ opfunc_async_create_and_await (vm_frame_ctx_t *frame_ctx_p, /**< frame context *
return result;
} /* opfunc_async_create_and_await */
/**
* Initialize implicit class fields.
*
* @return ECMA_VALUE_ERROR - initialization fails
* ECMA_VALUE_UNDEFINED - otherwise
*/
ecma_value_t
ecma_op_init_class_fields (ecma_value_t function_object, /**< the function itself */
ecma_value_t this_val) /**< this_arg of the function */
{
JERRY_ASSERT (ecma_is_value_object (function_object));
JERRY_ASSERT (ecma_is_value_object (this_val));
ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_INIT);
ecma_object_t *function_object_p = ecma_get_object_from_value (function_object);
ecma_property_t *property_p = ecma_find_named_property (function_object_p, name_p);
if (property_p == NULL)
{
return ECMA_VALUE_UNDEFINED;
}
ecma_property_value_t *property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
ecma_value_t *computed_class_fields_p = NULL;
name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED);
ecma_property_t *class_field_property_p = ecma_find_named_property (function_object_p, name_p);
if (class_field_property_p != NULL)
{
ecma_property_value_t *class_field_property_value_p = ECMA_PROPERTY_VALUE_PTR (class_field_property_p);
computed_class_fields_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_value_t, class_field_property_value_p->value);
}
JERRY_ASSERT (ecma_op_is_callable (property_value_p->value));
ecma_extended_object_t *ext_function_p;
ext_function_p = (ecma_extended_object_t *) ecma_get_object_from_value (property_value_p->value);
ecma_object_t *scope_p = ECMA_GET_NON_NULL_POINTER_FROM_POINTER_TAG (ecma_object_t,
ext_function_p->u.function.scope_cp);
const ecma_compiled_code_t *bytecode_data_p = ecma_op_function_get_compiled_code (ext_function_p);
ecma_value_t *old_computed_class_fields_p = JERRY_CONTEXT (computed_class_fields_p);
JERRY_CONTEXT (computed_class_fields_p) = computed_class_fields_p;
ecma_value_t result = vm_run (bytecode_data_p, this_val, scope_p, NULL, 0);
JERRY_CONTEXT (computed_class_fields_p) = old_computed_class_fields_p;
JERRY_ASSERT (ECMA_IS_VALUE_ERROR (result) || result == ECMA_VALUE_UNDEFINED);
return result;
} /* ecma_op_init_class_fields */
ecma_value_t
ecma_op_add_computed_field (ecma_value_t class_object, /**< class object */
ecma_value_t name) /**< name of the property */
{
ecma_string_t *prop_name_p = ecma_op_to_property_key (name);
if (JERRY_UNLIKELY (prop_name_p == NULL))
{
return ECMA_VALUE_ERROR;
}
if (ecma_prop_name_is_symbol (prop_name_p))
{
name = ecma_make_symbol_value (prop_name_p);
}
else
{
name = ecma_make_string_value (prop_name_p);
}
ecma_string_t *name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED);
ecma_object_t *class_object_p = ecma_get_object_from_value (class_object);
ecma_property_t *property_p = ecma_find_named_property (class_object_p, name_p);
ecma_value_t *compact_collection_p;
ecma_property_value_t *property_value_p;
if (property_p == NULL)
{
property_value_p = ecma_create_named_data_property (class_object_p, name_p, ECMA_PROPERTY_FIXED, &property_p);
ECMA_CONVERT_DATA_PROPERTY_TO_INTERNAL_PROPERTY (property_p);
compact_collection_p = ecma_new_compact_collection ();
}
else
{
property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
compact_collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_value_t, property_value_p->value);
}
compact_collection_p = ecma_compact_collection_push_back (compact_collection_p, name);
ECMA_SET_INTERNAL_VALUE_POINTER (property_value_p->value, compact_collection_p);
return ECMA_VALUE_UNDEFINED;
} /* ecma_op_add_computed_field */
/**
* Implicit class constructor handler when the classHeritage is not present.
*
@@ -973,14 +1072,14 @@ ecma_op_implicit_constructor_handler_cb (const ecma_value_t function_obj, /**< t
const ecma_value_t args_p[], /**< argument list */
const uint32_t args_count) /**< argument number */
{
JERRY_UNUSED_4 (function_obj, this_val, args_p, args_count);
JERRY_UNUSED_2 (args_p, args_count);
if (JERRY_CONTEXT (current_new_target) == NULL)
{
return ecma_raise_type_error (ECMA_ERR_MSG ("Class constructor cannot be invoked without 'new'."));
}
return ECMA_VALUE_UNDEFINED;
return ecma_op_init_class_fields (function_obj, this_val);
} /* ecma_op_implicit_constructor_handler_cb */
/**
@@ -997,7 +1096,7 @@ ecma_op_implicit_constructor_handler_heritage_cb (const ecma_value_t function_ob
const ecma_value_t args_p[], /**< argument list */
const uint32_t args_count) /**< argument number */
{
JERRY_UNUSED_4 (function_obj, this_val, args_p, args_count);
JERRY_UNUSED (this_val);
if (JERRY_CONTEXT (current_new_target) == NULL)
{
@@ -1028,10 +1127,21 @@ ecma_op_implicit_constructor_handler_heritage_cb (const ecma_value_t function_ob
ecma_free_value (result);
result = ECMA_VALUE_ERROR;
}
else if (ecma_is_value_object (proto_value))
else
{
ECMA_SET_POINTER (ecma_get_object_from_value (result)->u2.prototype_cp,
ecma_get_object_from_value (proto_value));
if (ecma_is_value_object (proto_value))
{
ECMA_SET_POINTER (ecma_get_object_from_value (result)->u2.prototype_cp,
ecma_get_object_from_value (proto_value));
}
ecma_value_t fields_value = ecma_op_init_class_fields (function_obj, result);
if (ECMA_IS_VALUE_ERROR (fields_value))
{
ecma_free_value (result);
result = ECMA_VALUE_ERROR;
}
}
ecma_free_value (proto_value);
}
@@ -1302,10 +1412,9 @@ opfunc_set_class_attributes (ecma_object_t *obj_p, /**< object */
}
else
{
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_SPECIAL);
JERRY_ASSERT (property == ECMA_PROPERTY_TYPE_HASHMAP
|| property == ECMA_PROPERTY_TYPE_DELETED);
JERRY_ASSERT (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_SPECIAL
|| (ECMA_PROPERTY_GET_TYPE (property) == ECMA_PROPERTY_TYPE_INTERNAL
&& property_pair_p->names_cp[index] == LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED));
}
}
+6
View File
@@ -146,6 +146,12 @@ opfunc_async_generator_yield (ecma_extended_object_t *async_generator_object_p,
ecma_value_t
opfunc_async_create_and_await (vm_frame_ctx_t *frame_ctx_p, ecma_value_t value, uint16_t extra_flags);
ecma_value_t
ecma_op_init_class_fields (ecma_value_t function_object, ecma_value_t this_val);
ecma_value_t
ecma_op_add_computed_field (ecma_value_t class_object, ecma_value_t name);
ecma_value_t
opfunc_create_implicit_class_constructor (uint8_t opcode);
+72
View File
@@ -610,6 +610,18 @@ vm_super_call (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
ecma_collection_destroy (collection_p);
}
if (ecma_is_value_object (completion_value))
{
ecma_value_t current_function = ecma_make_object_value (JERRY_CONTEXT (current_function_obj_p));
ecma_value_t fields_value = ecma_op_init_class_fields (current_function, completion_value);
if (ECMA_IS_VALUE_ERROR (fields_value))
{
ecma_free_value (completion_value);
completion_value = ECMA_VALUE_ERROR;
}
}
ecma_free_value (func_value);
if (JERRY_UNLIKELY (ECMA_IS_VALUE_ERROR (completion_value)))
@@ -1787,6 +1799,16 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
}
goto free_left_value;
}
case VM_OC_ADD_COMPUTED_FIELD:
{
result = ecma_op_add_computed_field (stack_top_p[-2], left_value);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
goto free_left_value;
}
case VM_OC_COPY_DATA_PROPERTIES:
{
result = *(--stack_top_p);
@@ -1991,6 +2013,56 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
opfunc_finalize_class (frame_ctx_p, &stack_top_p, left_value);
goto free_left_value;
}
case VM_OC_SET_CLASS_FIELD_INIT:
{
ecma_string_t *property_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_INIT);
ecma_object_t *object_p = ecma_get_object_from_value (stack_top_p[-2]);
ecma_property_value_t *property_value_p = ecma_create_named_data_property (object_p,
property_name_p,
ECMA_PROPERTY_FIXED,
NULL);
property_value_p->value = left_value;
property_name_p = ecma_get_magic_string (LIT_INTERNAL_MAGIC_STRING_CLASS_FIELD_COMPUTED);
ecma_property_t *property_p = ecma_find_named_property (object_p, property_name_p);
if (property_p != NULL)
{
property_value_p = ECMA_PROPERTY_VALUE_PTR (property_p);
ecma_value_t *compact_collection_p = ECMA_GET_INTERNAL_VALUE_POINTER (ecma_value_t,
property_value_p->value);
compact_collection_p = ecma_compact_collection_shrink (compact_collection_p);
ECMA_SET_INTERNAL_VALUE_POINTER (property_value_p->value, compact_collection_p);
}
goto free_left_value;
}
case VM_OC_RUN_CLASS_FIELD_INIT:
{
result = ecma_op_init_class_fields (ecma_make_object_value (JERRY_CONTEXT (current_function_obj_p)),
frame_ctx_p->this_binding);
if (ECMA_IS_VALUE_ERROR (result))
{
goto error;
}
continue;
}
case VM_OC_SET_NEXT_COMPUTED_FIELD:
{
ecma_integer_value_t next_index = ecma_get_integer_from_value (stack_top_p[-2]) + 1;
stack_top_p[-2] = ecma_make_integer_value (next_index);
stack_top_p++;
ecma_value_t *computed_class_fields_p = JERRY_CONTEXT (computed_class_fields_p);
JERRY_ASSERT ((ecma_value_t) next_index < ECMA_COMPACT_COLLECTION_GET_SIZE (computed_class_fields_p));
result = stack_top_p[-2];
stack_top_p[-1] = ecma_copy_value (computed_class_fields_p[next_index]);
stack_top_p[-2] = ecma_copy_value (frame_ctx_p->this_binding);
break;
}
case VM_OC_PUSH_SUPER_CONSTRUCTOR:
{
result = ecma_op_function_get_super_constructor (JERRY_CONTEXT (current_function_obj_p));
+10 -2
View File
@@ -260,6 +260,9 @@ typedef enum
VM_OC_PUSH_IMPLICIT_CTOR, /**< create implicit class constructor */
VM_OC_INIT_CLASS, /**< initialize class */
VM_OC_FINALIZE_CLASS, /**< finalize class */
VM_OC_SET_CLASS_FIELD_INIT, /**< store the class field initializer function */
VM_OC_RUN_CLASS_FIELD_INIT, /**< run the class field initializer function */
VM_OC_SET_NEXT_COMPUTED_FIELD, /**< set the next computed field of a class */
VM_OC_PUSH_SUPER_CONSTRUCTOR, /**< getSuperConstructor operation */
VM_OC_RESOLVE_LEXICAL_THIS, /**< resolve this_binding from from the lexical environment */
VM_OC_SUPER_REFERENCE, /**< push super reference */
@@ -289,7 +292,8 @@ typedef enum
VM_OC_PUSH_NEW_TARGET, /**< push new.target onto the stack */
VM_OC_REQUIRE_OBJECT_COERCIBLE,/**< RequireObjectCoercible opretaion */
VM_OC_ASSIGN_SUPER, /**< assign super reference */
VM_OC_SET__PROTO__, /**< set prototpe when __proto__: form is used */
VM_OC_SET__PROTO__, /**< set prototype when __proto__: form is used */
VM_OC_ADD_COMPUTED_FIELD, /**< add computed field name */
#endif /* ENABLED (JERRY_ESNEXT) */
VM_OC_NONE, /**< a special opcode for unsupported byte codes */
} vm_oc_types;
@@ -337,6 +341,9 @@ typedef enum
VM_OC_PUSH_IMPLICIT_CTOR = VM_OC_NONE, /**< create implicit class constructor */
VM_OC_INIT_CLASS = VM_OC_NONE, /**< initialize class */
VM_OC_FINALIZE_CLASS = VM_OC_NONE, /**< finalize class */
VM_OC_SET_CLASS_FIELD_INIT = VM_OC_NONE, /**< store the class field initializer function */
VM_OC_RUN_CLASS_FIELD_INIT = VM_OC_NONE, /**< run the class field initializer function */
VM_OC_SET_NEXT_COMPUTED_FIELD = VM_OC_NONE, /**< set the next computed field of a class */
VM_OC_PUSH_SUPER_CONSTRUCTOR = VM_OC_NONE, /**< getSuperConstructor operation */
VM_OC_RESOLVE_LEXICAL_THIS = VM_OC_NONE, /**< resolve this_binding from from the lexical environment */
VM_OC_SUPER_REFERENCE = VM_OC_NONE, /**< push super reference */
@@ -366,7 +373,8 @@ typedef enum
VM_OC_PUSH_NEW_TARGET = VM_OC_NONE, /**< push new.target onto the stack */
VM_OC_REQUIRE_OBJECT_COERCIBLE = VM_OC_NONE,/**< RequireObjectCoercible opretaion */
VM_OC_ASSIGN_SUPER = VM_OC_NONE, /**< assign super reference */
VM_OC_SET__PROTO__ = VM_OC_NONE, /**< set prototpe when __proto__: form is used */
VM_OC_SET__PROTO__ = VM_OC_NONE, /**< set prototype when __proto__: form is used */
VM_OC_ADD_COMPUTED_FIELD = VM_OC_NONE, /**< add computed field name */
#endif /* !ENABLED (JERRY_ESNEXT) */
VM_OC_UNUSED = VM_OC_NONE /**< placeholder if the list is empty */