Skip to content

Commit 86e60dd

Browse files
rerobikaakosthekiss
authored andcommitted
Fix inner classes in class heritage environment (#2686)
This patch is the proper fix for #2667, since #2269 did not fix the problem entirely. JerryScript-DCO-1.0-Signed-off-by: Robert Fancsik frobert@inf.u-szeged.hu
1 parent cfdb5ed commit 86e60dd

File tree

7 files changed

+129
-25
lines changed

7 files changed

+129
-25
lines changed

jerry-core/ecma/base/ecma-globals.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,11 +99,12 @@ typedef enum
9999
ECMA_PARSE_NO_OPTS = 0, /**< no options passed */
100100
ECMA_PARSE_STRICT_MODE = (1u << 0), /**< enable strict mode */
101101
ECMA_PARSE_DIRECT_EVAL = (1u << 1), /**< eval is called directly (ECMA-262 v5, 15.1.2.1.1) */
102-
/* These three status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
102+
/* These four status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
103103
ECMA_PARSE_CLASS_CONSTRUCTOR = (1u << 2), /**< a class constructor is being parsed (this value must be kept in
104104
* in sync with PARSER_CLASS_CONSTRUCTOR) */
105105
ECMA_PARSE_HAS_SUPER = (1u << 3), /**< the current context has super reference */
106-
ECMA_PARSE_HAS_STATIC_SUPER = (1u << 4), /**< the current context is a static class method */
106+
ECMA_PARSE_HAS_IMPL_SUPER = (1u << 4), /**< the current context has implicit parent class */
107+
ECMA_PARSE_HAS_STATIC_SUPER = (1u << 5), /**< the current context is a static class method */
107108
} ecma_parse_opts_t;
108109

109110
/**

jerry-core/ecma/operations/ecma-function-object.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1053,7 +1053,7 @@ ecma_op_function_construct (ecma_object_t *func_obj_p, /**< Function object */
10531053
/* Catch the special case when a the class extends value in null
10541054
and the class has no explicit constructor to raise TypeError.*/
10551055
JERRY_ASSERT (!ecma_op_function_has_construct_flag (arguments_list_p));
1056-
JERRY_ASSERT (ecma_get_object_prototype (func_obj_p) == NULL);
1056+
JERRY_ASSERT (ecma_get_object_prototype (func_obj_p) == ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE));
10571057

10581058
ret_value = ecma_raise_type_error (ECMA_ERR_MSG ("Super constructor null is not a constructor."));
10591059
break;

jerry-core/parser/js/js-parser-expr.c

Lines changed: 25 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,8 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */
364364
parser_emit_cbc (context_p, CBC_CREATE_OBJECT);
365365

366366
bool super_called = false;
367-
uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE | (context_p->status_flags & PARSER_CLASS_HAS_SUPER);
367+
uint32_t status_flags = PARSER_IS_FUNCTION | PARSER_IS_CLOSURE;
368+
status_flags |= context_p->status_flags & (PARSER_CLASS_HAS_SUPER | PARSER_CLASS_IMPLICIT_SUPER);
368369

369370
while (true)
370371
{
@@ -472,12 +473,13 @@ parser_parse_class_literal (parser_context_t *context_p) /**< context */
472473
parser_raise_error (context_p, PARSER_ERR_LITERAL_LIMIT_REACHED);
473474
}
474475

476+
uint16_t result_index = context_p->literal_count;
475477
lexer_literal_t *literal_p = (lexer_literal_t *) parser_list_append (context_p, &context_p->literal_pool);
476478
literal_p->type = LEXER_UNUSED_LITERAL;
477479
literal_p->status_flags = 0;
478480
literal_p->u.bytecode_p = parser_parse_function (context_p, constructor_status_flags);
479481
literal_p->type = LEXER_FUNCTION_LITERAL;
480-
parser_emit_cbc_literal (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_SET_CLASS_LITERAL), context_p->literal_count);
482+
parser_emit_cbc_literal (context_p, PARSER_TO_EXT_OPCODE (CBC_EXT_SET_CLASS_LITERAL), result_index);
481483
context_p->literal_count++;
482484
continue;
483485
}
@@ -555,8 +557,6 @@ parser_parse_class (parser_context_t *context_p, /**< context */
555557
{
556558
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_CLASS);
557559

558-
context_p->status_flags &= (uint32_t) ~PARSER_CLASS_HAS_SUPER;
559-
560560
uint16_t class_ident_index = PARSER_MAXIMUM_NUMBER_OF_LITERALS;
561561

562562
if (is_statement)
@@ -582,7 +582,10 @@ parser_parse_class (parser_context_t *context_p, /**< context */
582582
}
583583
}
584584

