diff --git a/jerry-core/include/jerryscript-snapshot.h b/jerry-core/include/jerryscript-snapshot.h index 8193cf267..d5e30b42b 100644 --- a/jerry-core/include/jerryscript-snapshot.h +++ b/jerry-core/include/jerryscript-snapshot.h @@ -30,7 +30,7 @@ extern "C" /** * Jerry snapshot format version. */ -#define JERRY_SNAPSHOT_VERSION (53u) +#define JERRY_SNAPSHOT_VERSION (54u) /** * Flags for jerry_generate_snapshot and jerry_generate_function_snapshot. diff --git a/jerry-core/parser/js/byte-code.c b/jerry-core/parser/js/byte-code.c index 6849e52af..5445198eb 100644 --- a/jerry-core/parser/js/byte-code.c +++ b/jerry-core/parser/js/byte-code.c @@ -27,7 +27,7 @@ JERRY_STATIC_ASSERT ((sizeof (cbc_uint16_arguments_t) % sizeof (jmem_cpointer_t) */ JERRY_STATIC_ASSERT (CBC_END == 238, number_of_cbc_opcodes_changed); -JERRY_STATIC_ASSERT (CBC_EXT_END == 128, +JERRY_STATIC_ASSERT (CBC_EXT_END == 132, number_of_cbc_ext_opcodes_changed); #if ENABLED (JERRY_PARSER) diff --git a/jerry-core/parser/js/byte-code.h b/jerry-core/parser/js/byte-code.h index 6bdbd38a4..645dcf48a 100644 --- a/jerry-core/parser/js/byte-code.h +++ b/jerry-core/parser/js/byte-code.h @@ -676,6 +676,14 @@ VM_OC_SUPER_REFERENCE | VM_OC_GET_STACK) \ CBC_OPCODE (CBC_EXT_SUPER_PROP_LITERAL_ASSIGNMENT_REFERENCE, CBC_HAS_LITERAL_ARG, 2, \ VM_OC_SUPER_REFERENCE | VM_OC_GET_LITERAL) \ + CBC_OPCODE (CBC_EXT_OBJECT_LITERAL_SET_HOME_OBJECT, CBC_NO_FLAG, 0, \ + VM_OC_SET_HOME_OBJECT) \ + CBC_OPCODE (CBC_EXT_OBJECT_LITERAL_SET_HOME_OBJECT_COMPUTED, CBC_NO_FLAG, 0, \ + VM_OC_SET_HOME_OBJECT) \ + CBC_OPCODE (CBC_EXT_PUSH_OBJECT_SUPER_ENVIRONMENT, CBC_NO_FLAG, 1, \ + VM_OC_OBJECT_LITERAL_HOME_ENV) \ + CBC_OPCODE (CBC_EXT_POP_OBJECT_SUPER_ENVIRONMENT, CBC_NO_FLAG, -1, \ + VM_OC_OBJECT_LITERAL_HOME_ENV) \ CBC_OPCODE (CBC_EXT_RESOLVE_LEXICAL_THIS, CBC_NO_FLAG, 1, \ VM_OC_RESOLVE_LEXICAL_THIS | VM_OC_PUT_STACK) \ CBC_OPCODE (CBC_EXT_LOCAL_EVAL, CBC_HAS_BYTE_ARG, 0, \ diff --git a/jerry-core/parser/js/js-parser-expr.c b/jerry-core/parser/js/js-parser-expr.c index 7bbf9047a..c05f9308e 100644 --- a/jerry-core/parser/js/js-parser-expr.c +++ b/jerry-core/parser/js/js-parser-expr.c @@ -869,7 +869,8 @@ parser_parse_object_method (parser_context_t *context_p) /**< context */ { context_p->source_p--; context_p->column--; - uint16_t function_literal_index = lexer_construct_function_object (context_p, PARSER_FUNCTION_CLOSURE); + uint16_t function_literal_index = lexer_construct_function_object (context_p, (PARSER_FUNCTION_CLOSURE + | PARSER_ALLOW_SUPER)); parser_emit_cbc_literal (context_p, CBC_PUSH_LITERAL, @@ -932,6 +933,15 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ #if ENABLED (JERRY_ESNEXT) bool proto_seen = false; + bool has_super_env = false; + + if (context_p->next_scanner_info_p->source_p == context_p->source_p) + { + JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER); + scanner_release_next (context_p, sizeof (scanner_info_t)); + parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_OBJECT_SUPER_ENVIRONMENT); + has_super_env = true; + } #endif /* ENABLED (JERRY_ESNEXT) */ while (true) @@ -971,6 +981,10 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ #endif /* !ENABLED (JERRY_ESNEXT) */ } +#if ENABLED (JERRY_ESNEXT) + status_flags |= PARSER_ALLOW_SUPER; +#endif /* !ENABLED (JERRY_ESNEXT) */ + lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); /* This assignment is a nop for computed getters/setters. */ @@ -1008,16 +1022,32 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ { parser_emit_cbc_ext (context_p, is_getter ? CBC_EXT_SET_COMPUTED_GETTER_NAME : CBC_EXT_SET_COMPUTED_SETTER_NAME); + + if (has_super_env) + { + parser_emit_cbc_ext (context_p, CBC_EXT_OBJECT_LITERAL_SET_HOME_OBJECT_COMPUTED); + } parser_emit_cbc_ext (context_p, opcode); lexer_next_token (context_p); break; } parser_set_function_name (context_p, function_literal_index, literal_index, status_flags); -#endif /* ENABLED (JERRY_ESNEXT) */ - context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (opcode); - context_p->last_cbc.value = function_literal_index; + if (has_super_env) + { + context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS; + context_p->last_cbc.value = function_literal_index; + parser_emit_cbc_ext (context_p, CBC_EXT_OBJECT_LITERAL_SET_HOME_OBJECT_COMPUTED); + parser_emit_cbc_ext (context_p, is_getter ? CBC_EXT_SET_COMPUTED_GETTER + : CBC_EXT_SET_COMPUTED_SETTER); + } + else +#endif /* ENABLED (JERRY_ESNEXT) */ + { + context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (opcode); + context_p->last_cbc.value = function_literal_index; + } lexer_next_token (context_p); break; @@ -1035,6 +1065,10 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ if (parser_check_anonymous_function_declaration (context_p) < PARSER_NAMED_FUNCTION) { parser_emit_cbc_ext (context_p, CBC_EXT_SET_COMPUTED_FUNCTION_NAME); + if (has_super_env) + { + parser_emit_cbc_ext (context_p, CBC_EXT_OBJECT_LITERAL_SET_HOME_OBJECT_COMPUTED); + } parser_emit_cbc_ext (context_p, CBC_EXT_SET_COMPUTED_PROPERTY); } else @@ -1091,6 +1125,11 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD; } + if (has_super_env) + { + status_flags |= PARSER_ALLOW_SUPER; + } + lexer_expect_object_literal_id (context_p, LEXER_OBJ_IDENT_ONLY_IDENTIFIERS); uint16_t opcode = CBC_SET_LITERAL_PROPERTY; @@ -1114,6 +1153,10 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ if (is_computed) { parser_emit_cbc_ext (context_p, CBC_EXT_SET_COMPUTED_FUNCTION_NAME); + if (has_super_env) + { + parser_emit_cbc_ext (context_p, CBC_EXT_OBJECT_LITERAL_SET_HOME_OBJECT_COMPUTED); + } parser_emit_cbc_ext (context_p, opcode); lexer_next_token (context_p); break; @@ -1121,8 +1164,16 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ parser_set_function_name (context_p, function_literal_index, literal_index, status_flags); - context_p->last_cbc_opcode = opcode; - context_p->last_cbc.value = literal_index; + if (has_super_env) + { + parser_emit_cbc_ext (context_p, CBC_EXT_OBJECT_LITERAL_SET_HOME_OBJECT); + parser_emit_cbc_literal (context_p, CBC_SET_PROPERTY, literal_index); + } + else + { + context_p->last_cbc_opcode = opcode; + context_p->last_cbc.value = literal_index; + } lexer_next_token (context_p); break; @@ -1167,6 +1218,14 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ JERRY_ASSERT (context_p->last_cbc_opcode == CBC_PUSH_LITERAL); parser_set_function_name (context_p, context_p->last_cbc.literal_index, literal_index, 0); + + if (has_super_env) + { + parser_emit_cbc_ext (context_p, CBC_EXT_OBJECT_LITERAL_SET_HOME_OBJECT); + parser_emit_cbc_literal (context_p, CBC_SET_PROPERTY, literal_index); + break; + } + context_p->last_cbc_opcode = CBC_SET_LITERAL_PROPERTY; context_p->last_cbc.value = literal_index; break; @@ -1246,6 +1305,11 @@ parser_parse_object_literal (parser_context_t *context_p) /**< context */ } parser_stack_pop_uint8 (context_p); +#else /* ENABLED (JERRY_ESNEXT) */ + if (has_super_env) + { + parser_emit_cbc_ext (context_p, CBC_EXT_POP_OBJECT_SUPER_ENVIRONMENT); + } #endif /* !ENABLED (JERRY_ESNEXT) */ } /* parser_parse_object_literal */ @@ -1828,10 +1892,9 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */ case LEXER_LEFT_BRACE: { #if ENABLED (JERRY_ESNEXT) - if (context_p->next_scanner_info_p->source_p == context_p->source_p) + if (context_p->next_scanner_info_p->source_p == context_p->source_p + && context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER) { - JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_INITIALIZER); - if (parser_is_assignment_expr (context_p)) { parser_parse_object_initializer (context_p, PARSER_PATTERN_NO_OPTS); diff --git a/jerry-core/parser/js/js-parser-internal.h b/jerry-core/parser/js/js-parser-internal.h index 3bea5dcd9..db459dfa0 100644 --- a/jerry-core/parser/js/js-parser-internal.h +++ b/jerry-core/parser/js/js-parser-internal.h @@ -641,6 +641,7 @@ void parser_stack_init (parser_context_t *context_p); void parser_stack_free (parser_context_t *context_p); void parser_stack_push_uint8 (parser_context_t *context_p, uint8_t uint8_value); void parser_stack_pop_uint8 (parser_context_t *context_p); +void parser_stack_change_last_uint8 (parser_context_t *context_p, uint8_t new_value); void parser_stack_push_uint16 (parser_context_t *context_p, uint16_t uint16_value); uint16_t parser_stack_pop_uint16 (parser_context_t *context_p); void parser_stack_push (parser_context_t *context_p, const void *data_p, uint32_t length); diff --git a/jerry-core/parser/js/js-parser-mem.c b/jerry-core/parser/js/js-parser-mem.c index 4dc87252c..e6963eeeb 100644 --- a/jerry-core/parser/js/js-parser-mem.c +++ b/jerry-core/parser/js/js-parser-mem.c @@ -436,6 +436,22 @@ parser_stack_pop_uint8 (parser_context_t *context_p) /**< context */ context_p->stack_top_uint8 = page_p->bytes[context_p->stack.last_position - 1]; } /* parser_stack_pop_uint8 */ +/** + * Change last byte of the stack. + */ +void +parser_stack_change_last_uint8 (parser_context_t *context_p, /**< context */ + uint8_t new_value) /**< new value */ +{ + parser_mem_page_t *page_p = context_p->stack.first_p; + + JERRY_ASSERT (page_p != NULL + && context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]); + + page_p->bytes[context_p->stack.last_position - 1] = new_value; + context_p->stack_top_uint8 = new_value; +} /* parser_stack_change_last_uint8 */ + /** * Pushes an uint16_t value onto the stack. */ diff --git a/jerry-core/parser/js/js-parser-statm.c b/jerry-core/parser/js/js-parser-statm.c index 0a3b503f0..e6d1da5ec 100644 --- a/jerry-core/parser/js/js-parser-statm.c +++ b/jerry-core/parser/js/js-parser-statm.c @@ -331,22 +331,6 @@ parser_stack_iterator_read_uint8 (parser_stack_iterator_t *iterator) /**< iterat return iterator->current_p->bytes[iterator->current_position - 1]; } /* parser_stack_iterator_read_uint8 */ -/** - * Change last byte of the stack. - */ -static inline void -parser_stack_change_last_uint8 (parser_context_t *context_p, /**< context */ - uint8_t new_value) /**< new value */ -{ - parser_mem_page_t *page_p = context_p->stack.first_p; - - JERRY_ASSERT (page_p != NULL - && context_p->stack_top_uint8 == page_p->bytes[context_p->stack.last_position - 1]); - - page_p->bytes[context_p->stack.last_position - 1] = new_value; - context_p->stack_top_uint8 = new_value; -} /* parser_stack_change_last_uint8 */ - /** * Parse expression enclosed in parens. */ diff --git a/jerry-core/parser/js/js-scanner-internal.h b/jerry-core/parser/js/js-scanner-internal.h index 837c6d4ae..77cef99c1 100644 --- a/jerry-core/parser/js/js-scanner-internal.h +++ b/jerry-core/parser/js/js-scanner-internal.h @@ -115,6 +115,7 @@ typedef enum SCAN_STACK_CLASS_EXTENDS, /**< class extends expression */ SCAN_STACK_FUNCTION_PARAMETERS, /**< function parameter initializer */ SCAN_STACK_USE_ASYNC, /**< an "async" identifier is used */ + SCAN_STACK_OBJECT_LITERAL_WITH_SUPER, /**< object literal with inner super reference */ #endif /* ENABLED (JERRY_ESNEXT) */ } scan_stack_modes_t; @@ -287,6 +288,7 @@ typedef enum SCANNER_LITERAL_POOL_ARROW = (1 << 9), /**< arrow function */ SCANNER_LITERAL_POOL_GENERATOR = (1 << 10), /**< generator function */ SCANNER_LITERAL_POOL_ASYNC = (1 << 11), /**< async function */ + SCANNER_LITERAL_POOL_HAS_SUPER_REFERENCE = (1 << 12), /**< function body contains super reference */ #endif /* ENABLED (JERRY_ESNEXT) */ } scanner_literal_pool_flags_t; diff --git a/jerry-core/parser/js/js-scanner-ops.c b/jerry-core/parser/js/js-scanner-ops.c index 98a34eba2..ffc9484ca 100644 --- a/jerry-core/parser/js/js-scanner-ops.c +++ b/jerry-core/parser/js/js-scanner-ops.c @@ -66,6 +66,8 @@ scanner_check_arrow_body (parser_context_t *context_p, /**< context */ { lexer_next_token (context_p); + scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_ARROW; + if (context_p->token.type != LEXER_LEFT_BRACE) { scanner_context_p->mode = SCAN_MODE_PRIMARY_EXPRESSION; @@ -431,9 +433,12 @@ scanner_scan_bracket (parser_context_t *context_p, /**< context */ #if ENABLED (JERRY_ESNEXT) /* A function call cannot be an eval function. */ arrow_source_p = NULL; + const uint16_t flags = (uint16_t) (SCANNER_LITERAL_POOL_CAN_EVAL | SCANNER_LITERAL_POOL_HAS_SUPER_REFERENCE); +#else /* !ENABLED (JERRY_ESNEXT) */ + const uint16_t flags = SCANNER_LITERAL_POOL_CAN_EVAL; #endif /* ENABLED (JERRY_ESNEXT) */ - scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_CAN_EVAL; + scanner_context_p->active_literal_pool_p->status_flags |= flags; break; } diff --git a/jerry-core/parser/js/js-scanner-util.c b/jerry-core/parser/js/js-scanner-util.c index 62651208f..856295005 100644 --- a/jerry-core/parser/js/js-scanner-util.c +++ b/jerry-core/parser/js/js-scanner-util.c @@ -475,6 +475,14 @@ scanner_pop_literal_pool (parser_context_t *context_p, /**< context */ scanner_literal_pool_t *literal_pool_p = scanner_context_p->active_literal_pool_p; scanner_literal_pool_t *prev_literal_pool_p = literal_pool_p->prev_p; +#if ENABLED (JERRY_ESNEXT) + const uint32_t arrow_super_flags = (SCANNER_LITERAL_POOL_ARROW | SCANNER_LITERAL_POOL_HAS_SUPER_REFERENCE); + if ((literal_pool_p->status_flags & arrow_super_flags) == arrow_super_flags) + { + prev_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_HAS_SUPER_REFERENCE; + } +#endif /* ENABLED (JERRY_ESNEXT) */ + if (literal_pool_p->source_p == NULL) { JERRY_ASSERT (literal_pool_p->status_flags & SCANNER_LITERAL_POOL_FUNCTION); @@ -1287,7 +1295,13 @@ scanner_detect_eval_call (parser_context_t *context_p, /**< context */ if (context_p->token.keyword_type == LEXER_KEYW_EVAL && lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)) { - scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_CAN_EVAL; +#if ENABLED (JERRY_ESNEXT) + const uint16_t flags = (uint16_t) (SCANNER_LITERAL_POOL_CAN_EVAL | SCANNER_LITERAL_POOL_HAS_SUPER_REFERENCE); +#else /* !ENABLED (JERRY_ESNEXT) */ + const uint16_t flags = SCANNER_LITERAL_POOL_CAN_EVAL; +#endif /* ENABLED (JERRY_ESNEXT) */ + + scanner_context_p->active_literal_pool_p->status_flags |= flags; } } /* scanner_detect_eval_call */ @@ -1654,6 +1668,7 @@ scanner_cleanup (parser_context_t *context_p) /**< context */ JERRY_ASSERT (scanner_info_p->type == SCANNER_TYPE_END_ARGUMENTS || scanner_info_p->type == SCANNER_TYPE_LET_EXPRESSION || scanner_info_p->type == SCANNER_TYPE_CLASS_CONSTRUCTOR + || scanner_info_p->type == SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER || scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED || scanner_info_p->type == SCANNER_TYPE_ERR_ASYNC_FUNCTION); #else /* !ENABLED (JERRY_ESNEXT) */ diff --git a/jerry-core/parser/js/js-scanner.c b/jerry-core/parser/js/js-scanner.c index 5cd680ef8..5beb12628 100644 --- a/jerry-core/parser/js/js-scanner.c +++ b/jerry-core/parser/js/js-scanner.c @@ -193,7 +193,6 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ /* FALLTHRU */ } case LEXER_KEYW_THIS: - case LEXER_KEYW_SUPER: case LEXER_LIT_TRUE: case LEXER_LIT_FALSE: case LEXER_LIT_NULL: @@ -202,6 +201,12 @@ scanner_scan_primary_expression (parser_context_t *context_p, /**< context */ break; } #if ENABLED (JERRY_ESNEXT) + case LEXER_KEYW_SUPER: + { + scanner_context_p->active_literal_pool_p->status_flags |= SCANNER_LITERAL_POOL_HAS_SUPER_REFERENCE; + scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; + break; + } case LEXER_KEYW_CLASS: { scanner_push_class_declaration (context_p, scanner_context_p, SCAN_STACK_CLASS_EXPRESSION); @@ -442,6 +447,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * return SCAN_NEXT_TOKEN; } + case SCAN_STACK_OBJECT_LITERAL_WITH_SUPER: #endif /* ENABLED (JERRY_ESNEXT) */ case SCAN_STACK_OBJECT_LITERAL: { @@ -555,6 +561,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_ARRAY_LITERAL || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL + || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER || context_p->stack_top_uint8 == SCAN_STACK_LET || context_p->stack_top_uint8 == SCAN_STACK_CONST || context_p->stack_top_uint8 == SCAN_STACK_FOR_LET_START @@ -586,6 +593,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_ARRAY_LITERAL || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL + || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER || context_p->stack_top_uint8 == SCAN_STACK_LET || context_p->stack_top_uint8 == SCAN_STACK_CONST || context_p->stack_top_uint8 == SCAN_STACK_FOR_LET_START @@ -593,8 +601,10 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * || context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_PARAMETERS || context_p->stack_top_uint8 == SCAN_STACK_ARROW_ARGUMENTS); - JERRY_ASSERT ((stack_top != SCAN_STACK_ARRAY_LITERAL && stack_top != SCAN_STACK_OBJECT_LITERAL) - || SCANNER_NEEDS_BINDING_LIST (scanner_context_p->binding_type)); + JERRY_ASSERT (SCANNER_NEEDS_BINDING_LIST (scanner_context_p->binding_type) + || (stack_top != SCAN_STACK_ARRAY_LITERAL + && stack_top != SCAN_STACK_OBJECT_LITERAL + && stack_top != SCAN_STACK_OBJECT_LITERAL_WITH_SUPER)); if (binding_literal.literal_p->type & SCANNER_LITERAL_IS_USED) { @@ -823,9 +833,12 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * #if ENABLED (JERRY_ESNEXT) case SCAN_STACK_ARRAY_LITERAL: case SCAN_STACK_OBJECT_LITERAL: + case SCAN_STACK_OBJECT_LITERAL_WITH_SUPER: { - if (((stack_top == SCAN_STACK_ARRAY_LITERAL) && (type != LEXER_RIGHT_SQUARE)) - || ((stack_top == SCAN_STACK_OBJECT_LITERAL) && (type != LEXER_RIGHT_BRACE))) + bool is_array = stack_top == SCAN_STACK_ARRAY_LITERAL; + + if ((is_array && (type != LEXER_RIGHT_SQUARE)) + || (!is_array && (type != LEXER_RIGHT_BRACE))) { break; } @@ -867,6 +880,13 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * scanner_pop_binding_list (scanner_context_p); } +#if ENABLED (JERRY_ESNEXT) + if (stack_top == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER) + { + scanner_info_t *info_p = scanner_insert_info (context_p, source_start.source_p, sizeof (scanner_info_t)); + info_p->type = SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER; + } +#endif /* ENABLED (JERRY_ESNEXT) */ scanner_context_p->mode = SCAN_MODE_POST_PRIMARY_EXPRESSION; return SCAN_KEEP_TOKEN; } @@ -941,7 +961,8 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * return SCAN_KEEP_TOKEN; } - JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL); + JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL + || stack_top == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER); if (context_p->token.type == LEXER_LEFT_PAREN) { @@ -978,6 +999,7 @@ scanner_scan_primary_expression_end (parser_context_t *context_p, /**< context * parser_stack_pop_uint8 (context_p); JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL + || context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER || context_p->stack_top_uint8 == SCAN_STACK_FUNCTION_PROPERTY); uint16_t status_flags = (uint16_t) (SCANNER_LITERAL_POOL_FUNCTION @@ -1966,6 +1988,10 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ break; } +#if ENABLED (JERRY_ESNEXT) + bool has_super_reference = (scanner_context_p->active_literal_pool_p->status_flags + & SCANNER_LITERAL_POOL_HAS_SUPER_REFERENCE) != 0; +#endif /* ENABLED (JERRY_ESNEXT) */ scanner_pop_literal_pool (context_p, scanner_context_p); parser_stack_pop_uint8 (context_p); @@ -1976,9 +2002,14 @@ scanner_scan_statement_end (parser_context_t *context_p, /**< context */ scanner_context_p->mode = SCAN_MODE_CLASS_METHOD; return SCAN_KEEP_TOKEN; } -#endif /* ENABLED (JERRY_ESNEXT) */ + if (has_super_reference && context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL) + { + parser_stack_change_last_uint8 (context_p, SCAN_STACK_OBJECT_LITERAL_WITH_SUPER); + } +#else /* ENABLED (JERRY_ESNEXT) */ JERRY_ASSERT (context_p->stack_top_uint8 == SCAN_STACK_OBJECT_LITERAL); +#endif /* ENABLED (JERRY_ESNEXT) */ lexer_next_token (context_p); @@ -2869,7 +2900,12 @@ scanner_scan_all (parser_context_t *context_p, /**< context */ } case SCAN_MODE_PROPERTY_NAME: { +#if ENABLED (JERRY_ESNEXT) + JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL + || stack_top == SCAN_STACK_OBJECT_LITERAL_WITH_SUPER); +#else /* !ENABLED (JERRY_ESNEXT) */ JERRY_ASSERT (stack_top == SCAN_STACK_OBJECT_LITERAL); +#endif /* ENABLED (JERRY_ESNEXT) */ if (lexer_scan_identifier (context_p)) { @@ -3471,6 +3507,13 @@ scan_completed: print_location = true; break; } + case SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER: + { + JERRY_DEBUG_MSG (" OBJECT-LITERAL-WITH-SUPER: source:%d\n", + (int) (info_p->source_p - source_start_p)); + print_location = false; + break; + } case SCANNER_TYPE_CLASS_CONSTRUCTOR: { JERRY_DEBUG_MSG (" CLASS-CONSTRUCTOR: source:%d\n", diff --git a/jerry-core/parser/js/js-scanner.h b/jerry-core/parser/js/js-scanner.h index 47beccec2..298f645fc 100644 --- a/jerry-core/parser/js/js-scanner.h +++ b/jerry-core/parser/js/js-scanner.h @@ -50,6 +50,7 @@ typedef enum SCANNER_TYPE_LET_EXPRESSION, /**< let expression */ SCANNER_TYPE_ERR_REDECLARED, /**< syntax error: a variable is redeclared */ SCANNER_TYPE_ERR_ASYNC_FUNCTION, /**< an invalid async function follows */ + SCANNER_TYPE_OBJECT_LITERAL_WITH_SUPER, /**< object literal with inner super reference */ #endif /* ENABLED (JERRY_ESNEXT) */ } scanner_info_type_t; diff --git a/jerry-core/vm/opcodes.c b/jerry-core/vm/opcodes.c index d433bb3d2..030b5c416 100644 --- a/jerry-core/vm/opcodes.c +++ b/jerry-core/vm/opcodes.c @@ -1050,10 +1050,12 @@ opfunc_create_implicit_class_constructor (uint8_t opcode) /**< current cbc opcod /** * Set the [[HomeObject]] attribute of the given functon object */ -static inline void JERRY_ATTR_ALWAYS_INLINE +inline void JERRY_ATTR_ALWAYS_INLINE opfunc_set_home_object (ecma_object_t *func_p, /**< function object */ ecma_object_t *parent_env_p) /**< parent environment */ { + JERRY_ASSERT (ecma_is_lexical_environment (parent_env_p)); + if (ecma_get_object_type (func_p) == ECMA_OBJECT_TYPE_FUNCTION) { JERRY_ASSERT (!ecma_get_object_is_builtin (func_p)); diff --git a/jerry-core/vm/opcodes.h b/jerry-core/vm/opcodes.h index 6064ac6f2..5766f4bb6 100644 --- a/jerry-core/vm/opcodes.h +++ b/jerry-core/vm/opcodes.h @@ -147,6 +147,9 @@ opfunc_async_create_and_await (vm_frame_ctx_t *frame_ctx_p, ecma_value_t value, ecma_value_t opfunc_create_implicit_class_constructor (uint8_t opcode); +void +opfunc_set_home_object (ecma_object_t *func_p, ecma_object_t *parent_env_p); + void opfunc_push_class_environment (vm_frame_ctx_t *frame_ctx_p, ecma_value_t **vm_stack_top, ecma_value_t class_name); diff --git a/jerry-core/vm/vm.c b/jerry-core/vm/vm.c index db541b916..0b7b43cce 100644 --- a/jerry-core/vm/vm.c +++ b/jerry-core/vm/vm.c @@ -1970,6 +1970,34 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */ *stack_top_p++ = result; continue; } + case VM_OC_OBJECT_LITERAL_HOME_ENV: + { + if (opcode == CBC_EXT_PUSH_OBJECT_SUPER_ENVIRONMENT) + { + ecma_value_t obj_value = stack_top_p[-1]; + ecma_object_t *obj_env_p = ecma_create_object_lex_env (frame_ctx_p->lex_env_p, + ecma_get_object_from_value (obj_value), + ECMA_LEXICAL_ENVIRONMENT_HOME_OBJECT_BOUND); + + stack_top_p[-1] = ecma_make_object_value (obj_env_p); + *stack_top_p++ = obj_value; + } + else + { + JERRY_ASSERT (opcode == CBC_EXT_POP_OBJECT_SUPER_ENVIRONMENT); + ecma_deref_object (ecma_get_object_from_value (stack_top_p[-2])); + stack_top_p[-2] = stack_top_p[-1]; + stack_top_p--; + } + continue; + } + case VM_OC_SET_HOME_OBJECT: + { + int offset = opcode == CBC_EXT_OBJECT_LITERAL_SET_HOME_OBJECT_COMPUTED ? -1 : 0; + opfunc_set_home_object (ecma_get_object_from_value (stack_top_p[-1]), + ecma_get_object_from_value (stack_top_p[-3 + offset])); + continue; + } case VM_OC_SUPER_REFERENCE: { result = opfunc_form_super_reference (&stack_top_p, frame_ctx_p, left_value, opcode); diff --git a/jerry-core/vm/vm.h b/jerry-core/vm/vm.h index bafd49afd..7b462f7a7 100644 --- a/jerry-core/vm/vm.h +++ b/jerry-core/vm/vm.h @@ -259,6 +259,8 @@ typedef enum 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 */ + VM_OC_SET_HOME_OBJECT, /**< set the [[HomeObject]] environment in an object literal */ + VM_OC_OBJECT_LITERAL_HOME_ENV, /**< create/destroy [[HomeObject]] environment of an object literal */ VM_OC_SET_FUNCTION_NAME, /**< set function name property */ VM_OC_PUSH_SPREAD_ELEMENT, /**< push spread element */ @@ -331,6 +333,8 @@ typedef enum 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 */ + VM_OC_SET_HOME_OBJECT = VM_OC_NONE, /**< set the [[HomeObject]] internal property in an object literal */ + VM_OC_OBJECT_LITERAL_HOME_ENV = VM_OC_NONE, /**< create/destroy [[HomeObject]] environment of an object literal */ VM_OC_SET_FUNCTION_NAME = VM_OC_NONE, /**< set function name property */ VM_OC_PUSH_SPREAD_ELEMENT = VM_OC_NONE, /**< push spread element */ diff --git a/tests/jerry/es.next/object-literal-super.js b/tests/jerry/es.next/object-literal-super.js new file mode 100644 index 000000000..9c42d9302 --- /dev/null +++ b/tests/jerry/es.next/object-literal-super.js @@ -0,0 +1,132 @@ +// 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 setter1_called = false; +var setter2_called = false; + +var obj1 = { + method1() { + return 1; + }, + ['method2']() { + return 2; + }, + *method3() { + return 3; + }, + *['method4']() { + return 4; + }, + get getter1() { + return 5; + }, + get ['getter2']() { + return 6; + }, + set setter1(rhs) { + setter1_called = true; + assert(rhs === 7); + }, + set ['setter2'](rhs) { + setter2_called = true; + assert(rhs === 8); + }, +} + +var obj2 = { + method1() { + return super.method1(); + }, + ['method2']() { + return super.method2(); + }, + *method3() { + return super.method3(); + }, + *['method4']() { + return super.method4(); + }, + get getter1() { + return super.getter1; + }, + get ['getter2']() { + return super.getter2; + }, + set setter1(rhs) { + super.setter1 = rhs; + }, + set ['setter2'](rhs) { + super.setter2 = rhs; + }, + __proto__: obj1, +} + +assert(obj2.method1() === 1); +assert(obj2.method2() === 2); +assert(obj2.method3().next().value.next().value === 3); +assert(obj2.method4().next().value.next().value === 4); + +assert(obj2.getter1 === 5); +assert(obj2.getter2 === 6); + +obj2.setter1 = 7; +assert(setter1_called); +obj2.setter2 = 8; +assert(setter2_called); + +let obj3 = { + a() { + return 9; + } +} + +let obj4 = { + a() { + return eval('super.a()'); + }, + __proto__: obj3, +} + +assert(obj4.a() === 9); + +let obj5 = { + a() { + return (_ => super.a())(); + }, + __proto__: obj3, +} + +assert(obj5.a() === 9); + +let obj6 = { + a() { + return (_ => _ => super.a())()(); + }, + __proto__: obj3, +} + +assert(obj6.a() === 9); + + +function checkSyntax(src) { + try { + eval(src); + assert(false); + } catch (e) { + assert(e instanceof SyntaxError); + } +} + +checkSyntax('({ a : function () { super.a }})') +checkSyntax('({ [\'a\'] : function () { super.a }})') diff --git a/tests/test262-es6-excludelist.xml b/tests/test262-es6-excludelist.xml index ac677670a..f21fc0c63 100644 --- a/tests/test262-es6-excludelist.xml +++ b/tests/test262-es6-excludelist.xml @@ -258,9 +258,6 @@ - - - @@ -294,12 +291,8 @@ - - - - @@ -335,10 +328,6 @@ - - - -