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<CodeT> 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<CodeT> 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 == SaveFPRegsMode::kIgnore && am == ArgvMode::kStack &&
35 !be) {
36 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit);
37 } else if (rs == 1 && sd == SaveFPRegsMode::kIgnore &&
38 am == ArgvMode::kStack && be) {
39 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, BuiltinExit);
40 } else if (rs == 1 && sd == SaveFPRegsMode::kIgnore &&
41 am == ArgvMode::kRegister && !be) {
42 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit);
43 } else if (rs == 1 && sd == SaveFPRegsMode::kSave && am == ArgvMode::kStack &&
44 !be) {
45 return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, NoBuiltinExit);
46 } else if (rs == 1 && sd == SaveFPRegsMode::kSave && am == ArgvMode::kStack &&
47 be) {
48 return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, BuiltinExit);
49 } else if (rs == 2 && sd == SaveFPRegsMode::kIgnore &&
50 am == ArgvMode::kStack && !be) {
51 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit);
52 } else if (rs == 2 && sd == SaveFPRegsMode::kIgnore &&
53 am == ArgvMode::kStack && be) {
54 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, BuiltinExit);
55 } else if (rs == 2 && sd == SaveFPRegsMode::kIgnore &&
56 am == ArgvMode::kRegister && !be) {
57 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit);
58 } else if (rs == 2 && sd == SaveFPRegsMode::kSave && am == ArgvMode::kStack &&
59 !be) {
60 return CENTRY_CODE(Return2, SaveFPRegs, ArgvOnStack, NoBuiltinExit);
61 } else if (rs == 2 && sd == SaveFPRegsMode::kSave && am == ArgvMode::kStack &&
62 be) {
63 return CENTRY_CODE(Return2, SaveFPRegs, ArgvOnStack, BuiltinExit);
64 }
65
66 UNREACHABLE();
67 }
68
69 #undef CENTRY_CODE
70
71 // static
ApiGetter(Isolate * isolate)72 Callable CodeFactory::ApiGetter(Isolate* isolate) {
73 return Builtins::CallableFor(isolate, Builtin::kCallApiGetter);
74 }
75
76 // static
CallApiCallback(Isolate * isolate)77 Callable CodeFactory::CallApiCallback(Isolate* isolate) {
78 return Builtins::CallableFor(isolate, Builtin::kCallApiCallback);
79 }
80
81 // static
LoadGlobalIC(Isolate * isolate,TypeofMode typeof_mode)82 Callable CodeFactory::LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode) {
83 return typeof_mode == TypeofMode::kNotInside
84 ? Builtins::CallableFor(isolate, Builtin::kLoadGlobalICTrampoline)
85 : Builtins::CallableFor(
86 isolate, Builtin::kLoadGlobalICInsideTypeofTrampoline);
87 }
88
89 // static
LoadGlobalICInOptimizedCode(Isolate * isolate,TypeofMode typeof_mode)90 Callable CodeFactory::LoadGlobalICInOptimizedCode(Isolate* isolate,
91 TypeofMode typeof_mode) {
92 return typeof_mode == TypeofMode::kNotInside
93 ? Builtins::CallableFor(isolate, Builtin::kLoadGlobalIC)
94 : Builtins::CallableFor(isolate,
95 Builtin::kLoadGlobalICInsideTypeof);
96 }
97
DefineNamedOwnIC(Isolate * isolate)98 Callable CodeFactory::DefineNamedOwnIC(Isolate* isolate) {
99 return Builtins::CallableFor(isolate, Builtin::kDefineNamedOwnICTrampoline);
100 }
101
DefineNamedOwnICInOptimizedCode(Isolate * isolate)102 Callable CodeFactory::DefineNamedOwnICInOptimizedCode(Isolate* isolate) {
103 return Builtins::CallableFor(isolate, Builtin::kDefineNamedOwnIC);
104 }
105
106 // static
NonPrimitiveToPrimitive(Isolate * isolate,ToPrimitiveHint hint)107 Callable CodeFactory::NonPrimitiveToPrimitive(Isolate* isolate,
108 ToPrimitiveHint hint) {
109 return Callable(isolate->builtins()->NonPrimitiveToPrimitive(hint),
110 TypeConversionDescriptor{});
111 }
112
113 // static
OrdinaryToPrimitive(Isolate * isolate,OrdinaryToPrimitiveHint hint)114 Callable CodeFactory::OrdinaryToPrimitive(Isolate* isolate,
115 OrdinaryToPrimitiveHint hint) {
116 return Callable(isolate->builtins()->OrdinaryToPrimitive(hint),
117 TypeConversionDescriptor{});
118 }
119
120 // static
StringAdd(Isolate * isolate,StringAddFlags flags)121 Callable CodeFactory::StringAdd(Isolate* isolate, StringAddFlags flags) {
122 switch (flags) {
123 case STRING_ADD_CHECK_NONE:
124 return Builtins::CallableFor(isolate, Builtin::kStringAdd_CheckNone);
125 case STRING_ADD_CONVERT_LEFT:
126 return Builtins::CallableFor(isolate, Builtin::kStringAddConvertLeft);
127 case STRING_ADD_CONVERT_RIGHT:
128 return Builtins::CallableFor(isolate, Builtin::kStringAddConvertRight);
129 }
130 UNREACHABLE();
131 }
132
133 // static
ResumeGenerator(Isolate * isolate)134 Callable CodeFactory::ResumeGenerator(Isolate* isolate) {
135 return Builtins::CallableFor(isolate, Builtin::kResumeGeneratorTrampoline);
136 }
137
138 // static
FastNewFunctionContext(Isolate * isolate,ScopeType scope_type)139 Callable CodeFactory::FastNewFunctionContext(Isolate* isolate,
140 ScopeType scope_type) {
141 switch (scope_type) {
142 case ScopeType::EVAL_SCOPE:
143 return Builtins::CallableFor(isolate,
144 Builtin::kFastNewFunctionContextEval);
145 case ScopeType::FUNCTION_SCOPE:
146 return Builtins::CallableFor(isolate,
147 Builtin::kFastNewFunctionContextFunction);
148 default:
149 UNREACHABLE();
150 }
151 }
152
153 // static
Call(Isolate * isolate,ConvertReceiverMode mode)154 Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode) {
155 return Callable(isolate->builtins()->Call(mode), CallTrampolineDescriptor{});
156 }
157
158 // static
Call_WithFeedback(Isolate * isolate,ConvertReceiverMode mode)159 Callable CodeFactory::Call_WithFeedback(Isolate* isolate,
160 ConvertReceiverMode mode) {
161 switch (mode) {
162 case ConvertReceiverMode::kNullOrUndefined:
163 return Builtins::CallableFor(
164 isolate, Builtin::kCall_ReceiverIsNullOrUndefined_WithFeedback);
165 case ConvertReceiverMode::kNotNullOrUndefined:
166 return Builtins::CallableFor(
167 isolate, Builtin::kCall_ReceiverIsNotNullOrUndefined_WithFeedback);
168 case ConvertReceiverMode::kAny:
169 return Builtins::CallableFor(isolate,
170 Builtin::kCall_ReceiverIsAny_WithFeedback);
171 }
172 UNREACHABLE();
173 }
174
175 // static
CallWithArrayLike(Isolate * isolate)176 Callable CodeFactory::CallWithArrayLike(Isolate* isolate) {
177 return Builtins::CallableFor(isolate, Builtin::kCallWithArrayLike);
178 }
179
180 // static
CallWithSpread(Isolate * isolate)181 Callable CodeFactory::CallWithSpread(Isolate* isolate) {
182 return Builtins::CallableFor(isolate, Builtin::kCallWithSpread);
183 }
184
185 // static
CallFunction(Isolate * isolate,ConvertReceiverMode mode)186 Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) {
187 return Callable(isolate->builtins()->CallFunction(mode),
188 CallTrampolineDescriptor{});
189 }
190
191 // static
CallVarargs(Isolate * isolate)192 Callable CodeFactory::CallVarargs(Isolate* isolate) {
193 return Builtins::CallableFor(isolate, Builtin::kCallVarargs);
194 }
195
196 // static
CallForwardVarargs(Isolate * isolate)197 Callable CodeFactory::CallForwardVarargs(Isolate* isolate) {
198 return Builtins::CallableFor(isolate, Builtin::kCallForwardVarargs);
199 }
200
201 // static
CallFunctionForwardVarargs(Isolate * isolate)202 Callable CodeFactory::CallFunctionForwardVarargs(Isolate* isolate) {
203 return Builtins::CallableFor(isolate, Builtin::kCallFunctionForwardVarargs);
204 }
205
206 // static
Construct(Isolate * isolate)207 Callable CodeFactory::Construct(Isolate* isolate) {
208 return Builtins::CallableFor(isolate, Builtin::kConstruct);
209 }
210
211 // static
ConstructWithSpread(Isolate * isolate)212 Callable CodeFactory::ConstructWithSpread(Isolate* isolate) {
213 return Builtins::CallableFor(isolate, Builtin::kConstructWithSpread);
214 }
215
216 // static
ConstructFunction(Isolate * isolate)217 Callable CodeFactory::ConstructFunction(Isolate* isolate) {
218 return Builtins::CallableFor(isolate, Builtin::kConstructFunction);
219 }
220
221 // static
ConstructVarargs(Isolate * isolate)222 Callable CodeFactory::ConstructVarargs(Isolate* isolate) {
223 return Builtins::CallableFor(isolate, Builtin::kConstructVarargs);
224 }
225
226 // static
ConstructForwardVarargs(Isolate * isolate)227 Callable CodeFactory::ConstructForwardVarargs(Isolate* isolate) {
228 return Builtins::CallableFor(isolate, Builtin::kConstructForwardVarargs);
229 }
230
231 // static
ConstructFunctionForwardVarargs(Isolate * isolate)232 Callable CodeFactory::ConstructFunctionForwardVarargs(Isolate* isolate) {
233 return Builtins::CallableFor(isolate,
234 Builtin::kConstructFunctionForwardVarargs);
235 }
236
237 // static
InterpreterPushArgsThenCall(Isolate * isolate,ConvertReceiverMode receiver_mode,InterpreterPushArgsMode mode)238 Callable CodeFactory::InterpreterPushArgsThenCall(
239 Isolate* isolate, ConvertReceiverMode receiver_mode,
240 InterpreterPushArgsMode mode) {
241 switch (mode) {
242 case InterpreterPushArgsMode::kArrayFunction:
243 // There is no special-case handling of calls to Array. They will all go
244 // through the kOther case below.
245 UNREACHABLE();
246 case InterpreterPushArgsMode::kWithFinalSpread:
247 return Builtins::CallableFor(
248 isolate, Builtin::kInterpreterPushArgsThenCallWithFinalSpread);
249 case InterpreterPushArgsMode::kOther:
250 switch (receiver_mode) {
251 case ConvertReceiverMode::kNullOrUndefined:
252 return Builtins::CallableFor(
253 isolate, Builtin::kInterpreterPushUndefinedAndArgsThenCall);
254 case ConvertReceiverMode::kNotNullOrUndefined:
255 case ConvertReceiverMode::kAny:
256 return Builtins::CallableFor(isolate,
257 Builtin::kInterpreterPushArgsThenCall);
258 }
259 }
260 UNREACHABLE();
261 }
262
263 // static
InterpreterPushArgsThenConstruct(Isolate * isolate,InterpreterPushArgsMode mode)264 Callable CodeFactory::InterpreterPushArgsThenConstruct(
265 Isolate* isolate, InterpreterPushArgsMode mode) {
266 switch (mode) {
267 case InterpreterPushArgsMode::kArrayFunction:
268 return Builtins::CallableFor(
269 isolate, Builtin::kInterpreterPushArgsThenConstructArrayFunction);
270 case InterpreterPushArgsMode::kWithFinalSpread:
271 return Builtins::CallableFor(
272 isolate, Builtin::kInterpreterPushArgsThenConstructWithFinalSpread);
273 case InterpreterPushArgsMode::kOther:
274 return Builtins::CallableFor(isolate,
275 Builtin::kInterpreterPushArgsThenConstruct);
276 }
277 UNREACHABLE();
278 }
279
280 // static
InterpreterCEntry(Isolate * isolate,int result_size)281 Callable CodeFactory::InterpreterCEntry(Isolate* isolate, int result_size) {
282 // Note: If we ever use fpregs in the interpreter then we will need to
283 // save fpregs too.
284 Handle<CodeT> code = CodeFactory::CEntry(
285 isolate, result_size, SaveFPRegsMode::kIgnore, ArgvMode::kRegister);
286 if (result_size == 1) {
287 return Callable(code, InterpreterCEntry1Descriptor{});
288 } else {
289 DCHECK_EQ(result_size, 2);
290 return Callable(code, InterpreterCEntry2Descriptor{});
291 }
292 }
293
294 // static
InterpreterOnStackReplacement(Isolate * isolate)295 Callable CodeFactory::InterpreterOnStackReplacement(Isolate* isolate) {
296 return Builtins::CallableFor(isolate,
297 Builtin::kInterpreterOnStackReplacement);
298 }
299
300 // static
InterpreterOnStackReplacement_ToBaseline(Isolate * isolate)301 Callable CodeFactory::InterpreterOnStackReplacement_ToBaseline(
302 Isolate* isolate) {
303 return Builtins::CallableFor(
304 isolate, Builtin::kInterpreterOnStackReplacement_ToBaseline);
305 }
306
307 // static
ArrayNoArgumentConstructor(Isolate * isolate,ElementsKind kind,AllocationSiteOverrideMode override_mode)308 Callable CodeFactory::ArrayNoArgumentConstructor(
309 Isolate* isolate, ElementsKind kind,
310 AllocationSiteOverrideMode override_mode) {
311 #define CASE(kind_caps, kind_camel, mode_camel) \
312 case kind_caps: \
313 return Builtins::CallableFor( \
314 isolate, \
315 Builtin::kArrayNoArgumentConstructor_##kind_camel##_##mode_camel);
316 if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) {
317 DCHECK(IsSmiElementsKind(kind));
318 switch (kind) {
319 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride);
320 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride);
321 default:
322 UNREACHABLE();
323 }
324 } else {
325 DCHECK(override_mode == DISABLE_ALLOCATION_SITES ||
326 !AllocationSite::ShouldTrack(kind));
327 switch (kind) {
328 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites);
329 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites);
330 CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites);
331 CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites);
332 CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites);
333 CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites);
334 default:
335 UNREACHABLE();
336 }
337 }
338 #undef CASE
339 }
340
341 // static
ArraySingleArgumentConstructor(Isolate * isolate,ElementsKind kind,AllocationSiteOverrideMode override_mode)342 Callable CodeFactory::ArraySingleArgumentConstructor(
343 Isolate* isolate, ElementsKind kind,
344 AllocationSiteOverrideMode override_mode) {
345 #define CASE(kind_caps, kind_camel, mode_camel) \
346 case kind_caps: \
347 return Builtins::CallableFor( \
348 isolate, \
349 Builtin::kArraySingleArgumentConstructor_##kind_camel##_##mode_camel)
350 if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) {
351 DCHECK(IsSmiElementsKind(kind));
352 switch (kind) {
353 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride);
354 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride);
355 default:
356 UNREACHABLE();
357 }
358 } else {
359 DCHECK(override_mode == DISABLE_ALLOCATION_SITES ||
360 !AllocationSite::ShouldTrack(kind));
361 switch (kind) {
362 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites);
363 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites);
364 CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites);
365 CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites);
366 CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites);
367 CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites);
368 default:
369 UNREACHABLE();
370 }
371 }
372 #undef CASE
373 }
374
375 #ifdef V8_IS_TSAN
376 // static
GetTSANStoreStub(SaveFPRegsMode fp_mode,int size,std::memory_order order)377 Builtin CodeFactory::GetTSANStoreStub(SaveFPRegsMode fp_mode, int size,
378 std::memory_order order) {
379 if (order == std::memory_order_relaxed) {
380 if (size == kInt8Size) {
381 return fp_mode == SaveFPRegsMode::kIgnore
382 ? Builtin::kTSANRelaxedStore8IgnoreFP
383 : Builtin::kTSANRelaxedStore8SaveFP;
384 } else if (size == kInt16Size) {
385 return fp_mode == SaveFPRegsMode::kIgnore
386 ? Builtin::kTSANRelaxedStore16IgnoreFP
387 : Builtin::kTSANRelaxedStore16SaveFP;
388 } else if (size == kInt32Size) {
389 return fp_mode == SaveFPRegsMode::kIgnore
390 ? Builtin::kTSANRelaxedStore32IgnoreFP
391 : Builtin::kTSANRelaxedStore32SaveFP;
392 } else {
393 CHECK_EQ(size, kInt64Size);
394 return fp_mode == SaveFPRegsMode::kIgnore
395 ? Builtin::kTSANRelaxedStore64IgnoreFP
396 : Builtin::kTSANRelaxedStore64SaveFP;
397 }
398 } else {
399 DCHECK_EQ(order, std::memory_order_seq_cst);
400 if (size == kInt8Size) {
401 return fp_mode == SaveFPRegsMode::kIgnore
402 ? Builtin::kTSANSeqCstStore8IgnoreFP
403 : Builtin::kTSANSeqCstStore8SaveFP;
404 } else if (size == kInt16Size) {
405 return fp_mode == SaveFPRegsMode::kIgnore
406 ? Builtin::kTSANSeqCstStore16IgnoreFP
407 : Builtin::kTSANSeqCstStore16SaveFP;
408 } else if (size == kInt32Size) {
409 return fp_mode == SaveFPRegsMode::kIgnore
410 ? Builtin::kTSANSeqCstStore32IgnoreFP
411 : Builtin::kTSANSeqCstStore32SaveFP;
412 } else {
413 CHECK_EQ(size, kInt64Size);
414 return fp_mode == SaveFPRegsMode::kIgnore
415 ? Builtin::kTSANSeqCstStore64IgnoreFP
416 : Builtin::kTSANSeqCstStore64SaveFP;
417 }
418 }
419 }
420
421 // static
GetTSANRelaxedLoadStub(SaveFPRegsMode fp_mode,int size)422 Builtin CodeFactory::GetTSANRelaxedLoadStub(SaveFPRegsMode fp_mode, int size) {
423 if (size == kInt32Size) {
424 return fp_mode == SaveFPRegsMode::kIgnore
425 ? Builtin::kTSANRelaxedLoad32IgnoreFP
426 : Builtin::kTSANRelaxedLoad32SaveFP;
427 } else {
428 CHECK_EQ(size, kInt64Size);
429 return fp_mode == SaveFPRegsMode::kIgnore
430 ? Builtin::kTSANRelaxedLoad64IgnoreFP
431 : Builtin::kTSANRelaxedLoad64SaveFP;
432 }
433 }
434 #endif // V8_IS_TSAN
435
436 } // namespace internal
437 } // namespace v8
438