Line data Source code
1 : // Copyright 2016 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 : #ifndef V8_IC_ACCESSOR_ASSEMBLER_H_
6 : #define V8_IC_ACCESSOR_ASSEMBLER_H_
7 :
8 : #include "src/code-stub-assembler.h"
9 :
10 : namespace v8 {
11 : namespace internal {
12 :
13 : namespace compiler {
14 : class CodeAssemblerState;
15 : }
16 :
17 : class ExitPoint;
18 :
19 2700 : class V8_EXPORT_PRIVATE AccessorAssembler : public CodeStubAssembler {
20 : public:
21 : using Node = compiler::Node;
22 : template <class T>
23 : using TNode = compiler::TNode<T>;
24 : template <class T>
25 : using SloppyTNode = compiler::SloppyTNode<T>;
26 :
27 : explicit AccessorAssembler(compiler::CodeAssemblerState* state)
28 2644 : : CodeStubAssembler(state) {}
29 :
30 : void GenerateLoadIC();
31 : void GenerateLoadIC_Megamorphic();
32 : void GenerateLoadIC_Noninlined();
33 : void GenerateLoadIC_Uninitialized();
34 : void GenerateLoadICTrampoline();
35 : void GenerateLoadICTrampoline_Megamorphic();
36 : void GenerateKeyedLoadIC();
37 : void GenerateKeyedLoadIC_Megamorphic();
38 : void GenerateKeyedLoadIC_PolymorphicName();
39 : void GenerateKeyedLoadICTrampoline();
40 : void GenerateKeyedLoadICTrampoline_Megamorphic();
41 : void GenerateStoreIC();
42 : void GenerateStoreICTrampoline();
43 : void GenerateStoreGlobalIC();
44 : void GenerateStoreGlobalICTrampoline();
45 : void GenerateCloneObjectIC();
46 : void GenerateCloneObjectIC_Slow();
47 : void GenerateKeyedHasIC();
48 : void GenerateKeyedHasIC_Megamorphic();
49 : void GenerateKeyedHasIC_PolymorphicName();
50 :
51 : void GenerateLoadGlobalIC(TypeofMode typeof_mode);
52 : void GenerateLoadGlobalICTrampoline(TypeofMode typeof_mode);
53 :
54 : void GenerateKeyedStoreIC();
55 : void GenerateKeyedStoreICTrampoline();
56 :
57 : void GenerateStoreInArrayLiteralIC();
58 :
59 : void TryProbeStubCache(StubCache* stub_cache, Node* receiver, Node* name,
60 : Label* if_handler, TVariable<MaybeObject>* var_handler,
61 : Label* if_miss);
62 :
63 : Node* StubCachePrimaryOffsetForTesting(Node* name, Node* map) {
64 8 : return StubCachePrimaryOffset(name, map);
65 : }
66 : Node* StubCacheSecondaryOffsetForTesting(Node* name, Node* map) {
67 4 : return StubCacheSecondaryOffset(name, map);
68 : }
69 :
70 : struct LoadICParameters {
71 : LoadICParameters(Node* context, Node* receiver, Node* name, Node* slot,
72 : Node* vector, Node* holder = nullptr)
73 : : context(context),
74 : receiver(receiver),
75 : name(name),
76 : slot(slot),
77 : vector(vector),
78 1960 : holder(holder ? holder : receiver) {}
79 :
80 : Node* context;
81 : Node* receiver;
82 : Node* name;
83 : Node* slot;
84 : Node* vector;
85 : Node* holder;
86 : };
87 :
88 : void LoadGlobalIC(Node* vector, Node* slot,
89 : const LazyNode<Context>& lazy_context,
90 : const LazyNode<Name>& lazy_name, TypeofMode typeof_mode,
91 : ExitPoint* exit_point,
92 : ParameterMode slot_mode = SMI_PARAMETERS);
93 :
94 : // Specialized LoadIC for inlined bytecode handler, hand-tuned to omit frame
95 : // construction on common paths.
96 : void LoadIC_BytecodeHandler(const LoadICParameters* p, ExitPoint* exit_point);
97 :
98 : // Loads dataX field from the DataHandler object.
99 : TNode<MaybeObject> LoadHandlerDataField(SloppyTNode<DataHandler> handler,
100 : int data_index);
101 :
102 : protected:
103 : struct StoreICParameters : public LoadICParameters {
104 : StoreICParameters(Node* context, Node* receiver, Node* name,
105 : SloppyTNode<Object> value, Node* slot, Node* vector)
106 : : LoadICParameters(context, receiver, name, slot, vector),
107 504 : value(value) {}
108 : SloppyTNode<Object> value;
109 : };
110 :
111 : enum class LoadAccessMode { kLoad, kHas };
112 : enum class ICMode { kNonGlobalIC, kGlobalIC };
113 : enum ElementSupport { kOnlyProperties, kSupportElements };
114 : void HandleStoreICHandlerCase(
115 : const StoreICParameters* p, TNode<MaybeObject> handler, Label* miss,
116 : ICMode ic_mode, ElementSupport support_elements = kOnlyProperties);
117 : enum StoreTransitionMapFlags {
118 : kCheckPrototypeValidity = 1 << 0,
119 : kValidateTransitionHandler = 1 << 1,
120 : kStoreTransitionMapFlagsMask =
121 : kCheckPrototypeValidity | kValidateTransitionHandler,
122 : };
123 : void HandleStoreICTransitionMapHandlerCase(const StoreICParameters* p,
124 : TNode<Map> transition_map,
125 : Label* miss,
126 : StoreTransitionMapFlags flags);
127 :
128 : void JumpIfDataProperty(Node* details, Label* writable, Label* readonly);
129 :
130 : void InvalidateValidityCellIfPrototype(Node* map, Node* bitfield2 = nullptr);
131 :
132 : void OverwriteExistingFastDataProperty(Node* object, Node* object_map,
133 : Node* descriptors,
134 : Node* descriptor_name_index,
135 : Node* details, Node* value,
136 : Label* slow,
137 : bool do_transitioning_store);
138 :
139 : void CheckFieldType(TNode<DescriptorArray> descriptors, Node* name_index,
140 : Node* representation, Node* value, Label* bailout);
141 :
142 : private:
143 : // Stub generation entry points.
144 :
145 : // LoadIC contains the full LoadIC logic, while LoadIC_Noninlined contains
146 : // logic not inlined into Ignition bytecode handlers.
147 : void LoadIC(const LoadICParameters* p);
148 : void LoadIC_Noninlined(const LoadICParameters* p, Node* receiver_map,
149 : TNode<HeapObject> feedback,
150 : TVariable<MaybeObject>* var_handler, Label* if_handler,
151 : Label* miss, ExitPoint* exit_point);
152 :
153 : TNode<Object> LoadDescriptorValue(TNode<Map> map,
154 : TNode<IntPtrT> descriptor_entry);
155 : TNode<MaybeObject> LoadDescriptorValueOrFieldType(
156 : TNode<Map> map, TNode<IntPtrT> descriptor_entry);
157 :
158 : void LoadIC_Uninitialized(const LoadICParameters* p);
159 :
160 : void KeyedLoadIC(const LoadICParameters* p, LoadAccessMode access_mode);
161 : void KeyedLoadICGeneric(const LoadICParameters* p);
162 : void KeyedLoadICPolymorphicName(const LoadICParameters* p,
163 : LoadAccessMode access_mode);
164 : void StoreIC(const StoreICParameters* p);
165 : void StoreGlobalIC(const StoreICParameters* p);
166 : void StoreGlobalIC_PropertyCellCase(Node* property_cell, Node* value,
167 : ExitPoint* exit_point, Label* miss);
168 : void KeyedStoreIC(const StoreICParameters* p);
169 : void StoreInArrayLiteralIC(const StoreICParameters* p);
170 :
171 : // IC dispatcher behavior.
172 :
173 : // Checks monomorphic case. Returns {feedback} entry of the vector.
174 : TNode<MaybeObject> TryMonomorphicCase(Node* slot, Node* vector,
175 : Node* receiver_map, Label* if_handler,
176 : TVariable<MaybeObject>* var_handler,
177 : Label* if_miss);
178 : void HandlePolymorphicCase(Node* receiver_map, TNode<WeakFixedArray> feedback,
179 : Label* if_handler,
180 : TVariable<MaybeObject>* var_handler,
181 : Label* if_miss);
182 :
183 : // LoadIC implementation.
184 : void HandleLoadICHandlerCase(
185 : const LoadICParameters* p, TNode<Object> handler, Label* miss,
186 : ExitPoint* exit_point, ICMode ic_mode = ICMode::kNonGlobalIC,
187 : OnNonExistent on_nonexistent = OnNonExistent::kReturnUndefined,
188 : ElementSupport support_elements = kOnlyProperties,
189 : LoadAccessMode access_mode = LoadAccessMode::kLoad);
190 :
191 : void HandleLoadICSmiHandlerCase(const LoadICParameters* p, Node* holder,
192 : SloppyTNode<Smi> smi_handler,
193 : SloppyTNode<Object> handler, Label* miss,
194 : ExitPoint* exit_point,
195 : OnNonExistent on_nonexistent,
196 : ElementSupport support_elements,
197 : LoadAccessMode access_mode);
198 :
199 : void HandleLoadICProtoHandler(const LoadICParameters* p, Node* handler,
200 : Variable* var_holder, Variable* var_smi_handler,
201 : Label* if_smi_handler, Label* miss,
202 : ExitPoint* exit_point, ICMode ic_mode,
203 : LoadAccessMode access_mode);
204 :
205 : void HandleLoadCallbackProperty(const LoadICParameters* p,
206 : TNode<JSObject> holder,
207 : TNode<WordT> handler_word,
208 : ExitPoint* exit_point);
209 :
210 : void HandleLoadAccessor(const LoadICParameters* p,
211 : TNode<CallHandlerInfo> call_handler_info,
212 : TNode<WordT> handler_word, TNode<DataHandler> handler,
213 : TNode<IntPtrT> handler_kind, ExitPoint* exit_point);
214 :
215 : void HandleLoadField(Node* holder, Node* handler_word,
216 : Variable* var_double_value, Label* rebox_double,
217 : ExitPoint* exit_point);
218 :
219 : void EmitAccessCheck(Node* expected_native_context, Node* context,
220 : Node* receiver, Label* can_access, Label* miss);
221 :
222 : void HandleLoadICSmiHandlerLoadNamedCase(
223 : const LoadICParameters* p, Node* holder, TNode<IntPtrT> handler_kind,
224 : TNode<WordT> handler_word, Label* rebox_double,
225 : Variable* var_double_value, SloppyTNode<Object> handler, Label* miss,
226 : ExitPoint* exit_point, OnNonExistent on_nonexistent,
227 : ElementSupport support_elements);
228 :
229 : void HandleLoadICSmiHandlerHasNamedCase(const LoadICParameters* p,
230 : Node* holder,
231 : TNode<IntPtrT> handler_kind,
232 : Label* miss, ExitPoint* exit_point);
233 :
234 : // LoadGlobalIC implementation.
235 :
236 : void LoadGlobalIC_TryPropertyCellCase(
237 : TNode<FeedbackVector> vector, Node* slot,
238 : const LazyNode<Context>& lazy_context, ExitPoint* exit_point,
239 : Label* try_handler, Label* miss,
240 : ParameterMode slot_mode = SMI_PARAMETERS);
241 :
242 : void LoadGlobalIC_TryHandlerCase(TNode<FeedbackVector> vector, Node* slot,
243 : const LazyNode<Context>& lazy_context,
244 : const LazyNode<Name>& lazy_name,
245 : TypeofMode typeof_mode,
246 : ExitPoint* exit_point, Label* miss,
247 : ParameterMode slot_mode);
248 :
249 : // StoreIC implementation.
250 :
251 : void HandleStoreICProtoHandler(const StoreICParameters* p,
252 : TNode<StoreHandler> handler, Label* miss,
253 : ICMode ic_mode,
254 : ElementSupport support_elements);
255 : void HandleStoreICSmiHandlerCase(Node* handler_word, Node* holder,
256 : Node* value, Label* miss);
257 : void HandleStoreFieldAndReturn(Node* handler_word, Node* holder,
258 : Representation representation, Node* value,
259 : Label* miss);
260 :
261 : void CheckPrototypeValidityCell(Node* maybe_validity_cell, Label* miss);
262 : void HandleStoreICNativeDataProperty(const StoreICParameters* p, Node* holder,
263 : Node* handler_word);
264 :
265 : void HandleStoreToProxy(const StoreICParameters* p, Node* proxy, Label* miss,
266 : ElementSupport support_elements);
267 :
268 : void HandleStoreAccessor(const StoreICParameters* p, Node* holder,
269 : Node* handler_word);
270 :
271 : // KeyedLoadIC_Generic implementation.
272 :
273 : void GenericElementLoad(Node* receiver, Node* receiver_map,
274 : SloppyTNode<Int32T> instance_type, Node* index,
275 : Label* slow);
276 :
277 : enum UseStubCache { kUseStubCache, kDontUseStubCache };
278 : void GenericPropertyLoad(Node* receiver, Node* receiver_map,
279 : SloppyTNode<Int32T> instance_type,
280 : const LoadICParameters* p, Label* slow,
281 : UseStubCache use_stub_cache = kUseStubCache);
282 :
283 : // Low-level helpers.
284 :
285 : using OnCodeHandler = std::function<void(Node* code_handler)>;
286 : using OnFoundOnReceiver =
287 : std::function<void(Node* properties, Node* name_index)>;
288 :
289 : template <typename ICHandler, typename ICParameters>
290 : Node* HandleProtoHandler(const ICParameters* p, Node* handler,
291 : const OnCodeHandler& on_code_handler,
292 : const OnFoundOnReceiver& on_found_on_receiver,
293 : Label* miss, ICMode ic_mode);
294 :
295 : Node* PrepareValueForStore(Node* handler_word, Node* holder,
296 : Representation representation, Node* value,
297 : Label* bailout);
298 :
299 : void BranchIfPrototypeShouldbeFast(Node* receiver_map,
300 : Label* prototype_not_fast,
301 : Label* prototype_fast);
302 :
303 : // Extends properties backing store by JSObject::kFieldsAdded elements,
304 : // returns updated properties backing store.
305 : Node* ExtendPropertiesBackingStore(Node* object, Node* index);
306 :
307 : void StoreNamedField(Node* handler_word, Node* object, bool is_inobject,
308 : Representation representation, Node* value,
309 : Label* bailout);
310 :
311 : void EmitFastElementsBoundsCheck(Node* object, Node* elements,
312 : Node* intptr_index,
313 : Node* is_jsarray_condition, Label* miss);
314 : void EmitElementLoad(Node* object, Node* elements, Node* elements_kind,
315 : SloppyTNode<IntPtrT> key, Node* is_jsarray_condition,
316 : Label* if_hole, Label* rebox_double,
317 : Variable* var_double_value,
318 : Label* unimplemented_elements_kind, Label* out_of_bounds,
319 : Label* miss, ExitPoint* exit_point,
320 : LoadAccessMode access_mode = LoadAccessMode::kLoad);
321 : void NameDictionaryNegativeLookup(Node* object, SloppyTNode<Name> name,
322 : Label* miss);
323 : TNode<BoolT> IsPropertyDetailsConst(Node* details);
324 :
325 : // Stub cache access helpers.
326 :
327 : // This enum is used here as a replacement for StubCache::Table to avoid
328 : // including stub cache header.
329 : enum StubCacheTable : int;
330 :
331 : Node* StubCachePrimaryOffset(Node* name, Node* map);
332 : Node* StubCacheSecondaryOffset(Node* name, Node* seed);
333 :
334 : void TryProbeStubCacheTable(StubCache* stub_cache, StubCacheTable table_id,
335 : Node* entry_offset, Node* name, Node* map,
336 : Label* if_handler,
337 : TVariable<MaybeObject>* var_handler,
338 : Label* if_miss);
339 : };
340 :
341 : // Abstraction over direct and indirect exit points. Direct exits correspond to
342 : // tailcalls and Return, while indirect exits store the result in a variable
343 : // and then jump to an exit label.
344 2240 : class ExitPoint {
345 : private:
346 : using Node = compiler::Node;
347 : using CodeAssemblerLabel = compiler::CodeAssemblerLabel;
348 : using CodeAssemblerVariable = compiler::CodeAssemblerVariable;
349 :
350 : public:
351 : using IndirectReturnHandler = std::function<void(Node* result)>;
352 :
353 : explicit ExitPoint(CodeStubAssembler* assembler)
354 : : ExitPoint(assembler, nullptr) {}
355 :
356 : ExitPoint(CodeStubAssembler* assembler,
357 : const IndirectReturnHandler& indirect_return_handler)
358 2240 : : asm_(assembler), indirect_return_handler_(indirect_return_handler) {}
359 :
360 168 : ExitPoint(CodeStubAssembler* assembler, CodeAssemblerLabel* out,
361 : CodeAssemblerVariable* var_result)
362 3528 : : ExitPoint(assembler, [=](Node* result) {
363 3528 : var_result->Bind(result);
364 3528 : assembler->Goto(out);
365 3696 : }) {
366 : DCHECK_EQ(out != nullptr, var_result != nullptr);
367 168 : }
368 :
369 : template <class... TArgs>
370 7112 : void ReturnCallRuntime(Runtime::FunctionId function, Node* context,
371 : TArgs... args) {
372 7112 : if (IsDirect()) {
373 2464 : asm_->TailCallRuntime(function, context, args...);
374 : } else {
375 4648 : indirect_return_handler_(asm_->CallRuntime(function, context, args...));
376 : }
377 7112 : }
378 :
379 : template <class... TArgs>
380 3136 : void ReturnCallStub(Callable const& callable, Node* context, TArgs... args) {
381 3136 : if (IsDirect()) {
382 1288 : asm_->TailCallStub(callable, context, args...);
383 : } else {
384 3696 : indirect_return_handler_(asm_->CallStub(callable, context, args...));
385 : }
386 3136 : }
387 :
388 : template <class... TArgs>
389 1568 : void ReturnCallStub(const CallInterfaceDescriptor& descriptor, Node* target,
390 : Node* context, TArgs... args) {
391 1568 : if (IsDirect()) {
392 560 : asm_->TailCallStub(descriptor, target, context, args...);
393 : } else {
394 2016 : indirect_return_handler_(
395 : asm_->CallStub(descriptor, target, context, args...));
396 : }
397 1568 : }
398 :
399 19264 : void Return(Node* const result) {
400 19264 : if (IsDirect()) {
401 9408 : asm_->Return(result);
402 : } else {
403 : indirect_return_handler_(result);
404 : }
405 19264 : }
406 :
407 : bool IsDirect() const { return !indirect_return_handler_; }
408 :
409 : private:
410 : CodeStubAssembler* const asm_;
411 : IndirectReturnHandler indirect_return_handler_;
412 : };
413 :
414 : } // namespace internal
415 : } // namespace v8
416 :
417 : #endif // V8_IC_ACCESSOR_ASSEMBLER_H_
|