1// Copyright 2012 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/builtins/builtins.h"
6#include "src/api.h"
7#include "src/code-events.h"
8#include "src/compiler/code-assembler.h"
9#include "src/ic/ic-state.h"
10#include "src/interface-descriptors.h"
11#include "src/isolate.h"
12#include "src/macro-assembler.h"
13#include "src/objects-inl.h"
14
15namespace v8 {
16namespace internal {
17
18// Forward declarations for C++ builtins.
19#define FORWARD_DECLARE(Name) \
20  Object* Builtin_##Name(int argc, Object** args, Isolate* isolate);
21BUILTIN_LIST_C(FORWARD_DECLARE)
22
23Builtins::Builtins() : initialized_(false) {
24  memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
25}
26
27Builtins::~Builtins() {}
28
29namespace {
30void PostBuildProfileAndTracing(Isolate* isolate, Code* code,
31                                const char* name) {
32  PROFILE(isolate, CodeCreateEvent(CodeEventListener::BUILTIN_TAG,
33                                   AbstractCode::cast(code), name));
34#ifdef ENABLE_DISASSEMBLER
35  if (FLAG_print_builtin_code) {
36    CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
37    OFStream os(trace_scope.file());
38    os << "Builtin: " << name << "\n";
39    code->Disassemble(name, os);
40    os << "\n";
41  }
42#endif
43}
44
45typedef void (*MacroAssemblerGenerator)(MacroAssembler*);
46typedef void (*CodeAssemblerGenerator)(compiler::CodeAssemblerState*);
47
48Code* BuildWithMacroAssembler(Isolate* isolate,
49                              MacroAssemblerGenerator generator,
50                              Code::Flags flags, const char* s_name) {
51  HandleScope scope(isolate);
52  const size_t buffer_size = 32 * KB;
53  byte buffer[buffer_size];  // NOLINT(runtime/arrays)
54  MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes);
55  DCHECK(!masm.has_frame());
56  generator(&masm);
57  CodeDesc desc;
58  masm.GetCode(&desc);
59  Handle<Code> code =
60      isolate->factory()->NewCode(desc, flags, masm.CodeObject());
61  PostBuildProfileAndTracing(isolate, *code, s_name);
62  return *code;
63}
64
65Code* BuildAdaptor(Isolate* isolate, Address builtin_address,
66                   Builtins::ExitFrameType exit_frame_type, Code::Flags flags,
67                   const char* name) {
68  HandleScope scope(isolate);
69  const size_t buffer_size = 32 * KB;
70  byte buffer[buffer_size];  // NOLINT(runtime/arrays)
71  MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes);
72  DCHECK(!masm.has_frame());
73  Builtins::Generate_Adaptor(&masm, builtin_address, exit_frame_type);
74  CodeDesc desc;
75  masm.GetCode(&desc);
76  Handle<Code> code =
77      isolate->factory()->NewCode(desc, flags, masm.CodeObject());
78  PostBuildProfileAndTracing(isolate, *code, name);
79  return *code;
80}
81
82// Builder for builtins implemented in TurboFan with JS linkage.
83Code* BuildWithCodeStubAssemblerJS(Isolate* isolate,
84                                   CodeAssemblerGenerator generator, int argc,
85                                   Code::Flags flags, const char* name) {
86  HandleScope scope(isolate);
87  Zone zone(isolate->allocator(), ZONE_NAME);
88  const int argc_with_recv =
89      (argc == SharedFunctionInfo::kDontAdaptArgumentsSentinel) ? 0 : argc + 1;
90  compiler::CodeAssemblerState state(isolate, &zone, argc_with_recv, flags,
91                                     name);
92  generator(&state);
93  Handle<Code> code = compiler::CodeAssembler::GenerateCode(&state);
94  PostBuildProfileAndTracing(isolate, *code, name);
95  return *code;
96}
97
98// Builder for builtins implemented in TurboFan with CallStub linkage.
99Code* BuildWithCodeStubAssemblerCS(Isolate* isolate,
100                                   CodeAssemblerGenerator generator,
101                                   CallDescriptors::Key interface_descriptor,
102                                   Code::Flags flags, const char* name,
103                                   int result_size) {
104  HandleScope scope(isolate);
105  Zone zone(isolate->allocator(), ZONE_NAME);
106  // The interface descriptor with given key must be initialized at this point
107  // and this construction just queries the details from the descriptors table.
108  CallInterfaceDescriptor descriptor(isolate, interface_descriptor);
109  // Ensure descriptor is already initialized.
110  DCHECK_LE(0, descriptor.GetRegisterParameterCount());
111  compiler::CodeAssemblerState state(isolate, &zone, descriptor, flags, name,
112                                     result_size);
113  generator(&state);
114  Handle<Code> code = compiler::CodeAssembler::GenerateCode(&state);
115  PostBuildProfileAndTracing(isolate, *code, name);
116  return *code;
117}
118}  // anonymous namespace
119
120void Builtins::SetUp(Isolate* isolate, bool create_heap_objects) {
121  DCHECK(!initialized_);
122
123  // Create a scope for the handles in the builtins.
124  HandleScope scope(isolate);
125
126  if (create_heap_objects) {
127    int index = 0;
128    const Code::Flags kBuiltinFlags = Code::ComputeFlags(Code::BUILTIN);
129    Code* code;
130#define BUILD_CPP(Name)                                                     \
131  code = BuildAdaptor(isolate, FUNCTION_ADDR(Builtin_##Name), BUILTIN_EXIT, \
132                      kBuiltinFlags, #Name);                                \
133  builtins_[index++] = code;
134#define BUILD_API(Name)                                             \
135  code = BuildAdaptor(isolate, FUNCTION_ADDR(Builtin_##Name), EXIT, \
136                      kBuiltinFlags, #Name);                        \
137  builtins_[index++] = code;
138#define BUILD_TFJ(Name, Argc)                                          \
139  code = BuildWithCodeStubAssemblerJS(isolate, &Generate_##Name, Argc, \
140                                      kBuiltinFlags, #Name);           \
141  builtins_[index++] = code;
142#define BUILD_TFS(Name, Kind, Extra, InterfaceDescriptor, result_size) \
143  { InterfaceDescriptor##Descriptor descriptor(isolate); }             \
144  code = BuildWithCodeStubAssemblerCS(                                 \
145      isolate, &Generate_##Name, CallDescriptors::InterfaceDescriptor, \
146      Code::ComputeFlags(Code::Kind, Extra), #Name, result_size);      \
147  builtins_[index++] = code;
148#define BUILD_ASM(Name)                                                        \
149  code =                                                                       \
150      BuildWithMacroAssembler(isolate, Generate_##Name, kBuiltinFlags, #Name); \
151  builtins_[index++] = code;
152#define BUILD_ASH(Name, Kind, Extra)                                           \
153  code = BuildWithMacroAssembler(                                              \
154      isolate, Generate_##Name, Code::ComputeFlags(Code::Kind, Extra), #Name); \
155  builtins_[index++] = code;
156
157    BUILTIN_LIST(BUILD_CPP, BUILD_API, BUILD_TFJ, BUILD_TFS, BUILD_ASM,
158                 BUILD_ASH, BUILD_ASM);
159
160#undef BUILD_CPP
161#undef BUILD_API
162#undef BUILD_TFJ
163#undef BUILD_TFS
164#undef BUILD_ASM
165#undef BUILD_ASH
166    CHECK_EQ(builtin_count, index);
167    for (int i = 0; i < builtin_count; i++) {
168      Code::cast(builtins_[i])->set_builtin_index(i);
169    }
170  }
171
172  // Mark as initialized.
173  initialized_ = true;
174}
175
176void Builtins::TearDown() { initialized_ = false; }
177
178void Builtins::IterateBuiltins(ObjectVisitor* v) {
179  v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
180}
181
182const char* Builtins::Lookup(byte* pc) {
183  // may be called during initialization (disassembler!)
184  if (initialized_) {
185    for (int i = 0; i < builtin_count; i++) {
186      Code* entry = Code::cast(builtins_[i]);
187      if (entry->contains(pc)) return name(i);
188    }
189  }
190  return NULL;
191}
192
193// static
194const char* Builtins::name(int index) {
195  switch (index) {
196#define CASE(Name, ...) \
197  case k##Name:         \
198    return #Name;
199    BUILTIN_LIST_ALL(CASE)
200#undef CASE
201    default:
202      UNREACHABLE();
203      break;
204  }
205  return "";
206}
207
208// static
209Address Builtins::CppEntryOf(int index) {
210  DCHECK(0 <= index && index < builtin_count);
211  switch (index) {
212#define CASE(Name, ...) \
213  case k##Name:         \
214    return FUNCTION_ADDR(Builtin_##Name);
215    BUILTIN_LIST_C(CASE)
216#undef CASE
217    default:
218      return nullptr;
219  }
220  UNREACHABLE();
221}
222
223// static
224bool Builtins::IsCpp(int index) {
225  DCHECK(0 <= index && index < builtin_count);
226  switch (index) {
227#define CASE(Name, ...) \
228  case k##Name:         \
229    return true;
230#define BUILTIN_LIST_CPP(V)                                       \
231  BUILTIN_LIST(V, IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, \
232               IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
233    BUILTIN_LIST_CPP(CASE)
234#undef BUILTIN_LIST_CPP
235#undef CASE
236    default:
237      return false;
238  }
239  UNREACHABLE();
240}
241
242// static
243bool Builtins::IsApi(int index) {
244  DCHECK(0 <= index && index < builtin_count);
245  switch (index) {
246#define CASE(Name, ...) \
247  case k##Name:         \
248    return true;
249#define BUILTIN_LIST_API(V)                                       \
250  BUILTIN_LIST(IGNORE_BUILTIN, V, IGNORE_BUILTIN, IGNORE_BUILTIN, \
251               IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN)
252    BUILTIN_LIST_API(CASE);
253#undef BUILTIN_LIST_API
254#undef CASE
255    default:
256      return false;
257  }
258  UNREACHABLE();
259}
260
261// static
262bool Builtins::HasCppImplementation(int index) {
263  DCHECK(0 <= index && index < builtin_count);
264  switch (index) {
265#define CASE(Name, ...) \
266  case k##Name:         \
267    return true;
268    BUILTIN_LIST_C(CASE)
269#undef CASE
270    default:
271      return false;
272  }
273  UNREACHABLE();
274}
275
276#define DEFINE_BUILTIN_ACCESSOR(Name, ...)                                    \
277  Handle<Code> Builtins::Name() {                                             \
278    Code** code_address = reinterpret_cast<Code**>(builtin_address(k##Name)); \
279    return Handle<Code>(code_address);                                        \
280  }
281BUILTIN_LIST_ALL(DEFINE_BUILTIN_ACCESSOR)
282#undef DEFINE_BUILTIN_ACCESSOR
283
284// static
285bool Builtins::AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target,
286                                    Handle<JSObject> target_global_proxy) {
287  if (FLAG_allow_unsafe_function_constructor) return true;
288  HandleScopeImplementer* impl = isolate->handle_scope_implementer();
289  Handle<Context> responsible_context =
290      impl->MicrotaskContextIsLastEnteredContext() ? impl->MicrotaskContext()
291                                                   : impl->LastEnteredContext();
292  // TODO(jochen): Remove this.
293  if (responsible_context.is_null()) {
294    return true;
295  }
296  if (*responsible_context == target->context()) return true;
297  return isolate->MayAccess(responsible_context, target_global_proxy);
298}
299
300}  // namespace internal
301}  // namespace v8
302