From 097e1862d2e8159ae85e5d095c8407bd6cdb850d Mon Sep 17 00:00:00 2001 From: legendecas Date: Mon, 29 Apr 2019 19:36:23 +0800 Subject: [PATCH] Set constructor to prototype for ES2015 Classes (#2818) JerryScript-DCO-1.0-Signed-off-by: legendecas legendecas@gmail.com --- jerry-core/parser/js/byte-code.h | 4 ++-- jerry-core/parser/js/js-parser-expr.c | 3 +-- jerry-core/vm/vm.c | 26 ++++++++++++++++---------- jerry-core/vm/vm.h | 4 ++-- tests/jerry/es2015/class.js | 11 ++++++++--- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 289dca77f..f51a45082 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -548,8 +548,8 @@ /* Class opcodes */ \ CBC_OPCODE (CBC_EXT_INHERIT_AND_SET_CONSTRUCTOR, CBC_NO_FLAG, 0, \ VM_OC_CLASS_INHERITANCE) \ - CBC_OPCODE (CBC_EXT_PUSH_CLASS_CONSTRUCTOR, CBC_NO_FLAG, 1, \ - VM_OC_PUSH_CLASS_CONSTRUCTOR | VM_OC_PUT_STACK) \ + CBC_OPCODE (CBC_EXT_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE, CBC_NO_FLAG, 2, \ + VM_OC_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_EXT_IMPLICIT_CONSTRUCTOR_CALL, CBC_NO_FLAG, 0, \ VM_OC_PUSH_IMPL_CONSTRUCTOR) \ CBC_OPCODE (CBC_EXT_SET_CLASS_LITERAL, CBC_HAS_LITERAL_ARG, 0, \ diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 7f81c604b..eb3cf9167 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -363,7 +363,6 @@ static void parser_parse_class_literal (parser_context_t *context_p) /**< context */ { JERRY_ASSERT (context_p->token.type == LEXER_LEFT_BRACE); - parser_emit_cbc (context_p, CBC_CREATE_OBJECT); bool super_called = false; uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE; @@ -605,7 +604,7 @@ parser_parse_class (parser_context_t *context_p, /**< context */ parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED); } - parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CLASS_CONSTRUCTOR); + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE); bool is_strict = context_p->status_flags & PARSER_IS_STRICT; diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index 4ea3ddc48..86f1f404d 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -1384,14 +1384,6 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_object_t *child_class_p = ecma_get_object_from_value (child_value); ecma_object_t *child_prototype_class_p = ecma_get_object_from_value (child_prototype_value); - ecma_property_value_t *prop_value_p; - - prop_value_p = ecma_create_named_data_property (child_prototype_class_p, - ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR), - ECMA_PROPERTY_CONFIGURABLE_WRITABLE, - NULL); - - ecma_named_data_property_assign_value (child_prototype_class_p, prop_value_p, child_value); ecma_object_t *super_class_p = ecma_get_lex_env_binding_object (frame_ctx_p->lex_env_p); @@ -1420,7 +1412,7 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ continue; } - case VM_OC_PUSH_CLASS_CONSTRUCTOR: + case VM_OC_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE: { ecma_object_t *prototype_obj_p = ecma_builtin_get (ECMA_BUILTIN_ID_FUNCTION_PROTOTYPE); @@ -1431,7 +1423,21 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ ecma_extended_object_t *ext_func_obj_p = (ecma_extended_object_t *) function_obj_p; ext_func_obj_p->u.external_handler_cb = ecma_op_function_implicit_constructor_handler_cb; - *stack_top_p++ = ecma_make_object_value (function_obj_p); + ecma_value_t function_obj_value = ecma_make_object_value (function_obj_p); + *stack_top_p++ = function_obj_value; + + ecma_object_t *prototype_class_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE), + 0, + ECMA_OBJECT_TYPE_GENERAL); + *stack_top_p++ = ecma_make_object_value (prototype_class_p); + + /* 14.5.14.18 Set constructor to prototype */ + ecma_property_value_t *prop_value_p; + prop_value_p = ecma_create_named_data_property (prototype_class_p, + ecma_get_magic_string (LIT_MAGIC_STRING_CONSTRUCTOR), + ECMA_PROPERTY_CONFIGURABLE_WRITABLE, + NULL); + ecma_named_data_property_assign_value (prototype_class_p, prop_value_p, function_obj_value); continue; } diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index 13a51a0c4..8df670773 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -215,7 +215,7 @@ typedef enum #if ENABLED (JERRY_ES2015_CLASS) VM_OC_CLASS_HERITAGE, /**< create a super class context */ VM_OC_CLASS_INHERITANCE, /**< inherit properties from the 'super' class */ - VM_OC_PUSH_CLASS_CONSTRUCTOR, /**< push class constructor */ + VM_OC_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE, /**< push class constructor */ VM_OC_SET_CLASS_CONSTRUCTOR, /**< set class constructor to the given function literal */ VM_OC_PUSH_IMPL_CONSTRUCTOR, /**< create implicit class constructor */ VM_OC_CLASS_EXPR_CONTEXT_END, /**< class expression heritage context end */ @@ -257,7 +257,7 @@ typedef enum #if !ENABLED (JERRY_ES2015_CLASS) VM_OC_CLASS_HERITAGE = VM_OC_NONE, /**< create a super class context */ VM_OC_CLASS_INHERITANCE = VM_OC_NONE, /**< inherit properties from the 'super' class */ - VM_OC_PUSH_CLASS_CONSTRUCTOR = VM_OC_NONE, /**< push class constructor */ + VM_OC_PUSH_CLASS_CONSTRUCTOR_AND_PROTOTYPE = VM_OC_NONE, /**< push class constructor */ VM_OC_SET_CLASS_CONSTRUCTOR = VM_OC_NONE, /**< set class constructor to the given function literal */ VM_OC_PUSH_IMPL_CONSTRUCTOR = VM_OC_NONE, /**< create implicit class constructor */ VM_OC_CLASS_EXPR_CONTEXT_END = VM_OC_NONE, /**< class expression heritage context end */ diff --git a/tests/jerry/es2015/class.js b/tests/jerry/es2015/class.js index 066b2e78e..75ae43217 100644 --- a/tests/jerry/es2015/class.js +++ b/tests/jerry/es2015/class.js @@ -68,8 +68,9 @@ class B { } var b = new B; -assert(typeof B === "function"); -assert(typeof b === "object"); +assert (typeof B === "function"); +assert (typeof b === "object"); +assert (b.constructor === B); class C { c1() { @@ -88,6 +89,7 @@ var c = new C; assert (c.c1() === 5); assert (c.c2() === undefined); assert (c["3"]() === 3); +assert (c.constructor === C); class D { constructor(d) { @@ -99,7 +101,8 @@ class D { } } var d = new D(5); -assert(d.d1() === 5); +assert (d.d1() === 5); +assert (d.constructor === D); class E { constructor(e) { @@ -118,6 +121,7 @@ var e = new E (5); assert (e.e === 5); e.e = 10; assert (e.e === 10); +assert (e.constructor === E); var F = class ClassF { constructor(f) { @@ -159,6 +163,7 @@ assert (F.f3(1, 1) === 2); assert (F.constructor(5) === 5); assert (F.static(5) === 5); assert (F["2"](5) === 10); +assert (f.constructor === F); var G = class { static set a(a) {