Line data Source code
1 : // Copyright 2012 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/builtins/builtins.h"
6 : #include "src/api.h"
7 : #include "src/assembler-inl.h"
8 : #include "src/builtins/builtins-descriptors.h"
9 : #include "src/callable.h"
10 : #include "src/isolate.h"
11 : #include "src/macro-assembler.h"
12 : #include "src/objects-inl.h"
13 : #include "src/visitors.h"
14 :
15 : namespace v8 {
16 : namespace internal {
17 :
18 : // Forward declarations for C++ builtins.
19 : #define FORWARD_DECLARE(Name) \
20 : Object* Builtin_##Name(int argc, Object** args, Isolate* isolate);
21 : BUILTIN_LIST_C(FORWARD_DECLARE)
22 : #undef FORWARD_DECLARE
23 :
24 : namespace {
25 :
26 : // TODO(jgruber): Pack in CallDescriptors::Key.
27 : struct BuiltinMetadata {
28 : const char* name;
29 : Builtins::Kind kind;
30 : union {
31 : Address cpp_entry; // For CPP and API builtins.
32 : int8_t parameter_count; // For TFJ builtins.
33 : } kind_specific_data;
34 : };
35 :
36 : // clang-format off
37 : #define DECL_CPP(Name, ...) { #Name, Builtins::CPP, \
38 : { FUNCTION_ADDR(Builtin_##Name) }},
39 : #define DECL_API(Name, ...) { #Name, Builtins::API, \
40 : { FUNCTION_ADDR(Builtin_##Name) }},
41 : #ifdef V8_TARGET_BIG_ENDIAN
42 : #define DECL_TFJ(Name, Count, ...) { #Name, Builtins::TFJ, \
43 : { reinterpret_cast<Address>(static_cast<uintptr_t>( \
44 : Count) << (kBitsPerByte * (kPointerSize - 1))) }},
45 : #else
46 : #define DECL_TFJ(Name, Count, ...) { #Name, Builtins::TFJ, \
47 : { reinterpret_cast<Address>(Count) }},
48 : #endif
49 : #define DECL_TFC(Name, ...) { #Name, Builtins::TFC, {} },
50 : #define DECL_TFS(Name, ...) { #Name, Builtins::TFS, {} },
51 : #define DECL_TFH(Name, ...) { #Name, Builtins::TFH, {} },
52 : #define DECL_ASM(Name, ...) { #Name, Builtins::ASM, {} },
53 : const BuiltinMetadata builtin_metadata[] = {
54 : BUILTIN_LIST(DECL_CPP, DECL_API, DECL_TFJ, DECL_TFC, DECL_TFS, DECL_TFH,
55 : DECL_ASM)
56 : };
57 : #undef DECL_CPP
58 : #undef DECL_API
59 : #undef DECL_TFJ
60 : #undef DECL_TFC
61 : #undef DECL_TFS
62 : #undef DECL_TFH
63 : #undef DECL_ASM
64 : // clang-format on
65 :
66 : } // namespace
67 :
68 54999 : Builtins::Builtins() : initialized_(false) {
69 54999 : memset(builtins_, 0, sizeof(builtins_[0]) * builtin_count);
70 54999 : }
71 :
72 53365 : Builtins::~Builtins() {}
73 :
74 2935 : BailoutId Builtins::GetContinuationBailoutId(Name name) {
75 : DCHECK(Builtins::KindOf(name) == TFJ || Builtins::KindOf(name) == TFC);
76 2935 : return BailoutId(BailoutId::kFirstBuiltinContinuationId + name);
77 : }
78 :
79 892 : Builtins::Name Builtins::GetBuiltinFromBailoutId(BailoutId id) {
80 892 : int builtin_index = id.ToInt() - BailoutId::kFirstBuiltinContinuationId;
81 : DCHECK(Builtins::KindOf(builtin_index) == TFJ ||
82 : Builtins::KindOf(builtin_index) == TFC);
83 892 : return static_cast<Name>(builtin_index);
84 : }
85 :
86 53365 : void Builtins::TearDown() { initialized_ = false; }
87 :
88 202771 : void Builtins::IterateBuiltins(RootVisitor* v) {
89 : v->VisitRootPointers(Root::kBuiltins, &builtins_[0],
90 202771 : &builtins_[0] + builtin_count);
91 202771 : }
92 :
93 0 : const char* Builtins::Lookup(byte* pc) {
94 : // may be called during initialization (disassembler!)
95 0 : if (initialized_) {
96 0 : for (int i = 0; i < builtin_count; i++) {
97 0 : Code* entry = Code::cast(builtins_[i]);
98 0 : if (entry->contains(pc)) return name(i);
99 : }
100 : }
101 : return nullptr;
102 : }
103 :
104 5491 : Handle<Code> Builtins::NewFunctionContext(ScopeType scope_type) {
105 5491 : switch (scope_type) {
106 : case ScopeType::EVAL_SCOPE:
107 : return builtin_handle(kFastNewFunctionContextEval);
108 : case ScopeType::FUNCTION_SCOPE:
109 : return builtin_handle(kFastNewFunctionContextFunction);
110 : default:
111 0 : UNREACHABLE();
112 : }
113 : return Handle<Code>::null();
114 : }
115 :
116 1990 : Handle<Code> Builtins::NonPrimitiveToPrimitive(ToPrimitiveHint hint) {
117 1990 : switch (hint) {
118 : case ToPrimitiveHint::kDefault:
119 : return builtin_handle(kNonPrimitiveToPrimitive_Default);
120 : case ToPrimitiveHint::kNumber:
121 : return builtin_handle(kNonPrimitiveToPrimitive_Number);
122 : case ToPrimitiveHint::kString:
123 : return builtin_handle(kNonPrimitiveToPrimitive_String);
124 : }
125 0 : UNREACHABLE();
126 : }
127 :
128 155 : Handle<Code> Builtins::OrdinaryToPrimitive(OrdinaryToPrimitiveHint hint) {
129 155 : switch (hint) {
130 : case OrdinaryToPrimitiveHint::kNumber:
131 : return builtin_handle(kOrdinaryToPrimitive_Number);
132 : case OrdinaryToPrimitiveHint::kString:
133 : return builtin_handle(kOrdinaryToPrimitive_String);
134 : }
135 0 : UNREACHABLE();
136 : }
137 :
138 63573869 : void Builtins::set_builtin(int index, HeapObject* builtin) {
139 : DCHECK(Builtins::IsBuiltinId(index));
140 : DCHECK(Internals::HasHeapObjectTag(builtin));
141 : // The given builtin may be completely uninitialized thus we cannot check its
142 : // type here.
143 63573869 : builtins_[index] = builtin;
144 63573869 : }
145 :
146 18481939 : Handle<Code> Builtins::builtin_handle(int index) {
147 : DCHECK(IsBuiltinId(index));
148 18520627 : return Handle<Code>(reinterpret_cast<Code**>(builtin_address(index)));
149 : }
150 :
151 : // static
152 0 : int Builtins::GetStackParameterCount(Name name) {
153 : DCHECK(Builtins::KindOf(name) == TFJ);
154 0 : return builtin_metadata[name].kind_specific_data.parameter_count;
155 : }
156 :
157 : // static
158 2109831 : Callable Builtins::CallableFor(Isolate* isolate, Name name) {
159 : Handle<Code> code(
160 2109831 : reinterpret_cast<Code**>(isolate->builtins()->builtin_address(name)));
161 : CallDescriptors::Key key;
162 2109831 : switch (name) {
163 : // This macro is deliberately crafted so as to emit very little code,
164 : // in order to keep binary size of this function under control.
165 : #define CASE_OTHER(Name, ...) \
166 : case k##Name: { \
167 : key = Builtin_##Name##_InterfaceDescriptor::key(); \
168 : break; \
169 : }
170 0 : BUILTIN_LIST(IGNORE_BUILTIN, IGNORE_BUILTIN, IGNORE_BUILTIN, CASE_OTHER,
171 : CASE_OTHER, CASE_OTHER, IGNORE_BUILTIN)
172 : #undef CASE_OTHER
173 : case kConsoleAssert: {
174 62 : return Callable(code, BuiltinDescriptor(isolate));
175 : }
176 : case kArrayForEach: {
177 : Handle<Code> code = BUILTIN_CODE(isolate, ArrayForEach);
178 0 : return Callable(code, BuiltinDescriptor(isolate));
179 : }
180 : case kArrayForEachLoopEagerDeoptContinuation: {
181 : Handle<Code> code =
182 : BUILTIN_CODE(isolate, ArrayForEachLoopEagerDeoptContinuation);
183 960 : return Callable(code, BuiltinDescriptor(isolate));
184 : }
185 : case kArrayForEachLoopLazyDeoptContinuation: {
186 : Handle<Code> code =
187 : BUILTIN_CODE(isolate, ArrayForEachLoopLazyDeoptContinuation);
188 2044 : return Callable(code, BuiltinDescriptor(isolate));
189 : }
190 : case kArrayMapLoopEagerDeoptContinuation: {
191 : Handle<Code> code =
192 : BUILTIN_CODE(isolate, ArrayMapLoopEagerDeoptContinuation);
193 692 : return Callable(code, BuiltinDescriptor(isolate));
194 : }
195 : case kArrayMapLoopLazyDeoptContinuation: {
196 : Handle<Code> code =
197 : BUILTIN_CODE(isolate, ArrayMapLoopLazyDeoptContinuation);
198 1468 : return Callable(code, BuiltinDescriptor(isolate));
199 : }
200 : default:
201 0 : UNREACHABLE();
202 : }
203 : CallInterfaceDescriptor descriptor(isolate, key);
204 : return Callable(code, descriptor);
205 : }
206 :
207 : // static
208 255095 : const char* Builtins::name(int index) {
209 : DCHECK(IsBuiltinId(index));
210 255095 : return builtin_metadata[index].name;
211 : }
212 :
213 : // static
214 7920 : Address Builtins::CppEntryOf(int index) {
215 : DCHECK(Builtins::HasCppImplementation(index));
216 7920 : return builtin_metadata[index].kind_specific_data.cpp_entry;
217 : }
218 :
219 : // static
220 366913850 : bool Builtins::IsLazy(int index) {
221 : DCHECK(IsBuiltinId(index));
222 : // There are a couple of reasons that builtins can require eager-loading,
223 : // i.e. deserialization at isolate creation instead of on-demand. For
224 : // instance:
225 : // * DeserializeLazy implements lazy loading.
226 : // * Immovability requirement. This can only conveniently be guaranteed at
227 : // isolate creation (at runtime, we'd have to allocate in LO space).
228 : // * To avoid conflicts in SharedFunctionInfo::function_data (Illegal,
229 : // HandleApiCall, interpreter entry trampolines).
230 : // * Frequent use makes lazy loading unnecessary (CompileLazy).
231 : // TODO(wasm): Remove wasm builtins once immovability is no longer required.
232 366913850 : switch (index) {
233 : case kAbort: // Required by wasm.
234 : case kArrayForEachLoopEagerDeoptContinuation: // https://crbug.com/v8/6786.
235 : case kArrayForEachLoopLazyDeoptContinuation: // https://crbug.com/v8/6786.
236 : case kArrayMapLoopEagerDeoptContinuation: // https://crbug.com/v8/6786.
237 : case kArrayMapLoopLazyDeoptContinuation: // https://crbug.com/v8/6786.
238 : case kCheckOptimizationMarker:
239 : case kCompileLazy:
240 : case kDeserializeLazy:
241 : case kFunctionPrototypeHasInstance: // https://crbug.com/v8/6786.
242 : case kHandleApiCall:
243 : case kIllegal:
244 : case kInterpreterEnterBytecodeAdvance:
245 : case kInterpreterEnterBytecodeDispatch:
246 : case kInterpreterEntryTrampoline:
247 : case kObjectConstructor_ConstructStub: // https://crbug.com/v8/6787.
248 : case kProxyConstructor_ConstructStub: // https://crbug.com/v8/6787.
249 : case kNumberConstructor_ConstructStub: // https://crbug.com/v8/6787.
250 : case kStringConstructor_ConstructStub: // https://crbug.com/v8/6787.
251 : case kProxyConstructor: // https://crbug.com/v8/6787.
252 : case kRecordWrite: // https://crbug.com/chromium/765301.
253 : case kThrowWasmTrapDivByZero: // Required by wasm.
254 : case kThrowWasmTrapDivUnrepresentable: // Required by wasm.
255 : case kThrowWasmTrapFloatUnrepresentable: // Required by wasm.
256 : case kThrowWasmTrapFuncInvalid: // Required by wasm.
257 : case kThrowWasmTrapFuncSigMismatch: // Required by wasm.
258 : case kThrowWasmTrapMemOutOfBounds: // Required by wasm.
259 : case kThrowWasmTrapRemByZero: // Required by wasm.
260 : case kThrowWasmTrapUnreachable: // Required by wasm.
261 : case kToNumber: // Required by wasm.
262 : case kWasmCompileLazy: // Required by wasm.
263 : case kWasmStackGuard: // Required by wasm.
264 : return false;
265 : default:
266 : // TODO(6624): Extend to other kinds.
267 280613472 : return KindOf(index) == TFJ;
268 : }
269 : UNREACHABLE();
270 : }
271 :
272 : // static
273 0 : Builtins::Kind Builtins::KindOf(int index) {
274 : DCHECK(IsBuiltinId(index));
275 280781359 : return builtin_metadata[index].kind;
276 : }
277 :
278 : // static
279 0 : const char* Builtins::KindNameOf(int index) {
280 : Kind kind = Builtins::KindOf(index);
281 : // clang-format off
282 0 : switch (kind) {
283 : case CPP: return "CPP";
284 0 : case API: return "API";
285 0 : case TFJ: return "TFJ";
286 0 : case TFC: return "TFC";
287 0 : case TFS: return "TFS";
288 0 : case TFH: return "TFH";
289 0 : case ASM: return "ASM";
290 : }
291 : // clang-format on
292 0 : UNREACHABLE();
293 : }
294 :
295 : // static
296 15680 : bool Builtins::IsCpp(int index) { return Builtins::KindOf(index) == CPP; }
297 :
298 : // static
299 160047 : bool Builtins::HasCppImplementation(int index) {
300 : Kind kind = Builtins::KindOf(index);
301 160047 : return (kind == CPP || kind == API);
302 : }
303 :
304 7858314 : Handle<Code> Builtins::JSConstructStubGeneric() {
305 : return FLAG_harmony_restrict_constructor_return
306 : ? builtin_handle(kJSConstructStubGenericRestrictedReturn)
307 15716628 : : builtin_handle(kJSConstructStubGenericUnrestrictedReturn);
308 : }
309 :
310 : // static
311 2397150 : bool Builtins::AllowDynamicFunction(Isolate* isolate, Handle<JSFunction> target,
312 : Handle<JSObject> target_global_proxy) {
313 1198683 : if (FLAG_allow_unsafe_function_constructor) return true;
314 : HandleScopeImplementer* impl = isolate->handle_scope_implementer();
315 : Handle<Context> responsible_context =
316 : impl->MicrotaskContextIsLastEnteredContext() ? impl->MicrotaskContext()
317 1198467 : : impl->LastEnteredContext();
318 : // TODO(jochen): Remove this.
319 1198467 : if (responsible_context.is_null()) {
320 : return true;
321 : }
322 1198467 : if (*responsible_context == target->context()) return true;
323 285 : return isolate->MayAccess(responsible_context, target_global_proxy);
324 : }
325 :
326 : } // namespace internal
327 : } // namespace v8
|