}
-void StringAddStub::PrintBaseName(std::ostream& os) const { // NOLINT
- os << "StringAddStub";
- if ((flags() & STRING_ADD_CHECK_BOTH) == STRING_ADD_CHECK_BOTH) {
- os << "_CheckBoth";
- } else if ((flags() & STRING_ADD_CHECK_LEFT) == STRING_ADD_CHECK_LEFT) {
- os << "_CheckLeft";
- } else if ((flags() & STRING_ADD_CHECK_RIGHT) == STRING_ADD_CHECK_RIGHT) {
- os << "_CheckRight";
- }
- if (pretenure_flag() == TENURED) {
- os << "_Tenured";
+std::ostream& operator<<(std::ostream& os, const StringAddFlags& flags) {
+ switch (flags) {
+ case STRING_ADD_CHECK_NONE:
+ return os << "CheckNone";
+ case STRING_ADD_CHECK_LEFT:
+ return os << "CheckLeft";
+ case STRING_ADD_CHECK_RIGHT:
+ return os << "CheckRight";
+ case STRING_ADD_CHECK_BOTH:
+ return os << "CheckBoth";
}
+ UNREACHABLE();
+ return os;
+}
+
+
+void StringAddStub::PrintBaseName(std::ostream& os) const { // NOLINT
+ os << "StringAddStub_" << flags() << "_" << pretenure_flag();
+}
+
+
+void StringAddTFStub::PrintBaseName(std::ostream& os) const { // NOLINT
+ os << "StringAddTFStub_" << flags() << "_" << pretenure_flag();
}
V(LoadIC) \
/* TurboFanCodeStubs */ \
V(StringLengthTF) \
+ V(StringAddTF) \
V(MathFloor) \
/* IC Handler stubs */ \
V(ArrayBufferViewLoadField) \
Handle<Code> GenerateCode() override; \
DEFINE_CODE_STUB(NAME, SUPER)
-#define DEFINE_TURBOFAN_CODE_STUB(NAME, SUPER, DESC, STACK_PARAMS) \
- public: \
- NAME##Stub(Isolate* isolate) : SUPER(isolate) {} \
- CallInterfaceDescriptor GetCallInterfaceDescriptor() override { \
- return DESC(isolate()); \
- }; \
- virtual const char* GetFunctionName() const override { \
- return #NAME "_STUB"; \
- } \
- int GetStackParameterCount() const override { return STACK_PARAMS; } \
- Code::StubType GetStubType() const override { return Code::FAST; } \
+#define DEFINE_TURBOFAN_CODE_STUB(NAME, SUPER) \
+ public: \
+ const char* GetFunctionName() const override { return #NAME "_STUB"; } \
DEFINE_CODE_STUB(NAME, SUPER)
#define DEFINE_HANDLER_CODE_STUB(NAME, SUPER) \
// Retrieve the code for the stub. Generate the code if needed.
Handle<Code> GenerateCode() override;
- Code::Kind GetCodeKind() const override { return Code::STUB; }
-
protected:
explicit PlatformCodeStub(Isolate* isolate) : CodeStub(isolate) {}
INITIALIZED
};
- Code::Kind GetCodeKind() const override { return Code::STUB; }
-
template<class SubClass>
static Handle<Code> GetUninitialized(Isolate* isolate) {
SubClass::GenerateAheadOfTime(isolate);
class TurboFanCodeStub : public CodeStub {
public:
- Code::Kind GetCodeKind() const override { return Code::STUB; }
-
// Retrieve the code for the stub. Generate the code if needed.
Handle<Code> GenerateCode() override;
+ Code::StubType GetStubType() const override { return Code::FAST; }
+
virtual const char* GetFunctionName() const = 0;
protected:
class MathFloorStub : public TurboFanCodeStub {
- DEFINE_TURBOFAN_CODE_STUB(MathFloor, TurboFanCodeStub,
- MathRoundVariantDescriptor, 1);
+ public:
+ explicit MathFloorStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
+ int GetStackParameterCount() const override { return 1; }
+
+ DEFINE_CALL_INTERFACE_DESCRIPTOR(MathRoundVariant);
+ DEFINE_TURBOFAN_CODE_STUB(MathFloor, TurboFanCodeStub);
};
class StringLengthTFStub : public TurboFanCodeStub {
- DEFINE_TURBOFAN_CODE_STUB(StringLengthTF, TurboFanCodeStub,
- LoadWithVectorDescriptor, 0);
-
public:
+ explicit StringLengthTFStub(Isolate* isolate) : TurboFanCodeStub(isolate) {}
+
Code::Kind GetCodeKind() const override { return Code::HANDLER; }
InlineCacheState GetICState() const override { return MONOMORPHIC; }
ExtraICState GetExtraICState() const override { return Code::LOAD_IC; }
+
+ DEFINE_CALL_INTERFACE_DESCRIPTOR(LoadWithVector);
+ DEFINE_TURBOFAN_CODE_STUB(StringLengthTF, TurboFanCodeStub);
+};
+
+
+enum StringAddFlags {
+ // Omit both parameter checks.
+ STRING_ADD_CHECK_NONE = 0,
+ // Check left parameter.
+ STRING_ADD_CHECK_LEFT = 1 << 0,
+ // Check right parameter.
+ STRING_ADD_CHECK_RIGHT = 1 << 1,
+ // Check both parameters.
+ STRING_ADD_CHECK_BOTH = STRING_ADD_CHECK_LEFT | STRING_ADD_CHECK_RIGHT
+};
+
+
+std::ostream& operator<<(std::ostream& os, const StringAddFlags& flags);
+
+
+class StringAddTFStub : public TurboFanCodeStub {
+ public:
+ StringAddTFStub(Isolate* isolate, StringAddFlags flags,
+ PretenureFlag pretenure_flag)
+ : TurboFanCodeStub(isolate) {
+ minor_key_ = StringAddFlagsBits::encode(flags) |
+ PretenureFlagBits::encode(pretenure_flag);
+ }
+
+ StringAddFlags flags() const {
+ return StringAddFlagsBits::decode(MinorKey());
+ }
+
+ PretenureFlag pretenure_flag() const {
+ return PretenureFlagBits::decode(MinorKey());
+ }
+
+ private:
+ class StringAddFlagsBits : public BitField<StringAddFlags, 0, 2> {};
+ class PretenureFlagBits : public BitField<PretenureFlag, 2, 1> {};
+
+ void PrintBaseName(std::ostream& os) const override; // NOLINT
+
+ DEFINE_CALL_INTERFACE_DESCRIPTOR(StringAdd);
+ DEFINE_TURBOFAN_CODE_STUB(StringAddTF, TurboFanCodeStub);
};
};
-enum StringAddFlags {
- // Omit both parameter checks.
- STRING_ADD_CHECK_NONE = 0,
- // Check left parameter.
- STRING_ADD_CHECK_LEFT = 1 << 0,
- // Check right parameter.
- STRING_ADD_CHECK_RIGHT = 1 << 1,
- // Check both parameters.
- STRING_ADD_CHECK_BOTH = STRING_ADD_CHECK_LEFT | STRING_ADD_CHECK_RIGHT
-};
-
-
class StringAddStub final : public HydrogenCodeStub {
public:
StringAddStub(Isolate* isolate, StringAddFlags flags,
private:
void GenerateNew(MacroAssembler* masm);
- virtual void PrintName(std::ostream& os) const override; // NOLINT
+ void PrintName(std::ostream& os) const override; // NOLINT
DEFINE_PLATFORM_CODE_STUB(RestParamAccess, PlatformCodeStub);
};
void GenerateForTrampoline(MacroAssembler* masm);
- virtual Code::Kind GetCodeKind() const override { return Code::LOAD_IC; }
+ Code::Kind GetCodeKind() const override { return Code::LOAD_IC; }
- virtual InlineCacheState GetICState() const final override { return DEFAULT; }
+ InlineCacheState GetICState() const final override { return DEFAULT; }
- virtual ExtraICState GetExtraICState() const final override {
+ ExtraICState GetExtraICState() const final override {
return static_cast<ExtraICState>(minor_key_);
}
void GenerateForTrampoline(MacroAssembler* masm);
- virtual Code::Kind GetCodeKind() const override {
- return Code::KEYED_LOAD_IC;
- }
+ Code::Kind GetCodeKind() const override { return Code::KEYED_LOAD_IC; }
- virtual InlineCacheState GetICState() const final override { return DEFAULT; }
+ InlineCacheState GetICState() const final override { return DEFAULT; }
DEFINE_CALL_INTERFACE_DESCRIPTOR(LoadWithVector);
DEFINE_PLATFORM_CODE_STUB(KeyedLoadIC, PlatformCodeStub);
__ Prologue(info->IsCodePreAgingActive());
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
- } else if (stack_slots > 0) {
+ } else if (needs_frame_) {
__ StubPrologue();
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
}
__ LeaveFrame(StackFrame::MANUAL);
__ Ret();
- } else if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
+ } else if (descriptor->IsJSFunctionCall() || needs_frame_) {
__ LeaveFrame(StackFrame::MANUAL);
int pop_count = descriptor->IsJSFunctionCall()
? static_cast<int>(descriptor->JSParameterCount())
__ Prologue(info->IsCodePreAgingActive());
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
- } else if (stack_slots > 0) {
+ } else if (needs_frame_) {
__ SetStackPointer(jssp);
__ StubPrologue();
frame()->SetRegisterSaveAreaSize(
__ Mov(csp, fp);
__ Pop(fp, lr);
__ Ret();
- } else if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
+ } else if (descriptor->IsJSFunctionCall() || needs_frame_) {
__ Mov(jssp, fp);
__ Pop(fp, lr);
int pop_count = descriptor->IsJSFunctionCall()
last_lazy_deopt_pc_(0),
jump_tables_(nullptr),
ools_(nullptr),
- osr_pc_offset_(-1) {
+ osr_pc_offset_(-1),
+ needs_frame_(frame->GetSpillSlotCount() > 0 || code->ContainsCall()) {
for (int i = 0; i < code->InstructionBlockCount(); ++i) {
new (&labels_[i]) Label;
}
JumpTable* jump_tables_;
OutOfLineCode* ools_;
int osr_pc_offset_;
+ bool needs_frame_;
};
} // namespace compiler
__ Prologue(info->IsCodePreAgingActive());
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
- } else if (stack_slots > 0) {
+ } else if (needs_frame_) {
__ StubPrologue();
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
__ pop(ebp); // Pop caller's frame pointer.
__ ret(0);
}
- } else if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
+ } else if (descriptor->IsJSFunctionCall() || needs_frame_) {
__ mov(esp, ebp); // Move stack pointer back to frame pointer.
__ pop(ebp); // Pop caller's frame pointer.
int pop_count = descriptor->IsJSFunctionCall()
SourcePosition* result) const;
void SetSourcePosition(const Instruction* instr, SourcePosition value);
+ bool ContainsCall() const {
+ for (Instruction* instr : instructions_) {
+ if (instr->IsCall()) return true;
+ }
+ return false;
+ }
+
private:
friend std::ostream& operator<<(std::ostream& os,
const PrintableInstructionSequence& code);
__ Prologue(info->IsCodePreAgingActive());
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
- } else if (stack_slots > 0) {
+ } else if (needs_frame_) {
__ StubPrologue();
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
__ mov(sp, fp);
__ Pop(ra, fp);
__ Ret();
- } else if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
+ } else if (descriptor->IsJSFunctionCall() || needs_frame_) {
__ mov(sp, fp);
__ Pop(ra, fp);
int pop_count = descriptor->IsJSFunctionCall()
__ Prologue(info->IsCodePreAgingActive());
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
- } else if (stack_slots > 0) {
+ } else if (needs_frame_) {
__ StubPrologue();
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
__ mov(sp, fp);
__ Pop(ra, fp);
__ Ret();
- } else if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
+ } else if (descriptor->IsJSFunctionCall() || needs_frame_) {
__ mov(sp, fp);
__ Pop(ra, fp);
int pop_count = descriptor->IsJSFunctionCall()
__ Prologue(info->IsCodePreAgingActive());
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
- } else if (stack_slots > 0) {
+ } else if (needs_frame_) {
__ StubPrologue();
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
}
__ LeaveFrame(StackFrame::MANUAL);
__ Ret();
- } else if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
+ } else if (descriptor->IsJSFunctionCall() || needs_frame_) {
int pop_count = descriptor->IsJSFunctionCall()
? static_cast<int>(descriptor->JSParameterCount())
: 0;
__ Prologue(info->IsCodePreAgingActive());
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
- } else if (stack_slots > 0) {
+ } else if (needs_frame_) {
__ StubPrologue();
frame()->SetRegisterSaveAreaSize(
StandardFrameConstants::kFixedFrameSizeFromFp);
__ popq(rbp); // Pop caller's frame pointer.
__ ret(0);
}
- } else if (descriptor->IsJSFunctionCall() || stack_slots > 0) {
+ } else if (descriptor->IsJSFunctionCall() || needs_frame_) {
__ movq(rsp, rbp); // Move stack pointer back to frame pointer.
__ popq(rbp); // Pop caller's frame pointer.
int pop_count = descriptor->IsJSFunctionCall()
};
-inline std::ostream& operator<<(std::ostream& os, LanguageMode mode) {
+inline std::ostream& operator<<(std::ostream& os, const LanguageMode& mode) {
switch (mode) {
case SLOPPY:
return os << "sloppy";
// allows).
enum PretenureFlag { NOT_TENURED, TENURED };
+inline std::ostream& operator<<(std::ostream& os, const PretenureFlag& flag) {
+ switch (flag) {
+ case NOT_TENURED:
+ return os << "NotTenured";
+ case TENURED:
+ return os << "Tenured";
+ }
+ UNREACHABLE();
+ return os;
+}
+
enum MinimumCapacity {
USE_DEFAULT_MINIMUM_CAPACITY,
USE_CUSTOM_MINIMUM_CAPACITY
var TO_NAME;
var StringLengthTF_STUB;
+var StringAddTF_STUB;
var MathFloor_STUB;
var $defaultNumber;
return %_StringGetLength(%_JSValueGetValue(receiver));
}
+StringAddTF_STUB = function StringAddTF_STUB(left, right) {
+ return %StringAdd(left, right);
+}
+
MathFloor_STUB = function MathFloor_STUB(f, i, v) {
// |f| is calling function's JSFunction
// |i| is TypeFeedbackVector slot # of callee's CallIC for Math.floor call
CHECK_EQ(static_cast<int>(strlen(testString)), Smi::cast(*result)->value());
}
+
+TEST(RunStringAddTFStub) {
+ HandleAndZoneScope scope;
+ Isolate* isolate = scope.main_isolate();
+ Zone* zone = scope.main_zone();
+
+ // Create code and an accompanying descriptor.
+ StringAddTFStub stub(isolate, STRING_ADD_CHECK_BOTH, NOT_TENURED);
+ Handle<Code> code = stub.GenerateCode();
+ CompilationInfo info(&stub, isolate, zone);
+ CallDescriptor* descriptor = Linkage::ComputeIncoming(zone, &info);
+
+ // Create a function to call the code using the descriptor.
+ Graph graph(zone);
+ CommonOperatorBuilder common(zone);
+ // FunctionTester (ab)uses a 2-argument function
+ Node* start = graph.NewNode(common.Start(2));
+ // Parameter 0 is the receiver
+ Node* leftParam = graph.NewNode(common.Parameter(1), start);
+ Node* rightParam = graph.NewNode(common.Parameter(2), start);
+ Unique<HeapObject> u = Unique<HeapObject>::CreateImmovable(code);
+ Node* theCode = graph.NewNode(common.HeapConstant(u));
+ Node* dummyContext = graph.NewNode(common.NumberConstant(0.0));
+ Node* call = graph.NewNode(common.Call(descriptor), theCode, leftParam,
+ rightParam, dummyContext, start, start);
+ Node* ret = graph.NewNode(common.Return(), call, call, start);
+ Node* end = graph.NewNode(common.End(), ret);
+ graph.SetStart(start);
+ graph.SetEnd(end);
+ FunctionTester ft(&graph);
+
+ // Actuall call through to the stub, verifying its result.
+ Handle<String> leftArg = ft.Val("links");
+ Handle<String> rightArg = ft.Val("rechts");
+ Handle<Object> result = ft.Call(leftArg, rightArg).ToHandleChecked();
+ CHECK(String::Equals(ft.Val("linksrechts"), Handle<String>::cast(result)));
+}
+
#endif // V8_TURBOFAN_TARGET