[builtins]: Uniformly push argument count in TF-generated builtins
Review-Url: https://codereview.chromium.org/2467513002 Cr-Commit-Position: refs/heads/master@{#40712}
This commit is contained in:
parent
4d2659a706
commit
4447405b17
@ -1690,6 +1690,9 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
}
|
||||
} else if (descriptor->IsJSFunctionCall()) {
|
||||
__ Prologue(this->info()->GeneratePreagedPrologue());
|
||||
if (descriptor->PushArgumentCount()) {
|
||||
__ Push(kJavaScriptCallArgCountRegister);
|
||||
}
|
||||
} else {
|
||||
__ StubPrologue(info()->GetOutputStackFrameType());
|
||||
}
|
||||
@ -1699,7 +1702,8 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
}
|
||||
}
|
||||
|
||||
int shrink_slots = frame()->GetSpillSlotCount();
|
||||
int shrink_slots =
|
||||
frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
|
||||
|
||||
if (info()->is_osr()) {
|
||||
// TurboFan OSR-compiled functions cannot be entered directly.
|
||||
|
@ -1795,43 +1795,57 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
__ AssertCspAligned();
|
||||
}
|
||||
|
||||
int fixed_frame_size = descriptor->CalculateFixedFrameSize();
|
||||
int shrink_slots =
|
||||
frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
|
||||
|
||||
if (frame_access_state()->has_frame()) {
|
||||
// Link the frame
|
||||
if (descriptor->IsJSFunctionCall()) {
|
||||
DCHECK(!descriptor->UseNativeStack());
|
||||
__ Prologue(this->info()->GeneratePreagedPrologue());
|
||||
} else {
|
||||
if (descriptor->IsCFunctionCall()) {
|
||||
__ Push(lr, fp);
|
||||
__ Mov(fp, masm_.StackPointer());
|
||||
__ Claim(frame()->GetSpillSlotCount());
|
||||
} else {
|
||||
__ StubPrologue(info()->GetOutputStackFrameType(),
|
||||
frame()->GetTotalFrameSlotCount());
|
||||
}
|
||||
__ Push(lr, fp);
|
||||
__ Mov(fp, masm_.StackPointer());
|
||||
}
|
||||
|
||||
if (!info()->GeneratePreagedPrologue()) {
|
||||
unwinding_info_writer_.MarkFrameConstructed(__ pc_offset());
|
||||
}
|
||||
}
|
||||
|
||||
int shrink_slots = frame()->GetSpillSlotCount();
|
||||
// Create OSR entry if applicable
|
||||
if (info()->is_osr()) {
|
||||
// TurboFan OSR-compiled functions cannot be entered directly.
|
||||
__ Abort(kShouldNotDirectlyEnterOsrFunction);
|
||||
|
||||
if (info()->is_osr()) {
|
||||
// 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
|
||||
// the unoptimized frame. Thus, all that needs to be done is to allocate
|
||||
// the
|
||||
// remaining stack slots.
|
||||
if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
|
||||
osr_pc_offset_ = __ pc_offset();
|
||||
shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
|
||||
}
|
||||
|
||||
// Unoptimized code jumps directly to this entrypoint while the unoptimized
|
||||
// frame is still on the stack. Optimized code uses OSR values directly from
|
||||
// the unoptimized frame. Thus, all that needs to be done is to allocate the
|
||||
// remaining stack slots.
|
||||
if (FLAG_code_comments) __ RecordComment("-- OSR entrypoint --");
|
||||
osr_pc_offset_ = __ pc_offset();
|
||||
shrink_slots -= OsrHelper(info()).UnoptimizedFrameSlots();
|
||||
}
|
||||
|
||||
if (descriptor->IsJSFunctionCall()) {
|
||||
__ Claim(shrink_slots);
|
||||
// Build remainder of frame, including accounting for and filling-in
|
||||
// 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.
|
||||
|
@ -41,8 +41,11 @@ CodeAssembler::CodeAssembler(Isolate* isolate, Zone* zone,
|
||||
CodeAssembler::CodeAssembler(Isolate* isolate, Zone* zone, int parameter_count,
|
||||
Code::Flags flags, const char* name)
|
||||
: CodeAssembler(isolate, zone,
|
||||
Linkage::GetJSCallDescriptor(zone, false, parameter_count,
|
||||
CallDescriptor::kNoFlags),
|
||||
Linkage::GetJSCallDescriptor(
|
||||
zone, false, parameter_count,
|
||||
Code::ExtractKindFromFlags(flags) == Code::BUILTIN
|
||||
? CallDescriptor::kPushArgumentCount
|
||||
: CallDescriptor::kNoFlags),
|
||||
flags, name) {}
|
||||
|
||||
CodeAssembler::CodeAssembler(Isolate* isolate, Zone* zone,
|
||||
|
@ -1945,12 +1945,16 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
__ mov(ebp, esp);
|
||||
} else if (descriptor->IsJSFunctionCall()) {
|
||||
__ Prologue(this->info()->GeneratePreagedPrologue());
|
||||
if (descriptor->PushArgumentCount()) {
|
||||
__ push(kJavaScriptCallArgCountRegister);
|
||||
}
|
||||
} else {
|
||||
__ StubPrologue(info()->GetOutputStackFrameType());
|
||||
}
|
||||
}
|
||||
|
||||
int shrink_slots = frame()->GetSpillSlotCount();
|
||||
int shrink_slots =
|
||||
frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
|
||||
|
||||
if (info()->is_osr()) {
|
||||
// TurboFan OSR-compiled functions cannot be entered directly.
|
||||
|
@ -107,6 +107,23 @@ bool CallDescriptor::CanTailCall(const Node* node) const {
|
||||
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) {
|
||||
DCHECK(!info->IsStub());
|
||||
|
@ -187,7 +187,9 @@ class V8_EXPORT_PRIVATE CallDescriptor final
|
||||
// Causes the code generator to initialize the root register.
|
||||
kInitializeRootRegister = 1u << 7,
|
||||
// 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;
|
||||
|
||||
@ -249,6 +251,7 @@ class V8_EXPORT_PRIVATE CallDescriptor final
|
||||
bool NeedsFrameState() const { return flags() & kNeedsFrameState; }
|
||||
bool SupportsTailCalls() const { return flags() & kSupportsTailCalls; }
|
||||
bool UseNativeStack() const { return flags() & kUseNativeStack; }
|
||||
bool PushArgumentCount() const { return flags() & kPushArgumentCount; }
|
||||
bool InitializeRootRegister() const {
|
||||
return flags() & kInitializeRootRegister;
|
||||
}
|
||||
@ -296,6 +299,8 @@ class V8_EXPORT_PRIVATE CallDescriptor final
|
||||
|
||||
bool CanTailCall(const Node* call) const;
|
||||
|
||||
int CalculateFixedFrameSize() const;
|
||||
|
||||
private:
|
||||
friend class Linkage;
|
||||
|
||||
|
@ -1922,6 +1922,9 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
__ mov(fp, sp);
|
||||
} else if (descriptor->IsJSFunctionCall()) {
|
||||
__ Prologue(this->info()->GeneratePreagedPrologue());
|
||||
if (descriptor->PushArgumentCount()) {
|
||||
__ Push(kJavaScriptCallArgCountRegister);
|
||||
}
|
||||
} else {
|
||||
__ StubPrologue(info()->GetOutputStackFrameType());
|
||||
}
|
||||
|
@ -2244,7 +2244,8 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
}
|
||||
}
|
||||
|
||||
int shrink_slots = frame()->GetSpillSlotCount();
|
||||
int shrink_slots =
|
||||
frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
|
||||
|
||||
if (info()->is_osr()) {
|
||||
// TurboFan OSR-compiled functions cannot be entered directly.
|
||||
|
@ -283,7 +283,7 @@ class PipelineData {
|
||||
DCHECK(frame_ == nullptr);
|
||||
int fixed_frame_size = 0;
|
||||
if (descriptor != nullptr) {
|
||||
fixed_frame_size = CalculateFixedFrameSize(descriptor);
|
||||
fixed_frame_size = descriptor->CalculateFixedFrameSize();
|
||||
}
|
||||
frame_ = new (instruction_zone()) Frame(fixed_frame_size);
|
||||
}
|
||||
@ -355,16 +355,6 @@ class PipelineData {
|
||||
// Source position output for --trace-turbo.
|
||||
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);
|
||||
};
|
||||
|
||||
|
@ -2397,6 +2397,9 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
__ movq(rbp, rsp);
|
||||
} else if (descriptor->IsJSFunctionCall()) {
|
||||
__ Prologue(this->info()->GeneratePreagedPrologue());
|
||||
if (descriptor->PushArgumentCount()) {
|
||||
__ pushq(kJavaScriptCallArgCountRegister);
|
||||
}
|
||||
} else {
|
||||
__ StubPrologue(info()->GetOutputStackFrameType());
|
||||
}
|
||||
@ -2405,7 +2408,8 @@ void CodeGenerator::AssembleConstructFrame() {
|
||||
unwinding_info_writer_.MarkFrameConstructed(pc_base);
|
||||
}
|
||||
}
|
||||
int shrink_slots = frame()->GetSpillSlotCount();
|
||||
int shrink_slots =
|
||||
frame()->GetTotalFrameSlotCount() - descriptor->CalculateFixedFrameSize();
|
||||
|
||||
if (info()->is_osr()) {
|
||||
// TurboFan OSR-compiled functions cannot be entered directly.
|
||||
|
@ -1285,6 +1285,19 @@ DeoptimizationInputData* OptimizedFrame::GetDeoptimizationData(
|
||||
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 {
|
||||
DCHECK(functions->length() == 0);
|
||||
|
44
src/frames.h
44
src/frames.h
@ -218,6 +218,48 @@ class StandardFrameConstants : public CommonFrameConstants {
|
||||
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
|
||||
// distinguish them from StandardFrames, which have a context in that position
|
||||
// instead.
|
||||
@ -941,6 +983,8 @@ class OptimizedFrame : public JavaScriptFrame {
|
||||
|
||||
DeoptimizationInputData* GetDeoptimizationData(int* deopt_index) const;
|
||||
|
||||
Object* receiver() const override;
|
||||
|
||||
static int StackSlotOffsetRelativeToFp(int slot_index);
|
||||
|
||||
protected:
|
||||
|
@ -35,10 +35,11 @@ class CodeAssemblerTesterImpl : private ZoneHolder, public CodeAssemblerT {
|
||||
scope_(isolate) {}
|
||||
|
||||
// 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),
|
||||
CodeAssemblerT(isolate, ZoneHolder::zone(), parameter_count,
|
||||
Code::ComputeFlags(Code::FUNCTION), "test"),
|
||||
Code::ComputeFlags(kind), "test"),
|
||||
scope_(isolate) {}
|
||||
|
||||
// This constructor is intended to be used for creating code objects with
|
||||
|
@ -1510,7 +1510,8 @@ TEST(GotoIfException) {
|
||||
Isolate* isolate(CcTest::InitIsolateOnce());
|
||||
|
||||
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* to_string_tag =
|
||||
@ -1529,9 +1530,6 @@ TEST(GotoIfException) {
|
||||
Handle<Code> code = m.GenerateCode();
|
||||
CHECK(!code.is_null());
|
||||
|
||||
// Emulate TFJ builtin
|
||||
code->set_flags(Code::ComputeFlags(Code::BUILTIN));
|
||||
|
||||
FunctionTester ft(code, kNumParams);
|
||||
Handle<Object> result = ft.Call().ToHandleChecked();
|
||||
|
||||
@ -1551,7 +1549,8 @@ TEST(GotoIfExceptionMultiple) {
|
||||
Isolate* isolate(CcTest::InitIsolateOnce());
|
||||
|
||||
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* first_value = m.Parameter(0);
|
||||
@ -1596,9 +1595,6 @@ TEST(GotoIfExceptionMultiple) {
|
||||
Handle<Code> code = m.GenerateCode();
|
||||
CHECK(!code.is_null());
|
||||
|
||||
// Emulate TFJ builtin
|
||||
code->set_flags(Code::ComputeFlags(Code::BUILTIN));
|
||||
|
||||
FunctionTester ft(code, kNumParams);
|
||||
|
||||
Handle<Object> result;
|
||||
|
Loading…
Reference in New Issue
Block a user