Skip to content

Commit 366d30c

Browse files
verwaestCommit Bot
authored andcommitted
[builtins] Streamline the construct stubs
- don't restore the context register after InvokeFunction unless we need to for throwing exceptions. - manually manage the frame to improve code layout for the fast path Change-Id: Ibccb3bf604085bd470c4279d0348edcf6f18d796 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2523196 Commit-Queue: Toon Verwaest <[email protected]> Reviewed-by: Igor Sheludko <[email protected]> Cr-Commit-Position: refs/heads/master@{#71094}
1 parent 6c69379 commit 366d30c

7 files changed

Lines changed: 551 additions & 561 deletions

File tree

src/builtins/arm/builtins-arm.cc

Lines changed: 124 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -151,158 +151,155 @@ void Builtins::Generate_JSConstructStubGeneric(MacroAssembler* masm) {
151151
// -- sp[...]: constructor arguments
152152
// -----------------------------------
153153

154+
FrameScope scope(masm, StackFrame::MANUAL);
154155
// Enter a construct frame.
155-
{
156-
FrameAndConstantPoolScope scope(masm, StackFrame::CONSTRUCT);
157-
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
158-
159-
// Preserve the incoming parameters on the stack.
160-
__ LoadRoot(r4, RootIndex::kTheHoleValue);
161-
__ SmiTag(r0);
162-
__ Push(cp, r0, r1, r4, r3);
163-
164-
// ----------- S t a t e -------------
165-
// -- sp[0*kPointerSize]: new target
166-
// -- sp[1*kPointerSize]: padding
167-
// -- r1 and sp[2*kPointerSize]: constructor function
168-
// -- sp[3*kPointerSize]: number of arguments (tagged)
169-
// -- sp[4*kPointerSize]: context
170-
// -----------------------------------
171-
172-
__ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
173-
__ ldr(r4, FieldMemOperand(r4, SharedFunctionInfo::kFlagsOffset));
174-
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(r4);
175-
__ JumpIfIsInRange(r4, kDefaultDerivedConstructor, kDerivedConstructor,
176-
&not_create_implicit_receiver);
177-
178-
// If not derived class constructor: Allocate the new receiver object.
179-
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1,
180-
r4, r5);
181-
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject),
182-
RelocInfo::CODE_TARGET);
183-
__ b(&post_instantiation_deopt_entry);
184-
185-
// Else: use TheHoleValue as receiver for constructor call
186-
__ bind(&not_create_implicit_receiver);
187-
__ LoadRoot(r0, RootIndex::kTheHoleValue);
188-
189-
// ----------- S t a t e -------------
190-
// -- r0: receiver
191-
// -- Slot 3 / sp[0*kPointerSize]: new target
192-
// -- Slot 2 / sp[1*kPointerSize]: constructor function
193-
// -- Slot 1 / sp[2*kPointerSize]: number of arguments (tagged)
194-
// -- Slot 0 / sp[3*kPointerSize]: context
195-
// -----------------------------------
196-
// Deoptimizer enters here.
197-
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
198-
masm->pc_offset());
199-
__ bind(&post_instantiation_deopt_entry);
200-
201-
// Restore new target.
202-
__ Pop(r3);
203-
204-
// Push the allocated receiver to the stack.
205-
__ Push(r0);
206-
// We need two copies because we may have to return the original one
207-
// and the calling conventions dictate that the called function pops the
208-
// receiver. The second copy is pushed after the arguments, we saved in r6
209-
// since r0 needs to store the number of arguments before
210-
// InvokingFunction.
211-
__ mov(r6, r0);
212-
213-
// Set up pointer to first argument (skip receiver).
214-
__ add(
215-
r4, fp,
216-
Operand(StandardFrameConstants::kCallerSPOffset + kSystemPointerSize));
156+
Label post_instantiation_deopt_entry, not_create_implicit_receiver;
157+
__ EnterFrame(StackFrame::CONSTRUCT);
217158

