• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
15 namespace v8 {
16 namespace internal {
17 
18 // Forward declarations for C++ builtins.
19 #define FORWARD_DECLARE(Name) \
20   Object* Builtin_##Name(int argc, Object** args, Isolate* isolate);
BUILTIN_LIST_C(FORWARD_DECLARE)21 BUILTIN_LIST_C(FORWARD_DECLARE)
22 
23 Builtins::Builtins() : initialized_(false) {
24   memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
25 }
26 
~Builtins()27 Builtins::~Builtins() {}
28 
29 namespace {
PostBuildProfileAndTracing(Isolate * isolate,Code * code,const char * name)30 void 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 
45 typedef void (*MacroAssemblerGenerator)(MacroAssembler*);
46 typedef void (*CodeAssemblerGenerator)(compiler::CodeAssemblerState*);
47 
BuildWithMacroAssembler(Isolate * isolate,MacroAssemblerGenerator generator,Code::Flags flags,const char * s_name)48 Code* 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 
BuildAdaptor(Isolate * isolate,Address builtin_address,Builtins::ExitFrameType exit_frame_type,Code::Flags flags,const char * name)65 Code* 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.
BuildWithCodeStubAssemblerJS(Isolate * isolate,CodeAssemblerGenerator generator,int argc,Code::Flags flags,const char * name)83 Code* 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.
BuildWithCodeStubAssemblerCS(Isolate * isolate,CodeAssemblerGenerator generator,CallDescriptors::Key interface_descriptor,Code::Flags flags,const char * name,int result_size)99 Code* 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 
SetUp(Isolate * isolate,bool create_heap_objects)120 void 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 
TearDown()176 void Builtins::TearDown() { initialized_ = false; }
177 
IterateBuiltins(ObjectVisitor * v)178 void Builtins::IterateBuiltins(ObjectVisitor* v) {
179   v->VisitPointers(&builtins_[0], &builtins_[0] + builtin_count);
180 }
181 
Lookup(byte * pc)182 const 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
name(int index)194 const 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
CppEntryOf(int index)209 Address 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
IsCpp(int index)224 bool 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
IsApi(int index)243 bool 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
HasCppImplementation(int index)262 bool 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   }
BUILTIN_LIST_ALL(DEFINE_BUILTIN_ACCESSOR)281 BUILTIN_LIST_ALL(DEFINE_BUILTIN_ACCESSOR)
282 #undef DEFINE_BUILTIN_ACCESSOR
283 
284 // static
285 bool 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