1// Copyright 2014 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/code-factory.h"
6
7#include "src/bootstrapper.h"
8#include "src/builtins/builtins-descriptors.h"
9#include "src/ic/ic.h"
10#include "src/objects-inl.h"
11#include "src/objects/allocation-site-inl.h"
12
13namespace v8 {
14namespace internal {
15
16// static
17Handle<Code> CodeFactory::RuntimeCEntry(Isolate* isolate, int result_size) {
18 return CodeFactory::CEntry(isolate, result_size);
19}
20
21#define CENTRY_CODE(RS, SD, AM, BE) \
22 BUILTIN_CODE(isolate, CEntry_##RS##_##SD##_##AM##_##BE)
23
24// static
25Handle<Code> CodeFactory::CEntry(Isolate* isolate, int result_size,
26 SaveFPRegsMode save_doubles,
27 ArgvMode argv_mode, bool builtin_exit_frame) {
28 // Aliases for readability below.
29 const int rs = result_size;
30 const SaveFPRegsMode sd = save_doubles;
31 const ArgvMode am = argv_mode;
32 const bool be = builtin_exit_frame;
33
34 if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvOnStack && !be) {
35 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit);
36 } else if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvOnStack && be) {
37 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, BuiltinExit);
38 } else if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvInRegister && !be) {
39 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit);
40 } else if (rs == 1 && sd == kSaveFPRegs && am == kArgvOnStack && !be) {
41 return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, NoBuiltinExit);
42 } else if (rs == 1 && sd == kSaveFPRegs && am == kArgvOnStack && be) {
43 return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, BuiltinExit);
44 } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvOnStack && !be) {
45 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit);
46 } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvOnStack && be) {
47 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, BuiltinExit);
48 } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvInRegister && !be) {
49 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit);
50 } else if (rs == 2 && sd == kSaveFPRegs && am == kArgvOnStack && !be) {
51 return CENTRY_CODE(Return2, SaveFPRegs, ArgvOnStack, NoBuiltinExit);
52 } else if (rs == 2 && sd == kSaveFPRegs && am == kArgvOnStack && be) {
53 return CENTRY_CODE(Return2, SaveFPRegs, ArgvOnStack, BuiltinExit);
54 }
55
56 UNREACHABLE();
57}
58
59#undef CENTRY_CODE
60
61// static
62Callable CodeFactory::ApiGetter(Isolate* isolate) {
63 return Builtins::CallableFor(isolate, Builtins::kCallApiGetter);
64}
65
66// static
67Callable CodeFactory::CallApiCallback(Isolate* isolate) {
68 return Builtins::CallableFor(isolate, Builtins::kCallApiCallback);
69}
70
71// static
72Callable CodeFactory::LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode) {
73 return typeof_mode == NOT_INSIDE_TYPEOF
74 ? Builtins::CallableFor(isolate, Builtins::kLoadGlobalICTrampoline)
75 : Builtins::CallableFor(
76 isolate, Builtins::kLoadGlobalICInsideTypeofTrampoline);
77}
78
79// static
80Callable CodeFactory::LoadGlobalICInOptimizedCode(Isolate* isolate,
81 TypeofMode typeof_mode) {
82 return typeof_mode == NOT_INSIDE_TYPEOF
83 ? Builtins::CallableFor(isolate, Builtins::kLoadGlobalIC)
84 : Builtins::CallableFor(isolate,
85 Builtins::kLoadGlobalICInsideTypeof);
86}
87
88Callable CodeFactory::StoreOwnIC(Isolate* isolate) {
89 // TODO(ishell): Currently we use StoreOwnIC only for storing properties that
90 // already exist in the boilerplate therefore we can use StoreIC.
91 return Builtins::CallableFor(isolate, Builtins::kStoreICTrampoline);
92}
93
94Callable CodeFactory::StoreOwnICInOptimizedCode(Isolate* isolate) {
95 // TODO(ishell): Currently we use StoreOwnIC only for storing properties that
96 // already exist in the boilerplate therefore we can use StoreIC.
97 return Builtins::CallableFor(isolate, Builtins::kStoreIC);
98}
99
100Callable CodeFactory::KeyedStoreIC_SloppyArguments(Isolate* isolate,
101 KeyedAccessStoreMode mode) {
102 Builtins::Name builtin_index;
103 switch (mode) {
104 case STANDARD_STORE:
105 builtin_index = Builtins::kKeyedStoreIC_SloppyArguments_Standard;
106 break;
107 case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
108 builtin_index =
109 Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW;
110 break;
111 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
112 builtin_index =
113 Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB;
114 break;
115 case STORE_NO_TRANSITION_HANDLE_COW:
116 builtin_index =
117 Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW;
118 break;
119 default:
120 UNREACHABLE();
121 }
122 return isolate->builtins()->CallableFor(isolate, builtin_index);
123}
124
125Callable CodeFactory::KeyedStoreIC_Slow(Isolate* isolate,
126 KeyedAccessStoreMode mode) {
127 Builtins::Name builtin_index;
128 switch (mode) {
129 case STANDARD_STORE:
130 builtin_index = Builtins::kKeyedStoreIC_Slow_Standard;
131 break;
132 case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
133 builtin_index = Builtins::kKeyedStoreIC_Slow_GrowNoTransitionHandleCOW;
134 break;
135 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
136 builtin_index = Builtins::kKeyedStoreIC_Slow_NoTransitionIgnoreOOB;
137 break;
138 case STORE_NO_TRANSITION_HANDLE_COW:
139 builtin_index = Builtins::kKeyedStoreIC_Slow_NoTransitionHandleCOW;
140 break;
141 default:
142 UNREACHABLE();
143 }
144 return isolate->builtins()->CallableFor(isolate, builtin_index);
145}
146
147Callable CodeFactory::StoreInArrayLiteralIC_Slow(Isolate* isolate,
148 KeyedAccessStoreMode mode) {
149 Builtins::Name builtin_index;
150 switch (mode) {
151 case STANDARD_STORE:
152 builtin_index = Builtins::kStoreInArrayLiteralIC_Slow_Standard;
153 break;
154 case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
155 builtin_index =
156 Builtins::kStoreInArrayLiteralIC_Slow_GrowNoTransitionHandleCOW;
157 break;
158 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
159 builtin_index =
160 Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionIgnoreOOB;
161 break;
162 case STORE_NO_TRANSITION_HANDLE_COW:
163 builtin_index =
164 Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionHandleCOW;
165 break;
166 default:
167 UNREACHABLE();
168 }
169 return isolate->builtins()->CallableFor(isolate, builtin_index);
170}
171
172Callable CodeFactory::ElementsTransitionAndStore(Isolate* isolate,
173 KeyedAccessStoreMode mode) {
174 Builtins::Name builtin_index;
175 switch (mode) {
176 case STANDARD_STORE:
177 builtin_index = Builtins::kElementsTransitionAndStore_Standard;
178 break;
179 case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
180 builtin_index =
181 Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW;
182 break;
183 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
184 builtin_index =
185 Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB;
186 break;
187 case STORE_NO_TRANSITION_HANDLE_COW:
188 builtin_index =
189 Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW;
190 break;
191 default:
192 UNREACHABLE();
193 }
194 return isolate->builtins()->CallableFor(isolate, builtin_index);
195}
196
197Callable CodeFactory::StoreFastElementIC(Isolate* isolate,
198 KeyedAccessStoreMode mode) {
199 Builtins::Name builtin_index;
200 switch (mode) {
201 case STANDARD_STORE:
202 builtin_index = Builtins::kStoreFastElementIC_Standard;
203 break;
204 case STORE_AND_GROW_NO_TRANSITION_HANDLE_COW:
205 builtin_index = Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW;
206 break;
207 case STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS:
208 builtin_index = Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB;
209 break;
210 case STORE_NO_TRANSITION_HANDLE_COW:
211 builtin_index = Builtins::kStoreFastElementIC_NoTransitionHandleCOW;
212 break;
213 default:
214 UNREACHABLE();
215 }
216 return isolate->builtins()->CallableFor(isolate, builtin_index);
217}
218
219// static
220Callable CodeFactory::BinaryOperation(Isolate* isolate, Operation op) {
221 switch (op) {
222 case Operation::kShiftRight:
223 return Builtins::CallableFor(isolate, Builtins::kShiftRight);
224 case Operation::kShiftLeft:
225 return Builtins::CallableFor(isolate, Builtins::kShiftLeft);
226 case Operation::kShiftRightLogical:
227 return Builtins::CallableFor(isolate, Builtins::kShiftRightLogical);
228 case Operation::kAdd:
229 return Builtins::CallableFor(isolate, Builtins::kAdd);
230 case Operation::kSubtract:
231 return Builtins::CallableFor(isolate, Builtins::kSubtract);
232 case Operation::kMultiply:
233 return Builtins::CallableFor(isolate, Builtins::kMultiply);
234 case Operation::kDivide:
235 return Builtins::CallableFor(isolate, Builtins::kDivide);
236 case Operation::kModulus:
237 return Builtins::CallableFor(isolate, Builtins::kModulus);
238 case Operation::kBitwiseOr:
239 return Builtins::CallableFor(isolate, Builtins::kBitwiseOr);
240 case Operation::kBitwiseAnd:
241 return Builtins::CallableFor(isolate, Builtins::kBitwiseAnd);
242 case Operation::kBitwiseXor:
243 return Builtins::CallableFor(isolate, Builtins::kBitwiseXor);
244 default:
245 break;
246 }
247 UNREACHABLE();
248}
249
250// static
251Callable CodeFactory::NonPrimitiveToPrimitive(Isolate* isolate,
252 ToPrimitiveHint hint) {
253 return Callable(isolate->builtins()->NonPrimitiveToPrimitive(hint),
254 TypeConversionDescriptor{});
255}
256
257// static
258Callable CodeFactory::OrdinaryToPrimitive(Isolate* isolate,
259 OrdinaryToPrimitiveHint hint) {
260 return Callable(isolate->builtins()->OrdinaryToPrimitive(hint),
261 TypeConversionDescriptor{});
262}
263
264// static
265Callable CodeFactory::StringAdd(Isolate* isolate, StringAddFlags flags) {
266 switch (flags) {
267 case STRING_ADD_CHECK_NONE:
268 return Builtins::CallableFor(isolate, Builtins::kStringAdd_CheckNone);
269 case STRING_ADD_CONVERT_LEFT:
270 return Builtins::CallableFor(isolate, Builtins::kStringAdd_ConvertLeft);
271 case STRING_ADD_CONVERT_RIGHT:
272 return Builtins::CallableFor(isolate, Builtins::kStringAdd_ConvertRight);
273 }
274 UNREACHABLE();
275}
276
277// static
278Callable CodeFactory::ResumeGenerator(Isolate* isolate) {
279 return Builtins::CallableFor(isolate, Builtins::kResumeGeneratorTrampoline);
280}
281
282// static
283Callable CodeFactory::FrameDropperTrampoline(Isolate* isolate) {
284 return Builtins::CallableFor(isolate, Builtins::kFrameDropperTrampoline);
285}
286
287// static
288Callable CodeFactory::HandleDebuggerStatement(Isolate* isolate) {
289 return Builtins::CallableFor(isolate, Builtins::kHandleDebuggerStatement);
290}
291
292// static
293Callable CodeFactory::FastNewFunctionContext(Isolate* isolate,
294 ScopeType scope_type) {
295 switch (scope_type) {
296 case ScopeType::EVAL_SCOPE:
297 return Builtins::CallableFor(isolate,
298 Builtins::kFastNewFunctionContextEval);
299 case ScopeType::FUNCTION_SCOPE:
300 return Builtins::CallableFor(isolate,
301 Builtins::kFastNewFunctionContextFunction);
302 default:
303 UNREACHABLE();
304 }
305}
306
307// static
308Callable CodeFactory::ArgumentAdaptor(Isolate* isolate) {
309 return Builtins::CallableFor(isolate, Builtins::kArgumentsAdaptorTrampoline);
310}
311
312// static
313Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode) {
314 return Callable(isolate->builtins()->Call(mode), CallTrampolineDescriptor{});
315}
316
317// static
318Callable CodeFactory::CallWithArrayLike(Isolate* isolate) {
319 return Builtins::CallableFor(isolate, Builtins::kCallWithArrayLike);
320}
321
322// static
323Callable CodeFactory::CallWithSpread(Isolate* isolate) {
324 return Builtins::CallableFor(isolate, Builtins::kCallWithSpread);
325}
326
327// static
328Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) {
329 return Callable(isolate->builtins()->CallFunction(mode),
330 CallTrampolineDescriptor{});
331}
332
333// static
334Callable CodeFactory::CallVarargs(Isolate* isolate) {
335 return Builtins::CallableFor(isolate, Builtins::kCallVarargs);
336}
337
338// static
339Callable CodeFactory::CallForwardVarargs(Isolate* isolate) {
340 return Builtins::CallableFor(isolate, Builtins::kCallForwardVarargs);
341}
342
343// static
344Callable CodeFactory::CallFunctionForwardVarargs(Isolate* isolate) {
345 return Builtins::CallableFor(isolate, Builtins::kCallFunctionForwardVarargs);
346}
347
348// static
349Callable CodeFactory::Construct(Isolate* isolate) {
350 return Builtins::CallableFor(isolate, Builtins::kConstruct);
351}
352
353// static
354Callable CodeFactory::ConstructWithSpread(Isolate* isolate) {
355 return Builtins::CallableFor(isolate, Builtins::kConstructWithSpread);
356}
357
358// static
359Callable CodeFactory::ConstructFunction(Isolate* isolate) {
360 return Builtins::CallableFor(isolate, Builtins::kConstructFunction);
361}
362
363// static
364Callable CodeFactory::ConstructVarargs(Isolate* isolate) {
365 return Builtins::CallableFor(isolate, Builtins::kConstructVarargs);
366}
367
368// static
369Callable CodeFactory::ConstructForwardVarargs(Isolate* isolate) {
370 return Builtins::CallableFor(isolate, Builtins::kConstructForwardVarargs);
371}
372
373// static
374Callable CodeFactory::ConstructFunctionForwardVarargs(Isolate* isolate) {
375 return Builtins::CallableFor(isolate,
376 Builtins::kConstructFunctionForwardVarargs);
377}
378
379// static
380Callable CodeFactory::InterpreterPushArgsThenCall(
381 Isolate* isolate, ConvertReceiverMode receiver_mode,
382 InterpreterPushArgsMode mode) {
383 switch (mode) {
384 case InterpreterPushArgsMode::kArrayFunction:
385 // There is no special-case handling of calls to Array. They will all go
386 // through the kOther case below.
387 UNREACHABLE();
388 case InterpreterPushArgsMode::kWithFinalSpread:
389 return Builtins::CallableFor(
390 isolate, Builtins::kInterpreterPushArgsThenCallWithFinalSpread);
391 case InterpreterPushArgsMode::kOther:
392 switch (receiver_mode) {
393 case ConvertReceiverMode::kNullOrUndefined:
394 return Builtins::CallableFor(
395 isolate, Builtins::kInterpreterPushUndefinedAndArgsThenCall);
396 case ConvertReceiverMode::kNotNullOrUndefined:
397 case ConvertReceiverMode::kAny:
398 return Builtins::CallableFor(isolate,
399 Builtins::kInterpreterPushArgsThenCall);
400 }
401 }
402 UNREACHABLE();
403}
404
405// static
406Callable CodeFactory::InterpreterPushArgsThenConstruct(
407 Isolate* isolate, InterpreterPushArgsMode mode) {
408 switch (mode) {
409 case InterpreterPushArgsMode::kArrayFunction:
410 return Builtins::CallableFor(
411 isolate, Builtins::kInterpreterPushArgsThenConstructArrayFunction);
412 case InterpreterPushArgsMode::kWithFinalSpread:
413 return Builtins::CallableFor(
414 isolate, Builtins::kInterpreterPushArgsThenConstructWithFinalSpread);
415 case InterpreterPushArgsMode::kOther:
416 return Builtins::CallableFor(isolate,
417 Builtins::kInterpreterPushArgsThenConstruct);
418 }
419 UNREACHABLE();
420}
421
422// static
423Callable CodeFactory::InterpreterCEntry(Isolate* isolate, int result_size) {
424 // Note: If we ever use fpregs in the interpreter then we will need to
425 // save fpregs too.
426 Handle<Code> code = CodeFactory::CEntry(isolate, result_size, kDontSaveFPRegs,
427 kArgvInRegister);
428 if (result_size == 1) {
429 return Callable(code, InterpreterCEntry1Descriptor{});
430 } else {
431 DCHECK_EQ(result_size, 2);
432 return Callable(code, InterpreterCEntry2Descriptor{});
433 }
434}
435
436// static
437Callable CodeFactory::InterpreterOnStackReplacement(Isolate* isolate) {
438 return Builtins::CallableFor(isolate,
439 Builtins::kInterpreterOnStackReplacement);
440}
441
442// static
443Callable CodeFactory::ArrayNoArgumentConstructor(
444 Isolate* isolate, ElementsKind kind,
445 AllocationSiteOverrideMode override_mode) {
446#define CASE(kind_caps, kind_camel, mode_camel) \
447 case kind_caps: \
448 return Builtins::CallableFor( \
449 isolate, \
450 Builtins::kArrayNoArgumentConstructor_##kind_camel##_##mode_camel);
451 if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) {
452 DCHECK(IsSmiElementsKind(kind));
453 switch (kind) {
454 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride);
455 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride);
456 default:
457 UNREACHABLE();
458 }
459 } else {
460 DCHECK(override_mode == DISABLE_ALLOCATION_SITES ||
461 !AllocationSite::ShouldTrack(kind));
462 switch (kind) {
463 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites);
464 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites);
465 CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites);
466 CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites);
467 CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites);
468 CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites);
469 default:
470 UNREACHABLE();
471 }
472 }
473#undef CASE
474}
475
476// static
477Callable CodeFactory::ArraySingleArgumentConstructor(
478 Isolate* isolate, ElementsKind kind,
479 AllocationSiteOverrideMode override_mode) {
480#define CASE(kind_caps, kind_camel, mode_camel) \
481 case kind_caps: \
482 return Builtins::CallableFor( \
483 isolate, \
484 Builtins::kArraySingleArgumentConstructor_##kind_camel##_##mode_camel)
485 if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) {
486 DCHECK(IsSmiElementsKind(kind));
487 switch (kind) {
488 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride);
489 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride);
490 default:
491 UNREACHABLE();
492 }
493 } else {
494 DCHECK(override_mode == DISABLE_ALLOCATION_SITES ||
495 !AllocationSite::ShouldTrack(kind));
496 switch (kind) {
497 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites);
498 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites);
499 CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites);
500 CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites);
501 CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites);
502 CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites);
503 default:
504 UNREACHABLE();
505 }
506 }
507#undef CASE
508}
509
510} // namespace internal
511} // namespace v8
512