Commit b9aa3ce7 authored by binji's avatar binji Committed by Commit bot

CodeStubAssembler can generate code for builtins

This will be used for generating the Atomics builtins.

BUG=v8:4614
R=jarin@chromium.org
LOG=y

Review URL: https://codereview.chromium.org/1705073005

Cr-Commit-Position: refs/heads/master@{#34413}
parent f3fcdcfa
......@@ -39,6 +39,18 @@ CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone,
code_generated_(false),
variables_(zone) {}
CodeStubAssembler::CodeStubAssembler(Isolate* isolate, Zone* zone,
int parameter_count, Code::Flags flags,
const char* name)
: raw_assembler_(new RawMachineAssembler(
isolate, new (zone) Graph(zone),
Linkage::GetJSCallDescriptor(zone, false, parameter_count,
CallDescriptor::kNoFlags))),
flags_(flags),
name_(name),
code_generated_(false),
variables_(zone) {}
CodeStubAssembler::~CodeStubAssembler() {}
void CodeStubAssembler::CallPrologue() {}
......@@ -132,6 +144,14 @@ Node* CodeStubAssembler::SmiUntag(Node* value) {
return raw_assembler_->WordSar(value, SmiShiftBitsConstant());
}
Node* CodeStubAssembler::SmiToInt32(Node* value) {
Node* result = raw_assembler_->WordSar(value, SmiShiftBitsConstant());
if (raw_assembler_->machine()->Is64()) {
result = raw_assembler_->TruncateInt64ToInt32(result);
}
return result;
}
Node* CodeStubAssembler::SmiAdd(Node* a, Node* b) { return IntPtrAdd(a, b); }
Node* CodeStubAssembler::SmiEqual(Node* a, Node* b) { return WordEqual(a, b); }
......@@ -143,18 +163,15 @@ Node* CodeStubAssembler::SmiEqual(Node* a, Node* b) { return WordEqual(a, b); }
CODE_STUB_ASSEMBLER_BINARY_OP_LIST(DEFINE_CODE_STUB_ASSEMBER_BINARY_OP)
#undef DEFINE_CODE_STUB_ASSEMBER_BINARY_OP
Node* CodeStubAssembler::ChangeInt32ToInt64(Node* value) {
return raw_assembler_->ChangeInt32ToInt64(value);
}
Node* CodeStubAssembler::ChangeUint32ToUint64(Node* value) {
return raw_assembler_->ChangeUint32ToUint64(value);
}
Node* CodeStubAssembler::WordShl(Node* value, int shift) {
return raw_assembler_->WordShl(value, IntPtrConstant(shift));
}
#define DEFINE_CODE_STUB_ASSEMBER_UNARY_OP(name) \
Node* CodeStubAssembler::name(Node* a) { return raw_assembler_->name(a); }
CODE_STUB_ASSEMBLER_UNARY_OP_LIST(DEFINE_CODE_STUB_ASSEMBER_UNARY_OP)
#undef DEFINE_CODE_STUB_ASSEMBER_UNARY_OP
Node* CodeStubAssembler::WordIsSmi(Node* a) {
return WordEqual(raw_assembler_->WordAnd(a, IntPtrConstant(kSmiTagMask)),
IntPtrConstant(0));
......@@ -170,6 +187,12 @@ Node* CodeStubAssembler::LoadObjectField(Node* object, int offset) {
IntPtrConstant(offset - kHeapObjectTag));
}
Node* CodeStubAssembler::LoadHeapNumberValue(Node* object) {
return raw_assembler_->Load(
MachineType::Float64(), object,
IntPtrConstant(HeapNumber::kValueOffset - kHeapObjectTag));
}
Node* CodeStubAssembler::LoadFixedArrayElementSmiIndex(Node* object,
Node* smi_index,
int additional_offset) {
......@@ -255,6 +278,20 @@ Node* CodeStubAssembler::Projection(int index, Node* value) {
return raw_assembler_->Projection(index, value);
}
Node* CodeStubAssembler::LoadInstanceType(Node* object) {
return raw_assembler_->Word32And(
LoadObjectField(LoadObjectField(object, HeapObject::kMapOffset),
Map::kInstanceTypeOffset),
raw_assembler_->Int32Constant(255));
}
Node* CodeStubAssembler::BitFieldDecode(Node* word32, uint32_t shift,
uint32_t mask) {
return raw_assembler_->Word32Shr(
raw_assembler_->Word32And(word32, raw_assembler_->Int32Constant(mask)),
raw_assembler_->Int32Constant(shift));
}
Node* CodeStubAssembler::CallN(CallDescriptor* descriptor, Node* code_target,
Node** args) {
CallPrologue();
......@@ -314,6 +351,11 @@ Node* CodeStubAssembler::CallRuntime(Runtime::FunctionId function_id,
return return_value;
}
Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id,
Node* context) {
return raw_assembler_->TailCallRuntime0(function_id, context);
}
Node* CodeStubAssembler::TailCallRuntime(Runtime::FunctionId function_id,
Node* context, Node* arg1) {
return raw_assembler_->TailCallRuntime1(function_id, arg1, context);
......
......@@ -43,6 +43,7 @@ class Schedule;
V(Int32Sub) \
V(Int32Mul) \
V(Int32GreaterThanOrEqual) \
V(Int32LessThan) \
V(WordEqual) \
V(WordNotEqual) \
V(WordOr) \
......@@ -71,14 +72,26 @@ class Schedule;
V(Word64Ror) \
V(UintPtrGreaterThanOrEqual)
#define CODE_STUB_ASSEMBLER_UNARY_OP_LIST(V) \
V(ChangeFloat64ToUint32) \
V(ChangeInt32ToInt64) \
V(ChangeUint32ToFloat64) \
V(ChangeUint32ToUint64)
class CodeStubAssembler {
public:
// Create with CallStub linkage.
// |result_size| specifies the number of results returned by the stub.
// TODO(rmcilroy): move result_size to the CallInterfaceDescriptor.
CodeStubAssembler(Isolate* isolate, Zone* zone,
const CallInterfaceDescriptor& descriptor,
Code::Flags flags, const char* name,
size_t result_size = 1);
// Create with JSCall linkage.
CodeStubAssembler(Isolate* isolate, Zone* zone, int parameter_count,
Code::Flags flags, const char* name);
virtual ~CodeStubAssembler();
Handle<Code> GenerateCode();
......@@ -147,9 +160,10 @@ class CodeStubAssembler {
Node* WordShl(Node* value, int shift);
// Conversions
Node* ChangeInt32ToInt64(Node* value);
Node* ChangeUint32ToUint64(Node* value);
// Unary
#define DECLARE_CODE_STUB_ASSEMBER_UNARY_OP(name) Node* name(Node* a);
CODE_STUB_ASSEMBLER_UNARY_OP_LIST(DECLARE_CODE_STUB_ASSEMBER_UNARY_OP)
#undef DECLARE_CODE_STUB_ASSEMBER_UNARY_OP
// Projections
Node* Projection(int index, Node* value);
......@@ -166,6 +180,7 @@ class CodeStubAssembler {
Node* CallRuntime(Runtime::FunctionId function_id, Node* context, Node* arg1,
Node* arg2, Node* arg3, Node* arg4, Node* arg5);
Node* TailCallRuntime(Runtime::FunctionId function_id, Node* context);
Node* TailCallRuntime(Runtime::FunctionId function_id, Node* context,
Node* arg1);
Node* TailCallRuntime(Runtime::FunctionId function_id, Node* context,
......@@ -197,9 +212,12 @@ class CodeStubAssembler {
// Macros
// ===========================================================================
// Tag and untag Smi values.
// Tag a Word as a Smi value.
Node* SmiTag(Node* value);
// Untag a Smi value as a Word.
Node* SmiUntag(Node* value);
// Untag an Smi value as a 32-bit value.
Node* SmiToInt32(Node* value);
// Smi operations.
Node* SmiAdd(Node* a, Node* b);
......@@ -215,6 +233,8 @@ class CodeStubAssembler {
Node* LoadBufferObject(Node* buffer, int offset);
// Load a field from an object on the heap.
Node* LoadObjectField(Node* object, int offset);
// Load the HeapNumber value from a HeapNumber object.
Node* LoadHeapNumberValue(Node* object);
// Load an array element from a FixedArray.
Node* LoadFixedArrayElementSmiIndex(Node* object, Node* smi_index,
......@@ -224,6 +244,15 @@ class CodeStubAssembler {
// Store an array element to a FixedArray.
Node* StoreFixedArrayElementNoWriteBarrier(Node* object, Node* index,
Node* value);
Node* LoadInstanceType(Node* object);
// Returns a node that is true if the given bit is set in |word32|.
template <typename T>
Node* BitFieldDecode(Node* word32) {
return BitFieldDecode(word32, T::kShift, T::kMask);
}
Node* BitFieldDecode(Node* word32, uint32_t shift, uint32_t mask);
protected:
// Protected helpers which delegate to RawMachineAssembler.
......
......@@ -367,6 +367,11 @@ class Linkage : public ZoneObject {
// Get the location where an incoming OSR value is stored.
LinkageLocation GetOsrValueLocation(int index) const;
// A special {Parameter} index for Stub Calls that represents context.
static int GetStubCallContextParamIndex(int parameter_count) {
return parameter_count + 0; // Parameter (arity + 0) is special.
}
// A special {Parameter} index for JSCalls that represents the new target.
static int GetJSCallNewTargetParamIndex(int parameter_count) {
return parameter_count + 0; // Parameter (arity + 0) is special.
......
......@@ -247,6 +247,27 @@ Node* RawMachineAssembler::TailCallN(CallDescriptor* desc, Node* function,
return tail_call;
}
Node* RawMachineAssembler::TailCallRuntime0(Runtime::FunctionId function,
Node* context) {
const int kArity = 0;
CallDescriptor* desc = Linkage::GetRuntimeCallDescriptor(
zone(), function, kArity, Operator::kNoProperties,
CallDescriptor::kSupportsTailCalls);
int return_count = static_cast<int>(desc->ReturnCount());
Node* centry = HeapConstant(CEntryStub(isolate(), return_count).GetCode());
Node* ref = AddNode(
common()->ExternalConstant(ExternalReference(function, isolate())));
Node* arity = Int32Constant(kArity);
Node* nodes[] = {centry, ref, arity, context};
Node* tail_call = MakeNode(common()->TailCall(desc), arraysize(nodes), nodes);
NodeProperties::MergeControlToEnd(graph(), common(), tail_call);
schedule()->AddTailCall(CurrentBlock(), tail_call);
current_block_ = nullptr;
return tail_call;
}
Node* RawMachineAssembler::TailCallRuntime1(Runtime::FunctionId function,
Node* arg1, Node* context) {
......
......@@ -622,6 +622,8 @@ class RawMachineAssembler {
// Tail call the given call descriptor and the given arguments.
Node* TailCallN(CallDescriptor* call_descriptor, Node* function, Node** args);
// Tail call to a runtime function with zero arguments.
Node* TailCallRuntime0(Runtime::FunctionId function, Node* context);
// Tail call to a runtime function with one argument.
Node* TailCallRuntime1(Runtime::FunctionId function, Node* arg0,
Node* context);
......
......@@ -13,12 +13,19 @@ namespace compiler {
class CodeStubAssemblerTester : public CodeStubAssembler {
public:
// Test generating code for a stub.
CodeStubAssemblerTester(Isolate* isolate,
const CallInterfaceDescriptor& descriptor)
: CodeStubAssembler(isolate, isolate->runtime_zone(), descriptor,
Code::ComputeFlags(Code::STUB), "test"),
scope_(isolate) {}
// Test generating code for a JS function (e.g. builtins).
CodeStubAssemblerTester(Isolate* isolate, int parameter_count)
: CodeStubAssembler(isolate, isolate->runtime_zone(), parameter_count,
Code::ComputeFlags(Code::FUNCTION), "test"),
scope_(isolate) {}
private:
HandleScope scope_;
LocalContext context_;
......@@ -247,6 +254,83 @@ TEST(FixedArrayAccessSmiIndex) {
CHECK_EQ(733, Handle<Smi>::cast(result.ToHandleChecked())->value());
}
TEST(LoadHeapNumberValue) {
Isolate* isolate(CcTest::InitIsolateOnce());
VoidDescriptor descriptor(isolate);
CodeStubAssemblerTester m(isolate, descriptor);
Handle<HeapNumber> number = isolate->factory()->NewHeapNumber(1234);
m.Return(m.SmiTag(
m.ChangeFloat64ToUint32(m.LoadHeapNumberValue(m.HeapConstant(number)))));
Handle<Code> code = m.GenerateCode();
FunctionTester ft(descriptor, code);
MaybeHandle<Object> result = ft.Call();
CHECK_EQ(1234, Handle<Smi>::cast(result.ToHandleChecked())->value());
}
TEST(LoadInstanceType) {
Isolate* isolate(CcTest::InitIsolateOnce());
VoidDescriptor descriptor(isolate);
CodeStubAssemblerTester m(isolate, descriptor);
Handle<HeapObject> undefined = isolate->factory()->undefined_value();
m.Return(m.SmiTag(m.LoadInstanceType(m.HeapConstant(undefined))));
Handle<Code> code = m.GenerateCode();
FunctionTester ft(descriptor, code);
MaybeHandle<Object> result = ft.Call();
CHECK_EQ(InstanceType::ODDBALL_TYPE,
Handle<Smi>::cast(result.ToHandleChecked())->value());
}
namespace {
class TestBitField : public BitField<unsigned, 3, 3> {};
} // namespace
TEST(BitFieldDecode) {
Isolate* isolate(CcTest::InitIsolateOnce());
VoidDescriptor descriptor(isolate);
CodeStubAssemblerTester m(isolate, descriptor);
m.Return(m.SmiTag(m.BitFieldDecode<TestBitField>(m.Int32Constant(0x2f))));
Handle<Code> code = m.GenerateCode();
FunctionTester ft(descriptor, code);
MaybeHandle<Object> result = ft.Call();
// value = 00101111
// mask = 00111000
// result = 101
CHECK_EQ(5, Handle<Smi>::cast(result.ToHandleChecked())->value());
}
namespace {
Handle<JSFunction> CreateFunctionFromCode(int parameter_count_with_receiver,
Handle<Code> code) {
Isolate* isolate = code->GetIsolate();
Handle<String> name = isolate->factory()->InternalizeUtf8String("test");
Handle<JSFunction> function =
isolate->factory()->NewFunctionWithoutPrototype(name, code);
function->shared()->set_internal_formal_parameter_count(
parameter_count_with_receiver - 1); // Implicit undefined receiver.
return function;
}
} // namespace
TEST(JSFunction) {
const int kNumParams = 3; // Receiver, left, right.
Isolate* isolate(CcTest::InitIsolateOnce());
CodeStubAssemblerTester m(isolate, kNumParams);
m.Return(m.SmiTag(
m.Int32Add(m.SmiToInt32(m.Parameter(1)), m.SmiToInt32(m.Parameter(2)))));
Handle<Code> code = m.GenerateCode();
Handle<JSFunction> function = CreateFunctionFromCode(kNumParams, code);
Handle<Object> args[] = {Handle<Smi>(Smi::FromInt(23), isolate),
Handle<Smi>(Smi::FromInt(34), isolate)};
MaybeHandle<Object> result =
Execution::Call(isolate, function, isolate->factory()->undefined_value(),
arraysize(args), args);
CHECK_EQ(57, Handle<Smi>::cast(result.ToHandleChecked())->value());
}
} // namespace compiler
} // 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