218-
// Restore constructor function and argument count.
219-
__ ldr(r1, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
220-
__ ldr(r0, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
221-
__ SmiUntag(r0);
159+
// Preserve the incoming parameters on the stack.
160+
__ LoadRoot(r4, RootIndex::kTheHoleValue);
161+
__ SmiTag(r0);
162+
__ Push(cp, r0, r1, r4, r3);
222163

223-
Label enough_stack_space, stack_overflow;
224-
__ StackOverflowCheck(r0, r5, &stack_overflow);
225-
__ b(&enough_stack_space);
164+
// ----------- S t a t e -------------
165+
// -- sp[0*kPointerSize]: new target
166+
// -- sp[1*kPointerSize]: padding
167+
// -- r1 and sp[2*kPointerSize]: constructor function
168+
// -- sp[3*kPointerSize]: number of arguments (tagged)
169+
// -- sp[4*kPointerSize]: context
170+
// -----------------------------------
226171

227-
__ bind(&stack_overflow);
228-
// Restore the context from the frame.
229-
__ ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
230-
__ CallRuntime(Runtime::kThrowStackOverflow);
231-
// Unreachable code.
232-
__ bkpt(0);
172+
__ ldr(r4, FieldMemOperand(r1, JSFunction::kSharedFunctionInfoOffset));
173+
__ ldr(r4, FieldMemOperand(r4, SharedFunctionInfo::kFlagsOffset));
174+
__ DecodeField<SharedFunctionInfo::FunctionKindBits>(r4);
175+
__ JumpIfIsInRange(r4, kDefaultDerivedConstructor, kDerivedConstructor,
176+
&not_create_implicit_receiver);
233177

234-
__ bind(&enough_stack_space);
178+
// If not derived class constructor: Allocate the new receiver object.
179+
__ IncrementCounter(masm->isolate()->counters()->constructed_objects(), 1, r4,
180+
r5);
181+
__ Call(BUILTIN_CODE(masm->isolate(), FastNewObject), RelocInfo::CODE_TARGET);
182+
__ b(&post_instantiation_deopt_entry);
235183

236-
// TODO(victorgomes): When the arguments adaptor is completely removed, we
237-
// should get the formal parameter count and copy the arguments in its
238-
// correct position (including any undefined), instead of delaying this to
239-
// InvokeFunction.
184+
// Else: use TheHoleValue as receiver for constructor call
185+
__ bind(&not_create_implicit_receiver);
186+
__ LoadRoot(r0, RootIndex::kTheHoleValue);
240187

241-
// Copy arguments to the expression stack.
242-
__ PushArray(r4, r0, r5);
188+
// ----------- S t a t e -------------
189+
// -- r0: receiver
190+
// -- Slot 3 / sp[0*kPointerSize]: new target
191+
// -- Slot 2 / sp[1*kPointerSize]: constructor function
192+
// -- Slot 1 / sp[2*kPointerSize]: number of arguments (tagged)
193+
// -- Slot 0 / sp[3*kPointerSize]: context
194+
// -----------------------------------
195+
// Deoptimizer enters here.
196+
masm->isolate()->heap()->SetConstructStubCreateDeoptPCOffset(
197+
masm->pc_offset());
198+
__ bind(&post_instantiation_deopt_entry);
199+
200+
// Restore new target.
201+
__ Pop(r3);
202+
203+
// Push the allocated receiver to the stack.
204+
__ Push(r0);
205+
// We need two copies because we may have to return the original one
206+
// and the calling conventions dictate that the called function pops the
207+
// receiver. The second copy is pushed after the arguments, we saved in r6
208+
// since r0 needs to store the number of arguments before
209+
// InvokingFunction.
210+
__ mov(r6, r0);
211+
212+
// Set up pointer to first argument (skip receiver).
213+
__ add(r4, fp,
214+
Operand(StandardFrameConstants::kCallerSPOffset + kSystemPointerSize));
215+
216+
// Restore constructor function and argument count.
217+
__ ldr(r1, MemOperand(fp, ConstructFrameConstants::kConstructorOffset));
218+
__ ldr(r0, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
219+
__ SmiUntag(r0);
243220

244-
// Push implicit receiver.
245-
__ Push(r6);
221+
Label stack_overflow;
222+
__ StackOverflowCheck(r0, r5, &stack_overflow);
246223

247-
// Call the function.
248-
__ InvokeFunctionWithNewTarget(r1, r3, r0, CALL_FUNCTION);
224+
// TODO(victorgomes): When the arguments adaptor is completely removed, we
225+
// should get the formal parameter count and copy the arguments in its
226+
// correct position (including any undefined), instead of delaying this to
227+
// InvokeFunction.
249228

250-
// ----------- S t a t e -------------
251-
// -- r0: constructor result
252-
// -- sp[0*kPointerSize]: implicit receiver
253-
// -- sp[1*kPointerSize]: padding
254-
// -- sp[2*kPointerSize]: constructor function
255-
// -- sp[3*kPointerSize]: number of arguments
256-
// -- sp[4*kPointerSize]: context
257-
// -----------------------------------
229+
// Copy arguments to the expression stack.
230+
__ PushArray(r4, r0, r5);
258231

259-
// Store offset of return address for deoptimizer.
260-
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
261-
masm->pc_offset());
232+
// Push implicit receiver.
233+
__ Push(r6);
262234

263-
// Restore the context from the frame.
264-
__ ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
235+
// Call the function.
236+
__ InvokeFunctionWithNewTarget(r1, r3, r0, CALL_FUNCTION);
265237

266-
// If the result is an object (in the ECMA sense), we should get rid
267-
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
268-
// on page 74.
269-
Label use_receiver, do_throw, leave_frame;
238+
// ----------- S t a t e -------------
239+
// -- r0: constructor result
240+
// -- sp[0*kPointerSize]: implicit receiver
241+
// -- sp[1*kPointerSize]: padding
242+
// -- sp[2*kPointerSize]: constructor function
243+
// -- sp[3*kPointerSize]: number of arguments
244+
// -- sp[4*kPointerSize]: context
245+
// -----------------------------------
270246

271-
// If the result is undefined, we jump out to using the implicit receiver.
272-
__ JumpIfRoot(r0, RootIndex::kUndefinedValue, &use_receiver);
247+
// Store offset of return address for deoptimizer.
248+
masm->isolate()->heap()->SetConstructStubInvokeDeoptPCOffset(
249+
masm->pc_offset());
273250

274-
// Otherwise we do a smi check and fall through to check if the return value
275-
// is a valid receiver.
251+
// If the result is an object (in the ECMA sense), we should get rid
252+
// of the receiver and use the result; see ECMA-262 section 13.2.2-7
253+
// on page 74.
254+
Label use_receiver, do_throw, leave_and_return, check_receiver;
276255

277-
// If the result is a smi, it is *not* an object in the ECMA sense.
278-
__ JumpIfSmi(r0, &use_receiver);
256+
// If the result is undefined, we jump out to using the implicit receiver.
257+
__ JumpIfNotRoot(r0, RootIndex::kUndefinedValue, &check_receiver);
279258

280-
// If the type of the result (stored in its map) is less than
281-
// FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
282-
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
283-
__ CompareObjectType(r0, r4, r5, FIRST_JS_RECEIVER_TYPE);
284-
__ b(ge, &leave_frame);
285-
__ b(&use_receiver);
259+
// Otherwise we do a smi check and fall through to check if the return value
260+
// is a valid receiver.
286261

287-
__ bind(&do_throw);
288-
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
262+
// Throw away the result of the constructor invocation and use the
263+
// on-stack receiver as the result.
264+
__ bind(&use_receiver);
265+
__ ldr(r0, MemOperand(sp, 0 * kPointerSize));
266+
__ JumpIfRoot(r0, RootIndex::kTheHoleValue, &do_throw);
289267

290-
// Throw away the result of the constructor invocation and use the
291-
// on-stack receiver as the result.
292-
__ bind(&use_receiver);
293-
__ ldr(r0, MemOperand(sp, 0 * kPointerSize));
294-
__ JumpIfRoot(r0, RootIndex::kTheHoleValue, &do_throw);
268+
__ bind(&leave_and_return);
269+
// Restore smi-tagged arguments count from the frame.
270+
__ ldr(r1, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
271+
// Leave construct frame.
272+
__ LeaveFrame(StackFrame::CONSTRUCT);
295273

296-
__ bind(&leave_frame);
297-
// Restore smi-tagged arguments count from the frame.
298-
__ ldr(r1, MemOperand(fp, ConstructFrameConstants::kLengthOffset));
299-
// Leave construct frame.
300-
}
301274
// Remove caller arguments from the stack and return.
302275
STATIC_ASSERT(kSmiTagSize == 1 && kSmiTag == 0);
303276
__ add(sp, sp, Operand(r1, LSL, kPointerSizeLog2 - kSmiTagSize));
304277
__ add(sp, sp, Operand(kPointerSize));
305278
__ Jump(lr);
279+
280+
__ bind(&check_receiver);
281+
// If the result is a smi, it is *not* an object in the ECMA sense.
282+
__ JumpIfSmi(r0, &use_receiver);
283+
284+
// If the type of the result (stored in its map) is less than
285+
// FIRST_JS_RECEIVER_TYPE, it is not an object in the ECMA sense.
286+
STATIC_ASSERT(LAST_JS_RECEIVER_TYPE == LAST_TYPE);
287+
__ CompareObjectType(r0, r4, r5, FIRST_JS_RECEIVER_TYPE);
288+
__ b(ge, &leave_and_return);
289+
__ b(&use_receiver);
290+
291+
__ bind(&do_throw);
292+
// Restore the context from the frame.
293+
__ ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
294+
__ CallRuntime(Runtime::kThrowConstructorReturnedNonObject);
295+
__ bkpt(0);
296+
297+
__ bind(&stack_overflow);
298+
// Restore the context from the frame.
299+
__ ldr(cp, MemOperand(fp, ConstructFrameConstants::kContextOffset));
300+
__ CallRuntime(Runtime::kThrowStackOverflow);
301+
// Unreachable code.
302+
__ bkpt(0);
306303
}
307304

308305
void Builtins::Generate_JSBuiltinsConstructStub(MacroAssembler* masm) {

0 commit comments

Comments
 (0)