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