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