585-
if (context_p->token.type == LEXER_KEYW_EXTENDS)
585+
bool create_class_env = (context_p->token.type == LEXER_KEYW_EXTENDS
586+
|| (context_p->status_flags & PARSER_CLASS_HAS_SUPER));
587+
588+
if (create_class_env)
586589
{
587590
parser_parse_super_class_context_start (context_p);
588591
}
@@ -615,10 +618,10 @@ parser_parse_class (parser_context_t *context_p, /**< context */
615618
parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, class_ident_index);
616619
}
617620

618-
if (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
621+
if (create_class_env)
619622
{
620623
parser_parse_super_class_context_end (context_p, is_statement);
621-
context_p->status_flags &= (uint32_t) ~PARSER_CLASS_HAS_SUPER;
624+
context_p->status_flags &= (uint32_t) ~(PARSER_CLASS_HAS_SUPER | PARSER_CLASS_IMPLICIT_SUPER);
622625
}
623626

624627
parser_flush_cbc (context_p);
@@ -1366,7 +1369,14 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
13661369
#ifndef CONFIG_DISABLE_ES2015_CLASS
13671370
if (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags))
13681371
{
1369-
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
1372+
if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER)
1373+
{
1374+
parser_emit_cbc (context_p, CBC_PUSH_THIS);
1375+
}
1376+
else
1377+
{
1378+
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
1379+
}
13701380
}
13711381
else
13721382
{
@@ -1415,13 +1425,20 @@ parser_parse_unary_expression (parser_context_t *context_p, /**< context */
14151425
break;
14161426
}
14171427

1428+
if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER)
1429+
{
1430+
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_STATIC_SUPER);
1431+
break;
1432+
}
1433+
14181434
bool is_static = (context_p->status_flags & PARSER_CLASS_STATIC_FUNCTION) != 0;
14191435
parser_emit_cbc_ext (context_p, is_static ? CBC_EXT_PUSH_STATIC_SUPER : CBC_EXT_PUSH_SUPER);
14201436
break;
14211437
}
14221438

14231439
if (lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN)
14241440
&& (context_p->status_flags & PARSER_CLASS_HAS_SUPER)
1441+
&& !(context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER)
14251442
&& (context_p->status_flags & (PARSER_IS_ARROW_FUNCTION | PARSER_CLASS_CONSTRUCTOR)))
14261443
{
14271444
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_SUPER);

jerry-core/parser/js/js-parser-internal.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,13 @@ typedef enum
6767
PARSER_ARROW_PARSE_ARGS = (1u << 19), /**< parse the argument list of an arrow function */
6868
#endif /* !CONFIG_DISABLE_ES2015_ARROW_FUNCTION */
6969
#ifndef CONFIG_DISABLE_ES2015_CLASS
70-
/* These three status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
70+
/* These four status flags must be in this order. See PARSER_CLASS_PARSE_OPTS_OFFSET. */
7171
PARSER_CLASS_CONSTRUCTOR = (1u << 20), /**< a class constructor is parsed (this value must be kept in
7272
* in sync with ECMA_PARSE_CLASS_CONSTRUCTOR) */
7373
PARSER_CLASS_HAS_SUPER = (1u << 21), /**< class has super reference */
74-
PARSER_CLASS_STATIC_FUNCTION = (1u << 22), /**< this function is a static class method */
75-
PARSER_CLASS_SUPER_PROP_REFERENCE = (1u << 23), /**< super property call or assignment */
74+
PARSER_CLASS_IMPLICIT_SUPER = (1u << 22), /**< class has implicit parent class */
75+
PARSER_CLASS_STATIC_FUNCTION = (1u << 23), /**< this function is a static class method */
76+
PARSER_CLASS_SUPER_PROP_REFERENCE = (1u << 24), /**< super property call or assignment */
7677
#endif /* !CONFIG_DISABLE_ES2015_CLASS */
7778
} parser_general_flags_t;
7879

jerry-core/parser/js/js-parser-statm.c

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -606,16 +606,25 @@ parser_parse_with_statement_end (parser_context_t *context_p) /**< context */
606606
void
607607
parser_parse_super_class_context_start (parser_context_t *context_p) /**< context */
608608
{
609-
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_EXTENDS);
610-
609+
JERRY_ASSERT (context_p->token.type == LEXER_KEYW_EXTENDS
610+
|| (context_p->status_flags & PARSER_CLASS_HAS_SUPER));
611611
parser_with_statement_t with_statement;
612612

