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 :
12 : #include "src/handles-inl.h"
13 : #include "src/interface-descriptors.h"
14 : #include "src/interpreter/bytecodes.h"
15 : #include "src/interpreter/interpreter-generator.h"
16 : #include "src/interpreter/interpreter.h"
17 : #include "src/isolate.h"
18 : #include "src/macro-assembler.h"
19 : #include "src/objects-inl.h"
20 : #include "src/objects/shared-function-info.h"
21 : #include "src/objects/smi.h"
22 :
23 : namespace v8 {
24 : namespace internal {
25 :
26 : // Forward declarations for C++ builtins.
27 : #define FORWARD_DECLARE(Name) \
28 : Address Builtin_##Name(int argc, Address* args, Isolate* isolate);
29 : BUILTIN_LIST_C(FORWARD_DECLARE)
30 : #undef FORWARD_DECLARE
31 :
32 : namespace {
33 :
34 84616 : void PostBuildProfileAndTracing(Isolate* isolate, Code code, const char* name) {
35 84616 : PROFILE(isolate, CodeCreateEvent(CodeEventListener::BUILTIN_TAG,
36 : AbstractCode::cast(code), name));
37 84616 : }
38 :
39 84616 : AssemblerOptions BuiltinAssemblerOptions(Isolate* isolate,
40 : int32_t builtin_index) {
41 84616 : AssemblerOptions options = AssemblerOptions::Default(isolate);
42 84616 : CHECK(!options.isolate_independent_code);
43 84616 : CHECK(!options.use_pc_relative_calls_and_jumps);
44 :
45 84616 : if (!isolate->ShouldLoadConstantsFromRootList() ||
46 : !Builtins::IsIsolateIndependent(builtin_index)) {
47 : return options;
48 : }
49 :
50 84616 : const base::AddressRegion& code_range =
51 84616 : isolate->heap()->memory_allocator()->code_range();
52 : bool pc_relative_calls_fit_in_code_range =
53 169232 : !code_range.is_empty() &&
54 84616 : std::ceil(static_cast<float>(code_range.size() / MB)) <=
55 : kMaxPCRelativeCodeRangeInMB;
56 :
57 84616 : options.isolate_independent_code = true;
58 84616 : options.use_pc_relative_calls_and_jumps = pc_relative_calls_fit_in_code_range;
59 :
60 : return options;
61 : }
62 :
63 : typedef void (*MacroAssemblerGenerator)(MacroAssembler*);
64 : typedef void (*CodeAssemblerGenerator)(compiler::CodeAssemblerState*);
65 :
66 84616 : Handle<Code> BuildPlaceholder(Isolate* isolate, int32_t builtin_index) {
67 84616 : HandleScope scope(isolate);
68 : constexpr int kBufferSize = 1 * KB;
69 : byte buffer[kBufferSize];
70 : MacroAssembler masm(isolate, CodeObjectRequired::kYes,
71 253848 : ExternalAssemblerBuffer(buffer, kBufferSize));
72 : DCHECK(!masm.has_frame());
73 : {
74 84616 : FrameScope scope(&masm, StackFrame::NONE);
75 : // The contents of placeholder don't matter, as long as they don't create
76 : // embedded constants or external references.
77 84616 : masm.Move(kJavaScriptCallCodeStartRegister, Smi::zero());
78 84616 : masm.Call(kJavaScriptCallCodeStartRegister);
79 : }
80 84616 : CodeDesc desc;
81 84616 : masm.GetCode(isolate, &desc);
82 : Handle<Code> code = isolate->factory()->NewCode(
83 169232 : desc, Code::BUILTIN, masm.CodeObject(), builtin_index);
84 169232 : return scope.CloseAndEscape(code);
85 : }
86 :
87 4032 : Code BuildWithMacroAssembler(Isolate* isolate, int32_t builtin_index,
88 : MacroAssemblerGenerator generator,
89 : const char* s_name) {
90 4032 : HandleScope scope(isolate);
91 : // Canonicalize handles, so that we can share constant pool entries pointing
92 : // to code targets without dereferencing their handles.
93 8064 : CanonicalHandleScope canonical(isolate);
94 : constexpr int kBufferSize = 32 * KB;
95 : byte buffer[kBufferSize];
96 :
97 4032 : MacroAssembler masm(isolate, BuiltinAssemblerOptions(isolate, builtin_index),
98 : CodeObjectRequired::kYes,
99 16128 : ExternalAssemblerBuffer(buffer, kBufferSize));
100 : masm.set_builtin_index(builtin_index);
101 : DCHECK(!masm.has_frame());
102 4032 : generator(&masm);
103 :
104 : int handler_table_offset = 0;
105 :
106 : // JSEntry builtins are a special case and need to generate a handler table.
107 : DCHECK_EQ(Builtins::KindOf(Builtins::kJSEntry), Builtins::ASM);
108 : DCHECK_EQ(Builtins::KindOf(Builtins::kJSConstructEntry), Builtins::ASM);
109 : DCHECK_EQ(Builtins::KindOf(Builtins::kJSRunMicrotasksEntry), Builtins::ASM);
110 4032 : if (Builtins::IsJSEntryVariant(builtin_index)) {
111 : static constexpr int kJSEntryHandlerCount = 1;
112 : handler_table_offset =
113 168 : HandlerTable::EmitReturnTableStart(&masm, kJSEntryHandlerCount);
114 : HandlerTable::EmitReturnEntry(
115 168 : &masm, 0, isolate->builtins()->js_entry_handler_offset());
116 : }
117 :
118 4032 : CodeDesc desc;
119 4032 : masm.GetCode(isolate, &desc);
120 :
121 : static constexpr bool kIsNotTurbofanned = false;
122 : static constexpr int kStackSlots = 0;
123 : static constexpr int kSafepointTableOffset = 0;
124 :
125 : Handle<Code> code = isolate->factory()->NewCode(
126 : desc, Code::BUILTIN, masm.CodeObject(), builtin_index,
127 : MaybeHandle<ByteArray>(), DeoptimizationData::Empty(isolate), kMovable,
128 : kIsNotTurbofanned, kStackSlots, kSafepointTableOffset,
129 12096 : handler_table_offset);
130 4032 : PostBuildProfileAndTracing(isolate, *code, s_name);
131 4032 : return *code;
132 : }
133 :
134 15624 : Code BuildAdaptor(Isolate* isolate, int32_t builtin_index,
135 : Address builtin_address,
136 : Builtins::ExitFrameType exit_frame_type, const char* name) {
137 15624 : HandleScope scope(isolate);
138 : // Canonicalize handles, so that we can share constant pool entries pointing
139 : // to code targets without dereferencing their handles.
140 31248 : CanonicalHandleScope canonical(isolate);
141 : constexpr int kBufferSize = 32 * KB;
142 : byte buffer[kBufferSize];
143 15624 : MacroAssembler masm(isolate, BuiltinAssemblerOptions(isolate, builtin_index),
144 : CodeObjectRequired::kYes,
145 62496 : ExternalAssemblerBuffer(buffer, kBufferSize));
146 : masm.set_builtin_index(builtin_index);
147 : DCHECK(!masm.has_frame());
148 15624 : Builtins::Generate_Adaptor(&masm, builtin_address, exit_frame_type);
149 15624 : CodeDesc desc;
150 15624 : masm.GetCode(isolate, &desc);
151 : Handle<Code> code = isolate->factory()->NewCode(
152 31248 : desc, Code::BUILTIN, masm.CodeObject(), builtin_index);
153 15624 : PostBuildProfileAndTracing(isolate, *code, name);
154 15624 : return *code;
155 : }
156 :
157 : // Builder for builtins implemented in TurboFan with JS linkage.
158 56952 : Code BuildWithCodeStubAssemblerJS(Isolate* isolate, int32_t builtin_index,
159 : CodeAssemblerGenerator generator, int argc,
160 : const char* name) {
161 : HandleScope scope(isolate);
162 : // Canonicalize handles, so that we can share constant pool entries pointing
163 : // to code targets without dereferencing their handles.
164 37968 : CanonicalHandleScope canonical(isolate);
165 :
166 : SegmentSize segment_size = isolate->serializer_enabled()
167 : ? SegmentSize::kLarge
168 18984 : : SegmentSize::kDefault;
169 37968 : Zone zone(isolate->allocator(), ZONE_NAME, segment_size);
170 : const int argc_with_recv =
171 18984 : (argc == SharedFunctionInfo::kDontAdaptArgumentsSentinel) ? 0 : argc + 1;
172 : compiler::CodeAssemblerState state(
173 : isolate, &zone, argc_with_recv, Code::BUILTIN, name,
174 37968 : PoisoningMitigationLevel::kDontPoison, builtin_index);
175 18984 : generator(&state);
176 : Handle<Code> code = compiler::CodeAssembler::GenerateCode(
177 18984 : &state, BuiltinAssemblerOptions(isolate, builtin_index));
178 18984 : PostBuildProfileAndTracing(isolate, *code, name);
179 18984 : return *code;
180 : }
181 :
182 : // Builder for builtins implemented in TurboFan with CallStub linkage.
183 58296 : Code BuildWithCodeStubAssemblerCS(Isolate* isolate, int32_t builtin_index,
184 : CodeAssemblerGenerator generator,
185 : CallDescriptors::Key interface_descriptor,
186 : const char* name, int result_size) {
187 : HandleScope scope(isolate);
188 : // Canonicalize handles, so that we can share constant pool entries pointing
189 : // to code targets without dereferencing their handles.
190 38864 : CanonicalHandleScope canonical(isolate);
191 : SegmentSize segment_size = isolate->serializer_enabled()
192 : ? SegmentSize::kLarge
193 19432 : : SegmentSize::kDefault;
194 38864 : Zone zone(isolate->allocator(), ZONE_NAME, segment_size);
195 : // The interface descriptor with given key must be initialized at this point
196 : // and this construction just queries the details from the descriptors table.
197 : CallInterfaceDescriptor descriptor(interface_descriptor);
198 : // Ensure descriptor is already initialized.
199 : DCHECK_EQ(result_size, descriptor.GetReturnCount());
200 : DCHECK_LE(0, descriptor.GetRegisterParameterCount());
201 : compiler::CodeAssemblerState state(
202 : isolate, &zone, descriptor, Code::BUILTIN, name,
203 38864 : PoisoningMitigationLevel::kDontPoison, builtin_index);
204 19432 : generator(&state);
205 : Handle<Code> code = compiler::CodeAssembler::GenerateCode(
206 19432 : &state, BuiltinAssemblerOptions(isolate, builtin_index));
207 19432 : PostBuildProfileAndTracing(isolate, *code, name);
208 19432 : return *code;
209 : }
210 :
211 : } // anonymous namespace
212 :
213 : // static
214 0 : void SetupIsolateDelegate::AddBuiltin(Builtins* builtins, int index,
215 : Code code) {
216 : DCHECK_EQ(index, code->builtin_index());
217 169232 : builtins->set_builtin(index, code);
218 0 : }
219 :
220 : // static
221 56 : void SetupIsolateDelegate::PopulateWithPlaceholders(Isolate* isolate) {
222 : // Fill the builtins list with placeholders. References to these placeholder
223 : // builtins are eventually replaced by the actual builtins. This is to
224 : // support circular references between builtins.
225 56 : Builtins* builtins = isolate->builtins();
226 : HandleScope scope(isolate);
227 84672 : for (int i = 0; i < Builtins::builtin_count; i++) {
228 84616 : Handle<Code> placeholder = BuildPlaceholder(isolate, i);
229 : AddBuiltin(builtins, i, *placeholder);
230 : }
231 56 : }
232 :
233 : // static
234 56 : void SetupIsolateDelegate::ReplacePlaceholders(Isolate* isolate) {
235 : // Replace references from all code objects to placeholders.
236 56 : Builtins* builtins = isolate->builtins();
237 : DisallowHeapAllocation no_gc;
238 56 : CodeSpaceMemoryModificationScope modification_scope(isolate->heap());
239 : static const int kRelocMask =
240 : RelocInfo::ModeMask(RelocInfo::CODE_TARGET) |
241 : RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) |
242 : RelocInfo::ModeMask(RelocInfo::RELATIVE_CODE_TARGET);
243 112 : HeapIterator iterator(isolate->heap());
244 1444800 : for (HeapObject obj = iterator.next(); !obj.is_null();
245 : obj = iterator.next()) {
246 722344 : if (!obj->IsCode()) continue;
247 : Code code = Code::cast(obj);
248 : bool flush_icache = false;
249 1027936 : for (RelocIterator it(code, kRelocMask); !it.done(); it.next()) {
250 1606192 : RelocInfo* rinfo = it.rinfo();
251 803096 : if (RelocInfo::IsCodeTargetMode(rinfo->rmode())) {
252 803096 : Code target = Code::GetCodeFromTargetAddress(rinfo->target_address());
253 : DCHECK_IMPLIES(RelocInfo::IsRelativeCodeTarget(rinfo->rmode()),
254 : Builtins::IsIsolateIndependent(target->builtin_index()));
255 803096 : if (!target->is_builtin()) continue;
256 803096 : Code new_target = builtins->builtin(target->builtin_index());
257 : rinfo->set_target_address(new_target->raw_instruction_start(),
258 803096 : UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
259 : } else {
260 : DCHECK(RelocInfo::IsEmbeddedObject(rinfo->rmode()));
261 0 : Object object = rinfo->target_object();
262 0 : if (!object->IsCode()) continue;
263 : Code target = Code::cast(object);
264 0 : if (!target->is_builtin()) continue;
265 0 : Code new_target = builtins->builtin(target->builtin_index());
266 : rinfo->set_target_object(isolate->heap(), new_target,
267 : UPDATE_WRITE_BARRIER, SKIP_ICACHE_FLUSH);
268 : }
269 : flush_icache = true;
270 : }
271 224840 : if (flush_icache) {
272 : Assembler::FlushICache(code->raw_instruction_start(),
273 121520 : code->raw_instruction_size());
274 : }
275 56 : }
276 56 : }
277 :
278 : namespace {
279 :
280 26544 : Code GenerateBytecodeHandler(Isolate* isolate, int builtin_index,
281 : const char* name,
282 : interpreter::OperandScale operand_scale,
283 : interpreter::Bytecode bytecode) {
284 : DCHECK(interpreter::Bytecodes::BytecodeHasHandler(bytecode, operand_scale));
285 :
286 : Handle<Code> code = interpreter::GenerateBytecodeHandler(
287 : isolate, bytecode, operand_scale, builtin_index,
288 26544 : BuiltinAssemblerOptions(isolate, builtin_index));
289 :
290 26544 : PostBuildProfileAndTracing(isolate, *code, name);
291 :
292 26544 : return *code;
293 : }
294 :
295 : } // namespace
296 :
297 : // static
298 56 : void SetupIsolateDelegate::SetupBuiltinsInternal(Isolate* isolate) {
299 56 : Builtins* builtins = isolate->builtins();
300 : DCHECK(!builtins->initialized_);
301 :
302 56 : PopulateWithPlaceholders(isolate);
303 :
304 : // Create a scope for the handles in the builtins.
305 : HandleScope scope(isolate);
306 :
307 : int index = 0;
308 : Code code;
309 : #define BUILD_CPP(Name) \
310 : code = BuildAdaptor(isolate, index, FUNCTION_ADDR(Builtin_##Name), \
311 : Builtins::BUILTIN_EXIT, #Name); \
312 : AddBuiltin(builtins, index++, code);
313 : #define BUILD_API(Name) \
314 : code = BuildAdaptor(isolate, index, FUNCTION_ADDR(Builtin_##Name), \
315 : Builtins::EXIT, #Name); \
316 : AddBuiltin(builtins, index++, code);
317 : #define BUILD_TFJ(Name, Argc, ...) \
318 : code = BuildWithCodeStubAssemblerJS( \
319 : isolate, index, &Builtins::Generate_##Name, Argc, #Name); \
320 : AddBuiltin(builtins, index++, code);
321 : #define BUILD_TFC(Name, InterfaceDescriptor, result_size) \
322 : code = BuildWithCodeStubAssemblerCS( \
323 : isolate, index, &Builtins::Generate_##Name, \
324 : CallDescriptors::InterfaceDescriptor, #Name, result_size); \
325 : AddBuiltin(builtins, index++, code);
326 : #define BUILD_TFS(Name, ...) \
327 : /* Return size for generic TF builtins (stub linkage) is always 1. */ \
328 : code = \
329 : BuildWithCodeStubAssemblerCS(isolate, index, &Builtins::Generate_##Name, \
330 : CallDescriptors::Name, #Name, 1); \
331 : AddBuiltin(builtins, index++, code);
332 : #define BUILD_TFH(Name, InterfaceDescriptor) \
333 : /* Return size for IC builtins/handlers is always 1. */ \
334 : code = BuildWithCodeStubAssemblerCS( \
335 : isolate, index, &Builtins::Generate_##Name, \
336 : CallDescriptors::InterfaceDescriptor, #Name, 1); \
337 : AddBuiltin(builtins, index++, code);
338 :
339 : #define BUILD_BCH(Name, OperandScale, Bytecode) \
340 : code = GenerateBytecodeHandler(isolate, index, Builtins::name(index), \
341 : OperandScale, Bytecode); \
342 : AddBuiltin(builtins, index++, code);
343 :
344 : #define BUILD_ASM(Name, InterfaceDescriptor) \
345 : code = BuildWithMacroAssembler(isolate, index, Builtins::Generate_##Name, \
346 : #Name); \
347 : AddBuiltin(builtins, index++, code);
348 :
349 84616 : BUILTIN_LIST(BUILD_CPP, BUILD_API, BUILD_TFJ, BUILD_TFC, BUILD_TFS, BUILD_TFH,
350 : BUILD_BCH, BUILD_ASM);
351 :
352 : #undef BUILD_CPP
353 : #undef BUILD_API
354 : #undef BUILD_TFJ
355 : #undef BUILD_TFC
356 : #undef BUILD_TFS
357 : #undef BUILD_TFH
358 : #undef BUILD_BCH
359 : #undef BUILD_ASM
360 : CHECK_EQ(Builtins::builtin_count, index);
361 :
362 56 : ReplacePlaceholders(isolate);
363 :
364 : #define SET_PROMISE_REJECTION_PREDICTION(Name) \
365 : builtins->builtin(Builtins::k##Name)->set_is_promise_rejection(true);
366 :
367 56 : BUILTIN_PROMISE_REJECTION_PREDICTION_LIST(SET_PROMISE_REJECTION_PREDICTION)
368 : #undef SET_PROMISE_REJECTION_PREDICTION
369 :
370 : #define SET_EXCEPTION_CAUGHT_PREDICTION(Name) \
371 : builtins->builtin(Builtins::k##Name)->set_is_exception_caught(true);
372 :
373 56 : BUILTIN_EXCEPTION_CAUGHT_PREDICTION_LIST(SET_EXCEPTION_CAUGHT_PREDICTION)
374 : #undef SET_EXCEPTION_CAUGHT_PREDICTION
375 :
376 : builtins->MarkInitialized();
377 56 : }
378 :
379 : } // namespace internal
380 94089 : } // namespace v8
|