• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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