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