[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:
danno 2016-11-03 01:36:02 -07:00 committed by Commit bot
parent 4d2659a706
commit 4447405b17
14 changed files with 152 additions and 53 deletions

View File

@ -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.

View File

@ -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.

View File

@ -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,

View File

@ -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.

View File

@ -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());

View File

@ -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;

View File

@ -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());
}

View File

@ -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.

View File

@ -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);
};

View File

@ -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.

View File

@ -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);

View File

@ -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:

View File

@ -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

View File

@ -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;