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