V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Pages
builtins-handler-gen.cc
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 #include "src/builtins/builtins-utils-gen.h"
6 #include "src/builtins/builtins.h"
7 #include "src/code-stub-assembler.h"
8 #include "src/ic/ic.h"
9 #include "src/ic/keyed-store-generic.h"
10 #include "src/objects-inl.h"
11 
12 namespace v8 {
13 namespace internal {
14 
16  public:
18  : CodeStubAssembler(state) {}
19 
20  protected:
21  void Generate_KeyedStoreIC_SloppyArguments();
22  void Generate_KeyedStoreIC_Slow();
23  void Generate_StoreInArrayLiteralIC_Slow();
24 
25  // Essentially turns runtime elements kinds (TNode<Int32T>) into
26  // compile-time types (int) by dispatching over the runtime type and
27  // emitting a specialized copy of the given case function for each elements
28  // kind. Use with caution. This produces a *lot* of code.
29  typedef std::function<void(ElementsKind)> ElementsKindSwitchCase;
30  void DispatchByElementsKind(TNode<Int32T> elements_kind,
31  const ElementsKindSwitchCase& case_function);
32 
33  // Dispatches over all possible combinations of {from,to} elements kinds.
34  typedef std::function<void(ElementsKind, ElementsKind)>
35  ElementsKindTransitionSwitchCase;
36  void DispatchForElementsKindTransition(
37  TNode<Int32T> from_kind, TNode<Int32T> to_kind,
38  const ElementsKindTransitionSwitchCase& case_function);
39 
40  void Generate_ElementsTransitionAndStore(KeyedAccessStoreMode store_mode);
41  void Generate_StoreFastElementIC(KeyedAccessStoreMode store_mode);
42 };
43 
44 TF_BUILTIN(LoadIC_StringLength, CodeStubAssembler) {
45  Node* string = Parameter(Descriptor::kReceiver);
46  Return(LoadStringLengthAsSmi(string));
47 }
48 
49 TF_BUILTIN(LoadIC_StringWrapperLength, CodeStubAssembler) {
50  Node* value = Parameter(Descriptor::kReceiver);
51  Node* string = LoadJSValueValue(value);
52  Return(LoadStringLengthAsSmi(string));
53 }
54 
55 TF_BUILTIN(KeyedLoadIC_Slow, CodeStubAssembler) {
56  Node* receiver = Parameter(Descriptor::kReceiver);
57  Node* name = Parameter(Descriptor::kName);
58  Node* context = Parameter(Descriptor::kContext);
59 
60  TailCallRuntime(Runtime::kGetProperty, context, receiver, name);
61 }
62 
63 void Builtins::Generate_KeyedStoreIC_Megamorphic(
64  compiler::CodeAssemblerState* state) {
65  KeyedStoreGenericGenerator::Generate(state);
66 }
67 
68 void Builtins::Generate_StoreIC_Uninitialized(
69  compiler::CodeAssemblerState* state) {
70  StoreICUninitializedGenerator::Generate(state);
71 }
72 
73 void HandlerBuiltinsAssembler::Generate_KeyedStoreIC_Slow() {
74  typedef StoreWithVectorDescriptor Descriptor;
75  Node* receiver = Parameter(Descriptor::kReceiver);
76  Node* name = Parameter(Descriptor::kName);
77  Node* value = Parameter(Descriptor::kValue);
78  Node* slot = Parameter(Descriptor::kSlot);
79  Node* vector = Parameter(Descriptor::kVector);
80  Node* context = Parameter(Descriptor::kContext);
81 
82  // The slow case calls into the runtime to complete the store without causing
83  // an IC miss that would otherwise cause a transition to the generic stub.
84  TailCallRuntime(Runtime::kKeyedStoreIC_Slow, context, value, slot, vector,
85  receiver, name);
86 }
87 
88 TF_BUILTIN(KeyedStoreIC_Slow, HandlerBuiltinsAssembler) {
89  Generate_KeyedStoreIC_Slow();
90 }
91 
92 TF_BUILTIN(KeyedStoreIC_Slow_Standard, HandlerBuiltinsAssembler) {
93  Generate_KeyedStoreIC_Slow();
94 }
95 
96 TF_BUILTIN(KeyedStoreIC_Slow_GrowNoTransitionHandleCOW,
97  HandlerBuiltinsAssembler) {
98  Generate_KeyedStoreIC_Slow();
99 }
100 
101 TF_BUILTIN(KeyedStoreIC_Slow_NoTransitionIgnoreOOB, HandlerBuiltinsAssembler) {
102  Generate_KeyedStoreIC_Slow();
103 }
104 
105 TF_BUILTIN(KeyedStoreIC_Slow_NoTransitionHandleCOW, HandlerBuiltinsAssembler) {
106  Generate_KeyedStoreIC_Slow();
107 }
108 
109 void HandlerBuiltinsAssembler::Generate_StoreInArrayLiteralIC_Slow() {
110  typedef StoreWithVectorDescriptor Descriptor;
111  Node* array = Parameter(Descriptor::kReceiver);
112  Node* index = Parameter(Descriptor::kName);
113  Node* value = Parameter(Descriptor::kValue);
114  Node* context = Parameter(Descriptor::kContext);
115  TailCallRuntime(Runtime::kStoreInArrayLiteralIC_Slow, context, value, array,
116  index);
117 }
118 
119 TF_BUILTIN(StoreInArrayLiteralIC_Slow, HandlerBuiltinsAssembler) {
120  Generate_StoreInArrayLiteralIC_Slow();
121 }
122 
123 TF_BUILTIN(StoreInArrayLiteralIC_Slow_Standard, HandlerBuiltinsAssembler) {
124  Generate_StoreInArrayLiteralIC_Slow();
125 }
126 
127 TF_BUILTIN(StoreInArrayLiteralIC_Slow_GrowNoTransitionHandleCOW,
128  HandlerBuiltinsAssembler) {
129  Generate_StoreInArrayLiteralIC_Slow();
130 }
131 
132 TF_BUILTIN(StoreInArrayLiteralIC_Slow_NoTransitionIgnoreOOB,
133  HandlerBuiltinsAssembler) {
134  Generate_StoreInArrayLiteralIC_Slow();
135 }
136 
137 TF_BUILTIN(StoreInArrayLiteralIC_Slow_NoTransitionHandleCOW,
138  HandlerBuiltinsAssembler) {
139  Generate_StoreInArrayLiteralIC_Slow();
140 }
141 
142 // All possible fast-to-fast transitions. Transitions to dictionary mode are not
143 // handled by ElementsTransitionAndStore.
144 #define ELEMENTS_KIND_TRANSITIONS(V) \
145  V(PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS) \
146  V(PACKED_SMI_ELEMENTS, PACKED_DOUBLE_ELEMENTS) \
147  V(PACKED_SMI_ELEMENTS, HOLEY_DOUBLE_ELEMENTS) \
148  V(PACKED_SMI_ELEMENTS, PACKED_ELEMENTS) \
149  V(PACKED_SMI_ELEMENTS, HOLEY_ELEMENTS) \
150  V(HOLEY_SMI_ELEMENTS, HOLEY_DOUBLE_ELEMENTS) \
151  V(HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS) \
152  V(PACKED_DOUBLE_ELEMENTS, HOLEY_DOUBLE_ELEMENTS) \
153  V(PACKED_DOUBLE_ELEMENTS, PACKED_ELEMENTS) \
154  V(PACKED_DOUBLE_ELEMENTS, HOLEY_ELEMENTS) \
155  V(HOLEY_DOUBLE_ELEMENTS, HOLEY_ELEMENTS) \
156  V(PACKED_ELEMENTS, HOLEY_ELEMENTS)
157 
158 void HandlerBuiltinsAssembler::DispatchForElementsKindTransition(
159  TNode<Int32T> from_kind, TNode<Int32T> to_kind,
160  const ElementsKindTransitionSwitchCase& case_function) {
161  STATIC_ASSERT(sizeof(ElementsKind) == sizeof(uint8_t));
162 
163  Label next(this), if_unknown_type(this, Label::kDeferred);
164 
165  int32_t combined_elements_kinds[] = {
166 #define ELEMENTS_KINDS_CASE(FROM, TO) (FROM << kBitsPerByte) | TO,
167  ELEMENTS_KIND_TRANSITIONS(ELEMENTS_KINDS_CASE)
168 #undef ELEMENTS_KINDS_CASE
169  };
170 
171 #define ELEMENTS_KINDS_CASE(FROM, TO) Label if_##FROM##_##TO(this);
172  ELEMENTS_KIND_TRANSITIONS(ELEMENTS_KINDS_CASE)
173 #undef ELEMENTS_KINDS_CASE
174 
175  Label* elements_kind_labels[] = {
176 #define ELEMENTS_KINDS_CASE(FROM, TO) &if_##FROM##_##TO,
177  ELEMENTS_KIND_TRANSITIONS(ELEMENTS_KINDS_CASE)
178 #undef ELEMENTS_KINDS_CASE
179  };
180  STATIC_ASSERT(arraysize(combined_elements_kinds) ==
181  arraysize(elements_kind_labels));
182 
183  TNode<Word32T> combined_elements_kind =
184  Word32Or(Word32Shl(from_kind, Int32Constant(kBitsPerByte)), to_kind);
185 
186  Switch(combined_elements_kind, &if_unknown_type, combined_elements_kinds,
187  elements_kind_labels, arraysize(combined_elements_kinds));
188 
189 #define ELEMENTS_KINDS_CASE(FROM, TO) \
190  BIND(&if_##FROM##_##TO); \
191  { \
192  case_function(FROM, TO); \
193  Goto(&next); \
194  }
195  ELEMENTS_KIND_TRANSITIONS(ELEMENTS_KINDS_CASE)
196 #undef ELEMENTS_KINDS_CASE
197 
198  BIND(&if_unknown_type);
199  Unreachable();
200 
201  BIND(&next);
202 }
203 
204 #undef ELEMENTS_KIND_TRANSITIONS
205 
206 void HandlerBuiltinsAssembler::Generate_ElementsTransitionAndStore(
207  KeyedAccessStoreMode store_mode) {
208  typedef StoreTransitionDescriptor Descriptor;
209  Node* receiver = Parameter(Descriptor::kReceiver);
210  Node* key = Parameter(Descriptor::kName);
211  Node* value = Parameter(Descriptor::kValue);
212  Node* map = Parameter(Descriptor::kMap);
213  Node* slot = Parameter(Descriptor::kSlot);
214  Node* vector = Parameter(Descriptor::kVector);
215  Node* context = Parameter(Descriptor::kContext);
216 
217  Comment("ElementsTransitionAndStore: store_mode=%d", store_mode);
218 
219  Label miss(this);
220 
221  if (FLAG_trace_elements_transitions) {
222  // Tracing elements transitions is the job of the runtime.
223  Goto(&miss);
224  } else {
225  // TODO(v8:8481): Pass from_kind and to_kind in feedback vector slots.
226  DispatchForElementsKindTransition(
227  LoadElementsKind(receiver), LoadMapElementsKind(map),
228  [=, &miss](ElementsKind from_kind, ElementsKind to_kind) {
229  TransitionElementsKind(receiver, map, from_kind, to_kind, &miss);
230  EmitElementStore(receiver, key, value, to_kind, store_mode, &miss,
231  context);
232  });
233  Return(value);
234  }
235 
236  BIND(&miss);
237  TailCallRuntime(Runtime::kElementsTransitionAndStoreIC_Miss, context,
238  receiver, key, value, map, slot, vector);
239 }
240 
241 TF_BUILTIN(ElementsTransitionAndStore_Standard, HandlerBuiltinsAssembler) {
242  Generate_ElementsTransitionAndStore(STANDARD_STORE);
243 }
244 
245 TF_BUILTIN(ElementsTransitionAndStore_GrowNoTransitionHandleCOW,
246  HandlerBuiltinsAssembler) {
247  Generate_ElementsTransitionAndStore(STORE_AND_GROW_NO_TRANSITION_HANDLE_COW);
248 }
249 
250 TF_BUILTIN(ElementsTransitionAndStore_NoTransitionIgnoreOOB,
251  HandlerBuiltinsAssembler) {
252  Generate_ElementsTransitionAndStore(STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS);
253 }
254 
255 TF_BUILTIN(ElementsTransitionAndStore_NoTransitionHandleCOW,
256  HandlerBuiltinsAssembler) {
257  Generate_ElementsTransitionAndStore(STORE_NO_TRANSITION_HANDLE_COW);
258 }
259 
260 // All elements kinds handled by EmitElementStore. Specifically, this includes
261 // fast elements and fixed typed array elements.
262 #define ELEMENTS_KINDS(V) \
263  V(PACKED_SMI_ELEMENTS) \
264  V(HOLEY_SMI_ELEMENTS) \
265  V(PACKED_ELEMENTS) \
266  V(HOLEY_ELEMENTS) \
267  V(PACKED_DOUBLE_ELEMENTS) \
268  V(HOLEY_DOUBLE_ELEMENTS) \
269  V(UINT8_ELEMENTS) \
270  V(INT8_ELEMENTS) \
271  V(UINT16_ELEMENTS) \
272  V(INT16_ELEMENTS) \
273  V(UINT32_ELEMENTS) \
274  V(INT32_ELEMENTS) \
275  V(FLOAT32_ELEMENTS) \
276  V(FLOAT64_ELEMENTS) \
277  V(UINT8_CLAMPED_ELEMENTS) \
278  V(BIGUINT64_ELEMENTS) \
279  V(BIGINT64_ELEMENTS)
280 
281 void HandlerBuiltinsAssembler::DispatchByElementsKind(
282  TNode<Int32T> elements_kind, const ElementsKindSwitchCase& case_function) {
283  Label next(this), if_unknown_type(this, Label::kDeferred);
284 
285  int32_t elements_kinds[] = {
286 #define ELEMENTS_KINDS_CASE(KIND) KIND,
287  ELEMENTS_KINDS(ELEMENTS_KINDS_CASE)
288 #undef ELEMENTS_KINDS_CASE
289  };
290 
291 #define ELEMENTS_KINDS_CASE(KIND) Label if_##KIND(this);
292  ELEMENTS_KINDS(ELEMENTS_KINDS_CASE)
293 #undef ELEMENTS_KINDS_CASE
294 
295  Label* elements_kind_labels[] = {
296 #define ELEMENTS_KINDS_CASE(KIND) &if_##KIND,
297  ELEMENTS_KINDS(ELEMENTS_KINDS_CASE)
298 #undef ELEMENTS_KINDS_CASE
299  };
300  STATIC_ASSERT(arraysize(elements_kinds) == arraysize(elements_kind_labels));
301 
302  Switch(elements_kind, &if_unknown_type, elements_kinds, elements_kind_labels,
303  arraysize(elements_kinds));
304 
305 #define ELEMENTS_KINDS_CASE(KIND) \
306  BIND(&if_##KIND); \
307  { \
308  case_function(KIND); \
309  Goto(&next); \
310  }
311  ELEMENTS_KINDS(ELEMENTS_KINDS_CASE)
312 #undef ELEMENTS_KINDS_CASE
313 
314  BIND(&if_unknown_type);
315  Unreachable();
316 
317  BIND(&next);
318 }
319 
320 #undef ELEMENTS_KINDS
321 
322 void HandlerBuiltinsAssembler::Generate_StoreFastElementIC(
323  KeyedAccessStoreMode store_mode) {
324  typedef StoreWithVectorDescriptor Descriptor;
325  Node* receiver = Parameter(Descriptor::kReceiver);
326  Node* key = Parameter(Descriptor::kName);
327  Node* value = Parameter(Descriptor::kValue);
328  Node* slot = Parameter(Descriptor::kSlot);
329  Node* vector = Parameter(Descriptor::kVector);
330  Node* context = Parameter(Descriptor::kContext);
331 
332  Comment("StoreFastElementStub: store_mode=%d", store_mode);
333 
334  Label miss(this);
335 
336  // TODO(v8:8481): Pass elements_kind in feedback vector slots.
337  DispatchByElementsKind(LoadElementsKind(receiver),
338  [=, &miss](ElementsKind elements_kind) {
339  EmitElementStore(receiver, key, value, elements_kind,
340  store_mode, &miss, context);
341  });
342  Return(value);
343 
344  BIND(&miss);
345  TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
346  receiver, key);
347 }
348 
349 TF_BUILTIN(StoreFastElementIC_Standard, HandlerBuiltinsAssembler) {
350  Generate_StoreFastElementIC(STANDARD_STORE);
351 }
352 
353 TF_BUILTIN(StoreFastElementIC_GrowNoTransitionHandleCOW,
354  HandlerBuiltinsAssembler) {
355  Generate_StoreFastElementIC(STORE_AND_GROW_NO_TRANSITION_HANDLE_COW);
356 }
357 
358 TF_BUILTIN(StoreFastElementIC_NoTransitionIgnoreOOB, HandlerBuiltinsAssembler) {
359  Generate_StoreFastElementIC(STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS);
360 }
361 
362 TF_BUILTIN(StoreFastElementIC_NoTransitionHandleCOW, HandlerBuiltinsAssembler) {
363  Generate_StoreFastElementIC(STORE_NO_TRANSITION_HANDLE_COW);
364 }
365 
366 TF_BUILTIN(LoadGlobalIC_Slow, CodeStubAssembler) {
367  Node* name = Parameter(Descriptor::kName);
368  Node* slot = Parameter(Descriptor::kSlot);
369  Node* vector = Parameter(Descriptor::kVector);
370  Node* context = Parameter(Descriptor::kContext);
371 
372  TailCallRuntime(Runtime::kLoadGlobalIC_Slow, context, name, slot, vector);
373 }
374 
375 TF_BUILTIN(LoadIC_FunctionPrototype, CodeStubAssembler) {
376  Node* receiver = Parameter(Descriptor::kReceiver);
377  Node* name = Parameter(Descriptor::kName);
378  Node* slot = Parameter(Descriptor::kSlot);
379  Node* vector = Parameter(Descriptor::kVector);
380  Node* context = Parameter(Descriptor::kContext);
381 
382  Label miss(this, Label::kDeferred);
383  Return(LoadJSFunctionPrototype(receiver, &miss));
384 
385  BIND(&miss);
386  TailCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name, slot, vector);
387 }
388 
389 TF_BUILTIN(LoadIC_Slow, CodeStubAssembler) {
390  Node* receiver = Parameter(Descriptor::kReceiver);
391  Node* name = Parameter(Descriptor::kName);
392  Node* context = Parameter(Descriptor::kContext);
393 
394  TailCallRuntime(Runtime::kGetProperty, context, receiver, name);
395 }
396 
397 TF_BUILTIN(StoreGlobalIC_Slow, CodeStubAssembler) {
398  Node* receiver = Parameter(Descriptor::kReceiver);
399  Node* name = Parameter(Descriptor::kName);
400  Node* value = Parameter(Descriptor::kValue);
401  Node* slot = Parameter(Descriptor::kSlot);
402  Node* vector = Parameter(Descriptor::kVector);
403  Node* context = Parameter(Descriptor::kContext);
404 
405  // The slow case calls into the runtime to complete the store without causing
406  // an IC miss that would otherwise cause a transition to the generic stub.
407  TailCallRuntime(Runtime::kStoreGlobalIC_Slow, context, value, slot, vector,
408  receiver, name);
409 }
410 
411 TF_BUILTIN(KeyedLoadIC_SloppyArguments, CodeStubAssembler) {
412  Node* receiver = Parameter(Descriptor::kReceiver);
413  Node* key = Parameter(Descriptor::kName);
414  Node* slot = Parameter(Descriptor::kSlot);
415  Node* vector = Parameter(Descriptor::kVector);
416  Node* context = Parameter(Descriptor::kContext);
417 
418  Label miss(this);
419 
420  Node* result = LoadKeyedSloppyArguments(receiver, key, &miss);
421  Return(result);
422 
423  BIND(&miss);
424  {
425  Comment("Miss");
426  TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, slot,
427  vector);
428  }
429 }
430 
431 void HandlerBuiltinsAssembler::Generate_KeyedStoreIC_SloppyArguments() {
432  typedef StoreWithVectorDescriptor Descriptor;
433  Node* receiver = Parameter(Descriptor::kReceiver);
434  Node* key = Parameter(Descriptor::kName);
435  Node* value = Parameter(Descriptor::kValue);
436  Node* slot = Parameter(Descriptor::kSlot);
437  Node* vector = Parameter(Descriptor::kVector);
438  Node* context = Parameter(Descriptor::kContext);
439 
440  Label miss(this);
441 
442  StoreKeyedSloppyArguments(receiver, key, value, &miss);
443  Return(value);
444 
445  BIND(&miss);
446  TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
447  receiver, key);
448 }
449 
450 TF_BUILTIN(KeyedStoreIC_SloppyArguments_Standard, HandlerBuiltinsAssembler) {
451  Generate_KeyedStoreIC_SloppyArguments();
452 }
453 
454 TF_BUILTIN(KeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW,
455  HandlerBuiltinsAssembler) {
456  Generate_KeyedStoreIC_SloppyArguments();
457 }
458 
459 TF_BUILTIN(KeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB,
460  HandlerBuiltinsAssembler) {
461  Generate_KeyedStoreIC_SloppyArguments();
462 }
463 
464 TF_BUILTIN(KeyedStoreIC_SloppyArguments_NoTransitionHandleCOW,
465  HandlerBuiltinsAssembler) {
466  Generate_KeyedStoreIC_SloppyArguments();
467 }
468 
469 TF_BUILTIN(StoreInterceptorIC, CodeStubAssembler) {
470  Node* receiver = Parameter(Descriptor::kReceiver);
471  Node* name = Parameter(Descriptor::kName);
472  Node* value = Parameter(Descriptor::kValue);
473  Node* slot = Parameter(Descriptor::kSlot);
474  Node* vector = Parameter(Descriptor::kVector);
475  Node* context = Parameter(Descriptor::kContext);
476  TailCallRuntime(Runtime::kStorePropertyWithInterceptor, context, value, slot,
477  vector, receiver, name);
478 }
479 
480 TF_BUILTIN(LoadIndexedInterceptorIC, CodeStubAssembler) {
481  Node* receiver = Parameter(Descriptor::kReceiver);
482  Node* key = Parameter(Descriptor::kName);
483  Node* slot = Parameter(Descriptor::kSlot);
484  Node* vector = Parameter(Descriptor::kVector);
485  Node* context = Parameter(Descriptor::kContext);
486 
487  Label if_keyispositivesmi(this), if_keyisinvalid(this);
488  Branch(TaggedIsPositiveSmi(key), &if_keyispositivesmi, &if_keyisinvalid);
489  BIND(&if_keyispositivesmi);
490  TailCallRuntime(Runtime::kLoadElementWithInterceptor, context, receiver, key);
491 
492  BIND(&if_keyisinvalid);
493  TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, slot,
494  vector);
495 }
496 
497 } // namespace internal
498 } // namespace v8
Definition: libplatform.h:13