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