Index: src/builtins/s390/builtins-s390.cc |
diff --git a/src/builtins/s390/builtins-s390.cc b/src/builtins/s390/builtins-s390.cc |
index 5311fcdfaa88432ba1e76aa205860f04f7aba63a..a8d8a3cec5b2ac10dc06dfc1da2adabcc9b17330 100644 |
--- a/src/builtins/s390/builtins-s390.cc |
+++ b/src/builtins/s390/builtins-s390.cc |
@@ -442,9 +442,7 @@ void Builtins::Generate_InOptimizationQueue(MacroAssembler* masm) { |
namespace { |
-void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function, |
- bool create_implicit_receiver, |
- bool disallow_non_object_return) { |
+void Generate_JSBuiltinsConstructStubHelper(MacroAssembler* masm) { |
Label post_instantiation_deopt_entry; |
// ----------- S t a t e ------------- |
// -- r2 : number of arguments |
@@ -455,52 +453,18 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function, |
// -- sp[...]: constructor arguments |
// ----------------------------------- |
- Isolate* isolate = masm->isolate(); |
- |
// Enter a construct frame. |
{ |
FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT); |
// Preserve the incoming parameters on the stack. |
- |
- if (!create_implicit_receiver) { |
- __ SmiTag(r6, r2); |
- __ LoadAndTestP(r6, r6); |
- __ Push(cp, r6); |
- __ PushRoot(Heap::kTheHoleValueRootIndex); |
- } else { |
- __ SmiTag(r2); |
- __ Push(cp, r2); |
- |
- // Allocate the new receiver object. |
- __ Push(r3, r5); |
- __ Call(CodeFactory::FastNewObject(masm->isolate()).code(), |
- RelocInfo::CODE_TARGET); |
- __ LoadRR(r6, r2); |
- __ Pop(r3, r5); |
- |
- // ----------- S t a t e ------------- |
- // -- r3: constructor function |
- // -- r5: new target |
- // -- r6: newly allocated object |
- // ----------------------------------- |
- |
- // Retrieve smi-tagged arguments count from the stack. |
- __ LoadP(r2, MemOperand(sp)); |
- __ SmiUntag(r2); |
- __ LoadAndTestP(r2, r2); |
- |
- // Push the allocated receiver to the stack. We need two copies |
- // because we may have to return the original one and the calling |
- // conventions dictate that the called function pops the receiver. |
- __ Push(r6, r6); |
- } |
- |
- // Deoptimizer re-enters stub code here. |
- __ bind(&post_instantiation_deopt_entry); |
- |
+ __ SmiTag(r2); |
+ __ Push(cp, r2); |
+ __ SmiUntag(r2); |
+ // The receiver for the builtin/api call. |
+ __ PushRoot(Heap::kTheHoleValueRootIndex); |
// Set up pointer to last argument. |
- __ la(r4, MemOperand(fp, StandardFrameConstants::kCallerSPOffset)); |
+ __ la(r6, MemOperand(fp, StandardFrameConstants::kCallerSPOffset)); |
// Copy arguments and receiver to the expression stack. |
// r2: number of arguments |
@@ -518,7 +482,7 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function, |
__ LoadRR(r1, r2); |
__ bind(&loop); |
__ lay(ip, MemOperand(ip, -kPointerSize)); |
- __ LoadP(r0, MemOperand(ip, r4)); |
+ __ LoadP(r0, MemOperand(ip, r6)); |
__ StoreP(r0, MemOperand(ip, sp)); |
__ BranchOnCount(r1, &loop); |
__ bind(&no_args); |
@@ -532,148 +496,228 @@ void Generate_JSConstructStubHelper(MacroAssembler* masm, bool is_api_function, |
__ InvokeFunction(r3, r5, actual, CALL_FUNCTION, |
CheckDebugStepCallWrapper()); |
- // Store offset of return address for deoptimizer. |
- if (create_implicit_receiver && !disallow_non_object_return && |
- !is_api_function) { |
- masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset( |
- masm->pc_offset()); |
- } |
- |
// Restore context from the frame. |
- // r2: result |
- // sp[0]: receiver |
- // sp[1]: number of arguments (smi-tagged) |
__ LoadP(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset)); |
- |
- if (create_implicit_receiver) { |
- // 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, 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) |
- // 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(&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. |
- __ bind(&use_receiver); |
- __ LoadP(r2, MemOperand(sp)); |
- |
- // Remove receiver from the stack, remove caller arguments, and |
- // return. |
- __ bind(&return_value); |
- // r2: result |
- // sp[0]: receiver (newly allocated object) |
- // sp[1]: number of arguments (smi-tagged) |
- __ LoadP(r3, MemOperand(sp, 1 * kPointerSize)); |
- } else { |
- __ LoadP(r3, MemOperand(sp)); |
- } |
+ // Restore smi-tagged arguments count from the frame. |
+ __ LoadP(r3, MemOperand(fp, ConstructFrameConstants::kLengthOffset)); |
// Leave construct frame. |
} |
- |
- // ES6 9.2.2. Step 13+ |
- // 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); |
- __ CompareObjectType(r2, r5, r5, FIRST_JS_RECEIVER_TYPE); |
- __ bge(&dont_throw); |
- __ bind(&do_throw); |
- { |
- FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
- __ CallRuntime(Runtime::kThrowConstructorReturnedNonObject); |
- } |
- __ bind(&dont_throw); |
- } |
+ // Remove caller arguments from the stack and return. |
+ STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
__ SmiToPtrArrayOffset(r3, r3); |
__ AddP(sp, sp, r3); |
__ AddP(sp, sp, Operand(kPointerSize)); |
- if (create_implicit_receiver) { |
- __ IncrementCounter(isolate->counters()->constructed_objects(), 1, r3, r4); |
- } |
__ Ret(); |
+} |
- // 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 && !disallow_non_object_return && |
- !is_api_function) { |
- masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset( |
- masm->pc_offset()); |
+// The construct stub for ES5 constructor functions and ES6 class constructors. |
+void Generate_JSConstructStubGeneric(MacroAssembler* masm, |
+ bool restrict_constructor_return) { |
+ // ----------- S t a t e ------------- |
+ // -- r2: number of arguments (untagged) |
+ // -- r3: constructor function |
+ // -- r5: new target |
+ // -- cp: context |
+ // -- lr: return address |
+ // -- sp[...]: constructor arguments |
+ // ----------------------------------- |
+ |
+ // Enter a construct frame. |
+ { |
+ FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT); |
+ Label post_instantiation_deopt_entry, not_create_implicit_receiver; |
+ |
+ // Preserve the incoming parameters on the stack. |
+ __ SmiTag(r2); |
+ __ Push(cp, r2, r3, r5); |
// ----------- S t a t e ------------- |
- // -- r2 : newly allocated object |
- // -- sp[0] : constructor function |
+ // -- sp[0*kPointerSize]: new target |
+ // -- r3 and sp[1*kPointerSize]: constructor function |
+ // -- sp[2*kPointerSize]: number of arguments (tagged) |
+ // -- sp[3*kPointerSize]: context |
// ----------------------------------- |
- __ pop(r3); |
+ __ LoadP(r6, FieldMemOperand(r3, JSFunction::kSharedFunctionInfoOffset)); |
+ __ LoadlW(r6, |
+ FieldMemOperand(r6, SharedFunctionInfo::kCompilerHintsOffset)); |
+ __ TestBitMask(r6, |
+ FunctionKind::kDerivedConstructor |
+ << SharedFunctionInfo::kFunctionKindShift, |
+ r0); |
+ __ bne(¬_create_implicit_receiver); |
+ |
+ // If not derived class constructor: Allocate the new receiver object. |
+ __ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1, |
+ r6, r7); |
+ __ Call(CodeFactory::FastNewObject(masm->isolate()).code(), |
+ RelocInfo::CODE_TARGET); |
+ __ b(&post_instantiation_deopt_entry); |
+ |
+ // Else: use TheHoleValue as receiver for constructor call |
+ __ bind(¬_create_implicit_receiver); |
+ __ LoadRoot(r2, Heap::kTheHoleValueRootIndex); |
+ |
+ // ----------- S t a t e ------------- |
+ // -- r2: receiver |
+ // -- Slot 3 / sp[0*kPointerSize]: new target |
+ // -- Slot 2 / sp[1*kPointerSize]: constructor function |
+ // -- Slot 1 / sp[2*kPointerSize]: number of arguments (tagged) |
+ // -- Slot 0 / sp[3*kPointerSize]: context |
+ // ----------------------------------- |
+ // Deoptimizer enters here. |
+ masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset( |
+ masm->pc_offset()); |
+ __ bind(&post_instantiation_deopt_entry); |
+ |
+ // Restore new target. |
+ __ Pop(r5); |
+ // Push the allocated receiver to the stack. We need two copies |
+ // because we may have to return the original one and the calling |
+ // conventions dictate that the called function pops the receiver. |
__ Push(r2, r2); |
- // Retrieve smi-tagged arguments count from the stack. |
+ // ----------- S t a t e ------------- |
+ // -- r5: new target |
+ // -- sp[0*kPointerSize]: implicit receiver |
+ // -- sp[1*kPointerSize]: implicit receiver |
+ // -- sp[2*kPointerSize]: constructor function |
+ // -- sp[3*kPointerSize]: number of arguments (tagged) |
+ // -- sp[4*kPointerSize]: context |
+ // ----------------------------------- |
+ |
+ // Restore constructor function and argument count. |
+ __ LoadP(r3, MemOperand(fp, ConstructFrameConstants::kConstructorOffset)); |
__ LoadP(r2, MemOperand(fp, ConstructFrameConstants::kLengthOffset)); |
__ SmiUntag(r2); |
- // Retrieve the new target value from the stack. This was placed into the |
- // frame description in place of the receiver by the optimizing compiler. |
- __ la(r5, MemOperand(fp, StandardFrameConstants::kCallerSPOffset)); |
+ // Set up pointer to last argument. |
+ __ la(r6, MemOperand(fp, StandardFrameConstants::kCallerSPOffset)); |
+ |
+ // Copy arguments and receiver to the expression stack. |
+ Label loop, no_args; |
+ // ----------- S t a t e ------------- |
+ // -- r2: number of arguments (untagged) |
+ // -- r5: new target |
+ // -- r6: pointer to last argument |
+ // -- cr0: condition indicating whether r2 is zero |
+ // -- sp[0*kPointerSize]: implicit receiver |
+ // -- sp[1*kPointerSize]: implicit receiver |
+ // -- r3 and sp[2*kPointerSize]: constructor function |
+ // -- sp[3*kPointerSize]: number of arguments (tagged) |
+ // -- sp[4*kPointerSize]: context |
+ // ----------------------------------- |
+ |
+ __ beq(&no_args); |
__ ShiftLeftP(ip, r2, Operand(kPointerSizeLog2)); |
- __ LoadP(r5, MemOperand(r5, ip)); |
+ __ SubP(sp, sp, ip); |
+ __ LoadRR(r1, r2); |
+ __ bind(&loop); |
+ __ lay(ip, MemOperand(ip, -kPointerSize)); |
+ __ LoadP(r0, MemOperand(ip, r6)); |
+ __ StoreP(r0, MemOperand(ip, sp)); |
+ __ BranchOnCount(r1, &loop); |
+ __ bind(&no_args); |
- // Continue with constructor function invocation. |
- __ b(&post_instantiation_deopt_entry); |
- } |
-} |
+ // Call the function. |
+ ParameterCount actual(r2); |
+ __ InvokeFunction(r3, r5, actual, CALL_FUNCTION, |
+ CheckDebugStepCallWrapper()); |
-} // namespace |
+ // ----------- S t a t e ------------- |
+ // -- r0: constructor result |
+ // -- sp[0*kPointerSize]: implicit receiver |
+ // -- sp[1*kPointerSize]: constructor function |
+ // -- sp[2*kPointerSize]: number of arguments |
+ // -- sp[3*kPointerSize]: context |
+ // ----------------------------------- |
-void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) { |
- Generate_JSConstructStubHelper(masm, false, true, false); |
-} |
+ // Store offset of return address for deoptimizer. |
+ masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset( |
+ masm->pc_offset()); |
-void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { |
- Generate_JSConstructStubHelper(masm, true, false, false); |
-} |
+ // Restore the context from the frame. |
+ __ LoadP(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset)); |
-void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) { |
- Generate_JSConstructStubHelper(masm, false, false, false); |
-} |
+ // 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, do_throw, other_result, leave_frame; |
+ |
+ // If the result is undefined, we jump out to using the implicit receiver. |
+ __ JumpIfRoot(r2, Heap::kUndefinedValueRootIndex, &use_receiver); |
+ |
+ // Otherwise we do a smi check and fall through to check if the return value |
+ // is a valid receiver. |
+ |
+ // If the result is a smi, it is *not* an object in the ECMA sense. |
+ __ JumpIfSmi(r2, &other_result); |
+ |
+ // 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. |
+ STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE); |
+ __ CompareObjectType(r2, r6, r6, FIRST_JS_RECEIVER_TYPE); |
+ __ bge(&leave_frame); |
+ |
+ __ bind(&other_result); |
+ // The result is now neither undefined nor an object. |
+ if (restrict_constructor_return) { |
+ // Throw if constructor function is a class constructor |
+ __ LoadP(r6, MemOperand(fp, ConstructFrameConstants::kConstructorOffset)); |
+ __ LoadP(r6, FieldMemOperand(r6, JSFunction::kSharedFunctionInfoOffset)); |
+ __ LoadlW(r6, |
+ FieldMemOperand(r6, SharedFunctionInfo::kCompilerHintsOffset)); |
+ __ TestBitMask(r6, |
+ FunctionKind::kClassConstructor |
+ << SharedFunctionInfo::kFunctionKindShift, |
+ r0); |
+ __ beq(&use_receiver); |
+ } else { |
+ __ b(&use_receiver); |
+ } |
+ __ bind(&do_throw); |
+ { |
+ FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL); |
+ __ CallRuntime(Runtime::kThrowConstructorReturnedNonObject); |
+ } |
+ |
+ // Throw away the result of the constructor invocation and use the |
+ // on-stack receiver as the result. |
+ __ bind(&use_receiver); |
+ __ LoadP(r2, MemOperand(sp)); |
+ __ JumpIfRoot(r2, Heap::kTheHoleValueRootIndex, &do_throw); |
-void Builtins::Generate_JSBuiltinsConstructStubForBase(MacroAssembler* masm) { |
- Generate_JSConstructStubHelper(masm, false, true, true); |
+ __ bind(&leave_frame); |
+ // Restore smi-tagged arguments count from the frame. |
+ __ LoadP(r3, MemOperand(fp, ConstructFrameConstants::kLengthOffset)); |
+ // Leave construct frame. |
+ } |
+ |
+ // Remove caller arguments from the stack and return. |
+ STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0); |
+ |
+ __ SmiToPtrArrayOffset(r3, r3); |
+ __ AddP(sp, sp, r3); |
+ __ AddP(sp, sp, Operand(kPointerSize)); |
+ __ Ret(); |
} |
+} // namespace |
-void Builtins::Generate_JSBuiltinsConstructStubForDerived( |
+void Builtins::Generate_JSConstructStubGenericRestrictedReturn( |
+ MacroAssembler* masm) { |
+ Generate_JSConstructStubGeneric(masm, true); |
+} |
+void Builtins::Generate_JSConstructStubGenericUnrestrictedReturn( |
MacroAssembler* masm) { |
- Generate_JSConstructStubHelper(masm, false, false, true); |
+ Generate_JSConstructStubGeneric(masm, false); |
+} |
+void Builtins::Generate_JSConstructStubApi(MacroAssembler* masm) { |
+ Generate_JSBuiltinsConstructStubHelper(masm); |
+} |
+void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) { |
+ Generate_JSBuiltinsConstructStubHelper(masm); |
} |
// static |