87a65911b9
This is in preparation for introducing more specialized CodeStubAssembler subclasses. The state object can be handed around, while the Assembler instances are temporary-scoped. BUG=v8:5628 Original review: https://codereview.chromium.org/2498073002/ Review-Url: https://codereview.chromium.org/2502293002 Cr-Commit-Position: refs/heads/master@{#41028}
291 lines
9.6 KiB
C++
291 lines
9.6 KiB
C++
// Copyright 2015 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
#include "src/fast-accessor-assembler.h"
|
|
|
|
#include "src/base/logging.h"
|
|
#include "src/code-stub-assembler.h"
|
|
#include "src/code-stubs.h" // For CallApiCallbackStub.
|
|
#include "src/handles-inl.h"
|
|
#include "src/objects.h" // For FAA::LoadInternalField impl.
|
|
|
|
using v8::internal::compiler::Node;
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
|
|
FastAccessorAssembler::FastAccessorAssembler(Isolate* isolate)
|
|
: zone_(isolate->allocator(), ZONE_NAME),
|
|
isolate_(isolate),
|
|
assembler_state_(isolate, zone(), 1, Code::ComputeFlags(Code::STUB),
|
|
"FastAccessorAssembler"),
|
|
assembler_(new CodeStubAssembler(&assembler_state_)),
|
|
state_(kBuilding) {}
|
|
|
|
FastAccessorAssembler::~FastAccessorAssembler() { Clear(); }
|
|
|
|
FastAccessorAssembler::ValueId FastAccessorAssembler::IntegerConstant(
|
|
int const_value) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
return FromRaw(assembler_->NumberConstant(const_value));
|
|
}
|
|
|
|
FastAccessorAssembler::ValueId FastAccessorAssembler::GetReceiver() {
|
|
CHECK_EQ(kBuilding, state_);
|
|
|
|
// For JS functions, the receiver is parameter 0.
|
|
return FromRaw(assembler_->Parameter(0));
|
|
}
|
|
|
|
FastAccessorAssembler::ValueId FastAccessorAssembler::LoadInternalField(
|
|
ValueId value, int field_no) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
|
|
CodeStubAssembler::Variable result(assembler_.get(),
|
|
MachineRepresentation::kTagged);
|
|
LabelId is_not_jsobject = MakeLabel();
|
|
CodeStubAssembler::Label merge(assembler_.get(), &result);
|
|
|
|
CheckIsJSObjectOrJump(value, is_not_jsobject);
|
|
|
|
Node* internal_field = assembler_->LoadObjectField(
|
|
FromId(value), JSObject::kHeaderSize + kPointerSize * field_no,
|
|
MachineType::Pointer());
|
|
|
|
result.Bind(internal_field);
|
|
assembler_->Goto(&merge);
|
|
|
|
// Return null, mimicking the C++ counterpart.
|
|
SetLabel(is_not_jsobject);
|
|
result.Bind(assembler_->NullConstant());
|
|
assembler_->Goto(&merge);
|
|
|
|
// Return.
|
|
assembler_->Bind(&merge);
|
|
return FromRaw(result.value());
|
|
}
|
|
|
|
FastAccessorAssembler::ValueId
|
|
FastAccessorAssembler::LoadInternalFieldUnchecked(ValueId value, int field_no) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
|
|
// Defensive debug checks.
|
|
if (FLAG_debug_code) {
|
|
LabelId is_jsobject = MakeLabel();
|
|
LabelId is_not_jsobject = MakeLabel();
|
|
CheckIsJSObjectOrJump(value, is_not_jsobject);
|
|
assembler_->Goto(FromId(is_jsobject));
|
|
|
|
SetLabel(is_not_jsobject);
|
|
assembler_->DebugBreak();
|
|
assembler_->Goto(FromId(is_jsobject));
|
|
|
|
SetLabel(is_jsobject);
|
|
}
|
|
|
|
Node* result = assembler_->LoadObjectField(
|
|
FromId(value), JSObject::kHeaderSize + kPointerSize * field_no,
|
|
MachineType::Pointer());
|
|
|
|
return FromRaw(result);
|
|
}
|
|
|
|
FastAccessorAssembler::ValueId FastAccessorAssembler::LoadValue(ValueId value,
|
|
int offset) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
return FromRaw(assembler_->LoadBufferObject(FromId(value), offset,
|
|
MachineType::IntPtr()));
|
|
}
|
|
|
|
FastAccessorAssembler::ValueId FastAccessorAssembler::LoadObject(ValueId value,
|
|
int offset) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
return FromRaw(assembler_->LoadBufferObject(
|
|
assembler_->LoadBufferObject(FromId(value), offset,
|
|
MachineType::Pointer()),
|
|
0, MachineType::AnyTagged()));
|
|
}
|
|
|
|
FastAccessorAssembler::ValueId FastAccessorAssembler::ToSmi(ValueId value) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
return FromRaw(assembler_->SmiTag(FromId(value)));
|
|
}
|
|
|
|
void FastAccessorAssembler::ReturnValue(ValueId value) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
assembler_->Return(FromId(value));
|
|
}
|
|
|
|
void FastAccessorAssembler::CheckFlagSetOrReturnNull(ValueId value, int mask) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
CodeStubAssembler::Label pass(assembler_.get());
|
|
CodeStubAssembler::Label fail(assembler_.get());
|
|
assembler_->Branch(
|
|
assembler_->Word32Equal(
|
|
assembler_->Word32And(FromId(value), assembler_->Int32Constant(mask)),
|
|
assembler_->Int32Constant(0)),
|
|
&fail, &pass);
|
|
assembler_->Bind(&fail);
|
|
assembler_->Return(assembler_->NullConstant());
|
|
assembler_->Bind(&pass);
|
|
}
|
|
|
|
void FastAccessorAssembler::CheckNotZeroOrReturnNull(ValueId value) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
CodeStubAssembler::Label is_null(assembler_.get());
|
|
CodeStubAssembler::Label not_null(assembler_.get());
|
|
assembler_->Branch(
|
|
assembler_->WordEqual(FromId(value), assembler_->IntPtrConstant(0)),
|
|
&is_null, ¬_null);
|
|
assembler_->Bind(&is_null);
|
|
assembler_->Return(assembler_->NullConstant());
|
|
assembler_->Bind(¬_null);
|
|
}
|
|
|
|
FastAccessorAssembler::LabelId FastAccessorAssembler::MakeLabel() {
|
|
CHECK_EQ(kBuilding, state_);
|
|
return FromRaw(new CodeStubAssembler::Label(assembler_.get()));
|
|
}
|
|
|
|
void FastAccessorAssembler::SetLabel(LabelId label_id) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
assembler_->Bind(FromId(label_id));
|
|
}
|
|
|
|
void FastAccessorAssembler::Goto(LabelId label_id) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
assembler_->Goto(FromId(label_id));
|
|
}
|
|
|
|
void FastAccessorAssembler::CheckNotZeroOrJump(ValueId value_id,
|
|
LabelId label_id) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
CodeStubAssembler::Label pass(assembler_.get());
|
|
assembler_->Branch(
|
|
assembler_->WordEqual(FromId(value_id), assembler_->IntPtrConstant(0)),
|
|
FromId(label_id), &pass);
|
|
assembler_->Bind(&pass);
|
|
}
|
|
|
|
FastAccessorAssembler::ValueId FastAccessorAssembler::Call(
|
|
FunctionCallback callback_function, ValueId arg) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
|
|
// Wrap the FunctionCallback in an ExternalReference.
|
|
ApiFunction callback_api_function(FUNCTION_ADDR(callback_function));
|
|
ExternalReference callback(&callback_api_function,
|
|
ExternalReference::DIRECT_API_CALL, isolate());
|
|
|
|
// Create & call API callback via stub.
|
|
const int kJSParameterCount = 1;
|
|
CallApiCallbackStub stub(isolate(), kJSParameterCount, true, true);
|
|
CallInterfaceDescriptor descriptor = stub.GetCallInterfaceDescriptor();
|
|
DCHECK_EQ(4, descriptor.GetParameterCount());
|
|
DCHECK_EQ(0, descriptor.GetStackParameterCount());
|
|
// TODO(vogelheim): There is currently no clean way to retrieve the context
|
|
// parameter for a stub and the implementation details are hidden in
|
|
// compiler/*. The context_paramter is computed as:
|
|
// Linkage::GetJSCallContextParamIndex(descriptor->JSParameterCount())
|
|
const int kContextParameter = 3;
|
|
Node* context = assembler_->Parameter(kContextParameter);
|
|
Node* target = assembler_->HeapConstant(stub.GetCode());
|
|
|
|
int param_count = descriptor.GetParameterCount();
|
|
Node** args = zone()->NewArray<Node*>(param_count + 1 + kJSParameterCount);
|
|
// Stub/register parameters:
|
|
args[0] = assembler_->UndefinedConstant(); // callee (there's no JSFunction)
|
|
args[1] = assembler_->UndefinedConstant(); // call_data (undefined)
|
|
args[2] = assembler_->Parameter(0); // receiver (same as holder in this case)
|
|
args[3] = assembler_->ExternalConstant(callback); // API callback function
|
|
|
|
// JS arguments, on stack:
|
|
args[4] = FromId(arg);
|
|
|
|
// Context.
|
|
args[5] = context;
|
|
|
|
Node* call =
|
|
assembler_->CallStubN(descriptor, kJSParameterCount, target, args);
|
|
|
|
return FromRaw(call);
|
|
}
|
|
|
|
void FastAccessorAssembler::CheckIsJSObjectOrJump(ValueId value_id,
|
|
LabelId label_id) {
|
|
CHECK_EQ(kBuilding, state_);
|
|
|
|
// Determine the 'value' object's instance type.
|
|
Node* object_map = assembler_->LoadObjectField(
|
|
FromId(value_id), Internals::kHeapObjectMapOffset,
|
|
MachineType::Pointer());
|
|
|
|
Node* instance_type = assembler_->WordAnd(
|
|
assembler_->LoadObjectField(object_map,
|
|
Internals::kMapInstanceTypeAndBitFieldOffset,
|
|
MachineType::Uint16()),
|
|
assembler_->IntPtrConstant(0xff));
|
|
|
|
CodeStubAssembler::Label is_jsobject(assembler_.get());
|
|
|
|
// Check whether we have a proper JSObject.
|
|
assembler_->GotoIf(
|
|
assembler_->WordEqual(
|
|
instance_type, assembler_->IntPtrConstant(Internals::kJSObjectType)),
|
|
&is_jsobject);
|
|
|
|
// JSApiObject?.
|
|
assembler_->GotoUnless(
|
|
assembler_->WordEqual(instance_type, assembler_->IntPtrConstant(
|
|
Internals::kJSApiObjectType)),
|
|
FromId(label_id));
|
|
|
|
// Continue.
|
|
assembler_->Goto(&is_jsobject);
|
|
assembler_->Bind(&is_jsobject);
|
|
}
|
|
|
|
MaybeHandle<Code> FastAccessorAssembler::Build() {
|
|
CHECK_EQ(kBuilding, state_);
|
|
Handle<Code> code = compiler::CodeAssembler::GenerateCode(&assembler_state_);
|
|
state_ = !code.is_null() ? kBuilt : kError;
|
|
Clear();
|
|
return code;
|
|
}
|
|
|
|
FastAccessorAssembler::ValueId FastAccessorAssembler::FromRaw(Node* node) {
|
|
nodes_.push_back(node);
|
|
ValueId value = {nodes_.size() - 1};
|
|
return value;
|
|
}
|
|
|
|
FastAccessorAssembler::LabelId FastAccessorAssembler::FromRaw(
|
|
CodeStubAssembler::Label* label) {
|
|
labels_.push_back(label);
|
|
LabelId label_id = {labels_.size() - 1};
|
|
return label_id;
|
|
}
|
|
|
|
Node* FastAccessorAssembler::FromId(ValueId value) const {
|
|
CHECK_LT(value.value_id, nodes_.size());
|
|
CHECK_NOT_NULL(nodes_.at(value.value_id));
|
|
return nodes_.at(value.value_id);
|
|
}
|
|
|
|
CodeStubAssembler::Label* FastAccessorAssembler::FromId(LabelId label) const {
|
|
CHECK_LT(label.label_id, labels_.size());
|
|
CHECK_NOT_NULL(labels_.at(label.label_id));
|
|
return labels_.at(label.label_id);
|
|
}
|
|
|
|
void FastAccessorAssembler::Clear() {
|
|
for (auto label : labels_) {
|
|
delete label;
|
|
}
|
|
nodes_.clear();
|
|
labels_.clear();
|
|
}
|
|
|
|
} // namespace internal
|
|
} // namespace v8
|