613-
lexer_next_token (context_p);
613+
if (context_p->token.type == LEXER_KEYW_EXTENDS)
614+
{
615+
lexer_next_token (context_p);
614616

615-
/* NOTE: Currently there is no proper way to check whether the currently parsed expression
616-
is a valid lefthand-side expression or not, so we do not throw syntax error and parse
617-
the class extending value as an expression. */
618-
parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_NO_COMMA);
617+
/* NOTE: Currently there is no proper way to check whether the currently parsed expression
618+
is a valid lefthand-side expression or not, so we do not throw syntax error and parse
619+
the class extending value as an expression. */
620+
parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_NO_COMMA);
621+
}
622+
else
623+
{
624+
JERRY_ASSERT (context_p->status_flags & PARSER_CLASS_HAS_SUPER);
625+
parser_emit_cbc (context_p, CBC_PUSH_NULL);
626+
context_p->status_flags |= PARSER_CLASS_IMPLICIT_SUPER;
627+
}
619628

620629
#ifndef JERRY_NDEBUG
621630
PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_SUPER_CLASS_CONTEXT_STACK_ALLOCATION);
@@ -2022,7 +2031,14 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
20222031
#ifndef CONFIG_DISABLE_ES2015_CLASS
20232032
if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags)))
20242033
{
2025-
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
2034+
if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER)
2035+
{
2036+
parser_emit_cbc (context_p, CBC_PUSH_THIS);
2037+
}
2038+
else
2039+
{
2040+
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
2041+
}
20262042
parser_emit_cbc (context_p, CBC_RETURN);
20272043
}
20282044
else
@@ -2164,7 +2180,14 @@ parser_parse_statements (parser_context_t *context_p) /**< context */
21642180
#ifndef CONFIG_DISABLE_ES2015_CLASS
21652181
if (JERRY_UNLIKELY (PARSER_IS_CLASS_CONSTRUCTOR_SUPER (context_p->status_flags)))
21662182
{
2167-
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
2183+
if (context_p->status_flags & PARSER_CLASS_IMPLICIT_SUPER)
2184+
{
2185+
parser_emit_cbc (context_p, CBC_PUSH_THIS);
2186+
}
2187+
else
2188+
{
2189+
parser_emit_cbc_ext (context_p, CBC_EXT_PUSH_CONSTRUCTOR_THIS);
2190+
}
21682191
parser_emit_cbc (context_p, CBC_RETURN);
21692192
parser_flush_cbc (context_p);
21702193
}

jerry-core/vm/vm.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1336,7 +1336,9 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
13361336

13371337
if (ecma_is_value_null (super_value))
13381338
{
1339-
super_class_p = ecma_create_object (NULL, 0, ECMA_OBJECT_TYPE_GENERAL);
1339+
super_class_p = ecma_create_object (ecma_builtin_get (ECMA_BUILTIN_ID_OBJECT_PROTOTYPE),
1340+
0,
1341+
ECMA_OBJECT_TYPE_GENERAL);
13401342
}
13411343
else
13421344
{
@@ -1541,7 +1543,8 @@ vm_loop (vm_frame_ctx_t *frame_ctx_p) /**< frame context */
15411543
else
15421544
{
15431545
ecma_object_t *super_class_p = ecma_op_resolve_super_reference_value (frame_ctx_p->lex_env_p);
1544-
*stack_top_p++ = ecma_fast_copy_value (ecma_make_object_value (super_class_p));
1546+
ecma_ref_object (super_class_p);
1547+
*stack_top_p++ = ecma_make_object_value (super_class_p);
15451548
}
15461549

15471550
continue;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
/* Copyright JS Foundation and other contributors, http://js.foundation
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
var console = { assert : assert };
17+
18+
class C1 {
19+
f () {
20+
return 5;
21+
}
22+
}
23+
24+
class C2 extends C1 {
25+
f () {
26+
assert (super.f () === 5);
27+
28+
class G {
29+
g () {
30+
assert (super.f === undefined);
31+
assert (super.toString () === "[object Object]");
32+
var a = super.valueOf ();
33+
try {
34+
a ();
35+
assert (false);
36+
} catch (e) {
37+
assert (e instanceof TypeError);
38+
}
39+
}
40+
41+
constructor () {
42+
// Test to overwrite the current lit-object
43+
console.assert (Object.getPrototypeOf (this) === G.prototype);
44+
45+
try {
46+
eval ("super ()");
47+
assert (false);
48+
} catch (e) {
49+
assert (e instanceof SyntaxError);
50+
}
51+
}
52+
}
53+
54+
var g = new G ();
55+
g.g ();
56+
}
57+
}
58+
59+
(new C2).f ();

0 commit comments

Comments
 (0)