blob: 1fbe1a84119510c1182bc91a79554585ab7e91ba [file] [log] [blame]
Ben Murdochda12d292016-06-02 14:46:10 +01001// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/fast-accessor-assembler.h"
6
7#include "src/base/logging.h"
Ben Murdochc5610432016-08-08 18:44:38 +01008#include "src/code-stub-assembler.h"
Ben Murdochda12d292016-06-02 14:46:10 +01009#include "src/code-stubs.h" // For CallApiCallbackStub.
Ben Murdochda12d292016-06-02 14:46:10 +010010#include "src/handles-inl.h"
11#include "src/objects.h" // For FAA::LoadInternalField impl.
12
Ben Murdochc5610432016-08-08 18:44:38 +010013using v8::internal::CodeStubAssembler;
Ben Murdochda12d292016-06-02 14:46:10 +010014using v8::internal::compiler::Node;
15
16namespace v8 {
17namespace internal {
18
19FastAccessorAssembler::FastAccessorAssembler(Isolate* isolate)
20 : zone_(isolate->allocator()),
21 isolate_(isolate),
22 assembler_(new CodeStubAssembler(isolate, zone(), 1,
23 Code::ComputeFlags(Code::STUB),
24 "FastAccessorAssembler")),
25 state_(kBuilding) {}
26
27FastAccessorAssembler::~FastAccessorAssembler() { Clear(); }
28
29FastAccessorAssembler::ValueId FastAccessorAssembler::IntegerConstant(
30 int const_value) {
31 CHECK_EQ(kBuilding, state_);
32 return FromRaw(assembler_->NumberConstant(const_value));
33}
34
35FastAccessorAssembler::ValueId FastAccessorAssembler::GetReceiver() {
36 CHECK_EQ(kBuilding, state_);
37
38 // For JS functions, the receiver is parameter 0.
39 return FromRaw(assembler_->Parameter(0));
40}
41
42FastAccessorAssembler::ValueId FastAccessorAssembler::LoadInternalField(
43 ValueId value, int field_no) {
44 CHECK_EQ(kBuilding, state_);
45
46 // Determine the 'value' object's instance type.
47 Node* object_map = assembler_->LoadObjectField(
48 FromId(value), Internals::kHeapObjectMapOffset, MachineType::Pointer());
49 Node* instance_type = assembler_->WordAnd(
50 assembler_->LoadObjectField(object_map,
51 Internals::kMapInstanceTypeAndBitFieldOffset,
52 MachineType::Uint16()),
53 assembler_->IntPtrConstant(0xff));
54
55 // Check whether we have a proper JSObject.
56 CodeStubAssembler::Variable result(assembler_.get(),
57 MachineRepresentation::kTagged);
58 CodeStubAssembler::Label is_jsobject(assembler_.get());
Ben Murdochc5610432016-08-08 18:44:38 +010059 CodeStubAssembler::Label maybe_api_object(assembler_.get());
Ben Murdochda12d292016-06-02 14:46:10 +010060 CodeStubAssembler::Label is_not_jsobject(assembler_.get());
61 CodeStubAssembler::Label merge(assembler_.get(), &result);
62 assembler_->Branch(
63 assembler_->WordEqual(
64 instance_type, assembler_->IntPtrConstant(Internals::kJSObjectType)),
Ben Murdochc5610432016-08-08 18:44:38 +010065 &is_jsobject, &maybe_api_object);
Ben Murdochda12d292016-06-02 14:46:10 +010066
67 // JSObject? Then load the internal field field_no.
68 assembler_->Bind(&is_jsobject);
69 Node* internal_field = assembler_->LoadObjectField(
70 FromId(value), JSObject::kHeaderSize + kPointerSize * field_no,
71 MachineType::Pointer());
72 result.Bind(internal_field);
73 assembler_->Goto(&merge);
74
Ben Murdochc5610432016-08-08 18:44:38 +010075 assembler_->Bind(&maybe_api_object);
76 assembler_->Branch(
77 assembler_->WordEqual(instance_type, assembler_->IntPtrConstant(
78 Internals::kJSApiObjectType)),
79 &is_jsobject, &is_not_jsobject);
80
Ben Murdochda12d292016-06-02 14:46:10 +010081 // No JSObject? Return undefined.
82 // TODO(vogelheim): Check whether this is the appropriate action, or whether
83 // the method should take a label instead.
84 assembler_->Bind(&is_not_jsobject);
85 Node* fail_value = assembler_->UndefinedConstant();
86 result.Bind(fail_value);
87 assembler_->Goto(&merge);
88
89 // Return.
90 assembler_->Bind(&merge);
91 return FromRaw(result.value());
92}
93
94FastAccessorAssembler::ValueId FastAccessorAssembler::LoadValue(ValueId value,
95 int offset) {
96 CHECK_EQ(kBuilding, state_);
97 return FromRaw(assembler_->LoadBufferObject(FromId(value), offset,
98 MachineType::IntPtr()));
99}
100
101FastAccessorAssembler::ValueId FastAccessorAssembler::LoadObject(ValueId value,
102 int offset) {
103 CHECK_EQ(kBuilding, state_);
104 return FromRaw(assembler_->LoadBufferObject(
105 assembler_->LoadBufferObject(FromId(value), offset,
106 MachineType::Pointer()),
107 0, MachineType::AnyTagged()));
108}
109
110void FastAccessorAssembler::ReturnValue(ValueId value) {
111 CHECK_EQ(kBuilding, state_);
112 assembler_->Return(FromId(value));
113}
114
115void FastAccessorAssembler::CheckFlagSetOrReturnNull(ValueId value, int mask) {
116 CHECK_EQ(kBuilding, state_);
117 CodeStubAssembler::Label pass(assembler_.get());
118 CodeStubAssembler::Label fail(assembler_.get());
119 assembler_->Branch(
120 assembler_->Word32Equal(
121 assembler_->Word32And(FromId(value), assembler_->Int32Constant(mask)),
122 assembler_->Int32Constant(0)),
123 &pass, &fail);
124 assembler_->Bind(&fail);
125 assembler_->Return(assembler_->NullConstant());
126 assembler_->Bind(&pass);
127}
128
129void FastAccessorAssembler::CheckNotZeroOrReturnNull(ValueId value) {
130 CHECK_EQ(kBuilding, state_);
131 CodeStubAssembler::Label is_null(assembler_.get());
132 CodeStubAssembler::Label not_null(assembler_.get());
133 assembler_->Branch(
134 assembler_->WordEqual(FromId(value), assembler_->IntPtrConstant(0)),
135 &is_null, &not_null);
136 assembler_->Bind(&is_null);
137 assembler_->Return(assembler_->NullConstant());
138 assembler_->Bind(&not_null);
139}
140
141FastAccessorAssembler::LabelId FastAccessorAssembler::MakeLabel() {
142 CHECK_EQ(kBuilding, state_);
143 return FromRaw(new CodeStubAssembler::Label(assembler_.get()));
144}
145
146void FastAccessorAssembler::SetLabel(LabelId label_id) {
147 CHECK_EQ(kBuilding, state_);
148 assembler_->Bind(FromId(label_id));
149}
150
151void FastAccessorAssembler::CheckNotZeroOrJump(ValueId value_id,
152 LabelId label_id) {
153 CHECK_EQ(kBuilding, state_);
154 CodeStubAssembler::Label pass(assembler_.get());
155 assembler_->Branch(
156 assembler_->WordEqual(FromId(value_id), assembler_->IntPtrConstant(0)),
157 &pass, FromId(label_id));
158 assembler_->Bind(&pass);
159}
160
161FastAccessorAssembler::ValueId FastAccessorAssembler::Call(
162 FunctionCallback callback_function, ValueId arg) {
163 CHECK_EQ(kBuilding, state_);
164
165 // Wrap the FunctionCallback in an ExternalReference.
166 ApiFunction callback_api_function(FUNCTION_ADDR(callback_function));
167 ExternalReference callback(&callback_api_function,
168 ExternalReference::DIRECT_API_CALL, isolate());
169
170 // Create & call API callback via stub.
171 CallApiCallbackStub stub(isolate(), 1, true);
172 DCHECK_EQ(5, stub.GetCallInterfaceDescriptor().GetParameterCount());
173 DCHECK_EQ(1, stub.GetCallInterfaceDescriptor().GetStackParameterCount());
174 // TODO(vogelheim): There is currently no clean way to retrieve the context
175 // parameter for a stub and the implementation details are hidden in
176 // compiler/*. The context_paramter is computed as:
177 // Linkage::GetJSCallContextParamIndex(descriptor->JSParameterCount())
178 const int context_parameter = 2;
179 Node* call = assembler_->CallStub(
180 stub.GetCallInterfaceDescriptor(),
181 assembler_->HeapConstant(stub.GetCode()),
182 assembler_->Parameter(context_parameter),
183
184 // Stub/register parameters:
185 assembler_->Parameter(0), /* receiver (use accessor's) */
186 assembler_->UndefinedConstant(), /* call_data (undefined) */
187 assembler_->NullConstant(), /* holder (null) */
188 assembler_->ExternalConstant(callback), /* API callback function */
189
190 // JS arguments, on stack:
191 FromId(arg));
192
193 return FromRaw(call);
194}
195
196MaybeHandle<Code> FastAccessorAssembler::Build() {
197 CHECK_EQ(kBuilding, state_);
198 Handle<Code> code = assembler_->GenerateCode();
199 state_ = !code.is_null() ? kBuilt : kError;
200 Clear();
201 return code;
202}
203
204FastAccessorAssembler::ValueId FastAccessorAssembler::FromRaw(Node* node) {
205 nodes_.push_back(node);
206 ValueId value = {nodes_.size() - 1};
207 return value;
208}
209
210FastAccessorAssembler::LabelId FastAccessorAssembler::FromRaw(
211 CodeStubAssembler::Label* label) {
212 labels_.push_back(label);
213 LabelId label_id = {labels_.size() - 1};
214 return label_id;
215}
216
217Node* FastAccessorAssembler::FromId(ValueId value) const {
218 CHECK_LT(value.value_id, nodes_.size());
219 CHECK_NOT_NULL(nodes_.at(value.value_id));
220 return nodes_.at(value.value_id);
221}
222
223CodeStubAssembler::Label* FastAccessorAssembler::FromId(LabelId label) const {
224 CHECK_LT(label.label_id, labels_.size());
225 CHECK_NOT_NULL(labels_.at(label.label_id));
226 return labels_.at(label.label_id);
227}
228
229void FastAccessorAssembler::Clear() {
230 for (auto label : labels_) {
231 delete label;
232 }
233 nodes_.clear();
234 labels_.clear();
235}
236
237} // namespace internal
238} // namespace v8