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/runtime/runtime.h"
6
7 #include "src/base/hashmap.h"
8 #include "src/base/platform/wrappers.h"
9 #include "src/codegen/reloc-info.h"
10 #include "src/execution/isolate.h"
11 #include "src/handles/handles-inl.h"
12 #include "src/heap/heap.h"
13 #include "src/objects/contexts.h"
14 #include "src/objects/objects-inl.h"
15 #include "src/runtime/runtime-utils.h"
16
17 namespace v8 {
18 namespace internal {
19
20 // Header of runtime functions.
21 #define F(name, number_of_args, result_size) \
22 Address Runtime_##name(int args_length, Address* args_object, \
23 Isolate* isolate);
24 FOR_EACH_INTRINSIC_RETURN_OBJECT(F)
25 #undef F
26
27 #define P(name, number_of_args, result_size) \
28 ObjectPair Runtime_##name(int args_length, Address* args_object, \
29 Isolate* isolate);
30 FOR_EACH_INTRINSIC_RETURN_PAIR(P)
31 #undef P
32
33 #define F(name, number_of_args, result_size) \
34 { \
35 Runtime::k##name, Runtime::RUNTIME, #name, FUNCTION_ADDR(Runtime_##name), \
36 number_of_args, result_size \
37 } \
38 ,
39
40
41 #define I(name, number_of_args, result_size) \
42 { \
43 Runtime::kInline##name, Runtime::INLINE, "_" #name, \
44 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size \
45 } \
46 ,
47
48 static const Runtime::Function kIntrinsicFunctions[] = {
49 FOR_EACH_INTRINSIC(F) FOR_EACH_INLINE_INTRINSIC(I)};
50
51 #undef I
52 #undef F
53
54 namespace {
55
56 V8_DECLARE_ONCE(initialize_function_name_map_once);
57 static const base::CustomMatcherHashMap* kRuntimeFunctionNameMap;
58
59 struct IntrinsicFunctionIdentifier {
IntrinsicFunctionIdentifierv8::internal::__anon198ba05e0111::IntrinsicFunctionIdentifier60 IntrinsicFunctionIdentifier(const unsigned char* data, const int length)
61 : data_(data), length_(length) {}
62
Matchv8::internal::__anon198ba05e0111::IntrinsicFunctionIdentifier63 static bool Match(void* key1, void* key2) {
64 const IntrinsicFunctionIdentifier* lhs =
65 static_cast<IntrinsicFunctionIdentifier*>(key1);
66 const IntrinsicFunctionIdentifier* rhs =
67 static_cast<IntrinsicFunctionIdentifier*>(key2);
68 if (lhs->length_ != rhs->length_) return false;
69 return CompareCharsEqual(lhs->data_, rhs->data_, rhs->length_);
70 }
71
Hashv8::internal::__anon198ba05e0111::IntrinsicFunctionIdentifier72 uint32_t Hash() {
73 return StringHasher::HashSequentialString<uint8_t>(
74 data_, length_, v8::internal::kZeroHashSeed);
75 }
76
77 const unsigned char* data_;
78 const int length_;
79 };
80
InitializeIntrinsicFunctionNames()81 void InitializeIntrinsicFunctionNames() {
82 base::CustomMatcherHashMap* function_name_map =
83 new base::CustomMatcherHashMap(IntrinsicFunctionIdentifier::Match);
84 for (size_t i = 0; i < arraysize(kIntrinsicFunctions); ++i) {
85 const Runtime::Function* function = &kIntrinsicFunctions[i];
86 IntrinsicFunctionIdentifier* identifier = new IntrinsicFunctionIdentifier(
87 reinterpret_cast<const unsigned char*>(function->name),
88 static_cast<int>(strlen(function->name)));
89 base::HashMap::Entry* entry =
90 function_name_map->InsertNew(identifier, identifier->Hash());
91 entry->value = const_cast<Runtime::Function*>(function);
92 }
93 kRuntimeFunctionNameMap = function_name_map;
94 }
95
96 } // namespace
97
NeedsExactContext(FunctionId id)98 bool Runtime::NeedsExactContext(FunctionId id) {
99 switch (id) {
100 case Runtime::kInlineAsyncFunctionReject:
101 case Runtime::kInlineAsyncFunctionResolve:
102 // For %_AsyncFunctionReject and %_AsyncFunctionResolve we don't
103 // really need the current context, which in particular allows
104 // us to usually eliminate the catch context for the implicit
105 // try-catch in async function.
106 return false;
107 case Runtime::kCreatePrivateAccessors:
108 case Runtime::kCopyDataProperties:
109 case Runtime::kCreateDataProperty:
110 case Runtime::kCreatePrivateNameSymbol:
111 case Runtime::kCreatePrivateBrandSymbol:
112 case Runtime::kLoadPrivateGetter:
113 case Runtime::kLoadPrivateSetter:
114 case Runtime::kReThrow:
115 case Runtime::kReThrowWithMessage:
116 case Runtime::kThrow:
117 case Runtime::kThrowApplyNonFunction:
118 case Runtime::kThrowCalledNonCallable:
119 case Runtime::kThrowConstAssignError:
120 case Runtime::kThrowConstructorNonCallableError:
121 case Runtime::kThrowConstructedNonConstructable:
122 case Runtime::kThrowConstructorReturnedNonObject:
123 case Runtime::kThrowInvalidStringLength:
124 case Runtime::kThrowInvalidTypedArrayAlignment:
125 case Runtime::kThrowIteratorError:
126 case Runtime::kThrowIteratorResultNotAnObject:
127 case Runtime::kThrowNotConstructor:
128 case Runtime::kThrowRangeError:
129 case Runtime::kThrowReferenceError:
130 case Runtime::kThrowAccessedUninitializedVariable:
131 case Runtime::kThrowStackOverflow:
132 case Runtime::kThrowStaticPrototypeError:
133 case Runtime::kThrowSuperAlreadyCalledError:
134 case Runtime::kThrowSuperNotCalled:
135 case Runtime::kThrowSymbolAsyncIteratorInvalid:
136 case Runtime::kThrowSymbolIteratorInvalid:
137 case Runtime::kThrowThrowMethodMissing:
138 case Runtime::kThrowTypeError:
139 case Runtime::kThrowUnsupportedSuperError:
140 #if V8_ENABLE_WEBASSEMBLY
141 case Runtime::kThrowWasmError:
142 case Runtime::kThrowWasmStackOverflow:
143 #endif // V8_ENABLE_WEBASSEMBLY
144 return false;
145 default:
146 return true;
147 }
148 }
149
IsNonReturning(FunctionId id)150 bool Runtime::IsNonReturning(FunctionId id) {
151 switch (id) {
152 case Runtime::kThrowUnsupportedSuperError:
153 case Runtime::kThrowConstructorNonCallableError:
154 case Runtime::kThrowStaticPrototypeError:
155 case Runtime::kThrowSuperAlreadyCalledError:
156 case Runtime::kThrowSuperNotCalled:
157 case Runtime::kReThrow:
158 case Runtime::kReThrowWithMessage:
159 case Runtime::kThrow:
160 case Runtime::kThrowApplyNonFunction:
161 case Runtime::kThrowCalledNonCallable:
162 case Runtime::kThrowConstructedNonConstructable:
163 case Runtime::kThrowConstructorReturnedNonObject:
164 case Runtime::kThrowInvalidStringLength:
165 case Runtime::kThrowInvalidTypedArrayAlignment:
166 case Runtime::kThrowIteratorError:
167 case Runtime::kThrowIteratorResultNotAnObject:
168 case Runtime::kThrowThrowMethodMissing:
169 case Runtime::kThrowSymbolIteratorInvalid:
170 case Runtime::kThrowNotConstructor:
171 case Runtime::kThrowRangeError:
172 case Runtime::kThrowReferenceError:
173 case Runtime::kThrowAccessedUninitializedVariable:
174 case Runtime::kThrowStackOverflow:
175 case Runtime::kThrowSymbolAsyncIteratorInvalid:
176 case Runtime::kThrowTypeError:
177 case Runtime::kThrowConstAssignError:
178 #if V8_ENABLE_WEBASSEMBLY
179 case Runtime::kThrowWasmError:
180 case Runtime::kThrowWasmStackOverflow:
181 #endif // V8_ENABLE_WEBASSEMBLY
182 return true;
183 default:
184 return false;
185 }
186 }
187
MayAllocate(FunctionId id)188 bool Runtime::MayAllocate(FunctionId id) {
189 switch (id) {
190 case Runtime::kCompleteInobjectSlackTracking:
191 case Runtime::kCompleteInobjectSlackTrackingForMap:
192 return false;
193 default:
194 return true;
195 }
196 }
197
IsAllowListedForFuzzing(FunctionId id)198 bool Runtime::IsAllowListedForFuzzing(FunctionId id) {
199 CHECK(FLAG_fuzzing);
200 switch (id) {
201 // Runtime functions allowlisted for all fuzzers. Only add functions that
202 // help increase coverage.
203 case Runtime::kArrayBufferDetach:
204 case Runtime::kDeoptimizeFunction:
205 case Runtime::kDeoptimizeNow:
206 case Runtime::kDisableOptimizationFinalization:
207 case Runtime::kEnableCodeLoggingForTesting:
208 case Runtime::kFinalizeOptimization:
209 case Runtime::kGetUndetectable:
210 case Runtime::kNeverOptimizeFunction:
211 case Runtime::kOptimizeFunctionOnNextCall:
212 case Runtime::kOptimizeOsr:
213 case Runtime::kPrepareFunctionForOptimization:
214 case Runtime::kPretenureAllocationSite:
215 case Runtime::kSetAllocationTimeout:
216 case Runtime::kSimulateNewspaceFull:
217 case Runtime::kWaitForBackgroundOptimization:
218 return true;
219 // Runtime functions only permitted for non-differential fuzzers.
220 // This list may contain functions performing extra checks or returning
221 // different values in the context of different flags passed to V8.
222 case Runtime::kGetOptimizationStatus:
223 case Runtime::kHeapObjectVerify:
224 case Runtime::kIsBeingInterpreted:
225 return !FLAG_allow_natives_for_differential_fuzzing;
226 case Runtime::kVerifyType:
227 return !FLAG_allow_natives_for_differential_fuzzing &&
228 !FLAG_concurrent_recompilation;
229 case Runtime::kBaselineOsr:
230 case Runtime::kCompileBaseline:
231 return ENABLE_SPARKPLUG;
232 default:
233 return false;
234 }
235 }
236
FunctionForName(const unsigned char * name,int length)237 const Runtime::Function* Runtime::FunctionForName(const unsigned char* name,
238 int length) {
239 base::CallOnce(&initialize_function_name_map_once,
240 &InitializeIntrinsicFunctionNames);
241 IntrinsicFunctionIdentifier identifier(name, length);
242 base::HashMap::Entry* entry =
243 kRuntimeFunctionNameMap->Lookup(&identifier, identifier.Hash());
244 if (entry) {
245 return reinterpret_cast<Function*>(entry->value);
246 }
247 return nullptr;
248 }
249
250
FunctionForEntry(Address entry)251 const Runtime::Function* Runtime::FunctionForEntry(Address entry) {
252 for (size_t i = 0; i < arraysize(kIntrinsicFunctions); ++i) {
253 if (entry == kIntrinsicFunctions[i].entry) {
254 return &(kIntrinsicFunctions[i]);
255 }
256 }
257 return nullptr;
258 }
259
260
FunctionForId(Runtime::FunctionId id)261 const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
262 return &(kIntrinsicFunctions[static_cast<int>(id)]);
263 }
264
RuntimeFunctionTable(Isolate * isolate)265 const Runtime::Function* Runtime::RuntimeFunctionTable(Isolate* isolate) {
266 #ifdef USE_SIMULATOR
267 // When running with the simulator we need to provide a table which has
268 // redirected runtime entry addresses.
269 if (!isolate->runtime_state()->redirected_intrinsic_functions()) {
270 size_t function_count = arraysize(kIntrinsicFunctions);
271 Function* redirected_functions = new Function[function_count];
272 memcpy(redirected_functions, kIntrinsicFunctions,
273 sizeof(kIntrinsicFunctions));
274 for (size_t i = 0; i < function_count; i++) {
275 ExternalReference redirected_entry =
276 ExternalReference::Create(static_cast<Runtime::FunctionId>(i));
277 redirected_functions[i].entry = redirected_entry.address();
278 }
279 isolate->runtime_state()->set_redirected_intrinsic_functions(
280 redirected_functions);
281 }
282
283 return isolate->runtime_state()->redirected_intrinsic_functions();
284 #else
285 return kIntrinsicFunctions;
286 #endif
287 }
288
operator <<(std::ostream & os,Runtime::FunctionId id)289 std::ostream& operator<<(std::ostream& os, Runtime::FunctionId id) {
290 return os << Runtime::FunctionForId(id)->name;
291 }
292
293
294 } // namespace internal
295 } // namespace v8
296