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