1 // 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"
8 #include "src/code-stub-assembler.h"
9 #include "src/code-stubs.h" // For CallApiCallbackStub.
10 #include "src/handles-inl.h"
11 #include "src/objects-inl.h"
12 #include "src/objects.h" // For FAA::LoadInternalField impl.
13
14 namespace v8 {
15 namespace internal {
16
17 using compiler::Node;
18 using compiler::CodeAssemblerLabel;
19 using compiler::CodeAssemblerVariable;
20
FastAccessorAssembler(Isolate * isolate)21 FastAccessorAssembler::FastAccessorAssembler(Isolate* isolate)
22 : zone_(isolate->allocator(), ZONE_NAME),
23 isolate_(isolate),
24 assembler_state_(new compiler::CodeAssemblerState(
25 isolate, zone(), 1, Code::ComputeFlags(Code::STUB),
26 "FastAccessorAssembler")),
27 assembler_(new CodeStubAssembler(assembler_state_.get())),
28 state_(kBuilding) {}
29
~FastAccessorAssembler()30 FastAccessorAssembler::~FastAccessorAssembler() { Clear(); }
31
IntegerConstant(int const_value)32 FastAccessorAssembler::ValueId FastAccessorAssembler::IntegerConstant(
33 int const_value) {
34 CHECK_EQ(kBuilding, state_);
35 return FromRaw(assembler_->NumberConstant(const_value));
36 }
37
GetReceiver()38 FastAccessorAssembler::ValueId FastAccessorAssembler::GetReceiver() {
39 CHECK_EQ(kBuilding, state_);
40
41 // For JS functions, the receiver is parameter 0.
42 return FromRaw(assembler_->Parameter(0));
43 }
44
LoadInternalField(ValueId value_id,int field_no)45 FastAccessorAssembler::ValueId FastAccessorAssembler::LoadInternalField(
46 ValueId value_id, int field_no) {
47 CHECK_EQ(kBuilding, state_);
48
49 CodeAssemblerVariable result(assembler_.get(),
50 MachineRepresentation::kTagged);
51 LabelId is_not_jsobject = MakeLabel();
52 CodeAssemblerLabel merge(assembler_.get(), &result);
53
54 CheckIsJSObjectOrJump(value_id, is_not_jsobject);
55
56 Node* internal_field = assembler_->LoadObjectField(
57 FromId(value_id), JSObject::kHeaderSize + kPointerSize * field_no);
58
59 result.Bind(internal_field);
60 assembler_->Goto(&merge);
61
62 // Return null, mimicking the C++ counterpart.
63 SetLabel(is_not_jsobject);
64 result.Bind(assembler_->NullConstant());
65 assembler_->Goto(&merge);
66
67 // Return.
68 assembler_->Bind(&merge);
69 return FromRaw(result.value());
70 }
71
72 FastAccessorAssembler::ValueId
LoadInternalFieldUnchecked(ValueId value_id,int field_no)73 FastAccessorAssembler::LoadInternalFieldUnchecked(ValueId value_id,
74 int field_no) {
75 CHECK_EQ(kBuilding, state_);
76
77 // Defensive debug checks.
78 if (FLAG_debug_code) {
79 LabelId is_jsobject = MakeLabel();
80 LabelId is_not_jsobject = MakeLabel();
81 CheckIsJSObjectOrJump(value_id, is_not_jsobject);
82 assembler_->Goto(FromId(is_jsobject));
83
84 SetLabel(is_not_jsobject);
85 assembler_->DebugBreak();
86 assembler_->Goto(FromId(is_jsobject));
87
88 SetLabel(is_jsobject);
89 }
90
91 Node* result = assembler_->LoadObjectField(
92 FromId(value_id), JSObject::kHeaderSize + kPointerSize * field_no);
93
94 return FromRaw(result);
95 }
96
LoadValue(ValueId value_id,int offset)97 FastAccessorAssembler::ValueId FastAccessorAssembler::LoadValue(
98 ValueId value_id, int offset) {
99 CHECK_EQ(kBuilding, state_);
100 return FromRaw(assembler_->LoadBufferObject(FromId(value_id), offset,
101 MachineType::IntPtr()));
102 }
103
LoadObject(ValueId value_id,int offset)104 FastAccessorAssembler::ValueId FastAccessorAssembler::LoadObject(
105 ValueId value_id, int offset) {
106 CHECK_EQ(kBuilding, state_);
107 return FromRaw(assembler_->LoadBufferObject(
108 assembler_->LoadBufferObject(FromId(value_id), offset), 0,
109 MachineType::AnyTagged()));
110 }
111
ToSmi(ValueId value_id)112 FastAccessorAssembler::ValueId FastAccessorAssembler::ToSmi(ValueId value_id) {
113 CHECK_EQ(kBuilding, state_);
114 return FromRaw(assembler_->SmiTag(FromId(value_id)));
115 }
116
ReturnValue(ValueId value_id)117 void FastAccessorAssembler::ReturnValue(ValueId value_id) {
118 CHECK_EQ(kBuilding, state_);
119 assembler_->Return(FromId(value_id));
120 }
121
CheckFlagSetOrReturnNull(ValueId value_id,int mask)122 void FastAccessorAssembler::CheckFlagSetOrReturnNull(ValueId value_id,
123 int mask) {
124 CHECK_EQ(kBuilding, state_);
125 CodeAssemblerLabel pass(assembler_.get());
126 CodeAssemblerLabel fail(assembler_.get());
127 Node* value = FromId(value_id);
128 assembler_->Branch(
129 assembler_->IsSetWord(assembler_->BitcastTaggedToWord(value), mask),
130 &pass, &fail);
131 assembler_->Bind(&fail);
132 assembler_->Return(assembler_->NullConstant());
133 assembler_->Bind(&pass);
134 }
135
CheckNotZeroOrReturnNull(ValueId value_id)136 void FastAccessorAssembler::CheckNotZeroOrReturnNull(ValueId value_id) {
137 CHECK_EQ(kBuilding, state_);
138 CodeAssemblerLabel is_null(assembler_.get());
139 CodeAssemblerLabel not_null(assembler_.get());
140 assembler_->Branch(
141 assembler_->WordEqual(FromId(value_id), assembler_->SmiConstant(0)),
142 &is_null, ¬_null);
143 assembler_->Bind(&is_null);
144 assembler_->Return(assembler_->NullConstant());
145 assembler_->Bind(¬_null);
146 }
147
MakeLabel()148 FastAccessorAssembler::LabelId FastAccessorAssembler::MakeLabel() {
149 CHECK_EQ(kBuilding, state_);
150 return FromRaw(new CodeAssemblerLabel(assembler_.get()));
151 }
152
SetLabel(LabelId label_id)153 void FastAccessorAssembler::SetLabel(LabelId label_id) {
154 CHECK_EQ(kBuilding, state_);
155 assembler_->Bind(FromId(label_id));
156 }
157
Goto(LabelId label_id)158 void FastAccessorAssembler::Goto(LabelId label_id) {
159 CHECK_EQ(kBuilding, state_);
160 assembler_->Goto(FromId(label_id));
161 }
162
CheckNotZeroOrJump(ValueId value_id,LabelId label_id)163 void FastAccessorAssembler::CheckNotZeroOrJump(ValueId value_id,
164 LabelId label_id) {
165 CHECK_EQ(kBuilding, state_);
166 CodeAssemblerLabel pass(assembler_.get());
167 assembler_->Branch(
168 assembler_->WordEqual(FromId(value_id), assembler_->SmiConstant(0)),
169 FromId(label_id), &pass);
170 assembler_->Bind(&pass);
171 }
172
Call(FunctionCallback callback_function,ValueId arg)173 FastAccessorAssembler::ValueId FastAccessorAssembler::Call(
174 FunctionCallback callback_function, ValueId arg) {
175 CHECK_EQ(kBuilding, state_);
176
177 // Wrap the FunctionCallback in an ExternalReference.
178 ApiFunction callback_api_function(FUNCTION_ADDR(callback_function));
179 ExternalReference callback(&callback_api_function,
180 ExternalReference::DIRECT_API_CALL, isolate());
181
182 // Create & call API callback via stub.
183 const int kJSParameterCount = 1;
184 CallApiCallbackStub stub(isolate(), kJSParameterCount, true, true);
185 CallInterfaceDescriptor descriptor = stub.GetCallInterfaceDescriptor();
186 DCHECK_EQ(4, descriptor.GetParameterCount());
187 DCHECK_EQ(0, descriptor.GetStackParameterCount());
188 Node* context = assembler_->GetJSContextParameter();
189 Node* target = assembler_->HeapConstant(stub.GetCode());
190
191 Node* call = assembler_->CallStub(
192 descriptor, target, context,
193 assembler_->UndefinedConstant(), // callee (there's no JSFunction)
194 assembler_->UndefinedConstant(), // call_data (undefined)
195 assembler_->Parameter(0), // receiver (same as holder in this case)
196 assembler_->ExternalConstant(callback), // API callback function
197 FromId(arg)); // JS argument, on stack
198 return FromRaw(call);
199 }
200
CheckIsJSObjectOrJump(ValueId value_id,LabelId label_id)201 void FastAccessorAssembler::CheckIsJSObjectOrJump(ValueId value_id,
202 LabelId label_id) {
203 CHECK_EQ(kBuilding, state_);
204
205 // Determine the 'value' object's instance type.
206 Node* instance_type = assembler_->LoadInstanceType(FromId(value_id));
207
208 CodeAssemblerLabel is_jsobject(assembler_.get());
209
210 // Check whether we have a proper JSObject.
211 assembler_->GotoIf(
212 assembler_->Word32Equal(
213 instance_type, assembler_->Int32Constant(Internals::kJSObjectType)),
214 &is_jsobject);
215
216 // JSApiObject?.
217 assembler_->GotoIfNot(
218 assembler_->Word32Equal(instance_type, assembler_->Int32Constant(
219 Internals::kJSApiObjectType)),
220 FromId(label_id));
221
222 // Continue.
223 assembler_->Goto(&is_jsobject);
224 assembler_->Bind(&is_jsobject);
225 }
226
Build()227 MaybeHandle<Code> FastAccessorAssembler::Build() {
228 CHECK_EQ(kBuilding, state_);
229 Handle<Code> code =
230 compiler::CodeAssembler::GenerateCode(assembler_state_.get());
231 state_ = !code.is_null() ? kBuilt : kError;
232 Clear();
233 return code;
234 }
235
FromRaw(Node * node)236 FastAccessorAssembler::ValueId FastAccessorAssembler::FromRaw(Node* node) {
237 nodes_.push_back(node);
238 ValueId value_id = {nodes_.size() - 1};
239 return value_id;
240 }
241
FromRaw(CodeAssemblerLabel * label)242 FastAccessorAssembler::LabelId FastAccessorAssembler::FromRaw(
243 CodeAssemblerLabel* label) {
244 labels_.push_back(label);
245 LabelId label_id = {labels_.size() - 1};
246 return label_id;
247 }
248
FromId(ValueId value) const249 Node* FastAccessorAssembler::FromId(ValueId value) const {
250 CHECK_LT(value.value_id, nodes_.size());
251 CHECK_NOT_NULL(nodes_.at(value.value_id));
252 return nodes_.at(value.value_id);
253 }
254
FromId(LabelId label) const255 CodeAssemblerLabel* FastAccessorAssembler::FromId(LabelId label) const {
256 CHECK_LT(label.label_id, labels_.size());
257 CHECK_NOT_NULL(labels_.at(label.label_id));
258 return labels_.at(label.label_id);
259 }
260
Clear()261 void FastAccessorAssembler::Clear() {
262 for (auto label : labels_) {
263 delete label;
264 }
265 nodes_.clear();
266 labels_.clear();
267 }
268
269 } // namespace internal
270 } // namespace v8
271