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