Commit 32fdc694 authored by Sathya Gunasekaran's avatar Sathya Gunasekaran Committed by Commit Bot

Better error for accessing 'this' in derived constructor.

Previously we threw a generic error meesage on failing hole check for
accessing 'this'. But 'this' can be a hole only if the super() has not
been called so we change the error message.

BUG=v8:5957

Change-Id: I2f0e3d813f16919645d8a5efa7d26e73bd2d83fe
Reviewed-on: https://chromium-review.googlesource.com/459085
Commit-Queue: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: 's avatarRoss McIlroy <rmcilroy@chromium.org>
Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44162}
parent 926b7b70
......@@ -1920,7 +1920,7 @@ void BytecodeGenerator::BuildVariableLoad(Variable* variable, FeedbackSlot slot,
// subsequent expressions assign to the same variable.
builder()->LoadAccumulatorWithRegister(source);
if (hole_check_mode == HoleCheckMode::kRequired) {
BuildThrowIfHole(variable->raw_name());
BuildThrowIfHole(variable);
}
break;
}
......@@ -1933,7 +1933,7 @@ void BytecodeGenerator::BuildVariableLoad(Variable* variable, FeedbackSlot slot,
// subsequent expressions assign to the same variable.
builder()->LoadAccumulatorWithRegister(source);
if (hole_check_mode == HoleCheckMode::kRequired) {
BuildThrowIfHole(variable->raw_name());
BuildThrowIfHole(variable);
}
break;
}
......@@ -1968,7 +1968,7 @@ void BytecodeGenerator::BuildVariableLoad(Variable* variable, FeedbackSlot slot,
builder()->LoadContextSlot(context_reg, variable->index(), depth,
immutable);
if (hole_check_mode == HoleCheckMode::kRequired) {
BuildThrowIfHole(variable->raw_name());
BuildThrowIfHole(variable);
}
break;
}
......@@ -1981,7 +1981,7 @@ void BytecodeGenerator::BuildVariableLoad(Variable* variable, FeedbackSlot slot,
builder()->LoadLookupContextSlot(variable->raw_name(), typeof_mode,
local_variable->index(), depth);
if (hole_check_mode == HoleCheckMode::kRequired) {
BuildThrowIfHole(variable->raw_name());
BuildThrowIfHole(variable);
}
break;
}
......@@ -2001,7 +2001,7 @@ void BytecodeGenerator::BuildVariableLoad(Variable* variable, FeedbackSlot slot,
int depth = execution_context()->ContextChainDepth(variable->scope());
builder()->LoadModuleVariable(variable->index(), depth);
if (hole_check_mode == HoleCheckMode::kRequired) {
BuildThrowIfHole(variable->raw_name());
BuildThrowIfHole(variable);
}
break;
}
......@@ -2069,12 +2069,19 @@ void BytecodeGenerator::BuildThrowReferenceError(const AstRawString* name) {
Runtime::kThrowReferenceError, name_reg);
}
void BytecodeGenerator::BuildThrowIfHole(const AstRawString* name) {
void BytecodeGenerator::BuildThrowIfHole(Variable* variable) {
// TODO(interpreter): Can the parser reduce the number of checks
// performed? Or should there be a ThrowIfHole bytecode.
BytecodeLabel no_reference_error;
builder()->JumpIfNotHole(&no_reference_error);
BuildThrowReferenceError(name);
if (variable->is_this()) {
DCHECK(variable->mode() == CONST);
builder()->CallRuntime(Runtime::kThrowSuperNotCalled);
} else {
BuildThrowReferenceError(variable->raw_name());
}
builder()->Bind(&no_reference_error);
}
......@@ -2095,7 +2102,7 @@ void BytecodeGenerator::BuildHoleCheckForVariableAssignment(Variable* variable,
// Perform an initialization check for let/const declared variables.
// E.g. let x = (x = 20); is not allowed.
DCHECK(IsLexicalVariableMode(variable->mode()));
BuildThrowIfHole(variable->raw_name());
BuildThrowIfHole(variable);
}
}
......
......@@ -114,7 +114,7 @@ class BytecodeGenerator final : public AstVisitor<BytecodeGenerator> {
void BuildAsyncReturn();
void BuildReThrow();
void BuildAbort(BailoutReason bailout_reason);
void BuildThrowIfHole(const AstRawString* name);
void BuildThrowIfHole(Variable* variable);
void BuildThrowReferenceError(const AstRawString* name);
void BuildHoleCheckForVariableAssignment(Variable* variable, Token::Value op);
......
......@@ -605,6 +605,9 @@ class ErrorUtils : public AllStatic {
"Arg string terminates parameters early") \
T(UnexpectedEndOfArgString, "Unexpected end of arg string") \
T(RuntimeWrongNumArgs, "Runtime function given wrong number of arguments") \
T(SuperNotCalled, \
"Must call super constructor in derived class before accessing 'this' or " \
"returning from derived constructor") \
T(SingleFunctionLiteral, "Single function literal required") \
T(SloppyFunction, \
"In non-strict mode code, functions can only be declared at top level, " \
......
......@@ -52,6 +52,13 @@ RUNTIME_FUNCTION(Runtime_ThrowSuperAlreadyCalledError) {
isolate, NewReferenceError(MessageTemplate::kSuperAlreadyCalled));
}
RUNTIME_FUNCTION(Runtime_ThrowSuperNotCalled) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
THROW_NEW_ERROR_RETURN_FAILURE(
isolate, NewReferenceError(MessageTemplate::kSuperNotCalled));
}
namespace {
Object* ThrowNotSuperConstructor(Isolate* isolate, Handle<Object> constructor,
......
......@@ -72,6 +72,7 @@ namespace internal {
F(ThrowConstructorNonCallableError, 1, 1) \
F(ThrowStaticPrototypeError, 0, 1) \
F(ThrowSuperAlreadyCalledError, 0, 1) \
F(ThrowSuperNotCalled, 0, 1) \
F(ThrowNotSuperConstructor, 2, 1) \
F(HomeObjectSymbol, 0, 1) \
F(DefineClass, 4, 1) \
......
......@@ -107,7 +107,7 @@ snippet: "
"
frame size: 4
parameter count: 1
bytecode array length: 75
bytecode array length: 67
bytecodes: [
B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0),
......@@ -126,22 +126,17 @@ bytecodes: [
/* 118 E> */ B(CallRuntime), U16(Runtime::kThrowSuperAlreadyCalledError), R(0), U8(0),
B(Mov), R(2), R(this),
/* 128 S> */ B(Ldar), R(this),
B(JumpIfNotHole), U8(11),
B(LdaConstant), U8(0),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1),
B(JumpIfNotHole), U8(7),
B(CallRuntime), U16(Runtime::kThrowSuperNotCalled), R(0), U8(0),
B(Star), R(2),
B(LdaSmi), I8(2),
/* 136 E> */ B(StaNamedPropertyStrict), R(2), U8(1), U8(4),
/* 136 E> */ B(StaNamedPropertyStrict), R(2), U8(0), U8(4),
B(Ldar), R(this),
B(JumpIfNotHole), U8(11),
B(LdaConstant), U8(0),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1),
B(JumpIfNotHole), U8(7),
B(CallRuntime), U16(Runtime::kThrowSuperNotCalled), R(0), U8(0),
/* 141 S> */ B(Return),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["this"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["y_"],
]
handlers: [
......@@ -162,7 +157,7 @@ snippet: "
"
frame size: 3
parameter count: 1
bytecode array length: 71
bytecode array length: 63
bytecodes: [
B(Mov), R(closure), R(1),
B(Mov), R(new_target), R(0),
......@@ -179,22 +174,17 @@ bytecodes: [
/* 117 E> */ B(CallRuntime), U16(Runtime::kThrowSuperAlreadyCalledError), R(0), U8(0),
B(Mov), R(2), R(this),
/* 126 S> */ B(Ldar), R(this),
B(JumpIfNotHole), U8(11),
B(LdaConstant), U8(0),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1),
B(JumpIfNotHole), U8(7),
B(CallRuntime), U16(Runtime::kThrowSuperNotCalled), R(0), U8(0),
B(Star), R(2),
B(LdaSmi), I8(2),
/* 134 E> */ B(StaNamedPropertyStrict), R(2), U8(1), U8(4),
/* 134 E> */ B(StaNamedPropertyStrict), R(2), U8(0), U8(4),
B(Ldar), R(this),
B(JumpIfNotHole), U8(11),
B(LdaConstant), U8(0),
B(Star), R(2),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(2), U8(1),
B(JumpIfNotHole), U8(7),
B(CallRuntime), U16(Runtime::kThrowSuperNotCalled), R(0), U8(0),
/* 139 S> */ B(Return),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["this"],
ONE_BYTE_INTERNALIZED_STRING_TYPE ["y_"],
]
handlers: [
......
......@@ -53,7 +53,7 @@ snippet: "
"
frame size: 7
parameter count: 1
bytecode array length: 65
bytecode array length: 61
bytecodes: [
B(CreateRestParameter),
B(Star), R(2),
......@@ -78,14 +78,11 @@ bytecodes: [
/* 140 E> */ B(CallRuntime), U16(Runtime::kThrowSuperAlreadyCalledError), R(0), U8(0),
B(Mov), R(4), R(this),
B(Ldar), R(this),
B(JumpIfNotHole), U8(11),
B(LdaConstant), U8(0),
B(Star), R(4),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1),
B(JumpIfNotHole), U8(7),
B(CallRuntime), U16(Runtime::kThrowSuperNotCalled), R(0), U8(0),
/* 159 S> */ B(Return),
]
constant pool: [
ONE_BYTE_INTERNALIZED_STRING_TYPE ["this"],
]
handlers: [
]
......@@ -105,7 +102,7 @@ snippet: "
"
frame size: 10
parameter count: 1
bytecode array length: 98
bytecode array length: 94
bytecodes: [
B(CreateRestParameter),
B(Star), R(2),
......@@ -142,16 +139,13 @@ bytecodes: [
/* 140 E> */ B(CallRuntime), U16(Runtime::kThrowSuperAlreadyCalledError), R(0), U8(0),
B(Mov), R(4), R(this),
B(Ldar), R(this),
B(JumpIfNotHole), U8(11),
B(LdaConstant), U8(2),
B(Star), R(4),
B(CallRuntime), U16(Runtime::kThrowReferenceError), R(4), U8(1),
B(JumpIfNotHole), U8(7),
B(CallRuntime), U16(Runtime::kThrowSuperNotCalled), R(0), U8(0),
/* 162 S> */ B(Return),
]
constant pool: [
CONSTANT_ELEMENTS_PAIR_TYPE,
CONSTANT_ELEMENTS_PAIR_TYPE,
ONE_BYTE_INTERNALIZED_STRING_TYPE ["this"],
]
handlers: [
]
......
......@@ -63,10 +63,10 @@ PASS (new DerivedReturnSymbol) threw exception TypeError: Derived constructors m
PASS (new DerivedThrow) threw exception Thrown Exception String.
Derived class not calling super()
PASS (new DerivedNoSuperNoReturn) threw exception ReferenceError: this is not defined.
PASS (new DerivedNoSuperNoReturn) threw exception ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor.
PASS (new DerivedNoSuperReturnImplicit) threw exception ReferenceError: DerivedNoSuperReturnImplicit is not defined.
PASS (new DerivedNoSuperReturnUndefined) threw exception ReferenceError: this is not defined.
PASS (new DerivedNoSuperReturnThis) threw exception ReferenceError: this is not defined.
PASS (new DerivedNoSuperReturnUndefined) threw exception ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor.
PASS (new DerivedNoSuperReturnThis) threw exception ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor.
PASS (new DerivedNoSuperReturnObject) did not throw exception.
PASS (new DerivedNoSuperReturnObject2) did not throw exception.
PASS (new DerivedNoSuperReturnString) threw exception TypeError: Derived constructors may only return object or undefined.
......
......@@ -59,7 +59,7 @@ PASS new (class extends undefined { constructor () { super(); } }) threw excepti
PASS x = {}; new (class extends undefined { constructor () { return x; } }) threw exception TypeError: Class extends value undefined is not a constructor or null.
PASS y = 12; new (class extends undefined { constructor () { return y; } }) threw exception TypeError: Class extends value undefined is not a constructor or null.
PASS class x {}; new (class extends null { constructor () { return new x; } }) instanceof x is true
PASS new (class extends null { constructor () { this; } }) threw exception ReferenceError: this is not defined.
PASS new (class extends null { constructor () { this; } }) threw exception ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor.
PASS new (class extends null { constructor () { super(); } }) threw exception TypeError: Super constructor null of anonymous class is not a constructor.
PASS x = {}; new (class extends null { constructor () { return x } }) is x
PASS y = 12; new (class extends null { constructor () { return y; } }) threw exception TypeError: Derived constructors may only return object or undefined.
......
......@@ -97,7 +97,7 @@ shouldThrow('new (class extends undefined { constructor () { super(); } })', '"T
shouldThrow('x = {}; new (class extends undefined { constructor () { return x; } })', '"TypeError: Class extends value undefined is not a constructor or null"');
shouldThrow('y = 12; new (class extends undefined { constructor () { return y; } })', '"TypeError: Class extends value undefined is not a constructor or null"');
shouldBeTrue ('class x {}; new (class extends null { constructor () { return new x; } }) instanceof x');
shouldThrow('new (class extends null { constructor () { this; } })', '"ReferenceError: this is not defined"');
shouldThrow('new (class extends null { constructor () { this; } })', '"ReferenceError: Must call super constructor in derived class before accessing \'this\' or returning from derived constructor"');
shouldThrow('new (class extends null { constructor () { super(); } })', '"TypeError: Super constructor null of anonymous class is not a constructor"');
shouldBe('x = {}; new (class extends null { constructor () { return x } })', 'x');
shouldThrow('y = 12; new (class extends null { constructor () { return y; } })', '"TypeError: Derived constructors may only return object or undefined"');
......
......@@ -22,17 +22,17 @@ PASS (new x).method1() threw exception ReferenceError: Unsupported reference to
PASS (new x).method2() threw exception ReferenceError: Unsupported reference to 'super'.
PASS new (class { constructor() { return undefined; } }) instanceof Object is true
PASS new (class { constructor() { return 1; } }) instanceof Object is true
PASS new (class extends Base { constructor() { return undefined } }) threw exception ReferenceError: this is not defined.
PASS new (class extends Base { constructor() { return undefined } }) threw exception ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor.
PASS new (class extends Base { constructor() { super(); return undefined } }) instanceof Object is true
PASS x = { }; new (class extends Base { constructor() { return x } }); is x
PASS x instanceof Base is false
PASS new (class extends Base { constructor() { } }) threw exception ReferenceError: this is not defined.
PASS new (class extends Base { constructor() { } }) threw exception ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor.
PASS new (class extends Base { constructor() { return 1; } }) threw exception TypeError: Derived constructors may only return object or undefined.
PASS new (class extends null { constructor() { return undefined } }) threw exception ReferenceError: this is not defined.
PASS new (class extends null { constructor() { return undefined } }) threw exception ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor.
PASS new (class extends null { constructor() { super(); return undefined } }) threw exception TypeError: Super constructor null of anonymous class is not a constructor.
PASS x = { }; new (class extends null { constructor() { return x } }); is x
PASS x instanceof Object is true
PASS new (class extends null { constructor() { } }) threw exception ReferenceError: this is not defined.
PASS new (class extends null { constructor() { } }) threw exception ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor.
PASS new (class extends null { constructor() { return 1; } }) threw exception TypeError: Derived constructors may only return object or undefined.
PASS new (class extends null { constructor() { super() } }) threw exception TypeError: Super constructor null of anonymous class is not a constructor.
PASS new (class { constructor() { super() } }) threw exception SyntaxError: 'super' keyword unexpected here.
......
......@@ -75,13 +75,13 @@ shouldThrow('new (class extends Base { constructor() { return undefined } })');
shouldBeTrue('new (class extends Base { constructor() { super(); return undefined } }) instanceof Object');
shouldBe('x = { }; new (class extends Base { constructor() { return x } });', 'x');
shouldBeFalse('x instanceof Base');
shouldThrow('new (class extends Base { constructor() { } })', '"ReferenceError: this is not defined"');
shouldThrow('new (class extends Base { constructor() { } })', '"ReferenceError: Must call super constructor in derived class before accessing \'this\' or returning from derived constructor"');
shouldThrow('new (class extends Base { constructor() { return 1; } })', '"TypeError: Derived constructors may only return object or undefined"');
shouldThrow('new (class extends null { constructor() { return undefined } })');
shouldThrow('new (class extends null { constructor() { super(); return undefined } })', '"TypeError: Super constructor null of anonymous class is not a constructor"');
shouldBe('x = { }; new (class extends null { constructor() { return x } });', 'x');
shouldBeTrue('x instanceof Object');
shouldThrow('new (class extends null { constructor() { } })', '"ReferenceError: this is not defined"');
shouldThrow('new (class extends null { constructor() { } })', '"ReferenceError: Must call super constructor in derived class before accessing \'this\' or returning from derived constructor"');
shouldThrow('new (class extends null { constructor() { return 1; } })', '"TypeError: Derived constructors may only return object or undefined"');
shouldThrow('new (class extends null { constructor() { super() } })', '"TypeError: Super constructor null of anonymous class is not a constructor"');
shouldThrow('new (class { constructor() { super() } })', '"SyntaxError: \'super\' keyword unexpected here"');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment