v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
builtins-handler-gen.cc
Go to the documentation of this file.
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
8#include "src/ic/ic.h"
11#include "torque-generated/exported-macros-assembler.h"
12
13namespace v8 {
14namespace internal {
15
17
19 public:
22
23 protected:
25
26 // Essentially turns runtime elements kinds (TNode<Int32T>) into
27 // compile-time types (int) by dispatching over the runtime type and
28 // emitting a specialized copy of the given case function for each elements
29 // kind. Use with caution. This produces a *lot* of code.
30 using ElementsKindSwitchCase = std::function<void(ElementsKind)>;
31 void DispatchByElementsKind(TNode<Int32T> elements_kind,
32 const ElementsKindSwitchCase& case_function,
33 bool handle_typed_elements_kind);
34
35 // Dispatches over all possible combinations of {from,to} elements kinds.
37 std::function<void(ElementsKind, ElementsKind)>;
39 TNode<Int32T> from_kind, TNode<Int32T> to_kind,
40 const ElementsKindTransitionSwitchCase& case_function);
41
44};
45
46TF_BUILTIN(LoadIC_StringLength, CodeStubAssembler) {
47 auto string = Parameter<String>(Descriptor::kReceiver);
48 Return(LoadStringLengthAsSmi(string));
49}
50
51TF_BUILTIN(LoadIC_StringWrapperLength, CodeStubAssembler) {
52 auto value = Parameter<JSPrimitiveWrapper>(Descriptor::kReceiver);
53 TNode<String> string = CAST(LoadJSPrimitiveWrapperValue(value));
54 Return(LoadStringLengthAsSmi(string));
55}
56
57void Builtins::Generate_KeyedStoreIC_Megamorphic(
58 compiler::CodeAssemblerState* state) {
60}
61
62void Builtins::Generate_DefineKeyedOwnIC_Megamorphic(
63 compiler::CodeAssemblerState* state) {
65}
66
67void Builtins::Generate_StoreIC_NoFeedback(
68 compiler::CodeAssemblerState* state) {
70}
71
72void Builtins::Generate_DefineNamedOwnIC_NoFeedback(
73 compiler::CodeAssemblerState* state) {
75}
76
77// All possible fast-to-fast transitions. Transitions to dictionary mode are not
78// handled by ElementsTransitionAndStore builtins.
79#define ELEMENTS_KIND_TRANSITIONS(V) \
80 V(PACKED_SMI_ELEMENTS, HOLEY_SMI_ELEMENTS) \
81 V(PACKED_SMI_ELEMENTS, PACKED_DOUBLE_ELEMENTS) \
82 V(PACKED_SMI_ELEMENTS, HOLEY_DOUBLE_ELEMENTS) \
83 V(PACKED_SMI_ELEMENTS, PACKED_ELEMENTS) \
84 V(PACKED_SMI_ELEMENTS, HOLEY_ELEMENTS) \
85 V(HOLEY_SMI_ELEMENTS, HOLEY_DOUBLE_ELEMENTS) \
86 V(HOLEY_SMI_ELEMENTS, HOLEY_ELEMENTS) \
87 V(PACKED_DOUBLE_ELEMENTS, HOLEY_DOUBLE_ELEMENTS) \
88 V(PACKED_DOUBLE_ELEMENTS, PACKED_ELEMENTS) \
89 V(PACKED_DOUBLE_ELEMENTS, HOLEY_ELEMENTS) \
90 V(HOLEY_DOUBLE_ELEMENTS, HOLEY_ELEMENTS) \
91 V(PACKED_ELEMENTS, HOLEY_ELEMENTS)
92
94 TNode<Int32T> from_kind, TNode<Int32T> to_kind,
95 const ElementsKindTransitionSwitchCase& case_function) {
96 static_assert(sizeof(ElementsKind) == sizeof(uint8_t));
97
98 Label next(this), if_unknown_type(this, Label::kDeferred);
99
100 int32_t combined_elements_kinds[] = {
101#define ELEMENTS_KINDS_CASE(FROM, TO) (FROM << kBitsPerByte) | TO,
103#undef ELEMENTS_KINDS_CASE
104 };
105
106#define ELEMENTS_KINDS_CASE(FROM, TO) Label if_##FROM##_##TO(this);
108#undef ELEMENTS_KINDS_CASE
109
110 Label* elements_kind_labels[] = {
111#define ELEMENTS_KINDS_CASE(FROM, TO) &if_##FROM##_##TO,
113#undef ELEMENTS_KINDS_CASE
114 };
115 static_assert(arraysize(combined_elements_kinds) ==
116 arraysize(elements_kind_labels));
117
118 TNode<Int32T> combined_elements_kind =
119 Word32Or(Word32Shl(from_kind, Int32Constant(kBitsPerByte)), to_kind);
120
121 Switch(combined_elements_kind, &if_unknown_type, combined_elements_kinds,
122 elements_kind_labels, arraysize(combined_elements_kinds));
123
124#define ELEMENTS_KINDS_CASE(FROM, TO) \
125 BIND(&if_##FROM##_##TO); \
126 { \
127 case_function(FROM, TO); \
128 Goto(&next); \
129 }
131#undef ELEMENTS_KINDS_CASE
132
133 BIND(&if_unknown_type);
134 Unreachable();
135
136 BIND(&next);
137}
138
139#undef ELEMENTS_KIND_TRANSITIONS
140
142 KeyedAccessStoreMode store_mode) {
144 auto receiver = Parameter<JSObject>(Descriptor::kReceiver);
145 auto key = Parameter<Object>(Descriptor::kName);
146 auto value = Parameter<Object>(Descriptor::kValue);
147 auto map = Parameter<Map>(Descriptor::kMap);
148 auto slot = Parameter<Smi>(Descriptor::kSlot);
149 auto vector = Parameter<FeedbackVector>(Descriptor::kVector);
150 auto context = Parameter<Context>(Descriptor::kContext);
151
152 Comment("ElementsTransitionAndStore: store_mode=", store_mode);
153
154 Label miss(this);
155
156 if (v8_flags.trace_elements_transitions) {
157 // Tracing elements transitions is the job of the runtime.
158 Goto(&miss);
159 } else {
160 // TODO(v8:8481): Pass from_kind and to_kind in feedback vector slots.
163 [=, this, &miss](ElementsKind from_kind, ElementsKind to_kind) {
164 TransitionElementsKind(receiver, map, from_kind, to_kind, &miss);
165 EmitElementStore(receiver, key, value, to_kind, store_mode, &miss,
166 context, nullptr);
167 });
168 Return(value);
169 }
170
171 BIND(&miss);
172 TailCallRuntime(Runtime::kElementsTransitionAndStoreIC_Miss, context,
173 receiver, key, value, map, slot, vector);
174}
175
176TF_BUILTIN(ElementsTransitionAndStore_InBounds, HandlerBuiltinsAssembler) {
177 Generate_ElementsTransitionAndStore(KeyedAccessStoreMode::kInBounds);
178}
179
180TF_BUILTIN(ElementsTransitionAndStore_NoTransitionGrowAndHandleCOW,
182 Generate_ElementsTransitionAndStore(KeyedAccessStoreMode::kGrowAndHandleCOW);
183}
184
185TF_BUILTIN(ElementsTransitionAndStore_NoTransitionIgnoreTypedArrayOOB,
187 Generate_ElementsTransitionAndStore(
189}
190
191TF_BUILTIN(ElementsTransitionAndStore_NoTransitionHandleCOW,
193 Generate_ElementsTransitionAndStore(KeyedAccessStoreMode::kHandleCOW);
194}
195
196// All elements kinds handled by EmitElementStore. Specifically, this includes
197// fast elements and fixed typed array elements.
198#define ELEMENTS_KINDS(V) \
199 V(PACKED_SMI_ELEMENTS) \
200 V(HOLEY_SMI_ELEMENTS) \
201 V(PACKED_ELEMENTS) \
202 V(PACKED_NONEXTENSIBLE_ELEMENTS) \
203 V(PACKED_SEALED_ELEMENTS) \
204 V(SHARED_ARRAY_ELEMENTS) \
205 V(HOLEY_ELEMENTS) \
206 V(HOLEY_NONEXTENSIBLE_ELEMENTS) \
207 V(HOLEY_SEALED_ELEMENTS) \
208 V(PACKED_DOUBLE_ELEMENTS) \
209 V(HOLEY_DOUBLE_ELEMENTS) \
210 V(UINT8_ELEMENTS) \
211 V(INT8_ELEMENTS) \
212 V(UINT16_ELEMENTS) \
213 V(INT16_ELEMENTS) \
214 V(UINT32_ELEMENTS) \
215 V(INT32_ELEMENTS) \
216 V(FLOAT16_ELEMENTS) \
217 V(FLOAT32_ELEMENTS) \
218 V(FLOAT64_ELEMENTS) \
219 V(UINT8_CLAMPED_ELEMENTS) \
220 V(BIGUINT64_ELEMENTS) \
221 V(BIGINT64_ELEMENTS) \
222 V(RAB_GSAB_UINT8_ELEMENTS) \
223 V(RAB_GSAB_INT8_ELEMENTS) \
224 V(RAB_GSAB_UINT16_ELEMENTS) \
225 V(RAB_GSAB_INT16_ELEMENTS) \
226 V(RAB_GSAB_UINT32_ELEMENTS) \
227 V(RAB_GSAB_INT32_ELEMENTS) \
228 V(RAB_GSAB_FLOAT16_ELEMENTS) \
229 V(RAB_GSAB_FLOAT32_ELEMENTS) \
230 V(RAB_GSAB_FLOAT64_ELEMENTS) \
231 V(RAB_GSAB_UINT8_CLAMPED_ELEMENTS) \
232 V(RAB_GSAB_BIGUINT64_ELEMENTS) \
233 V(RAB_GSAB_BIGINT64_ELEMENTS)
234
236 TNode<Int32T> elements_kind, const ElementsKindSwitchCase& case_function,
237 bool handle_typed_elements_kind) {
238 Label next(this), if_unknown_type(this, Label::kDeferred);
239
240 int32_t elements_kinds[] = {
241#define ELEMENTS_KINDS_CASE(KIND) KIND,
243#undef ELEMENTS_KINDS_CASE
244 };
245
246#define ELEMENTS_KINDS_CASE(KIND) Label if_##KIND(this);
248#undef ELEMENTS_KINDS_CASE
249
250 Label* elements_kind_labels[] = {
251#define ELEMENTS_KINDS_CASE(KIND) &if_##KIND,
253#undef ELEMENTS_KINDS_CASE
254 };
255 static_assert(arraysize(elements_kinds) == arraysize(elements_kind_labels));
256
257 // TODO(mythria): Do not emit cases for typed elements kind when
258 // handle_typed_elements is false to decrease the size of the jump table.
259 Switch(elements_kind, &if_unknown_type, elements_kinds, elements_kind_labels,
260 arraysize(elements_kinds));
261
262#define ELEMENTS_KINDS_CASE(KIND) \
263 BIND(&if_##KIND); \
264 { \
265 if (!handle_typed_elements_kind && \
266 IsTypedArrayOrRabGsabTypedArrayElementsKind(KIND)) { \
267 Unreachable(); \
268 } else { \
269 case_function(KIND); \
270 Goto(&next); \
271 } \
272 }
274#undef ELEMENTS_KINDS_CASE
275
276 BIND(&if_unknown_type);
277 Unreachable();
278
279 BIND(&next);
280}
281
282#undef ELEMENTS_KINDS
283
285 KeyedAccessStoreMode store_mode) {
287 auto receiver = Parameter<JSObject>(Descriptor::kReceiver);
288 auto key = Parameter<Object>(Descriptor::kName);
289 auto value = Parameter<Object>(Descriptor::kValue);
290 auto slot = Parameter<Smi>(Descriptor::kSlot);
291 auto vector = Parameter<HeapObject>(Descriptor::kVector);
292 auto context = Parameter<Context>(Descriptor::kContext);
293
294 Comment("StoreFastElementStub: store_mode=", store_mode);
295
296 Label miss(this);
297
298 // For typed arrays maybe_converted_value contains the value obtained after
299 // calling ToNumber. We should pass the converted value to the runtime to
300 // avoid doing the user visible conversion again.
301 TVARIABLE(Object, maybe_converted_value, value);
302 // TODO(v8:8481): Pass elements_kind in feedback vector slots.
305 [=, this, &miss, &maybe_converted_value](ElementsKind elements_kind) {
306 EmitElementStore(receiver, key, value, elements_kind, store_mode, &miss,
307 context, &maybe_converted_value);
308 },
309 StoreModeSupportsTypeArray(store_mode));
310 Return(value);
311
312 BIND(&miss);
313 TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context,
314 maybe_converted_value.value(), slot, vector, receiver, key);
315}
316
317TF_BUILTIN(StoreFastElementIC_InBounds, HandlerBuiltinsAssembler) {
318 Generate_StoreFastElementIC(KeyedAccessStoreMode::kInBounds);
319}
320
321TF_BUILTIN(StoreFastElementIC_NoTransitionGrowAndHandleCOW,
323 Generate_StoreFastElementIC(KeyedAccessStoreMode::kGrowAndHandleCOW);
324}
325
326TF_BUILTIN(StoreFastElementIC_NoTransitionIgnoreTypedArrayOOB,
328 Generate_StoreFastElementIC(KeyedAccessStoreMode::kIgnoreTypedArrayOOB);
329}
330
331TF_BUILTIN(StoreFastElementIC_NoTransitionHandleCOW, HandlerBuiltinsAssembler) {
332 Generate_StoreFastElementIC(KeyedAccessStoreMode::kHandleCOW);
333}
334
335TF_BUILTIN(LoadIC_FunctionPrototype, CodeStubAssembler) {
336 auto receiver = Parameter<JSFunction>(Descriptor::kReceiver);
337 auto name = Parameter<Name>(Descriptor::kName);
338 auto slot = Parameter<Smi>(Descriptor::kSlot);
339 auto vector = Parameter<FeedbackVector>(Descriptor::kVector);
340 auto context = Parameter<Context>(Descriptor::kContext);
341
342 Label miss(this, Label::kDeferred);
343 Return(LoadJSFunctionPrototype(receiver, &miss));
344
345 BIND(&miss);
346 TailCallRuntime(Runtime::kLoadIC_Miss, context, receiver, name, slot, vector);
347}
348
349TF_BUILTIN(StoreGlobalIC_Slow, CodeStubAssembler) {
350 auto receiver = Parameter<Object>(Descriptor::kReceiver);
351 auto name = Parameter<Name>(Descriptor::kName);
352 auto value = Parameter<Object>(Descriptor::kValue);
353 auto slot = Parameter<Smi>(Descriptor::kSlot);
354 auto vector = Parameter<FeedbackVector>(Descriptor::kVector);
355 auto context = Parameter<Context>(Descriptor::kContext);
356
357 // The slow case calls into the runtime to complete the store without causing
358 // an IC miss that would otherwise cause a transition to the generic stub.
359 TailCallRuntime(Runtime::kStoreGlobalIC_Slow, context, value, slot, vector,
360 receiver, name);
361}
362
363TF_BUILTIN(KeyedLoadIC_SloppyArguments, HandlerBuiltinsAssembler) {
364 auto receiver = Parameter<JSObject>(Descriptor::kReceiver);
365 auto key = Parameter<Object>(Descriptor::kName);
366 auto slot = Parameter<Smi>(Descriptor::kSlot);
367 auto vector = Parameter<HeapObject>(Descriptor::kVector);
368 auto context = Parameter<Context>(Descriptor::kContext);
369
370 Label miss(this);
371
372 TNode<Object> result = SloppyArgumentsLoad(receiver, key, &miss);
373 Return(result);
374
375 BIND(&miss);
376 {
377 Comment("Miss");
378 TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, slot,
379 vector);
380 }
381}
382
385 auto receiver = Parameter<JSObject>(Descriptor::kReceiver);
386 auto key = Parameter<Object>(Descriptor::kName);
387 auto value = Parameter<JSAny>(Descriptor::kValue);
388 auto slot = Parameter<Smi>(Descriptor::kSlot);
389 auto vector = Parameter<HeapObject>(Descriptor::kVector);
390 auto context = Parameter<Context>(Descriptor::kContext);
391
392 Label miss(this);
393
394 SloppyArgumentsStore(receiver, key, value, &miss);
395 Return(value);
396
397 BIND(&miss);
398 TailCallRuntime(Runtime::kKeyedStoreIC_Miss, context, value, slot, vector,
399 receiver, key);
400}
401
402TF_BUILTIN(KeyedStoreIC_SloppyArguments_InBounds, HandlerBuiltinsAssembler) {
403 Generate_KeyedStoreIC_SloppyArguments();
404}
405
406TF_BUILTIN(KeyedStoreIC_SloppyArguments_NoTransitionGrowAndHandleCOW,
408 Generate_KeyedStoreIC_SloppyArguments();
409}
410
411TF_BUILTIN(KeyedStoreIC_SloppyArguments_NoTransitionIgnoreTypedArrayOOB,
413 Generate_KeyedStoreIC_SloppyArguments();
414}
415
416TF_BUILTIN(KeyedStoreIC_SloppyArguments_NoTransitionHandleCOW,
418 Generate_KeyedStoreIC_SloppyArguments();
419}
420
421TF_BUILTIN(LoadIndexedInterceptorIC, CodeStubAssembler) {
422 auto receiver = Parameter<JSObject>(Descriptor::kReceiver);
423 auto key = Parameter<Object>(Descriptor::kName);
424 auto slot = Parameter<Smi>(Descriptor::kSlot);
425 auto vector = Parameter<HeapObject>(Descriptor::kVector);
426 auto context = Parameter<Context>(Descriptor::kContext);
427
428 Label if_keyispositivesmi(this), if_keyisinvalid(this);
429 Branch(TaggedIsPositiveSmi(key), &if_keyispositivesmi, &if_keyisinvalid);
430 BIND(&if_keyispositivesmi);
431 TailCallRuntime(Runtime::kLoadElementWithInterceptor, context, receiver, key);
432
433 BIND(&if_keyisinvalid);
434 TailCallRuntime(Runtime::kKeyedLoadIC_Miss, context, receiver, key, slot,
435 vector);
436}
437
438TF_BUILTIN(KeyedHasIC_SloppyArguments, HandlerBuiltinsAssembler) {
439 auto receiver = Parameter<JSObject>(Descriptor::kReceiver);
440 auto key = Parameter<Object>(Descriptor::kName);
441 auto slot = Parameter<Smi>(Descriptor::kSlot);
442 auto vector = Parameter<HeapObject>(Descriptor::kVector);
443 auto context = Parameter<Context>(Descriptor::kContext);
444
445 Label miss(this);
446
447 TNode<Object> result = SloppyArgumentsHas(receiver, key, &miss);
448 Return(result);
449
450 BIND(&miss);
451 {
452 Comment("Miss");
453 TailCallRuntime(Runtime::kKeyedHasIC_Miss, context, receiver, key, slot,
454 vector);
455 }
456}
457
458TF_BUILTIN(HasIndexedInterceptorIC, CodeStubAssembler) {
459 auto receiver = Parameter<JSObject>(Descriptor::kReceiver);
460 auto key = Parameter<Object>(Descriptor::kName);
461 auto slot = Parameter<Smi>(Descriptor::kSlot);
462 auto vector = Parameter<HeapObject>(Descriptor::kVector);
463 auto context = Parameter<Context>(Descriptor::kContext);
464
465 Label if_keyispositivesmi(this), if_keyisinvalid(this);
466 Branch(TaggedIsPositiveSmi(key), &if_keyispositivesmi, &if_keyisinvalid);
467 BIND(&if_keyispositivesmi);
468 TailCallRuntime(Runtime::kHasElementWithInterceptor, context, receiver, key);
469
470 BIND(&if_keyisinvalid);
471 TailCallRuntime(Runtime::kKeyedHasIC_Miss, context, receiver, key, slot,
472 vector);
473}
474
476
477} // namespace internal
478} // namespace v8
#define BIND(label)
#define TVARIABLE(...)
#define ELEMENTS_KINDS(V)
#define ELEMENTS_KINDS_CASE(FROM, TO)
#define ELEMENTS_KIND_TRANSITIONS(V)
#define TF_BUILTIN(Name, AssemblerBase)
void TransitionElementsKind(TNode< JSObject > object, TNode< Map > map, ElementsKind from_kind, ElementsKind to_kind, Label *bailout)
void EmitElementStore(TNode< JSObject > object, TNode< Object > key, TNode< Object > value, ElementsKind elements_kind, KeyedAccessStoreMode store_mode, Label *bailout, TNode< Context > context, TVariable< Object > *maybe_converted_value=nullptr)
TNode< Int32T > LoadElementsKind(TNode< HeapObject > object)
TNode< Int32T > LoadMapElementsKind(TNode< Map > map)
static void Generate(compiler::CodeAssemblerState *state)
static void Generate(compiler::CodeAssemblerState *state)
void DispatchByElementsKind(TNode< Int32T > elements_kind, const ElementsKindSwitchCase &case_function, bool handle_typed_elements_kind)
std::function< void(ElementsKind, ElementsKind)> ElementsKindTransitionSwitchCase
void Generate_StoreFastElementIC(KeyedAccessStoreMode store_mode)
std::function< void(ElementsKind)> ElementsKindSwitchCase
void Generate_ElementsTransitionAndStore(KeyedAccessStoreMode store_mode)
HandlerBuiltinsAssembler(compiler::CodeAssemblerState *state)
void DispatchForElementsKindTransition(TNode< Int32T > from_kind, TNode< Int32T > to_kind, const ElementsKindTransitionSwitchCase &case_function)
static void Generate(compiler::CodeAssemblerState *state)
static void Generate(compiler::CodeAssemblerState *state)
void Comment(MessageWithSourceLocation message, Args &&... args)
void Return(TNode< Object > value)
void TailCallRuntime(Runtime::FunctionId function, TNode< Object > context, TArgs... args)
TNode< Int32T > Word32Or(TNode< Int32T > left, TNode< Int32T > right)
TNode< Int32T > Word32Shl(TNode< Int32T > left, TNode< Int32T > right)
void Switch(Node *index, Label *default_label, const int32_t *case_values, Label **case_labels, size_t case_count)
TNode< Int32T > Int32Constant(int32_t value)
TNode< T > Parameter(int value, const SourceLocation &loc=SourceLocation::Current())
#define CAST(x)
TNode< Object > receiver
ZoneVector< RpoNumber > & result
constexpr int kBitsPerByte
Definition globals.h:682
V8_EXPORT_PRIVATE FlagValues v8_flags
bool StoreModeSupportsTypeArray(KeyedAccessStoreMode store_mode)
Definition globals.h:2733
#define arraysize(array)
Definition macros.h:67