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, ...@@ -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 // Check that the result is not a Smi, indicating that the constructor result
// from a derived class is neither undefined nor an Object. // from a derived class is neither undefined nor an Object.
if (check_derived_construct) { if (check_derived_construct) {
Label dont_throw; Label do_throw, dont_throw;
__ JumpIfNotSmi(r0, &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); FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject); __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
......
...@@ -598,8 +598,11 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function, ...@@ -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 // Check that the result is not a Smi, indicating that the constructor result
// from a derived class is neither undefined nor an Object. // from a derived class is neither undefined nor an Object.
if (check_derived_construct) { if (check_derived_construct) {
Label dont_throw; Label do_throw, dont_throw;
__ JumpIfNotSmi(x0, &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); FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject); __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
......
...@@ -228,8 +228,12 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function, ...@@ -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 // Check that the result is not a Smi, indicating that the constructor result
// from a derived class is neither undefined nor an Object. // from a derived class is neither undefined nor an Object.
if (check_derived_construct) { if (check_derived_construct) {
Label dont_throw; Label do_throw, dont_throw;
__ JumpIfNotSmi(eax, &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); FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject); __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
......
...@@ -579,8 +579,12 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function, ...@@ -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 // Check that the result is not a Smi, indicating that the constructor result
// from a derived class is neither undefined nor an Object. // from a derived class is neither undefined nor an Object.
if (check_derived_construct) { if (check_derived_construct) {
Label dont_throw; Label do_throw, dont_throw;
__ JumpIfNotSmi(v0, &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); FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject); __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
......
...@@ -576,8 +576,12 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function, ...@@ -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 // Check that the result is not a Smi, indicating that the constructor result
// from a derived class is neither undefined nor an Object. // from a derived class is neither undefined nor an Object.
if (check_derived_construct) { if (check_derived_construct) {
Label dont_throw; Label do_throw, dont_throw;
__ JumpIfNotSmi(v0, &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); FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject); __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
......
...@@ -226,11 +226,15 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function, ...@@ -226,11 +226,15 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
} }
// ES6 9.2.2. Step 13+ // ES6 9.2.2. Step 13+
// Check that the result is not a Smi, indicating that the constructor result // For derived class constructors, throw a TypeError here if the result
// from a derived class is neither undefined nor an Object. // is not a JSReceiver.
if (check_derived_construct) { if (check_derived_construct) {
Label dont_throw; Label do_throw, dont_throw;
__ JumpIfNotSmi(rax, &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); FrameScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject); __ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
......
...@@ -1593,42 +1593,29 @@ Block* Parser::IgnoreCompletion(Statement* statement) { ...@@ -1593,42 +1593,29 @@ Block* Parser::IgnoreCompletion(Statement* statement) {
Expression* Parser::RewriteReturn(Expression* return_value, int pos) { Expression* Parser::RewriteReturn(Expression* return_value, int pos) {
if (IsDerivedConstructor(function_state_->kind())) { if (IsDerivedConstructor(function_state_->kind())) {
// For subclass constructors we need to return this in case of undefined // For subclass constructors we need to return this in case of undefined;
// return a Smi (transformed into an exception in the ConstructStub) // other primitive values trigger an exception in the ConstructStub.
// for a non object.
// //
// return expr; // return expr;
// //
// Is rewritten as: // Is rewritten as:
// //
// return (temp = expr) === undefined ? this : // return (temp = expr) === undefined ? this : temp;
// %_IsJSReceiver(temp) ? temp : 1;
// temp = expr // temp = expr
Variable* temp = NewTemporary(ast_value_factory()->empty_string()); Variable* temp = NewTemporary(ast_value_factory()->empty_string());
Assignment* assign = factory()->NewAssignment( Assignment* assign = factory()->NewAssignment(
Token::ASSIGN, factory()->NewVariableProxy(temp), return_value, pos); 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 // temp === undefined
Expression* is_undefined = factory()->NewCompareOperation( Expression* is_undefined = factory()->NewCompareOperation(
Token::EQ_STRICT, assign, Token::EQ_STRICT, assign,
factory()->NewUndefinedLiteral(kNoSourcePosition), pos); factory()->NewUndefinedLiteral(kNoSourcePosition), pos);
// is_undefined ? this : is_object_conditional // is_undefined ? this : temp
return_value = factory()->NewConditional(is_undefined, ThisExpression(pos), return_value =
is_object_conditional, pos); factory()->NewConditional(is_undefined, ThisExpression(pos),
factory()->NewVariableProxy(temp), pos);
} }
return return_value; 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