Commit 776d89f9 authored by bmeurer's avatar bmeurer Committed by Commit bot

[es2015] Simplify contract between parser and stub for derived constructors.

Rewrite returns in derived constructors to only replace undefined with
this, and otherwise just return the value, and let the construct stub
builtin throw an exception if the result is a primitive instead of a
JSReceiver.

R=yangguo@chromium.org
TBR=marja@chromium.org
BUG=chromium:706642

Review-Url: https://codereview.chromium.org/2788033002
Cr-Commit-Position: refs/heads/master@{#44288}
parent a6e635d6
......@@ -585,8 +585,12 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
// Check that the result is not a Smi, indicating that the constructor result
// from a derived class is neither undefined nor an Object.
if (check_derived_construct) {
Label dont_throw;
__ JumpIfNotSmi(r0, &dont_throw);
Label do_throw, dont_throw;
__ JumpIfSmi(r0, &do_throw);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CompareObjectType(r0, r3, r3, FIRST_JS_RECEIVER_TYPE);
__ b(ge, &dont_throw);
__ bind(&do_throw);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
......
......@@ -598,8 +598,11 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
// Check that the result is not a Smi, indicating that the constructor result
// from a derived class is neither undefined nor an Object.
if (check_derived_construct) {
Label dont_throw;
__ JumpIfNotSmi(x0, &dont_throw);
Label do_throw, dont_throw;
__ JumpIfSmi(x0, &do_throw);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ JumpIfObjectType(x0, x3, x3, FIRST_JS_RECEIVER_TYPE, &dont_throw, ge);
__ Bind(&do_throw);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
......
......@@ -228,8 +228,12 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
// Check that the result is not a Smi, indicating that the constructor result
// from a derived class is neither undefined nor an Object.
if (check_derived_construct) {
Label dont_throw;
__ JumpIfNotSmi(eax, &dont_throw);
Label do_throw, dont_throw;
__ JumpIfSmi(eax, &do_throw, Label::kNear);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CmpObjectType(eax, FIRST_JS_RECEIVER_TYPE, ecx);
__ j(above_equal, &dont_throw, Label::kNear);
__ bind(&do_throw);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
......
......@@ -579,8 +579,12 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
// Check that the result is not a Smi, indicating that the constructor result
// from a derived class is neither undefined nor an Object.
if (check_derived_construct) {
Label dont_throw;
__ JumpIfNotSmi(v0, &dont_throw);
Label do_throw, dont_throw;
__ JumpIfNotSmi(v0, &do_throw);
__ GetObjectType(v0, a1, a3);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ Branch(&dont_throw, greater_equal, a3, Operand(FIRST_JS_RECEIVER_TYPE));
__ bind(&do_throw);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
......
......@@ -576,8 +576,12 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
// Check that the result is not a Smi, indicating that the constructor result
// from a derived class is neither undefined nor an Object.
if (check_derived_construct) {
Label dont_throw;
__ JumpIfNotSmi(v0, &dont_throw);
Label do_throw, dont_throw;
__ JumpIfNotSmi(v0, &do_throw);
__ GetObjectType(v0, a1, a3);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ Branch(&dont_throw, greater_equal, a3, Operand(FIRST_JS_RECEIVER_TYPE));
__ bind(&do_throw);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
......
......@@ -226,11 +226,15 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
}
// ES6 9.2.2. Step 13+
// Check that the result is not a Smi, indicating that the constructor result
// from a derived class is neither undefined nor an Object.
// For derived class constructors, throw a TypeError here if the result
// is not a JSReceiver.
if (check_derived_construct) {
Label dont_throw;
__ JumpIfNotSmi(rax, &dont_throw);
Label do_throw, dont_throw;
__ JumpIfSmi(rax, &do_throw, Label::kNear);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
__ CmpObjectType(rax, FIRST_JS_RECEIVER_TYPE, rcx);
__ j(above_equal, &dont_throw, Label::kNear);
__ bind(&do_throw);
{
FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
......
......@@ -1593,42 +1593,29 @@ Block* Parser::IgnoreCompletion(Statement* statement) {
Expression* Parser::RewriteReturn(Expression* return_value, int pos) {
if (IsDerivedConstructor(function_state_->kind())) {
// For subclass constructors we need to return this in case of undefined
// return a Smi (transformed into an exception in the ConstructStub)
// for a non object.
// For subclass constructors we need to return this in case of undefined;
// other primitive values trigger an exception in the ConstructStub.
//
// return expr;
//
// Is rewritten as:
//
// return (temp = expr) === undefined ? this :
// %_IsJSReceiver(temp) ? temp : 1;
// return (temp = expr) === undefined ? this : temp;
// temp = expr
Variable* temp = NewTemporary(ast_value_factory()->empty_string());
Assignment* assign = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos);
// %_IsJSReceiver(temp)
ZoneList<Expression*>* is_spec_object_args =
new (zone()) ZoneList<Expression*>(1, zone());
is_spec_object_args->Add(factory()->NewVariableProxy(temp), zone());
Expression* is_spec_object_call = factory()->NewCallRuntime(
Runtime::kInlineIsJSReceiver, is_spec_object_args, pos);
// %_IsJSReceiver(temp) ? temp : 1;
Expression* is_object_conditional = factory()->NewConditional(
is_spec_object_call, factory()->NewVariableProxy(temp),
factory()->NewSmiLiteral(1, pos), pos);
// temp === undefined
Expression* is_undefined = factory()->NewCompareOperation(
Token::EQ_STRICT, assign,
factory()->NewUndefinedLiteral(kNoSourcePosition), pos);
// is_undefined ? this : is_object_conditional
return_value = factory()->NewConditional(is_undefined, ThisExpression(pos),
is_object_conditional, pos);
// is_undefined ? this : temp
return_value =
factory()->NewConditional(is_undefined, ThisExpression(pos),
factory()->NewVariableProxy(temp), pos);
}
return return_value;
}
......
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