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
13namespace v8 {
14namespace internal {
15
16// static
17Handle<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
25Handle<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
72Callable CodeFactory::ApiGetter(Isolate* isolate) {
73  return Builtins::CallableFor(isolate, Builtin::kCallApiGetter);
74}
75
76// static
77Callable CodeFactory::CallApiCallback(Isolate* isolate) {
78  return Builtins::CallableFor(isolate, Builtin::kCallApiCallback);
79}
80
81// static
82Callable 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
90Callable 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
98Callable CodeFactory::DefineNamedOwnIC(Isolate* isolate) {
99  return Builtins::CallableFor(isolate, Builtin::kDefineNamedOwnICTrampoline);
100}
101
102Callable CodeFactory::DefineNamedOwnICInOptimizedCode(Isolate* isolate) {
103  return Builtins::CallableFor(isolate, Builtin::kDefineNamedOwnIC);
104}
105
106// static
107Callable CodeFactory::NonPrimitiveToPrimitive(Isolate* isolate,
108                                              ToPrimitiveHint hint) {
109  return Callable(isolate->builtins()->NonPrimitiveToPrimitive(hint),
110                  TypeConversionDescriptor{});
111}
112
113// static
114Callable CodeFactory::OrdinaryToPrimitive(Isolate* isolate,
115                                          OrdinaryToPrimitiveHint hint) {
116  return Callable(isolate->builtins()->OrdinaryToPrimitive(hint),
117                  TypeConversionDescriptor{});
118}
119
120// static
121Callable 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
134Callable CodeFactory::ResumeGenerator(Isolate* isolate) {
135  return Builtins::CallableFor(isolate, Builtin::kResumeGeneratorTrampoline);
136}
137
138// static
139Callable 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
154Callable CodeFactory::Call(Isolate* isolate, ConvertReceiverMode mode) {
155  return Callable(isolate->builtins()->Call(mode), CallTrampolineDescriptor{});
156}
157
158// static
159Callable 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
176Callable CodeFactory::CallWithArrayLike(Isolate* isolate) {
177  return Builtins::CallableFor(isolate, Builtin::kCallWithArrayLike);
178}
179
180// static
181Callable CodeFactory::CallWithSpread(Isolate* isolate) {
182  return Builtins::CallableFor(isolate, Builtin::kCallWithSpread);
183}
184
185// static
186Callable CodeFactory::CallFunction(Isolate* isolate, ConvertReceiverMode mode) {
187  return Callable(isolate->builtins()->CallFunction(mode),
188                  CallTrampolineDescriptor{});
189}
190
191// static
192Callable CodeFactory::CallVarargs(Isolate* isolate) {
193  return Builtins::CallableFor(isolate, Builtin::kCallVarargs);
194}
195
196// static
197Callable CodeFactory::CallForwardVarargs(Isolate* isolate) {
198  return Builtins::CallableFor(isolate, Builtin::kCallForwardVarargs);
199}
200
201// static
202Callable CodeFactory::CallFunctionForwardVarargs(Isolate* isolate) {
203  return Builtins::CallableFor(isolate, Builtin::kCallFunctionForwardVarargs);
204}
205
206// static
207Callable CodeFactory::Construct(Isolate* isolate) {
208  return Builtins::CallableFor(isolate, Builtin::kConstruct);
209}
210
211// static
212Callable CodeFactory::ConstructWithSpread(Isolate* isolate) {
213  return Builtins::CallableFor(isolate, Builtin::kConstructWithSpread);
214}
215
216// static
217Callable CodeFactory::ConstructFunction(Isolate* isolate) {
218  return Builtins::CallableFor(isolate, Builtin::kConstructFunction);
219}
220
221// static
222Callable CodeFactory::ConstructVarargs(Isolate* isolate) {
223  return Builtins::CallableFor(isolate, Builtin::kConstructVarargs);
224}
225
226// static
227Callable CodeFactory::ConstructForwardVarargs(Isolate* isolate) {
228  return Builtins::CallableFor(isolate, Builtin::kConstructForwardVarargs);
229}
230
231// static
232Callable CodeFactory::ConstructFunctionForwardVarargs(Isolate* isolate) {
233  return Builtins::CallableFor(isolate,
234                               Builtin::kConstructFunctionForwardVarargs);
235}
236
237// static
238Callable 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
264Callable 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
281Callable 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
295Callable CodeFactory::InterpreterOnStackReplacement(Isolate* isolate) {
296  return Builtins::CallableFor(isolate,
297                               Builtin::kInterpreterOnStackReplacement);
298}
299
300// static
301Callable CodeFactory::InterpreterOnStackReplacement_ToBaseline(
302    Isolate* isolate) {
303  return Builtins::CallableFor(
304      isolate, Builtin::kInterpreterOnStackReplacement_ToBaseline);
305}
306
307// static
308Callable 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
342Callable 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
377Builtin 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
422Builtin 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