Commit 2445a502 authored by danno's avatar danno Committed by Commit bot

[stubs] Add a utility class to generate code to access builtin arguments

With an instance of CodeStubArguments, builtin stub generators can generate code
that accesses the receiver passed to the builtin, as well as access and iterate
over the variable number of arguments that are passed in.

Review-Url: https://codereview.chromium.org/2469273003
Cr-Commit-Position: refs/heads/master@{#40726}
parent 6322bf41
......@@ -8756,5 +8756,76 @@ compiler::Node* CodeStubAssembler::IsDetachedBuffer(compiler::Node* buffer) {
Int32Constant(0));
}
CodeStubArguments::CodeStubArguments(CodeStubAssembler* assembler,
compiler::Node* argc,
CodeStubAssembler::ParameterMode mode)
: assembler_(assembler),
argc_(argc),
arguments_(nullptr),
fp_(assembler->LoadFramePointer()) {
compiler::Node* offset = assembler->ElementOffsetFromIndex(
argc_, FAST_ELEMENTS, mode,
(StandardFrameConstants::kFixedSlotCountAboveFp - 1) * kPointerSize);
arguments_ = assembler_->IntPtrAddFoldConstants(fp_, offset);
if (mode == CodeStubAssembler::INTEGER_PARAMETERS) {
argc_ = assembler->ChangeInt32ToIntPtr(argc_);
} else if (mode == CodeStubAssembler::SMI_PARAMETERS) {
argc_ = assembler->SmiUntag(argc_);
}
}
compiler::Node* CodeStubArguments::GetReceiver() {
return assembler_->Load(MachineType::AnyTagged(), arguments_,
assembler_->IntPtrConstant(kPointerSize));
}
compiler::Node* CodeStubArguments::AtIndex(
compiler::Node* index, CodeStubAssembler::ParameterMode mode) {
typedef compiler::Node Node;
Node* negated_index = assembler_->IntPtrSubFoldConstants(
assembler_->IntPtrOrSmiConstant(0, mode), index);
Node* offset =
assembler_->ElementOffsetFromIndex(negated_index, FAST_ELEMENTS, mode, 0);
return assembler_->Load(MachineType::AnyTagged(), arguments_, offset);
}
compiler::Node* CodeStubArguments::AtIndex(int index) {
return AtIndex(assembler_->IntPtrConstant(index));
}
void CodeStubArguments::ForEach(const CodeStubAssembler::VariableList& vars,
CodeStubArguments::ForEachBodyFunction body,
compiler::Node* first, compiler::Node* last,
CodeStubAssembler::ParameterMode mode) {
assembler_->Comment("CodeStubArguments::ForEach");
DCHECK_IMPLIES(first == nullptr || last == nullptr,
mode == CodeStubAssembler::INTPTR_PARAMETERS);
if (first == nullptr) {
first = assembler_->IntPtrOrSmiConstant(0, mode);
}
if (last == nullptr) {
last = argc_;
}
compiler::Node* start = assembler_->IntPtrSubFoldConstants(
arguments_,
assembler_->ElementOffsetFromIndex(first, FAST_ELEMENTS, mode));
compiler::Node* end = assembler_->IntPtrSubFoldConstants(
arguments_,
assembler_->ElementOffsetFromIndex(last, FAST_ELEMENTS, mode));
assembler_->BuildFastLoop(
vars, MachineType::PointerRepresentation(), start, end,
[body](CodeStubAssembler* assembler, compiler::Node* current) {
Node* arg = assembler->Load(MachineType::AnyTagged(), current);
body(assembler, arg);
},
-kPointerSize, CodeStubAssembler::IndexAdvanceMode::kPost);
}
void CodeStubArguments::PopAndReturn(compiler::Node* value) {
assembler_->PopAndReturn(
assembler_->IntPtrAddFoldConstants(argc_, assembler_->IntPtrConstant(1)),
value);
}
} // namespace internal
} // namespace v8
......@@ -1108,6 +1108,8 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
compiler::Node* IsDetachedBuffer(compiler::Node* buffer);
private:
friend class CodeStubArguments;
enum ElementSupport { kOnlyProperties, kSupportElements };
void DescriptorLookupLinear(compiler::Node* unique_name,
......@@ -1208,6 +1210,53 @@ class V8_EXPORT_PRIVATE CodeStubAssembler : public compiler::CodeAssembler {
static const int kElementLoopUnrollThreshold = 8;
};
class CodeStubArguments {
public:
// |argc| specifies the number of arguments passed to the builtin excluding
// the receiver.
CodeStubArguments(CodeStubAssembler* assembler, compiler::Node* argc,
CodeStubAssembler::ParameterMode mode =
CodeStubAssembler::INTPTR_PARAMETERS);
compiler::Node* GetReceiver();
// |index| is zero-based and does not include the receiver
compiler::Node* AtIndex(compiler::Node* index,
CodeStubAssembler::ParameterMode mode =
CodeStubAssembler::INTPTR_PARAMETERS);
compiler::Node* AtIndex(int index);
typedef std::function<void(CodeStubAssembler* assembler, compiler::Node* arg)>
ForEachBodyFunction;
// Iteration doesn't include the receiver. |first| and |last| are zero-based.
void ForEach(ForEachBodyFunction body, compiler::Node* first = nullptr,
compiler::Node* last = nullptr,
CodeStubAssembler::ParameterMode mode =
CodeStubAssembler::INTPTR_PARAMETERS) {
CodeStubAssembler::VariableList list(0, assembler_->zone());
ForEach(list, body, first, last);
}
// Iteration doesn't include the receiver. |first| and |last| are zero-based.
void ForEach(const CodeStubAssembler::VariableList& vars,
ForEachBodyFunction body, compiler::Node* first = nullptr,
compiler::Node* last = nullptr,
CodeStubAssembler::ParameterMode mode =
CodeStubAssembler::INTPTR_PARAMETERS);
void PopAndReturn(compiler::Node* value);
private:
compiler::Node* GetArguments();
CodeStubAssembler* assembler_;
compiler::Node* argc_;
compiler::Node* arguments_;
compiler::Node* fp_;
};
#define CSA_ASSERT(x) Assert((x), #x, __FILE__, __LINE__)
#ifdef ENABLE_SLOW_DCHECKS
#define CSA_SLOW_ASSERT(x) \
......
......@@ -24,7 +24,8 @@ void FrameElider::MarkBlocks() {
for (int i = block->code_start(); i < block->code_end(); ++i) {
const Instruction* instr = InstructionAt(i);
if (instr->IsCall() || instr->IsDeoptimizeCall() ||
instr->arch_opcode() == ArchOpcode::kArchStackPointer) {
instr->arch_opcode() == ArchOpcode::kArchStackPointer ||
instr->arch_opcode() == ArchOpcode::kArchFramePointer) {
block->mark_needs_frame();
break;
}
......
......@@ -14,11 +14,11 @@ namespace compiler {
class ZoneHolder {
public:
explicit ZoneHolder(Isolate* isolate)
: zone_(isolate->allocator(), ZONE_NAME) {}
Zone* zone() { return &zone_; }
: held_zone_(isolate->allocator(), ZONE_NAME) {}
Zone* held_zone() { return &held_zone_; }
private:
Zone zone_;
Zone held_zone_;
};
// Inherit from ZoneHolder in order to create a zone that can be passed to
......@@ -30,7 +30,7 @@ class CodeAssemblerTesterImpl : private ZoneHolder, public CodeAssemblerT {
CodeAssemblerTesterImpl(Isolate* isolate,
const CallInterfaceDescriptor& descriptor)
: ZoneHolder(isolate),
CodeAssemblerT(isolate, ZoneHolder::zone(), descriptor,
CodeAssemblerT(isolate, ZoneHolder::held_zone(), descriptor,
Code::ComputeFlags(Code::STUB), "test"),
scope_(isolate) {}
......@@ -38,7 +38,7 @@ class CodeAssemblerTesterImpl : private ZoneHolder, public CodeAssemblerT {
CodeAssemblerTesterImpl(Isolate* isolate, int parameter_count,
Code::Kind kind = Code::FUNCTION)
: ZoneHolder(isolate),
CodeAssemblerT(isolate, ZoneHolder::zone(), parameter_count,
CodeAssemblerT(isolate, ZoneHolder::held_zone(), parameter_count,
Code::ComputeFlags(kind), "test"),
scope_(isolate) {}
......@@ -46,7 +46,7 @@ class CodeAssemblerTesterImpl : private ZoneHolder, public CodeAssemblerT {
// specific flags.
CodeAssemblerTesterImpl(Isolate* isolate, Code::Flags flags)
: ZoneHolder(isolate),
CodeAssemblerT(isolate, ZoneHolder::zone(), 0, flags, "test"),
CodeAssemblerT(isolate, ZoneHolder::held_zone(), 0, flags, "test"),
scope_(isolate) {}
Handle<Code> GenerateCodeCloseAndEscape() {
......
......@@ -1917,5 +1917,63 @@ TEST(TwoToTwoByteStringCopy) {
Handle<SeqTwoByteString>::cast(string2)->GetChars()[4]);
}
TEST(Arguments) {
Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 4;
CodeStubAssemblerTester m(isolate, kNumParams);
CodeStubArguments arguments(&m, m.IntPtrConstant(3));
m.Assert(m.WordEqual(arguments.AtIndex(0), m.SmiConstant(Smi::FromInt(12))));
m.Assert(m.WordEqual(arguments.AtIndex(1), m.SmiConstant(Smi::FromInt(13))));
m.Assert(m.WordEqual(arguments.AtIndex(2), m.SmiConstant(Smi::FromInt(14))));
m.Return(arguments.GetReceiver());
Handle<Code> code = m.GenerateCode();
CHECK(!code.is_null());
FunctionTester ft(code, kNumParams);
Handle<Object> result = ft.Call(isolate->factory()->undefined_value(),
Handle<Smi>(Smi::FromInt(12), isolate),
Handle<Smi>(Smi::FromInt(13), isolate),
Handle<Smi>(Smi::FromInt(14), isolate))
.ToHandleChecked();
CHECK_EQ(*isolate->factory()->undefined_value(), *result);
}
TEST(ArgumentsForEach) {
Isolate* isolate(CcTest::InitIsolateOnce());
const int kNumParams = 4;
CodeStubAssemblerTester m(isolate, kNumParams);
CodeStubArguments arguments(&m, m.IntPtrConstant(3));
CodeStubAssemblerTester::Variable sum(&m,
MachineType::PointerRepresentation());
CodeStubAssemblerTester::VariableList list({&sum}, m.zone());
sum.Bind(m.IntPtrConstant(0));
arguments.ForEach(list, [&m, &sum](CodeStubAssembler* assembler, Node* arg) {
sum.Bind(assembler->IntPtrAdd(sum.value(), arg));
});
m.Return(sum.value());
Handle<Code> code = m.GenerateCode();
CHECK(!code.is_null());
FunctionTester ft(code, kNumParams);
Handle<Object> result = ft.Call(isolate->factory()->undefined_value(),
Handle<Smi>(Smi::FromInt(12), isolate),
Handle<Smi>(Smi::FromInt(13), isolate),
Handle<Smi>(Smi::FromInt(14), isolate))
.ToHandleChecked();
CHECK_EQ(Smi::FromInt(12 + 13 + 14), *result);
}
} // namespace internal
} // namespace v8
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