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