Commit 4447405b authored by danno's avatar danno Committed by Commit bot

[builtins]: Uniformly push argument count in TF-generated builtins

Review-Url: https://codereview.chromium.org/2467513002
Cr-Commit-Position: refs/heads/master@{#40712}
parent 4d2659a7
...@@ -1690,6 +1690,9 @@ void CodeGenerator::AssembleConstructFrame() { ...@@ -1690,6 +1690,9 @@ void CodeGenerator::AssembleConstructFrame() {
} }
} else if (descriptor->IsJSFunctionCall()) { } else if (descriptor->IsJSFunctionCall()) {
__ Prologue(this->info()->GeneratePreagedPrologue()); __ Prologue(this->info()->GeneratePreagedPrologue());
if (descriptor->PushArgumentCount()) {
__ Push(kJavaScriptCallArgCountRegister);
}
} else { } else {
__ StubPrologue(info()->GetOutputStackFrameType()); __ StubPrologue(info()->GetOutputStackFrameType());
} }
...@@ -1699,7 +1702,8 @@ void CodeGenerator::AssembleConstructFrame() { ...@@ -1699,7 +1702,8 @@ void CodeGenerator::AssembleConstructFrame() {
} }
} }
int shrink_slots = frame()->GetSpillSlotCount(); int shrink_slots =
frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
if (info()->is_osr()) { if (info()->is_osr()) {
// TurboFan OSR-compiled functions cannot be entered directly. // TurboFan OSR-compiled functions cannot be entered directly.
......
...@@ -1795,43 +1795,57 @@ void CodeGenerator::AssembleConstructFrame() { ...@@ -1795,43 +1795,57 @@ void CodeGenerator::AssembleConstructFrame() {
__ AssertCspAligned(); __ AssertCspAligned();
} }
int fixed_frame_size = descriptor->CalculateFixedFrameSize();
int shrink_slots =
frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
if (frame_access_state()->has_frame()) { if (frame_access_state()->has_frame()) {
// Link the frame
if (descriptor->IsJSFunctionCall()) { if (descriptor->IsJSFunctionCall()) {
DCHECK(!descriptor->UseNativeStack()); DCHECK(!descriptor->UseNativeStack());
__ Prologue(this->info()->GeneratePreagedPrologue()); __ Prologue(this->info()->GeneratePreagedPrologue());
} else { } else {
if (descriptor->IsCFunctionCall()) { __ Push(lr, fp);
__ Push(lr, fp); __ Mov(fp, masm_.StackPointer());
__ Mov(fp, masm_.StackPointer());
__ Claim(frame()->GetSpillSlotCount());
} else {
__ StubPrologue(info()->GetOutputStackFrameType(),
frame()->GetTotalFrameSlotCount());
}
} }
if (!info()->GeneratePreagedPrologue()) { if (!info()->GeneratePreagedPrologue()) {
unwinding_info_writer_.MarkFrameConstructed(__ pc_offset()); unwinding_info_writer_.MarkFrameConstructed(__ pc_offset());
} }
}
int shrink_slots = frame()->GetSpillSlotCount();
if (info()->is_osr()) { // Create OSR entry if applicable
// TurboFan OSR-compiled functions cannot be entered directly. if (info()->is_osr()) {
__ Abort(kShouldNotDirectlyEnterOsrFunction); // TurboFan OSR-compiled functions cannot be entered directly.
__ Abort(kShouldNotDirectlyEnterOsrFunction);
// Unoptimized code jumps directly to this entrypoint while the unoptimized
// frame is still on the stack. Optimized code uses OSR values directly from // Unoptimized code jumps directly to this entrypoint while the
// the unoptimized frame. Thus, all that needs to be done is to allocate the // unoptimized
// remaining stack slots. // frame is still on the stack. Optimized code uses OSR values directly
if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --"); // from
osr_pc_offset_ = __ pc_offset(); // the unoptimized frame. Thus, all that needs to be done is to allocate
shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots(); // the
} // remaining stack slots.
if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
osr_pc_offset_ = __ pc_offset();
shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
}
if (descriptor->IsJSFunctionCall()) { // Build remainder of frame, including accounting for and filling-in
__ Claim(shrink_slots); // frame-specific header information, e.g. claiming the extra slot that
// other platforms explicitly push for STUB frames and frames recording
// their argument count.
__ Claim(shrink_slots + (fixed_frame_size & 1));
if (descriptor->PushArgumentCount()) {
__ Str(kJavaScriptCallArgCountRegister,
MemOperand(fp, OptimizedBuiltinFrameConstants::kArgCOffset));
}
bool is_stub_frame =
!descriptor->IsJSFunctionCall() && !descriptor->IsCFunctionCall();
if (is_stub_frame) {
UseScratchRegisterScope temps(masm());
Register temp = temps.AcquireX();
__ Mov(temp, Smi::FromInt(info()->GetOutputStackFrameType()));
__ Str(temp, MemOperand(fp, TypedFrameConstants::kFrameTypeOffset));
}
} }
// Save FP registers. // Save FP registers.
......
...@@ -41,8 +41,11 @@ CodeAssembler::CodeAssembler(Isolate* isolate, Zone* zone, ...@@ -41,8 +41,11 @@ CodeAssembler::CodeAssembler(Isolate* isolate, Zone* zone,
CodeAssembler::CodeAssembler(Isolate* isolate, Zone* zone, int parameter_count, CodeAssembler::CodeAssembler(Isolate* isolate, Zone* zone, int parameter_count,
Code::Flags flags, const char* name) Code::Flags flags, const char* name)
: CodeAssembler(isolate, zone, : CodeAssembler(isolate, zone,
Linkage::GetJSCallDescriptor(zone, false, parameter_count, Linkage::GetJSCallDescriptor(
CallDescriptor::kNoFlags), zone, false, parameter_count,
Code::ExtractKindFromFlags(flags) == Code::BUILTIN
? CallDescriptor::kPushArgumentCount
: CallDescriptor::kNoFlags),
flags, name) {} flags, name) {}
CodeAssembler::CodeAssembler(Isolate* isolate, Zone* zone, CodeAssembler::CodeAssembler(Isolate* isolate, Zone* zone,
......
...@@ -1945,12 +1945,16 @@ void CodeGenerator::AssembleConstructFrame() { ...@@ -1945,12 +1945,16 @@ void CodeGenerator::AssembleConstructFrame() {
__ mov(ebp, esp); __ mov(ebp, esp);
} else if (descriptor->IsJSFunctionCall()) { } else if (descriptor->IsJSFunctionCall()) {
__ Prologue(this->info()->GeneratePreagedPrologue()); __ Prologue(this->info()->GeneratePreagedPrologue());
if (descriptor->PushArgumentCount()) {
__ push(kJavaScriptCallArgCountRegister);
}
} else { } else {
__ StubPrologue(info()->GetOutputStackFrameType()); __ StubPrologue(info()->GetOutputStackFrameType());
} }
} }
int shrink_slots = frame()->GetSpillSlotCount(); int shrink_slots =
frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
if (info()->is_osr()) { if (info()->is_osr()) {
// TurboFan OSR-compiled functions cannot be entered directly. // TurboFan OSR-compiled functions cannot be entered directly.
......
...@@ -107,6 +107,23 @@ bool CallDescriptor::CanTailCall(const Node* node) const { ...@@ -107,6 +107,23 @@ bool CallDescriptor::CanTailCall(const Node* node) const {
return HasSameReturnLocationsAs(CallDescriptorOf(node->op())); return HasSameReturnLocationsAs(CallDescriptorOf(node->op()));
} }
int CallDescriptor::CalculateFixedFrameSize() const {
switch (kind_) {
case kCallJSFunction:
return PushArgumentCount()
? OptimizedBuiltinFrameConstants::kFixedSlotCount
: StandardFrameConstants::kFixedSlotCount;
break;
case kCallAddress:
return CommonFrameConstants::kFixedSlotCountAboveFp +
CommonFrameConstants::kCPSlotCount;
break;
case kCallCodeObject:
return TypedFrameConstants::kFixedSlotCount;
}
UNREACHABLE();
return 0;
}
CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) { CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
DCHECK(!info->IsStub()); DCHECK(!info->IsStub());
......
...@@ -187,7 +187,9 @@ class V8_EXPORT_PRIVATE CallDescriptor final ...@@ -187,7 +187,9 @@ class V8_EXPORT_PRIVATE CallDescriptor final
// Causes the code generator to initialize the root register. // Causes the code generator to initialize the root register.
kInitializeRootRegister = 1u << 7, kInitializeRootRegister = 1u << 7,
// Does not ever try to allocate space on our heap. // Does not ever try to allocate space on our heap.
kNoAllocate = 1u << 8 kNoAllocate = 1u << 8,
// Push argument count as part of function prologue.
kPushArgumentCount = 1u << 9
}; };
typedef base::Flags<Flag> Flags; typedef base::Flags<Flag> Flags;
...@@ -249,6 +251,7 @@ class V8_EXPORT_PRIVATE CallDescriptor final ...@@ -249,6 +251,7 @@ class V8_EXPORT_PRIVATE CallDescriptor final
bool NeedsFrameState() const { return flags() & kNeedsFrameState; } bool NeedsFrameState() const { return flags() & kNeedsFrameState; }
bool SupportsTailCalls() const { return flags() & kSupportsTailCalls; } bool SupportsTailCalls() const { return flags() & kSupportsTailCalls; }
bool UseNativeStack() const { return flags() & kUseNativeStack; } bool UseNativeStack() const { return flags() & kUseNativeStack; }
bool PushArgumentCount() const { return flags() & kPushArgumentCount; }
bool InitializeRootRegister() const { bool InitializeRootRegister() const {
return flags() & kInitializeRootRegister; return flags() & kInitializeRootRegister;
} }
...@@ -296,6 +299,8 @@ class V8_EXPORT_PRIVATE CallDescriptor final ...@@ -296,6 +299,8 @@ class V8_EXPORT_PRIVATE CallDescriptor final
bool CanTailCall(const Node* call) const; bool CanTailCall(const Node* call) const;
int CalculateFixedFrameSize() const;
private: private:
friend class Linkage; friend class Linkage;
......
...@@ -1922,6 +1922,9 @@ void CodeGenerator::AssembleConstructFrame() { ...@@ -1922,6 +1922,9 @@ void CodeGenerator::AssembleConstructFrame() {
__ mov(fp, sp); __ mov(fp, sp);
} else if (descriptor->IsJSFunctionCall()) { } else if (descriptor->IsJSFunctionCall()) {
__ Prologue(this->info()->GeneratePreagedPrologue()); __ Prologue(this->info()->GeneratePreagedPrologue());
if (descriptor->PushArgumentCount()) {
__ Push(kJavaScriptCallArgCountRegister);
}
} else { } else {
__ StubPrologue(info()->GetOutputStackFrameType()); __ StubPrologue(info()->GetOutputStackFrameType());
} }
......
...@@ -2244,7 +2244,8 @@ void CodeGenerator::AssembleConstructFrame() { ...@@ -2244,7 +2244,8 @@ void CodeGenerator::AssembleConstructFrame() {
} }
} }
int shrink_slots = frame()->GetSpillSlotCount(); int shrink_slots =
frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
if (info()->is_osr()) { if (info()->is_osr()) {
// TurboFan OSR-compiled functions cannot be entered directly. // TurboFan OSR-compiled functions cannot be entered directly.
......
...@@ -283,7 +283,7 @@ class PipelineData { ...@@ -283,7 +283,7 @@ class PipelineData {
DCHECK(frame_ == nullptr); DCHECK(frame_ == nullptr);
int fixed_frame_size = 0; int fixed_frame_size = 0;
if (descriptor != nullptr) { if (descriptor != nullptr) {
fixed_frame_size = CalculateFixedFrameSize(descriptor); fixed_frame_size = descriptor->CalculateFixedFrameSize();
} }
frame_ = new (instruction_zone()) Frame(fixed_frame_size); frame_ = new (instruction_zone()) Frame(fixed_frame_size);
} }
...@@ -355,16 +355,6 @@ class PipelineData { ...@@ -355,16 +355,6 @@ class PipelineData {
// Source position output for --trace-turbo. // Source position output for --trace-turbo.
std::string source_position_output_; std::string source_position_output_;
int CalculateFixedFrameSize(CallDescriptor* descriptor) {
if (descriptor->IsJSFunctionCall()) {
return StandardFrameConstants::kFixedSlotCount;
}
return descriptor->IsCFunctionCall()
? (CommonFrameConstants::kFixedSlotCountAboveFp +
CommonFrameConstants::kCPSlotCount)
: TypedFrameConstants::kFixedSlotCount;
}
DISALLOW_COPY_AND_ASSIGN(PipelineData); DISALLOW_COPY_AND_ASSIGN(PipelineData);
}; };
......
...@@ -2397,6 +2397,9 @@ void CodeGenerator::AssembleConstructFrame() { ...@@ -2397,6 +2397,9 @@ void CodeGenerator::AssembleConstructFrame() {
__ movq(rbp, rsp); __ movq(rbp, rsp);
} else if (descriptor->IsJSFunctionCall()) { } else if (descriptor->IsJSFunctionCall()) {
__ Prologue(this->info()->GeneratePreagedPrologue()); __ Prologue(this->info()->GeneratePreagedPrologue());
if (descriptor->PushArgumentCount()) {
__ pushq(kJavaScriptCallArgCountRegister);
}
} else { } else {
__ StubPrologue(info()->GetOutputStackFrameType()); __ StubPrologue(info()->GetOutputStackFrameType());
} }
...@@ -2405,7 +2408,8 @@ void CodeGenerator::AssembleConstructFrame() { ...@@ -2405,7 +2408,8 @@ void CodeGenerator::AssembleConstructFrame() {
unwinding_info_writer_.MarkFrameConstructed(pc_base); unwinding_info_writer_.MarkFrameConstructed(pc_base);
} }
} }
int shrink_slots = frame()->GetSpillSlotCount(); int shrink_slots =
frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
if (info()->is_osr()) { if (info()->is_osr()) {
// TurboFan OSR-compiled functions cannot be entered directly. // TurboFan OSR-compiled functions cannot be entered directly.
......
...@@ -1285,6 +1285,19 @@ DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData( ...@@ -1285,6 +1285,19 @@ DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
return nullptr; return nullptr;
} }
Object* OptimizedFrame::receiver() const {
Code* code = LookupCode();
if (code->kind() == Code::BUILTIN) {
Address argc_ptr = fp() + OptimizedBuiltinFrameConstants::kArgCOffset;
intptr_t argc = *reinterpret_cast<intptr_t*>(argc_ptr);
intptr_t args_size =
(StandardFrameConstants::kFixedSlotCountAboveFp + argc) * kPointerSize;
Address receiver_ptr = fp() + args_size;
return *reinterpret_cast<Object**>(receiver_ptr);
} else {
return JavaScriptFrame::receiver();
}
}
void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) const { void OptimizedFrame::GetFunctions(List<JSFunction*>* functions) const {
DCHECK(functions->length() == 0); DCHECK(functions->length() == 0);
......
...@@ -218,6 +218,48 @@ class StandardFrameConstants : public CommonFrameConstants { ...@@ -218,6 +218,48 @@ class StandardFrameConstants : public CommonFrameConstants {
static const int kLastObjectOffset = kContextOffset; static const int kLastObjectOffset = kContextOffset;
}; };
// OptimizedBuiltinFrameConstants are used for TF-generated builtins. They
// always have a context below the saved fp/constant pool and below that the
// JSFunction of the executing function and below that an integer (not a Smi)
// containing the number of arguments passed to the builtin.
//
// slot JS frame
// +-----------------+--------------------------------
// -n-1 | parameter 0 | ^
// |- - - - - - - - -| |
// -n | | Caller
// ... | ... | frame slots
// -2 | parameter n-1 | (slot < 0)
// |- - - - - - - - -| |
// -1 | parameter n | v
// -----+-----------------+--------------------------------
// 0 | return addr | ^ ^
// |- - - - - - - - -| | |
// 1 | saved frame ptr | Fixed |
// |- - - - - - - - -| Header <-- frame ptr |
// 2 | [Constant Pool] | | |
// |- - - - - - - - -| | |
// 2+cp | Context | | if a constant pool |
// |- - - - - - - - -| | is used, cp = 1, |
// 3+cp | JSFunction | | otherwise, cp = 0 |
// |- - - - - - - - -| | |
// 4+cp | argc | v |
// +-----------------+---- |
// 5+cp | | ^ Callee
// |- - - - - - - - -| | frame slots
// ... | | Frame slots (slot >= 0)
// |- - - - - - - - -| | |
// | | v |
// -----+-----------------+----- <-- stack ptr -------------
//
class OptimizedBuiltinFrameConstants : public StandardFrameConstants {
public:
static const int kArgCSize = kPointerSize;
static const int kArgCOffset = -3 * kPointerSize - kCPSlotSize;
static const int kFixedFrameSize = kFixedFrameSizeAboveFp - kArgCOffset;
static const int kFixedSlotCount = kFixedFrameSize / kPointerSize;
};
// TypedFrames have a SMI type maker value below the saved FP/constant pool to // TypedFrames have a SMI type maker value below the saved FP/constant pool to
// distinguish them from StandardFrames, which have a context in that position // distinguish them from StandardFrames, which have a context in that position
// instead. // instead.
...@@ -941,6 +983,8 @@ class OptimizedFrame : public JavaScriptFrame { ...@@ -941,6 +983,8 @@ class OptimizedFrame : public JavaScriptFrame {
DeoptimizationInputData* GetDeoptimizationData(int* deopt_index) const; DeoptimizationInputData* GetDeoptimizationData(int* deopt_index) const;
Object* receiver() const override;
static int StackSlotOffsetRelativeToFp(int slot_index); static int StackSlotOffsetRelativeToFp(int slot_index);
protected: protected:
......
...@@ -35,10 +35,11 @@ class CodeAssemblerTesterImpl : private ZoneHolder, public CodeAssemblerT { ...@@ -35,10 +35,11 @@ class CodeAssemblerTesterImpl : private ZoneHolder, public CodeAssemblerT {
scope_(isolate) {} scope_(isolate) {}
// Test generating code for a JS function (e.g. builtins). // Test generating code for a JS function (e.g. builtins).
CodeAssemblerTesterImpl(Isolate* isolate, int parameter_count) CodeAssemblerTesterImpl(Isolate* isolate, int parameter_count,
Code::Kind kind = Code::FUNCTION)
: ZoneHolder(isolate), : ZoneHolder(isolate),
CodeAssemblerT(isolate, ZoneHolder::zone(), parameter_count, CodeAssemblerT(isolate, ZoneHolder::zone(), parameter_count,
Code::ComputeFlags(Code::FUNCTION), "test"), Code::ComputeFlags(kind), "test"),
scope_(isolate) {} scope_(isolate) {}
// This constructor is intended to be used for creating code objects with // This constructor is intended to be used for creating code objects with
......
...@@ -1510,7 +1510,8 @@ TEST(GotoIfException) { ...@@ -1510,7 +1510,8 @@ TEST(GotoIfException) {
Isolate* isolate(CcTest::InitIsolateOnce()); Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 1; const int kNumParams = 1;
CodeStubAssemblerTester m(isolate, kNumParams); // Emulate TFJ builtin
CodeStubAssemblerTester m(isolate, kNumParams, Code::BUILTIN);
Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
Node* to_string_tag = Node* to_string_tag =
...@@ -1529,9 +1530,6 @@ TEST(GotoIfException) { ...@@ -1529,9 +1530,6 @@ TEST(GotoIfException) {
Handle<Code> code = m.GenerateCode(); Handle<Code> code = m.GenerateCode();
CHECK(!code.is_null()); CHECK(!code.is_null());
// Emulate TFJ builtin
code->set_flags(Code::ComputeFlags(Code::BUILTIN));
FunctionTester ft(code, kNumParams); FunctionTester ft(code, kNumParams);
Handle<Object> result = ft.Call().ToHandleChecked(); Handle<Object> result = ft.Call().ToHandleChecked();
...@@ -1551,7 +1549,8 @@ TEST(GotoIfExceptionMultiple) { ...@@ -1551,7 +1549,8 @@ TEST(GotoIfExceptionMultiple) {
Isolate* isolate(CcTest::InitIsolateOnce()); Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 4; // receiver, first, second, third const int kNumParams = 4; // receiver, first, second, third
CodeStubAssemblerTester m(isolate, kNumParams); // Emulate TFJ builtin
CodeStubAssemblerTester m(isolate, kNumParams, Code::BUILTIN);
Node* context = m.HeapConstant(Handle<Context>(isolate->native_context())); Node* context = m.HeapConstant(Handle<Context>(isolate->native_context()));
Node* first_value = m.Parameter(0); Node* first_value = m.Parameter(0);
...@@ -1596,9 +1595,6 @@ TEST(GotoIfExceptionMultiple) { ...@@ -1596,9 +1595,6 @@ TEST(GotoIfExceptionMultiple) {
Handle<Code> code = m.GenerateCode(); Handle<Code> code = m.GenerateCode();
CHECK(!code.is_null()); CHECK(!code.is_null());
// Emulate TFJ builtin
code->set_flags(Code::ComputeFlags(Code::BUILTIN));
FunctionTester ft(code, kNumParams); FunctionTester ft(code, kNumParams);
Handle<Object> result; Handle<Object> result;
......
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