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