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
12 namespace v8 {
13 namespace internal {
14
15 namespace {
16
17 // TODO(ishell): make it (const Stub& stub) once CodeStub::GetCode() is const.
18 template <typename Stub>
make_callable(Stub & stub)19 Callable make_callable(Stub& stub) {
20 typedef typename Stub::Descriptor Descriptor;
21 return Callable(stub.GetCode(), Descriptor{});
22 }
23
24 } // namespace
25
26 // static
RuntimeCEntry(Isolate * isolate,int result_size)27 Handle<Code> CodeFactory::RuntimeCEntry(Isolate* isolate, int result_size) {
28 return CodeFactory::CEntry(isolate, result_size);
29 }
30
31 #define CENTRY_CODE(RS, SD, AM, BE) \
32 BUILTIN_CODE(isolate, CEntry_##RS##_##SD##_##AM##_##BE)
33
34 // static
CEntry(Isolate * isolate,int result_size,SaveFPRegsMode save_doubles,ArgvMode argv_mode,bool builtin_exit_frame)35 Handle<Code> CodeFactory::CEntry(Isolate* isolate, int result_size,
36 SaveFPRegsMode save_doubles,
37 ArgvMode argv_mode, bool builtin_exit_frame) {
38 // Aliases for readability below.
39 const int rs = result_size;
40 const SaveFPRegsMode sd = save_doubles;
41 const ArgvMode am = argv_mode;
42 const bool be = builtin_exit_frame;
43
44 if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvOnStack && !be) {
45 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit);
46 } else if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvOnStack && be) {
47 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvOnStack, BuiltinExit);
48 } else if (rs == 1 && sd == kDontSaveFPRegs && am == kArgvInRegister && !be) {
49 return CENTRY_CODE(Return1, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit);
50 } else if (rs == 1 && sd == kSaveFPRegs && am == kArgvOnStack && !be) {
51 return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, NoBuiltinExit);
52 } else if (rs == 1 && sd == kSaveFPRegs && am == kArgvOnStack && be) {
53 return CENTRY_CODE(Return1, SaveFPRegs, ArgvOnStack, BuiltinExit);
54 } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvOnStack && !be) {
55 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, NoBuiltinExit);
56 } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvOnStack && be) {
57 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvOnStack, BuiltinExit);
58 } else if (rs == 2 && sd == kDontSaveFPRegs && am == kArgvInRegister && !be) {
59 return CENTRY_CODE(Return2, DontSaveFPRegs, ArgvInRegister, NoBuiltinExit);
60 } else if (rs == 2 && sd == kSaveFPRegs && am == kArgvOnStack && !be) {
61 return CENTRY_CODE(Return2, SaveFPRegs, ArgvOnStack, NoBuiltinExit);
62 } else if (rs == 2 && sd == kSaveFPRegs && am == kArgvOnStack && 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 Callable(BUILTIN_CODE(isolate, CallApiGetter), ApiGetterDescriptor{});
74 }
75
76 // static
CallApiCallback(Isolate * isolate,int argc)77 Callable CodeFactory::CallApiCallback(Isolate* isolate, int argc) {
78 switch (argc) {
79 case 0:
80 return Callable(BUILTIN_CODE(isolate, CallApiCallback_Argc0),
81 ApiCallbackDescriptor{});
82 case 1:
83 return Callable(BUILTIN_CODE(isolate, CallApiCallback_Argc1),
84 ApiCallbackDescriptor{});
85 default: {
86 CallApiCallbackStub stub(isolate, argc);
87 return make_callable(stub);
88 }
89 }
90 UNREACHABLE();
91 }
92
93 // static
LoadGlobalIC(Isolate * isolate,TypeofMode typeof_mode)94 Callable CodeFactory::LoadGlobalIC(Isolate* isolate, TypeofMode typeof_mode) {
95 return Callable(
96 typeof_mode == NOT_INSIDE_TYPEOF
97 ? BUILTIN_CODE(isolate, LoadGlobalICTrampoline)
98 : BUILTIN_CODE(isolate, LoadGlobalICInsideTypeofTrampoline),
99 LoadGlobalDescriptor{});
100 }
101
102 // static
LoadGlobalICInOptimizedCode(Isolate * isolate,TypeofMode typeof_mode)103 Callable CodeFactory::LoadGlobalICInOptimizedCode(Isolate* isolate,
104 TypeofMode typeof_mode) {
105 return Callable(typeof_mode == NOT_INSIDE_TYPEOF
106 ? BUILTIN_CODE(isolate, LoadGlobalIC)
107 : BUILTIN_CODE(isolate, LoadGlobalICInsideTypeof),
108 LoadGlobalWithVectorDescriptor{});
109 }
110
StoreOwnIC(Isolate * isolate)111 Callable CodeFactory::StoreOwnIC(Isolate* isolate) {
112 // TODO(ishell): Currently we use StoreOwnIC only for storing properties that
113 // already exist in the boilerplate therefore we can use StoreIC.
114 return Callable(BUILTIN_CODE(isolate, StoreICTrampoline), StoreDescriptor{});
115 }
116
StoreOwnICInOptimizedCode(Isolate * isolate)117 Callable CodeFactory::StoreOwnICInOptimizedCode(Isolate* isolate) {
118 // TODO(ishell): Currently we use StoreOwnIC only for storing properties that
119 // already exist in the boilerplate therefore we can use StoreIC.
120 return Callable(BUILTIN_CODE(isolate, StoreIC), StoreWithVectorDescriptor{});
121 }
122
123 // static
BinaryOperation(Isolate * isolate,Operation op)124 Callable CodeFactory::BinaryOperation(Isolate* isolate, Operation op) {
125 switch (op) {
126 case Operation::kShiftRight:
127 return Builtins::CallableFor(isolate, Builtins::kShiftRight);
128 case Operation::kShiftLeft:
129 return Builtins::CallableFor(isolate, Builtins::kShiftLeft);
130 case Operation::kShiftRightLogical:
131 return Builtins::CallableFor(isolate, Builtins::kShiftRightLogical);
132 case Operation::kAdd:
133 return Builtins::CallableFor(isolate, Builtins::kAdd);
134 case Operation::kSubtract:
135 return Builtins::CallableFor(isolate, Builtins::kSubtract);
136 case Operation::kMultiply:
137 return Builtins::CallableFor(isolate, Builtins::kMultiply);
138 case Operation::kDivide:
139 return Builtins::CallableFor(isolate, Builtins::kDivide);
140 case Operation::kModulus:
141 return Builtins::CallableFor(isolate, Builtins::kModulus);
142 case Operation::kBitwiseOr:
143 return Builtins::CallableFor(isolate, Builtins::kBitwiseOr);
144 case Operation::kBitwiseAnd:
145 return Builtins::CallableFor(isolate, Builtins::kBitwiseAnd);
146 case Operation::kBitwiseXor:
147 return Builtins::CallableFor(isolate, Builtins::kBitwiseXor);
148 default:
149 break;
150 }
151 UNREACHABLE();
152 }
153
154 // static
NonPrimitiveToPrimitive(Isolate * isolate,ToPrimitiveHint hint)155 Callable CodeFactory::NonPrimitiveToPrimitive(Isolate* isolate,
156 ToPrimitiveHint hint) {
157 return Callable(isolate->builtins()->NonPrimitiveToPrimitive(hint),
158 TypeConversionDescriptor{});
159 }
160
161 // static
OrdinaryToPrimitive(Isolate * isolate,OrdinaryToPrimitiveHint hint)162 Callable CodeFactory::OrdinaryToPrimitive(Isolate* isolate,
163 OrdinaryToPrimitiveHint hint) {
164 return Callable(isolate->builtins()->OrdinaryToPrimitive(hint),
165 TypeConversionDescriptor{});
166 }
167
168 // static
StringAdd(Isolate * isolate,StringAddFlags flags,PretenureFlag pretenure_flag)169 Callable CodeFactory::StringAdd(Isolate* isolate, StringAddFlags flags,
170 PretenureFlag pretenure_flag) {
171 if (pretenure_flag == NOT_TENURED) {
172 switch (flags) {
173 case STRING_ADD_CHECK_NONE:
174 return Builtins::CallableFor(isolate,
175 Builtins::kStringAdd_CheckNone_NotTenured);
176 case STRING_ADD_CONVERT_LEFT:
177 return Builtins::CallableFor(
178 isolate, Builtins::kStringAdd_ConvertLeft_NotTenured);
179 case STRING_ADD_CONVERT_RIGHT:
180 return Builtins::CallableFor(
181 isolate, Builtins::kStringAdd_ConvertRight_NotTenured);
182 }
183 } else {
184 CHECK_EQ(TENURED, pretenure_flag);
185 CHECK_EQ(STRING_ADD_CHECK_NONE, flags);
186 return Builtins::CallableFor(isolate,
187 Builtins::kStringAdd_CheckNone_Tenured);
188 }
189
190 UNREACHABLE();
191 }
192
193 // static
ResumeGenerator(Isolate * isolate)194 Callable CodeFactory::ResumeGenerator(Isolate* isolate) {
195 return Callable(BUILTIN_CODE(isolate, ResumeGeneratorTrampoline),
196 ResumeGeneratorDescriptor{});
197 }
198
199 // static
FrameDropperTrampoline(Isolate * isolate)200 Callable CodeFactory::FrameDropperTrampoline(Isolate* isolate) {
201 return Callable(BUILTIN_CODE(isolate, FrameDropperTrampoline),
202 FrameDropperTrampolineDescriptor{});
203 }
204
205 // static
HandleDebuggerStatement(Isolate * isolate)206 Callable CodeFactory::HandleDebuggerStatement(Isolate* isolate) {
207 return Callable(BUILTIN_CODE(isolate, HandleDebuggerStatement),
208 ContextOnlyDescriptor{});
209 }
210
211 // static
FastNewFunctionContext(Isolate * isolate,ScopeType scope_type)212 Callable CodeFactory::FastNewFunctionContext(Isolate* isolate,
213 ScopeType scope_type) {
214 return Callable(isolate->builtins()->NewFunctionContext(scope_type),
215 FastNewFunctionContextDescriptor{});
216 }
217
218 // static
ArgumentAdaptor(Isolate * isolate)219 Callable CodeFactory::ArgumentAdaptor(Isolate* isolate) {
220 return Callable(BUILTIN_CODE(isolate, ArgumentsAdaptorTrampoline),
221 ArgumentAdaptorDescriptor{});
222 }
223
224 // static
Call(Isolate * isolate,ConvertReceiverMode mode)225 Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode) {
226 return Callable(isolate->builtins()->Call(mode), CallTrampolineDescriptor{});
227 }
228
229 // static
CallWithArrayLike(Isolate * isolate)230 Callable CodeFactory::CallWithArrayLike(Isolate* isolate) {
231 return Callable(BUILTIN_CODE(isolate, CallWithArrayLike),
232 CallWithArrayLikeDescriptor{});
233 }
234
235 // static
CallWithSpread(Isolate * isolate)236 Callable CodeFactory::CallWithSpread(Isolate* isolate) {
237 return Callable(BUILTIN_CODE(isolate, CallWithSpread),
238 CallWithSpreadDescriptor{});
239 }
240
241 // static
CallFunction(Isolate * isolate,ConvertReceiverMode mode)242 Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) {
243 return Callable(isolate->builtins()->CallFunction(mode),
244 CallTrampolineDescriptor{});
245 }
246
247 // static
CallVarargs(Isolate * isolate)248 Callable CodeFactory::CallVarargs(Isolate* isolate) {
249 return Callable(BUILTIN_CODE(isolate, CallVarargs), CallVarargsDescriptor{});
250 }
251
252 // static
CallForwardVarargs(Isolate * isolate)253 Callable CodeFactory::CallForwardVarargs(Isolate* isolate) {
254 return Callable(BUILTIN_CODE(isolate, CallForwardVarargs),
255 CallForwardVarargsDescriptor{});
256 }
257
258 // static
CallFunctionForwardVarargs(Isolate * isolate)259 Callable CodeFactory::CallFunctionForwardVarargs(Isolate* isolate) {
260 return Callable(BUILTIN_CODE(isolate, CallFunctionForwardVarargs),
261 CallForwardVarargsDescriptor{});
262 }
263
264 // static
Construct(Isolate * isolate)265 Callable CodeFactory::Construct(Isolate* isolate) {
266 return Callable(BUILTIN_CODE(isolate, Construct), JSTrampolineDescriptor{});
267 }
268
269 // static
ConstructWithSpread(Isolate * isolate)270 Callable CodeFactory::ConstructWithSpread(Isolate* isolate) {
271 return Callable(BUILTIN_CODE(isolate, ConstructWithSpread),
272 ConstructWithSpreadDescriptor{});
273 }
274
275 // static
ConstructFunction(Isolate * isolate)276 Callable CodeFactory::ConstructFunction(Isolate* isolate) {
277 return Callable(BUILTIN_CODE(isolate, ConstructFunction),
278 JSTrampolineDescriptor{});
279 }
280
281 // static
ConstructVarargs(Isolate * isolate)282 Callable CodeFactory::ConstructVarargs(Isolate* isolate) {
283 return Callable(BUILTIN_CODE(isolate, ConstructVarargs),
284 ConstructVarargsDescriptor{});
285 }
286
287 // static
ConstructForwardVarargs(Isolate * isolate)288 Callable CodeFactory::ConstructForwardVarargs(Isolate* isolate) {
289 return Callable(BUILTIN_CODE(isolate, ConstructForwardVarargs),
290 ConstructForwardVarargsDescriptor{});
291 }
292
293 // static
ConstructFunctionForwardVarargs(Isolate * isolate)294 Callable CodeFactory::ConstructFunctionForwardVarargs(Isolate* isolate) {
295 return Callable(BUILTIN_CODE(isolate, ConstructFunctionForwardVarargs),
296 ConstructForwardVarargsDescriptor{});
297 }
298
299 // static
InterpreterPushArgsThenCall(Isolate * isolate,ConvertReceiverMode receiver_mode,InterpreterPushArgsMode mode)300 Callable CodeFactory::InterpreterPushArgsThenCall(
301 Isolate* isolate, ConvertReceiverMode receiver_mode,
302 InterpreterPushArgsMode mode) {
303 return Callable(
304 isolate->builtins()->InterpreterPushArgsThenCall(receiver_mode, mode),
305 InterpreterPushArgsThenCallDescriptor{});
306 }
307
308 // static
InterpreterPushArgsThenConstruct(Isolate * isolate,InterpreterPushArgsMode mode)309 Callable CodeFactory::InterpreterPushArgsThenConstruct(
310 Isolate* isolate, InterpreterPushArgsMode mode) {
311 return Callable(isolate->builtins()->InterpreterPushArgsThenConstruct(mode),
312 InterpreterPushArgsThenConstructDescriptor{});
313 }
314
315 // static
InterpreterCEntry(Isolate * isolate,int result_size)316 Callable CodeFactory::InterpreterCEntry(Isolate* isolate, int result_size) {
317 // Note: If we ever use fpregs in the interpreter then we will need to
318 // save fpregs too.
319 Handle<Code> code = CodeFactory::CEntry(isolate, result_size, kDontSaveFPRegs,
320 kArgvInRegister);
321 if (result_size == 1) {
322 return Callable(code, InterpreterCEntry1Descriptor{});
323 } else {
324 DCHECK_EQ(result_size, 2);
325 return Callable(code, InterpreterCEntry2Descriptor{});
326 }
327 }
328
329 // static
InterpreterOnStackReplacement(Isolate * isolate)330 Callable CodeFactory::InterpreterOnStackReplacement(Isolate* isolate) {
331 return Callable(BUILTIN_CODE(isolate, InterpreterOnStackReplacement),
332 ContextOnlyDescriptor{});
333 }
334
335 // static
ArrayNoArgumentConstructor(Isolate * isolate,ElementsKind kind,AllocationSiteOverrideMode override_mode)336 Callable CodeFactory::ArrayNoArgumentConstructor(
337 Isolate* isolate, ElementsKind kind,
338 AllocationSiteOverrideMode override_mode) {
339 #define CASE(kind_caps, kind_camel, mode_camel) \
340 case kind_caps: \
341 return Callable( \
342 BUILTIN_CODE(isolate, \
343 ArrayNoArgumentConstructor_##kind_camel##_##mode_camel), \
344 ArrayNoArgumentConstructorDescriptor{})
345 if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) {
346 DCHECK(IsSmiElementsKind(kind));
347 switch (kind) {
348 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride);
349 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride);
350 default:
351 UNREACHABLE();
352 }
353 } else {
354 DCHECK(override_mode == DISABLE_ALLOCATION_SITES ||
355 !AllocationSite::ShouldTrack(kind));
356 switch (kind) {
357 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites);
358 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites);
359 CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites);
360 CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites);
361 CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites);
362 CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites);
363 default:
364 UNREACHABLE();
365 }
366 }
367 #undef CASE
368 }
369
370 // static
ArraySingleArgumentConstructor(Isolate * isolate,ElementsKind kind,AllocationSiteOverrideMode override_mode)371 Callable CodeFactory::ArraySingleArgumentConstructor(
372 Isolate* isolate, ElementsKind kind,
373 AllocationSiteOverrideMode override_mode) {
374 #define CASE(kind_caps, kind_camel, mode_camel) \
375 case kind_caps: \
376 return Callable( \
377 BUILTIN_CODE( \
378 isolate, \
379 ArraySingleArgumentConstructor_##kind_camel##_##mode_camel), \
380 ArraySingleArgumentConstructorDescriptor{})
381 if (override_mode == DONT_OVERRIDE && AllocationSite::ShouldTrack(kind)) {
382 DCHECK(IsSmiElementsKind(kind));
383 switch (kind) {
384 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DontOverride);
385 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DontOverride);
386 default:
387 UNREACHABLE();
388 }
389 } else {
390 DCHECK(override_mode == DISABLE_ALLOCATION_SITES ||
391 !AllocationSite::ShouldTrack(kind));
392 switch (kind) {
393 CASE(PACKED_SMI_ELEMENTS, PackedSmi, DisableAllocationSites);
394 CASE(HOLEY_SMI_ELEMENTS, HoleySmi, DisableAllocationSites);
395 CASE(PACKED_ELEMENTS, Packed, DisableAllocationSites);
396 CASE(HOLEY_ELEMENTS, Holey, DisableAllocationSites);
397 CASE(PACKED_DOUBLE_ELEMENTS, PackedDouble, DisableAllocationSites);
398 CASE(HOLEY_DOUBLE_ELEMENTS, HoleyDouble, DisableAllocationSites);
399 default:
400 UNREACHABLE();
401 }
402 }
403 #undef CASE
404 }
405
406 // static
InternalArrayNoArgumentConstructor(Isolate * isolate,ElementsKind kind)407 Callable CodeFactory::InternalArrayNoArgumentConstructor(Isolate* isolate,
408 ElementsKind kind) {
409 switch (kind) {
410 case PACKED_ELEMENTS:
411 return Callable(
412 BUILTIN_CODE(isolate, InternalArrayNoArgumentConstructor_Packed),
413 ArrayNoArgumentConstructorDescriptor{});
414 case HOLEY_ELEMENTS:
415 return Callable(
416 BUILTIN_CODE(isolate, InternalArrayNoArgumentConstructor_Holey),
417 ArrayNoArgumentConstructorDescriptor{});
418 default:
419 UNREACHABLE();
420 }
421 }
422
423 // static
InternalArraySingleArgumentConstructor(Isolate * isolate,ElementsKind kind)424 Callable CodeFactory::InternalArraySingleArgumentConstructor(
425 Isolate* isolate, ElementsKind kind) {
426 switch (kind) {
427 case PACKED_ELEMENTS:
428 return Callable(
429 BUILTIN_CODE(isolate, InternalArraySingleArgumentConstructor_Packed),
430 ArraySingleArgumentConstructorDescriptor{});
431 case HOLEY_ELEMENTS:
432 return Callable(
433 BUILTIN_CODE(isolate, InternalArraySingleArgumentConstructor_Holey),
434 ArraySingleArgumentConstructorDescriptor{});
435 default:
436 UNREACHABLE();
437 }
438 }
439
440 } // namespace internal
441 } // namespace v8
442