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/codegen/code-factory.h"
6
7 #include "src/builtins/builtins-descriptors.h"
8 #include "src/ic/ic.h"
9 #include "src/init/bootstrapper.h"
10 #include "src/objects/allocation-site-inl.h"
11 #include "src/objects/objects-inl.h"
12
13 namespace v8 {
14 namespace internal {
15
16 // static
RuntimeCEntry(Isolate * isolate,int result_size)17 Handle<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
CEntry(Isolate * isolate,int result_size,SaveFPRegsMode save_doubles,ArgvMode argv_mode,bool builtin_exit_frame)25 Handle<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
ApiGetter(Isolate * isolate)62 Callable CodeFactory::ApiGetter(Isolate* isolate) {
63 return Builtins::CallableFor(isolate, Builtins::kCallApiGetter);
64 }
65
66 // static
CallApiCallback(Isolate * isolate)67 Callable CodeFactory::CallApiCallback(Isolate* isolate) {
68 return Builtins::CallableFor(isolate, Builtins::kCallApiCallback);
69 }
70
71 // static
LoadGlobalIC(Isolate * isolate,TypeofMode typeof_mode)72 Callable 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
LoadGlobalICInOptimizedCode(Isolate * isolate,TypeofMode typeof_mode)80 Callable 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
StoreOwnIC(Isolate * isolate)88 Callable 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
StoreOwnICInOptimizedCode(Isolate * isolate)94 Callable 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
KeyedStoreIC_SloppyArguments(Isolate * isolate,KeyedAccessStoreMode mode)100 Callable 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_HANDLE_COW:
108 builtin_index =
109 Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW;
110 break;
111 case STORE_IGNORE_OUT_OF_BOUNDS:
112 builtin_index =
113 Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB;
114 break;
115 case STORE_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
ElementsTransitionAndStore(Isolate * isolate,KeyedAccessStoreMode mode)125 Callable CodeFactory::ElementsTransitionAndStore(Isolate* isolate,
126 KeyedAccessStoreMode mode) {
127 Builtins::Name builtin_index;
128 switch (mode) {
129 case STANDARD_STORE:
130 builtin_index = Builtins::kElementsTransitionAndStore_Standard;
131 break;
132 case STORE_AND_GROW_HANDLE_COW:
133 builtin_index =
134 Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW;
135 break;
136 case STORE_IGNORE_OUT_OF_BOUNDS:
137 builtin_index =
138 Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB;
139 break;
140 case STORE_HANDLE_COW:
141 builtin_index =
142 Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW;
143 break;
144 default:
145 UNREACHABLE();
146 }
147 return isolate->builtins()->CallableFor(isolate, builtin_index);
148 }
149
StoreFastElementIC(Isolate * isolate,KeyedAccessStoreMode mode)150 Callable CodeFactory::StoreFastElementIC(Isolate* isolate,
151 KeyedAccessStoreMode mode) {
152 Builtins::Name builtin_index;
153 switch (mode) {
154 case STANDARD_STORE:
155 builtin_index = Builtins::kStoreFastElementIC_Standard;
156 break;
157 case STORE_AND_GROW_HANDLE_COW:
158 builtin_index = Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW;
159 break;
160 case STORE_IGNORE_OUT_OF_BOUNDS:
161 builtin_index = Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB;
162 break;
163 case STORE_HANDLE_COW:
164 builtin_index = Builtins::kStoreFastElementIC_NoTransitionHandleCOW;
165 break;
166 default:
167 UNREACHABLE();
168 }
169 return isolate->builtins()->CallableFor(isolate, builtin_index);
170 }
171
172 // static
BinaryOperation(Isolate * isolate,Operation op)173 Callable CodeFactory::BinaryOperation(Isolate* isolate, Operation op) {
174 switch (op) {
175 case Operation::kShiftRight:
176 return Builtins::CallableFor(isolate, Builtins::kShiftRight);
177 case Operation::kShiftLeft:
178 return Builtins::CallableFor(isolate, Builtins::kShiftLeft);
179 case Operation::kShiftRightLogical:
180 return Builtins::CallableFor(isolate, Builtins::kShiftRightLogical);
181 case Operation::kAdd:
182 return Builtins::CallableFor(isolate, Builtins::kAdd);
183 case Operation::kSubtract:
184 return Builtins::CallableFor(isolate, Builtins::kSubtract);
185 case Operation::kMultiply:
186 return Builtins::CallableFor(isolate, Builtins::kMultiply);
187 case Operation::kDivide:
188 return Builtins::CallableFor(isolate, Builtins::kDivide);
189 case Operation::kModulus:
190 return Builtins::CallableFor(isolate, Builtins::kModulus);
191 case Operation::kBitwiseOr:
192 return Builtins::CallableFor(isolate, Builtins::kBitwiseOr);
193 case Operation::kBitwiseAnd:
194 return Builtins::CallableFor(isolate, Builtins::kBitwiseAnd);
195 case Operation::kBitwiseXor:
196 return Builtins::CallableFor(isolate, Builtins::kBitwiseXor);
197 default:
198 break;
199 }
200 UNREACHABLE();
201 }
202
203 // static
NonPrimitiveToPrimitive(Isolate * isolate,ToPrimitiveHint hint)204 Callable CodeFactory::NonPrimitiveToPrimitive(Isolate* isolate,
205 ToPrimitiveHint hint) {
206 return Callable(isolate->builtins()->NonPrimitiveToPrimitive(hint),
207 TypeConversionDescriptor{});
208 }
209
210 // static
OrdinaryToPrimitive(Isolate * isolate,OrdinaryToPrimitiveHint hint)211 Callable CodeFactory::OrdinaryToPrimitive(Isolate* isolate,
212 OrdinaryToPrimitiveHint hint) {
213 return Callable(isolate->builtins()->OrdinaryToPrimitive(hint),
214 TypeConversionDescriptor{});
215 }
216
217 // static
StringAdd(Isolate * isolate,StringAddFlags flags)218 Callable CodeFactory::StringAdd(Isolate* isolate, StringAddFlags flags) {
219 switch (flags) {
220 case STRING_ADD_CHECK_NONE:
221 return Builtins::CallableFor(isolate, Builtins::kStringAdd_CheckNone);
222 case STRING_ADD_CONVERT_LEFT:
223 return Builtins::CallableFor(isolate, Builtins::kStringAddConvertLeft);
224 case STRING_ADD_CONVERT_RIGHT:
225 return Builtins::CallableFor(isolate, Builtins::kStringAddConvertRight);
226 }
227 UNREACHABLE();
228 }
229
230 // static
ResumeGenerator(Isolate * isolate)231 Callable CodeFactory::ResumeGenerator(Isolate* isolate) {
232 return Builtins::CallableFor(isolate, Builtins::kResumeGeneratorTrampoline);
233 }
234
235 // static
FrameDropperTrampoline(Isolate * isolate)236 Callable CodeFactory::FrameDropperTrampoline(Isolate* isolate) {
237 return Builtins::CallableFor(isolate, Builtins::kFrameDropperTrampoline);
238 }
239
240 // static
HandleDebuggerStatement(Isolate * isolate)241 Callable CodeFactory::HandleDebuggerStatement(Isolate* isolate) {
242 return Builtins::CallableFor(isolate, Builtins::kHandleDebuggerStatement);
243 }
244
245 // static
FastNewFunctionContext(Isolate * isolate,ScopeType scope_type)246 Callable CodeFactory::FastNewFunctionContext(Isolate* isolate,
247 ScopeType scope_type) {
248 switch (scope_type) {
249 case ScopeType::EVAL_SCOPE:
250 return Builtins::CallableFor(isolate,
251 Builtins::kFastNewFunctionContextEval);
252 case ScopeType::FUNCTION_SCOPE:
253 return Builtins::CallableFor(isolate,
254 Builtins::kFastNewFunctionContextFunction);
255 default:
256 UNREACHABLE();
257 }
258 }
259
260 // static
ArgumentAdaptor(Isolate * isolate)261 Callable CodeFactory::ArgumentAdaptor(Isolate* isolate) {
262 return Builtins::CallableFor(isolate, Builtins::kArgumentsAdaptorTrampoline);
263 }
264
265 // static
Call(Isolate * isolate,ConvertReceiverMode mode)266 Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode) {
267 return Callable(isolate->builtins()->Call(mode), CallTrampolineDescriptor{});
268 }
269
270 // static
Call_WithFeedback(Isolate * isolate,ConvertReceiverMode mode)271 Callable CodeFactory::Call_WithFeedback(Isolate* isolate,
272 ConvertReceiverMode mode) {
273 switch (mode) {
274 case ConvertReceiverMode::kNullOrUndefined:
275 return Builtins::CallableFor(
276 isolate, Builtins::kCall_ReceiverIsNullOrUndefined_WithFeedback);
277 case ConvertReceiverMode::kNotNullOrUndefined:
278 return Builtins::CallableFor(
279 isolate, Builtins::kCall_ReceiverIsNotNullOrUndefined_WithFeedback);
280 case ConvertReceiverMode::kAny:
281 return Builtins::CallableFor(isolate,
282 Builtins::kCall_ReceiverIsAny_WithFeedback);
283 }
284 UNREACHABLE();
285 }
286
287 // static
CallWithArrayLike(Isolate * isolate)288 Callable CodeFactory::CallWithArrayLike(Isolate* isolate) {
289 return Builtins::CallableFor(isolate, Builtins::kCallWithArrayLike);
290 }
291
292 // static
CallWithSpread(Isolate * isolate)293 Callable CodeFactory::CallWithSpread(Isolate* isolate) {
294 return Builtins::CallableFor(isolate, Builtins::kCallWithSpread);
295 }
296
297 // static
CallFunction(Isolate * isolate,ConvertReceiverMode mode)298 Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) {
299 return Callable(isolate->builtins()->CallFunction(mode),
300 CallTrampolineDescriptor{});
301 }
302
303 // static
CallVarargs(Isolate * isolate)304 Callable CodeFactory::CallVarargs(Isolate* isolate) {
305 return Builtins::CallableFor(isolate, Builtins::kCallVarargs);
306 }
307
308 // static
CallForwardVarargs(Isolate * isolate)309 Callable CodeFactory::CallForwardVarargs(Isolate* isolate) {
310 return Builtins::CallableFor(isolate, Builtins::kCallForwardVarargs);
311 }
312
313 // static
CallFunctionForwardVarargs(Isolate * isolate)314 Callable CodeFactory::CallFunctionForwardVarargs(Isolate* isolate) {
315 return Builtins::CallableFor(isolate, Builtins::kCallFunctionForwardVarargs);
316 }
317
318 // static
Construct(Isolate * isolate)319 Callable CodeFactory::Construct(Isolate* isolate) {
320 return Builtins::CallableFor(isolate, Builtins::kConstruct);
321 }
322
323 // static
ConstructWithSpread(Isolate * isolate)324 Callable CodeFactory::ConstructWithSpread(Isolate* isolate) {
325 return Builtins::CallableFor(isolate, Builtins::kConstructWithSpread);
326 }
327
328 // static
ConstructFunction(Isolate * isolate)329 Callable CodeFactory::ConstructFunction(Isolate* isolate) {
330 return Builtins::CallableFor(isolate, Builtins::kConstructFunction);
331 }
332
333 // static
ConstructVarargs(Isolate * isolate)334 Callable CodeFactory::ConstructVarargs(Isolate* isolate) {
335 return Builtins::CallableFor(isolate, Builtins::kConstructVarargs);
336 }
337
338 // static
ConstructForwardVarargs(Isolate * isolate)339 Callable CodeFactory::ConstructForwardVarargs(Isolate* isolate) {
340 return Builtins::CallableFor(isolate, Builtins::kConstructForwardVarargs);
341 }
342
343 // static
ConstructFunctionForwardVarargs(Isolate * isolate)344 Callable CodeFactory::ConstructFunctionForwardVarargs(Isolate* isolate) {
345 return Builtins::CallableFor(isolate,
346 Builtins::kConstructFunctionForwardVarargs);
347 }
348
349 // static
InterpreterPushArgsThenCall(Isolate * isolate,ConvertReceiverMode receiver_mode,InterpreterPushArgsMode mode)350 Callable CodeFactory::InterpreterPushArgsThenCall(
351 Isolate* isolate, ConvertReceiverMode receiver_mode,
352 InterpreterPushArgsMode mode) {
353 switch (mode) {
354 case InterpreterPushArgsMode::kArrayFunction:
355 // There is no special-case handling of calls to Array. They will all go
356 // through the kOther case below.
357 UNREACHABLE();
358 case InterpreterPushArgsMode::kWithFinalSpread:
359 return Builtins::CallableFor(
360 isolate, Builtins::kInterpreterPushArgsThenCallWithFinalSpread);
361 case InterpreterPushArgsMode::kOther:
362 switch (receiver_mode) {
363 case ConvertReceiverMode::kNullOrUndefined:
364 return Builtins::CallableFor(
365 isolate, Builtins::kInterpreterPushUndefinedAndArgsThenCall);
366 case ConvertReceiverMode::kNotNullOrUndefined:
367 case ConvertReceiverMode::kAny:
368 return Builtins::CallableFor(isolate,
369 Builtins::kInterpreterPushArgsThenCall);
370 }
371 }
372 UNREACHABLE();
373 }
374
375 // static
InterpreterPushArgsThenConstruct(Isolate * isolate,InterpreterPushArgsMode mode)376 Callable CodeFactory::InterpreterPushArgsThenConstruct(
377 Isolate* isolate, InterpreterPushArgsMode mode) {
378 switch (mode) {
379 case InterpreterPushArgsMode::kArrayFunction:
380 return Builtins::CallableFor(
381 isolate, Builtins::kInterpreterPushArgsThenConstructArrayFunction);
382 case InterpreterPushArgsMode::kWithFinalSpread:
383 return Builtins::CallableFor(
384 isolate, Builtins::kInterpreterPushArgsThenConstructWithFinalSpread);
385 case InterpreterPushArgsMode::kOther:
386 return Builtins::CallableFor(isolate,
387 Builtins::kInterpreterPushArgsThenConstruct);
388 }
389 UNREACHABLE();
390 }
391
392 // static
InterpreterCEntry(Isolate * isolate,int result_size)393 Callable CodeFactory::InterpreterCEntry(Isolate* isolate, int result_size) {
394 // Note: If we ever use fpregs in the interpreter then we will need to
395 // save fpregs too.
396 Handle<Code> code = CodeFactory::CEntry(isolate, result_size, kDontSaveFPRegs,
397 kArgvInRegister);
398 if (result_size == 1) {
399 return Callable(code, InterpreterCEntry1Descriptor{});
400 } else {
401 DCHECK_EQ(result_size, 2);
402 return Callable(code, InterpreterCEntry2Descriptor{});
403 }
404 }
405
406 // static
InterpreterOnStackReplacement(Isolate * isolate)407 Callable CodeFactory::InterpreterOnStackReplacement(Isolate* isolate) {
408 return Builtins::CallableFor(isolate,
409 Builtins::kInterpreterOnStackReplacement);
410 }
411
412 // static
ArrayNoArgumentConstructor(Isolate * isolate,ElementsKind kind,AllocationSiteOverrideMode override_mode)413 Callable CodeFactory::ArrayNoArgumentConstructor(
414 Isolate* isolate, ElementsKind kind,
415 AllocationSiteOverrideMode override_mode) {
416 #define CASE(kind_caps, kind_camel, mode_camel) \
417 case kind_caps: \
418 return Builtins::CallableFor( \
419 isolate, \
420 Builtins::kArrayNoArgumentConstructor_##kind_camel##_##mode_camel);
421 if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) {
422 DCHECK(IsSmiElementsKind(kind));
423 switch (kind) {
424 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride);
425 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride);
426 default:
427 UNREACHABLE();
428 }
429 } else {
430 DCHECK(override_mode == DISABLE_ALLOCATION_SITES ||
431 !AllocationSite::ShouldTrack(kind));
432 switch (kind) {
433 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites);
434 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites);
435 CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites);
436 CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites);
437 CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites);
438 CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites);
439 default:
440 UNREACHABLE();
441 }
442 }
443 #undef CASE
444 }
445
446 // static
ArraySingleArgumentConstructor(Isolate * isolate,ElementsKind kind,AllocationSiteOverrideMode override_mode)447 Callable CodeFactory::ArraySingleArgumentConstructor(
448 Isolate* isolate, ElementsKind kind,
449 AllocationSiteOverrideMode override_mode) {
450 #define CASE(kind_caps, kind_camel, mode_camel) \
451 case kind_caps: \
452 return Builtins::CallableFor( \
453 isolate, \
454 Builtins::kArraySingleArgumentConstructor_##kind_camel##_##mode_camel)
455 if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) {
456 DCHECK(IsSmiElementsKind(kind));
457 switch (kind) {
458 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride);
459 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride);
460 default:
461 UNREACHABLE();
462 }
463 } else {
464 DCHECK(override_mode == DISABLE_ALLOCATION_SITES ||
465 !AllocationSite::ShouldTrack(kind));
466 switch (kind) {
467 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites);
468 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites);
469 CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites);
470 CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites);
471 CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites);
472 CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites);
473 default:
474 UNREACHABLE();
475 }
476 }
477 #undef CASE
478 }
479
480 } // namespace internal
481 } // namespace v8
482