Line data Source code
1 : // Copyright 2017 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/setup-isolate.h"
6 :
7 : #include "src/assembler-inl.h"
8 : #include "src/builtins/builtins.h"
9 : #include "src/code-events.h"
10 : #include "src/compiler/code-assembler.h"
11 : #include "src/handles-inl.h"
12 : #include "src/interface-descriptors.h"
13 : #include "src/isolate.h"
14 : #include "src/objects-inl.h"
15 : #include "src/objects/shared-function-info.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 :
20 : // Forward declarations for C++ builtins.
21 : #define FORWARD_DECLARE(Name) \
22 : Object* Builtin_##Name(int argc, Object** args, Isolate* isolate);
23 : BUILTIN_LIST_C(FORWARD_DECLARE)
24 : #undef FORWARD_DECLARE
25 :
26 : namespace {
27 : void PostBuildProfileAndTracing(Isolate* isolate, Code* code,
28 : const char* name) {
29 21731 : PROFILE(isolate, CodeCreateEvent(CodeEventListener::BUILTIN_TAG,
30 : AbstractCode::cast(code), name));
31 : #ifdef ENABLE_DISASSEMBLER
32 : if (FLAG_print_builtin_code) {
33 : CodeTracer::Scope trace_scope(isolate->GetCodeTracer());
34 : OFStream os(trace_scope.file());
35 : os << "Builtin: " << name << "\n";
36 : code->Disassemble(name, os);
37 : os << "\n";
38 : }
39 : #endif
40 : }
41 :
42 : typedef void (*MacroAssemblerGenerator)(MacroAssembler*);
43 : typedef void (*CodeAssemblerGenerator)(compiler::CodeAssemblerState*);
44 :
45 31 : Handle<Code> BuildPlaceholder(Isolate* isolate) {
46 : HandleScope scope(isolate);
47 : const size_t buffer_size = 1 * KB;
48 : byte buffer[buffer_size]; // NOLINT(runtime/arrays)
49 31 : MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes);
50 : DCHECK(!masm.has_frame());
51 : {
52 31 : FrameScope scope(&masm, StackFrame::NONE);
53 31 : masm.CallRuntime(Runtime::kSystemBreak);
54 : }
55 : CodeDesc desc;
56 31 : masm.GetCode(isolate, &desc);
57 : Handle<Code> code =
58 31 : isolate->factory()->NewCode(desc, Code::BUILTIN, masm.CodeObject());
59 62 : return scope.CloseAndEscape(code);
60 : }
61 :
62 2077 : Code* BuildWithMacroAssembler(Isolate* isolate,
63 : MacroAssemblerGenerator generator,
64 : const char* s_name) {
65 : HandleScope scope(isolate);
66 : // Canonicalize handles, so that we can share constant pool entries pointing
67 : // to code targets without dereferencing their handles.
68 4154 : CanonicalHandleScope canonical(isolate);
69 : const size_t buffer_size = 32 * KB;
70 : byte buffer[buffer_size]; // NOLINT(runtime/arrays)
71 2077 : MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes);
72 : DCHECK(!masm.has_frame());
73 2077 : generator(&masm);
74 : CodeDesc desc;
75 2077 : masm.GetCode(isolate, &desc);
76 : Handle<Code> code =
77 2077 : isolate->factory()->NewCode(desc, Code::BUILTIN, masm.CodeObject());
78 : PostBuildProfileAndTracing(isolate, *code, s_name);
79 2077 : return *code;
80 : }
81 :
82 7037 : Code* BuildAdaptor(Isolate* isolate, Address builtin_address,
83 : Builtins::ExitFrameType exit_frame_type, const char* name) {
84 : HandleScope scope(isolate);
85 : // Canonicalize handles, so that we can share constant pool entries pointing
86 : // to code targets without dereferencing their handles.
87 14074 : CanonicalHandleScope canonical(isolate);
88 : const size_t buffer_size = 32 * KB;
89 : byte buffer[buffer_size]; // NOLINT(runtime/arrays)
90 7037 : MacroAssembler masm(isolate, buffer, buffer_size, CodeObjectRequired::kYes);
91 : DCHECK(!masm.has_frame());
92 7037 : Builtins::Generate_Adaptor(&masm, builtin_address, exit_frame_type);
93 : CodeDesc desc;
94 7037 : masm.GetCode(isolate, &desc);
95 : Handle<Code> code =
96 7037 : isolate->factory()->NewCode(desc, Code::BUILTIN, masm.CodeObject());
97 : PostBuildProfileAndTracing(isolate, *code, name);
98 7037 : return *code;
99 : }
100 :
101 : // Builder for builtins implemented in TurboFan with JS linkage.
102 15996 : Code* BuildWithCodeStubAssemblerJS(Isolate* isolate,
103 : CodeAssemblerGenerator generator, int argc,
104 : const char* name) {
105 : HandleScope scope(isolate);
106 : // Canonicalize handles, so that we can share constant pool entries pointing
107 : // to code targets without dereferencing their handles.
108 15996 : CanonicalHandleScope canonical(isolate);
109 15996 : Zone zone(isolate->allocator(), ZONE_NAME);
110 : const int argc_with_recv =
111 7998 : (argc == SharedFunctionInfo::kDontAdaptArgumentsSentinel) ? 0 : argc + 1;
112 : compiler::CodeAssemblerState state(isolate, &zone, argc_with_recv,
113 15996 : Code::BUILTIN, name);
114 7998 : generator(&state);
115 7998 : Handle<Code> code = compiler::CodeAssembler::GenerateCode(&state);
116 : PostBuildProfileAndTracing(isolate, *code, name);
117 7998 : return *code;
118 : }
119 :
120 : // Builder for builtins implemented in TurboFan with CallStub linkage.
121 9238 : Code* BuildWithCodeStubAssemblerCS(Isolate* isolate,
122 : CodeAssemblerGenerator generator,
123 : CallDescriptors::Key interface_descriptor,
124 : const char* name, int result_size) {
125 : HandleScope scope(isolate);
126 : // Canonicalize handles, so that we can share constant pool entries pointing
127 : // to code targets without dereferencing their handles.
128 9238 : CanonicalHandleScope canonical(isolate);
129 9238 : Zone zone(isolate->allocator(), ZONE_NAME);
130 : // The interface descriptor with given key must be initialized at this point
131 : // and this construction just queries the details from the descriptors table.
132 : CallInterfaceDescriptor descriptor(isolate, interface_descriptor);
133 : // Ensure descriptor is already initialized.
134 : DCHECK_LE(0, descriptor.GetRegisterParameterCount());
135 : compiler::CodeAssemblerState state(isolate, &zone, descriptor, Code::BUILTIN,
136 9238 : name, result_size);
137 4619 : generator(&state);
138 4619 : Handle<Code> code = compiler::CodeAssembler::GenerateCode(&state);
139 : PostBuildProfileAndTracing(isolate, *code, name);
140 4619 : return *code;
141 : }
142 : } // anonymous namespace
143 :
144 0 : void SetupIsolateDelegate::AddBuiltin(Builtins* builtins, int index,
145 : Code* code) {
146 43462 : builtins->builtins_[index] = code;
147 : code->set_builtin_index(index);
148 0 : }
149 :
150 31 : void SetupIsolateDelegate::PopulateWithPlaceholders(Isolate* isolate) {
151 : // Fill the builtins list with placeholders. References to these placeholder
152 : // builtins are eventually replaced by the actual builtins. This is to
153 : // support circular references between builtins.
154 : Builtins* builtins = isolate->builtins();
155 : HandleScope scope(isolate);
156 31 : Handle<Code> placeholder = BuildPlaceholder(isolate);
157 : AddBuiltin(builtins, 0, *placeholder);
158 21731 : for (int i = 1; i < Builtins::builtin_count; i++) {
159 43400 : AddBuiltin(builtins, i, *isolate->factory()->CopyCode(placeholder));
160 : }
161 31 : }
162 :
163 31 : void SetupIsolateDelegate::ReplacePlaceholders(Isolate* isolate) {
164 : // Replace references from all code objects to placeholders.
165 : Builtins* builtins = isolate->builtins();
166 : DisallowHeapAllocation no_gc;
167 : static const int kRelocMask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
168 31 : RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT);
169 31 : HeapIterator iterator(isolate->heap());
170 112220 : while (HeapObject* obj = iterator.next()) {
171 112189 : if (!obj->IsCode()) continue;
172 : Code* code = Code::cast(obj);
173 : bool flush_icache = false;
174 324322 : for (RelocIterator it(code, kRelocMask); !it.done(); it.next()) {
175 535680 : RelocInfo* rinfo = it.rinfo();
176 267840 : if (RelocInfo::IsCodeTarget(rinfo->rmode())) {
177 : Code* target = Code::GetCodeFromTargetAddress(rinfo->target_address());
178 252774 : if (!target->is_builtin()) continue;
179 : Code* new_target =
180 93775 : Code::cast(builtins->builtins_[target->builtin_index()]);
181 : rinfo->set_target_address(isolate, new_target->instruction_start(),
182 93775 : UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
183 : } else {
184 : DCHECK(RelocInfo::IsEmbeddedObject(rinfo->rmode()));
185 : Object* object = rinfo->target_object();
186 15066 : if (!object->IsCode()) continue;
187 : Code* target = Code::cast(object);
188 1674 : if (!target->is_builtin()) continue;
189 : Code* new_target =
190 1581 : Code::cast(builtins->builtins_[target->builtin_index()]);
191 : rinfo->set_target_object(new_target, UPDATE_WRITE_BARRIER,
192 : SKIP_ICACHE_FLUSH);
193 : }
194 : flush_icache = true;
195 : }
196 56482 : if (flush_icache) {
197 25761 : Assembler::FlushICache(isolate, code->instruction_start(),
198 51522 : code->instruction_size());
199 : }
200 31 : }
201 31 : }
202 :
203 31 : void SetupIsolateDelegate::SetupBuiltinsInternal(Isolate* isolate) {
204 : Builtins* builtins = isolate->builtins();
205 : DCHECK(!builtins->initialized_);
206 :
207 31 : PopulateWithPlaceholders(isolate);
208 :
209 : // Create a scope for the handles in the builtins.
210 : HandleScope scope(isolate);
211 :
212 : int index = 0;
213 : Code* code;
214 : #define BUILD_CPP(Name) \
215 : code = BuildAdaptor(isolate, FUNCTION_ADDR(Builtin_##Name), \
216 : Builtins::BUILTIN_EXIT, #Name); \
217 : AddBuiltin(builtins, index++, code);
218 : #define BUILD_API(Name) \
219 : code = BuildAdaptor(isolate, FUNCTION_ADDR(Builtin_##Name), Builtins::EXIT, \
220 : #Name); \
221 : AddBuiltin(builtins, index++, code);
222 : #define BUILD_TFJ(Name, Argc, ...) \
223 : code = BuildWithCodeStubAssemblerJS(isolate, &Builtins::Generate_##Name, \
224 : Argc, #Name); \
225 : AddBuiltin(builtins, index++, code);
226 : #define BUILD_TFC(Name, InterfaceDescriptor, result_size) \
227 : { InterfaceDescriptor##Descriptor descriptor(isolate); } \
228 : code = BuildWithCodeStubAssemblerCS(isolate, &Builtins::Generate_##Name, \
229 : CallDescriptors::InterfaceDescriptor, \
230 : #Name, result_size); \
231 : AddBuiltin(builtins, index++, code);
232 : #define BUILD_TFS(Name, ...) \
233 : /* Return size for generic TF builtins (stub linkage) is always 1. */ \
234 : code = BuildWithCodeStubAssemblerCS(isolate, &Builtins::Generate_##Name, \
235 : CallDescriptors::Name, #Name, 1); \
236 : AddBuiltin(builtins, index++, code);
237 : #define BUILD_TFH(Name, InterfaceDescriptor) \
238 : { InterfaceDescriptor##Descriptor descriptor(isolate); } \
239 : /* Return size for IC builtins/handlers is always 1. */ \
240 : code = BuildWithCodeStubAssemblerCS(isolate, &Builtins::Generate_##Name, \
241 : CallDescriptors::InterfaceDescriptor, \
242 : #Name, 1); \
243 : AddBuiltin(builtins, index++, code);
244 : #define BUILD_ASM(Name) \
245 : code = BuildWithMacroAssembler(isolate, Builtins::Generate_##Name, #Name); \
246 : AddBuiltin(builtins, index++, code);
247 :
248 24924 : BUILTIN_LIST(BUILD_CPP, BUILD_API, BUILD_TFJ, BUILD_TFC, BUILD_TFS, BUILD_TFH,
249 : BUILD_ASM);
250 :
251 : #undef BUILD_CPP
252 : #undef BUILD_API
253 : #undef BUILD_TFJ
254 : #undef BUILD_TFC
255 : #undef BUILD_TFS
256 : #undef BUILD_TFH
257 : #undef BUILD_ASM
258 : CHECK_EQ(Builtins::builtin_count, index);
259 :
260 31 : ReplacePlaceholders(isolate);
261 :
262 : #define SET_PROMISE_REJECTION_PREDICTION(Name) \
263 : Code::cast(builtins->builtins_[Builtins::k##Name]) \
264 : ->set_is_promise_rejection(true);
265 :
266 558 : BUILTIN_PROMISE_REJECTION_PREDICTION_LIST(SET_PROMISE_REJECTION_PREDICTION)
267 : #undef SET_PROMISE_REJECTION_PREDICTION
268 :
269 : #define SET_EXCEPTION_CAUGHT_PREDICTION(Name) \
270 : Code::cast(builtins->builtins_[Builtins::k##Name]) \
271 : ->set_is_exception_caught(true);
272 :
273 31 : BUILTIN_EXCEPTION_CAUGHT_PREDICTION_LIST(SET_EXCEPTION_CAUGHT_PREDICTION)
274 : #undef SET_EXCEPTION_CAUGHT_PREDICTION
275 :
276 : #define SET_CODE_NON_TAGGED_PARAMS(Name) \
277 : Code::cast(builtins->builtins_[Builtins::k##Name]) \
278 : ->set_has_tagged_params(false);
279 :
280 31 : BUILTINS_WITH_UNTAGGED_PARAMS(SET_CODE_NON_TAGGED_PARAMS)
281 : #undef SET_CODE_NON_TAGGED_PARAMS
282 :
283 : builtins->MarkInitialized();
284 31 : }
285 :
286 : } // namespace internal
287 : } // namespace v8
|