Commit d9f6dd89 authored by jyan's avatar jyan Committed by Commit bot

PPC/s390: [builtins] Change semantics of class constructors returning primitives

Port a7c4e778

Original Commit Message:

    This change mirrors the semantics for derived class constructors. This
    change doesn't affect non class constructors.

    This change could potentially break web compat. More details:
    https://github.com/tc39/ecma262/pull/469

R=gsathya@chromium.org, joransiu@ca.ibm.com, bjaideep@ca.ibm.com, michael_dawson@ca.ibm.com
BUG=
LOG=N

Review-Url: https://codereview.chromium.org/2815873003
Cr-Commit-Position: refs/heads/master@{#44627}
parent 7b300ba2
......@@ -448,7 +448,7 @@ namespace {
void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
bool create_implicit_receiver,
bool check_derived_construct) {
bool disallow_non_object_return) {
Label post_instantiation_deopt_entry;
// ----------- S t a t e -------------
// -- r3 : number of arguments
......@@ -537,7 +537,8 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
}
// Store offset of return address for deoptimizer.
if (create_implicit_receiver && !is_api_function) {
if (create_implicit_receiver && !disallow_non_object_return &&
!is_api_function) {
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
}
......@@ -552,18 +553,32 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
// If the result is an object (in the ECMA sense), we should get rid
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
// on page 74.
Label use_receiver, exit;
Label use_receiver, return_value, do_throw;
// If the result is a smi, it is *not* an object in the ECMA sense.
// r3: result
// sp[0]: receiver
// sp[1]: number of arguments (smi-tagged)
__ JumpIfSmi(r3, &use_receiver);
// If the result is undefined, we jump out to using the implicit
// receiver, otherwise we do a smi check and fall through to
// check if the return value is a valid receiver.
if (disallow_non_object_return) {
__ CompareRoot(r3, Heap::kUndefinedValueRootIndex);
__ beq(&use_receiver);
__ JumpIfSmi(r3, &do_throw);
} else {
__ JumpIfSmi(r3, &use_receiver);
}
// If the type of the result (stored in its map) is less than
// FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
__ CompareObjectType(r3, r4, r6, FIRST_JS_RECEIVER_TYPE);
__ bge(&exit);
__ bge(&return_value);
if (disallow_non_object_return) {
__ bind(&do_throw);
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
}
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
......@@ -572,7 +587,7 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
// Remove receiver from the stack, remove caller arguments, and
// return.
__ bind(&exit);
__ bind(&return_value);
// r3: result
// sp[0]: receiver (newly allocated object)
// sp[1]: number of arguments (smi-tagged)
......@@ -585,9 +600,10 @@ 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.
if (check_derived_construct) {
// For derived class constructors, throw a TypeError here if the result
// is not a JSReceiver. For the base constructor, we've already checked
// the result, so we omit the check.
if (disallow_non_object_return && !create_implicit_receiver) {
Label do_throw, dont_throw;
__ JumpIfSmi(r3, &do_throw);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
......@@ -596,7 +612,7 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
__ bind(&do_throw);
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
}
__ bind(&dont_throw);
}
......@@ -611,7 +627,8 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
// Store offset of trampoline address for deoptimizer. This is the bailout
// point after the receiver instantiation but before the function invocation.
// We need to restore some registers in order to continue the above code.
if (create_implicit_receiver && !is_api_function) {
if (create_implicit_receiver && !disallow_non_object_return &&
!is_api_function) {
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
......@@ -652,6 +669,10 @@ void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, false, false);
}
void Builtins::Generate_JSBuiltinsConstructStubForBase(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, true, true);
}
void Builtins::Generate_JSBuiltinsConstructStubForDerived(
MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, false, true);
......
......@@ -444,7 +444,7 @@ namespace {
void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
bool create_implicit_receiver,
bool check_derived_construct) {
bool disallow_non_object_return) {
Label post_instantiation_deopt_entry;
// ----------- S t a t e -------------
// -- r2 : number of arguments
......@@ -533,7 +533,8 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
CheckDebugStepCallWrapper());
// Store offset of return address for deoptimizer.
if (create_implicit_receiver && !is_api_function) {
if (create_implicit_receiver && !disallow_non_object_return &&
!is_api_function) {
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
masm->pc_offset());
}
......@@ -548,19 +549,33 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
// If the result is an object (in the ECMA sense), we should get rid
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
// on page 74.
Label use_receiver, exit;
Label use_receiver, return_value, do_throw;
// If the result is a smi, it is *not* an object in the ECMA sense.
// r2: result
// sp[0]: receiver
// sp[1]: new.target
// sp[2]: number of arguments (smi-tagged)
__ JumpIfSmi(r2, &use_receiver);
// If the result is undefined, we jump out to using the implicit
// receiver, otherwise we do a smi check and fall through to
// check if the return value is a valid receiver.
if (disallow_non_object_return) {
__ CompareRoot(r2, Heap::kUndefinedValueRootIndex);
__ beq(&use_receiver);
__ JumpIfSmi(r2, &do_throw);
} else {
__ JumpIfSmi(r2, &use_receiver);
}
// If the type of the result (stored in its map) is less than
// FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
__ CompareObjectType(r2, r3, r5, FIRST_JS_RECEIVER_TYPE);
__ bge(&exit);
__ bge(&return_value);
if (disallow_non_object_return) {
__ bind(&do_throw);
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
}
// Throw away the result of the constructor invocation and use the
// on-stack receiver as the result.
......@@ -569,7 +584,7 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
// Remove receiver from the stack, remove caller arguments, and
// return.
__ bind(&exit);
__ bind(&return_value);
// r2: result
// sp[0]: receiver (newly allocated object)
// sp[1]: number of arguments (smi-tagged)
......@@ -582,9 +597,10 @@ 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.
if (check_derived_construct) {
// For derived class constructors, throw a TypeError here if the result
// is not a JSReceiver. For the base constructor, we've already checked
// the result, so we omit the check.
if (disallow_non_object_return && !create_implicit_receiver) {
Label do_throw, dont_throw;
__ JumpIfSmi(r2, &do_throw);
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
......@@ -593,7 +609,7 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
__ bind(&do_throw);
{
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
__ CallRuntime(Runtime::kThrowDerivedConstructorReturnedNonObject);
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
}
__ bind(&dont_throw);
}
......@@ -609,7 +625,8 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function,
// Store offset of trampoline address for deoptimizer. This is the bailout
// point after the receiver instantiation but before the function invocation.
// We need to restore some registers in order to continue the above code.
if (create_implicit_receiver && !is_api_function) {
if (create_implicit_receiver && !disallow_non_object_return &&
!is_api_function) {
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
masm->pc_offset());
......@@ -650,6 +667,10 @@ void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, false, false);
}
void Builtins::Generate_JSBuiltinsConstructStubForBase(MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, true, true);
}
void Builtins::Generate_JSBuiltinsConstructStubForDerived(
MacroAssembler* masm) {
Generate_JSConstructStubHelper(masm, false, false, true);
......
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