PPC: [runtime] Optimize and unify rest parameters.
Port 3ef573e9f1
Original commit message:
Replace the somewhat awkward RestParamAccessStub, which would always
call into the runtime anyway with a proper FastNewRestParameterStub,
which is basically based on the code that was already there for strict
arguments object materialization. But for rest parameters we could
optimize even further (leading to 8-10x improvements for functions with
rest parameters), by fixing the internal formal parameter count:
Every SharedFunctionInfo has a formal_parameter_count field, which
specifies the number of formal parameters, and is used to decide whether
we need to create an arguments adaptor frame when calling a function
(i.e. if there's a mismatch between the actual and expected parameters).
Previously the formal_parameter_count included the rest parameter, which
was sort of unfortunate, as that meant that calling a function with only
the non-rest parameters still required an arguments adaptor (plus some
other oddities). Now with this CL we fix, so that we do no longer
include the rest parameter in that count. Thereby checking for rest
parameters is very efficient, as we only need to check whether there is
an arguments adaptor frame, and if not create an empty array, otherwise
check whether the arguments adaptor frame has more parameters than
specified by the formal_parameter_count.
The FastNewRestParameterStub is written in a way that it can be directly
used by Ignition as well, and with some tweaks to the TurboFan backends
and the CodeStubAssembler, we should be able to rewrite it as
TurboFanCodeStub in the near future.
Drive-by-fix: Refactor and unify the CreateArgumentsType which was
different in TurboFan and Ignition; now we have a single enum class
xwhich is used in both TurboFan and Ignition.
R=bmeurer@chromium.org, joransiu@ca.ibm.com, jyan@ca.ibm.com, michael_dawson@ca.ibm.com
BUG=v8:2159
LOG=n
Review URL: https://codereview.chromium.org/1677223002
Cr-Commit-Position: refs/heads/master@{#33829}
This commit is contained in:
parent
7a004a02da
commit
605aced062
@ -263,21 +263,12 @@ void FullCodeGenerator::Generate() {
|
|||||||
Variable* rest_param = scope()->rest_parameter(&rest_index);
|
Variable* rest_param = scope()->rest_parameter(&rest_index);
|
||||||
if (rest_param) {
|
if (rest_param) {
|
||||||
Comment cmnt(masm_, "[ Allocate rest parameter array");
|
Comment cmnt(masm_, "[ Allocate rest parameter array");
|
||||||
|
if (!function_in_register_r4) {
|
||||||
int num_parameters = info->scope()->num_parameters();
|
__ LoadP(r4, MemOperand(fp, JavaScriptFrameConstants::kFunctionOffset));
|
||||||
int offset = num_parameters * kPointerSize;
|
}
|
||||||
|
FastNewRestParameterStub stub(isolate());
|
||||||
__ LoadSmiLiteral(RestParamAccessDescriptor::parameter_count(),
|
|
||||||
Smi::FromInt(num_parameters));
|
|
||||||
__ addi(RestParamAccessDescriptor::parameter_pointer(), fp,
|
|
||||||
Operand(StandardFrameConstants::kCallerSPOffset + offset));
|
|
||||||
__ LoadSmiLiteral(RestParamAccessDescriptor::rest_parameter_index(),
|
|
||||||
Smi::FromInt(rest_index));
|
|
||||||
function_in_register_r4 = false;
|
|
||||||
|
|
||||||
RestParamAccessStub stub(isolate());
|
|
||||||
__ CallStub(&stub);
|
__ CallStub(&stub);
|
||||||
|
function_in_register_r4 = false;
|
||||||
SetVar(rest_param, r3, r4, r5);
|
SetVar(rest_param, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1968,29 +1968,6 @@ void ArgumentsAccessStub::GenerateNewStrict(MacroAssembler* masm) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RestParamAccessStub::GenerateNew(MacroAssembler* masm) {
|
|
||||||
// r5 : number of parameters (tagged)
|
|
||||||
// r6 : parameters pointer
|
|
||||||
// r7 : rest parameter index (tagged)
|
|
||||||
|
|
||||||
Label runtime;
|
|
||||||
__ LoadP(r8, MemOperand(fp, StandardFrameConstants::kCallerFPOffset));
|
|
||||||
__ LoadP(r3, MemOperand(r8, StandardFrameConstants::kContextOffset));
|
|
||||||
__ CmpSmiLiteral(r3, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
|
|
||||||
__ bne(&runtime);
|
|
||||||
|
|
||||||
// Patch the arguments.length and the parameters pointer.
|
|
||||||
__ LoadP(r5, MemOperand(r8, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
|
||||||
__ SmiToPtrArrayOffset(r0, r5);
|
|
||||||
__ add(r6, r8, r0);
|
|
||||||
__ addi(r6, r6, Operand(StandardFrameConstants::kCallerSPOffset));
|
|
||||||
|
|
||||||
__ bind(&runtime);
|
|
||||||
__ Push(r5, r6, r7);
|
|
||||||
__ TailCallRuntime(Runtime::kNewRestParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RegExpExecStub::Generate(MacroAssembler* masm) {
|
void RegExpExecStub::Generate(MacroAssembler* masm) {
|
||||||
// Just jump directly to runtime if native RegExp is not selected at compile
|
// Just jump directly to runtime if native RegExp is not selected at compile
|
||||||
// time or if regexp entry in generated code is turned off runtime switch or
|
// time or if regexp entry in generated code is turned off runtime switch or
|
||||||
@ -5155,6 +5132,149 @@ void InternalArrayConstructorStub::Generate(MacroAssembler* masm) {
|
|||||||
GenerateCase(masm, FAST_ELEMENTS);
|
GenerateCase(masm, FAST_ELEMENTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FastNewRestParameterStub::Generate(MacroAssembler* masm) {
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- r4 : function
|
||||||
|
// -- cp : context
|
||||||
|
// -- fp : frame pointer
|
||||||
|
// -- lr : return address
|
||||||
|
// -----------------------------------
|
||||||
|
__ AssertFunction(r4);
|
||||||
|
|
||||||
|
// For Ignition we need to skip all possible handler/stub frames until
|
||||||
|
// we reach the JavaScript frame for the function (similar to what the
|
||||||
|
// runtime fallback implementation does). So make r5 point to that
|
||||||
|
// JavaScript frame.
|
||||||
|
{
|
||||||
|
Label loop, loop_entry;
|
||||||
|
__ mr(r5, fp);
|
||||||
|
__ b(&loop_entry);
|
||||||
|
__ bind(&loop);
|
||||||
|
__ LoadP(r5, MemOperand(r5, StandardFrameConstants::kCallerFPOffset));
|
||||||
|
__ bind(&loop_entry);
|
||||||
|
__ LoadP(ip, MemOperand(r5, StandardFrameConstants::kMarkerOffset));
|
||||||
|
__ cmp(ip, r4);
|
||||||
|
__ bne(&loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have rest parameters (only possible if we have an
|
||||||
|
// arguments adaptor frame below the function frame).
|
||||||
|
Label no_rest_parameters;
|
||||||
|
__ LoadP(r5, MemOperand(r5, StandardFrameConstants::kCallerFPOffset));
|
||||||
|
__ LoadP(ip, MemOperand(r5, StandardFrameConstants::kContextOffset));
|
||||||
|
__ CmpSmiLiteral(ip, Smi::FromInt(StackFrame::ARGUMENTS_ADAPTOR), r0);
|
||||||
|
__ bne(&no_rest_parameters);
|
||||||
|
|
||||||
|
// Check if the arguments adaptor frame contains more arguments than
|
||||||
|
// specified by the function's internal formal parameter count.
|
||||||
|
Label rest_parameters;
|
||||||
|
__ LoadP(r3, MemOperand(r5, ArgumentsAdaptorFrameConstants::kLengthOffset));
|
||||||
|
__ LoadP(r4, FieldMemOperand(r4, JSFunction::kSharedFunctionInfoOffset));
|
||||||
|
__ LoadWordArith(
|
||||||
|
r4, FieldMemOperand(r4, SharedFunctionInfo::kFormalParameterCountOffset));
|
||||||
|
#if V8_TARGET_ARCH_PPC64
|
||||||
|
__ SmiTag(r4);
|
||||||
|
#endif
|
||||||
|
__ sub(r3, r3, r4, LeaveOE, SetRC);
|
||||||
|
__ bgt(&rest_parameters, cr0);
|
||||||
|
|
||||||
|
// Return an empty rest parameter array.
|
||||||
|
__ bind(&no_rest_parameters);
|
||||||
|
{
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- cp : context
|
||||||
|
// -- lr : return address
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// Allocate an empty rest parameter array.
|
||||||
|
Label allocate, done_allocate;
|
||||||
|
__ Allocate(JSArray::kSize, r3, r4, r5, &allocate, TAG_OBJECT);
|
||||||
|
__ bind(&done_allocate);
|
||||||
|
|
||||||
|
// Setup the rest parameter array in r0.
|
||||||
|
__ LoadNativeContextSlot(Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX, r4);
|
||||||
|
__ StoreP(r4, FieldMemOperand(r3, JSArray::kMapOffset), r0);
|
||||||
|
__ LoadRoot(r4, Heap::kEmptyFixedArrayRootIndex);
|
||||||
|
__ StoreP(r4, FieldMemOperand(r3, JSArray::kPropertiesOffset), r0);
|
||||||
|
__ StoreP(r4, FieldMemOperand(r3, JSArray::kElementsOffset), r0);
|
||||||
|
__ li(r4, Operand::Zero());
|
||||||
|
__ StoreP(r4, FieldMemOperand(r3, JSArray::kLengthOffset), r0);
|
||||||
|
STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
|
||||||
|
__ Ret();
|
||||||
|
|
||||||
|
// Fall back to %AllocateInNewSpace.
|
||||||
|
__ bind(&allocate);
|
||||||
|
{
|
||||||
|
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
__ Push(Smi::FromInt(JSArray::kSize));
|
||||||
|
__ CallRuntime(Runtime::kAllocateInNewSpace);
|
||||||
|
}
|
||||||
|
__ b(&done_allocate);
|
||||||
|
}
|
||||||
|
|
||||||
|
__ bind(&rest_parameters);
|
||||||
|
{
|
||||||
|
// Compute the pointer to the first rest parameter (skippping the receiver).
|
||||||
|
__ SmiToPtrArrayOffset(r9, r3);
|
||||||
|
__ add(r5, r5, r9);
|
||||||
|
__ addi(r5, r5, Operand(StandardFrameConstants::kCallerSPOffset));
|
||||||
|
|
||||||
|
// ----------- S t a t e -------------
|
||||||
|
// -- cp : context
|
||||||
|
// -- r3 : number of rest parameters (tagged)
|
||||||
|
// -- r5 : pointer just past first rest parameters
|
||||||
|
// -- r9 : size of rest parameters
|
||||||
|
// -- lr : return address
|
||||||
|
// -----------------------------------
|
||||||
|
|
||||||
|
// Allocate space for the rest parameter array plus the backing store.
|
||||||
|
Label allocate, done_allocate;
|
||||||
|
__ mov(r4, Operand(JSArray::kSize + FixedArray::kHeaderSize));
|
||||||
|
__ add(r4, r4, r9);
|
||||||
|
__ Allocate(r4, r6, r7, r8, &allocate, TAG_OBJECT);
|
||||||
|
__ bind(&done_allocate);
|
||||||
|
|
||||||
|
// Setup the elements array in r6.
|
||||||
|
__ LoadRoot(r4, Heap::kFixedArrayMapRootIndex);
|
||||||
|
__ StoreP(r4, FieldMemOperand(r6, FixedArray::kMapOffset), r0);
|
||||||
|
__ StoreP(r3, FieldMemOperand(r6, FixedArray::kLengthOffset), r0);
|
||||||
|
__ addi(r7, r6,
|
||||||
|
Operand(FixedArray::kHeaderSize - kHeapObjectTag - kPointerSize));
|
||||||
|
{
|
||||||
|
Label loop;
|
||||||
|
__ SmiUntag(r0, r3);
|
||||||
|
__ mtctr(r0);
|
||||||
|
__ bind(&loop);
|
||||||
|
__ LoadPU(ip, MemOperand(r5, -kPointerSize));
|
||||||
|
__ StorePU(ip, MemOperand(r7, kPointerSize));
|
||||||
|
__ bdnz(&loop);
|
||||||
|
__ addi(r7, r7, Operand(kPointerSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup the rest parameter array in r7.
|
||||||
|
__ LoadNativeContextSlot(Context::JS_ARRAY_FAST_ELEMENTS_MAP_INDEX, r4);
|
||||||
|
__ StoreP(r4, MemOperand(r7, JSArray::kMapOffset));
|
||||||
|
__ LoadRoot(r4, Heap::kEmptyFixedArrayRootIndex);
|
||||||
|
__ StoreP(r4, MemOperand(r7, JSArray::kPropertiesOffset));
|
||||||
|
__ StoreP(r6, MemOperand(r7, JSArray::kElementsOffset));
|
||||||
|
__ StoreP(r3, MemOperand(r7, JSArray::kLengthOffset));
|
||||||
|
STATIC_ASSERT(JSArray::kSize == 4 * kPointerSize);
|
||||||
|
__ addi(r3, r7, Operand(kHeapObjectTag));
|
||||||
|
__ Ret();
|
||||||
|
|
||||||
|
// Fall back to %AllocateInNewSpace.
|
||||||
|
__ bind(&allocate);
|
||||||
|
{
|
||||||
|
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
|
||||||
|
__ SmiTag(r4);
|
||||||
|
__ Push(r3, r5, r9, r4);
|
||||||
|
__ CallRuntime(Runtime::kAllocateInNewSpace);
|
||||||
|
__ mr(r6, r3);
|
||||||
|
__ Pop(r3, r5, r9);
|
||||||
|
}
|
||||||
|
__ b(&done_allocate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void LoadGlobalViaContextStub::Generate(MacroAssembler* masm) {
|
void LoadGlobalViaContextStub::Generate(MacroAssembler* masm) {
|
||||||
Register context = cp;
|
Register context = cp;
|
||||||
|
@ -63,11 +63,6 @@ const Register ArgumentsAccessNewDescriptor::parameter_count() { return r5; }
|
|||||||
const Register ArgumentsAccessNewDescriptor::parameter_pointer() { return r6; }
|
const Register ArgumentsAccessNewDescriptor::parameter_pointer() { return r6; }
|
||||||
|
|
||||||
|
|
||||||
const Register RestParamAccessDescriptor::parameter_count() { return r5; }
|
|
||||||
const Register RestParamAccessDescriptor::parameter_pointer() { return r6; }
|
|
||||||
const Register RestParamAccessDescriptor::rest_parameter_index() { return r7; }
|
|
||||||
|
|
||||||
|
|
||||||
const Register ApiGetterDescriptor::function_address() { return r5; }
|
const Register ApiGetterDescriptor::function_address() { return r5; }
|
||||||
|
|
||||||
|
|
||||||
@ -96,6 +91,12 @@ void FastNewContextDescriptor::InitializePlatformSpecific(
|
|||||||
data->InitializePlatformSpecific(arraysize(registers), registers);
|
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FastNewRestParameterDescriptor::InitializePlatformSpecific(
|
||||||
|
CallInterfaceDescriptorData* data) {
|
||||||
|
Register registers[] = {r4};
|
||||||
|
data->InitializePlatformSpecific(arraysize(registers), registers);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ToNumberDescriptor::InitializePlatformSpecific(
|
void ToNumberDescriptor::InitializePlatformSpecific(
|
||||||
CallInterfaceDescriptorData* data) {
|
CallInterfaceDescriptorData* data) {
|
||||||
|
Loading…
Reference in New Issue
Block a user