runtime.cc 10.5 KB
Newer Older
1
// Copyright 2012 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// 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 14
#include "src/objects/contexts.h"
#include "src/objects/objects-inl.h"
15
#include "src/runtime/runtime-utils.h"
16

17 18
namespace v8 {
namespace internal {
19

20 21
// Header of runtime functions.
#define F(name, number_of_args, result_size)                    \
22
  Address Runtime_##name(int args_length, Address* args_object, \
23
                         Isolate* isolate);
24 25
FOR_EACH_INTRINSIC_RETURN_OBJECT(F)
#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 34 35 36 37 38
#define F(name, number_of_args, result_size)                                  \
  {                                                                           \
    Runtime::k##name, Runtime::RUNTIME, #name, FUNCTION_ADDR(Runtime_##name), \
        number_of_args, result_size                                           \
  }                                                                           \
  ,
39 40


41 42 43 44 45
#define I(name, number_of_args, result_size)                       \
  {                                                                \
    Runtime::kInline##name, Runtime::INLINE, "_" #name,            \
        FUNCTION_ADDR(Runtime_##name), number_of_args, result_size \
  }                                                                \
46
  ,
47

48
static const Runtime::Function kIntrinsicFunctions[] = {
49
    FOR_EACH_INTRINSIC(F) FOR_EACH_INLINE_INTRINSIC(I)};
50

51 52 53
#undef I
#undef F

54
namespace {
55

56
V8_DECLARE_ONCE(initialize_function_name_map_once);
57
static const base::CustomMatcherHashMap* kRuntimeFunctionNameMap;
58 59 60 61 62 63 64 65 66 67 68

struct IntrinsicFunctionIdentifier {
  IntrinsicFunctionIdentifier(const unsigned char* data, const int length)
      : data_(data), length_(length) {}

  static bool Match(void* key1, void* key2) {
    const IntrinsicFunctionIdentifier* lhs =
        static_cast<IntrinsicFunctionIdentifier*>(key1);
    const IntrinsicFunctionIdentifier* rhs =
        static_cast<IntrinsicFunctionIdentifier*>(key2);
    if (lhs->length_ != rhs->length_) return false;
69
    return CompareCharsEqual(lhs->data_, rhs->data_, rhs->length_);
70 71 72 73 74
  }

  uint32_t Hash() {
    return StringHasher::HashSequentialString<uint8_t>(
        data_, length_, v8::internal::kZeroHashSeed);
75
  }
76

77 78 79 80 81
  const unsigned char* data_;
  const int length_;
};

void InitializeIntrinsicFunctionNames() {
82 83
  base::CustomMatcherHashMap* function_name_map =
      new base::CustomMatcherHashMap(IntrinsicFunctionIdentifier::Match);
84 85 86 87 88 89 90 91 92 93 94
  for (size_t i = 0; i < arraysize(kIntrinsicFunctions); ++i) {
    const Runtime::Function* function = &kIntrinsicFunctions[i];
    IntrinsicFunctionIdentifier* identifier = new IntrinsicFunctionIdentifier(
        reinterpret_cast<const unsigned char*>(function->name),
        static_cast<int>(strlen(function->name)));
    base::HashMap::Entry* entry =
        function_name_map->InsertNew(identifier, identifier->Hash());
    entry->value = const_cast<Runtime::Function*>(function);
  }
  kRuntimeFunctionNameMap = function_name_map;
}
95

96 97
}  // namespace

98 99
bool Runtime::NeedsExactContext(FunctionId id) {
  switch (id) {
100 101 102 103 104 105 106
    case Runtime::kInlineAsyncFunctionReject:
    case Runtime::kInlineAsyncFunctionResolve:
      // For %_AsyncFunctionReject and %_AsyncFunctionResolve we don't
      // really need the current context, which in particular allows
      // us to usually eliminate the catch context for the implicit
      // try-catch in async function.
      return false;
107
    case Runtime::kCreatePrivateAccessors:
108 109
    case Runtime::kCopyDataProperties:
    case Runtime::kCreateDataProperty:
110
    case Runtime::kCreatePrivateNameSymbol:
111
    case Runtime::kCreatePrivateBrandSymbol:
112 113
    case Runtime::kLoadPrivateGetter:
    case Runtime::kLoadPrivateSetter:
114
    case Runtime::kReThrow:
115
    case Runtime::kReThrowWithMessage:
116 117 118 119 120 121 122 123 124 125 126 127 128 129
    case Runtime::kThrow:
    case Runtime::kThrowApplyNonFunction:
    case Runtime::kThrowCalledNonCallable:
    case Runtime::kThrowConstAssignError:
    case Runtime::kThrowConstructorNonCallableError:
    case Runtime::kThrowConstructedNonConstructable:
    case Runtime::kThrowConstructorReturnedNonObject:
    case Runtime::kThrowInvalidStringLength:
    case Runtime::kThrowInvalidTypedArrayAlignment:
    case Runtime::kThrowIteratorError:
    case Runtime::kThrowIteratorResultNotAnObject:
    case Runtime::kThrowNotConstructor:
    case Runtime::kThrowRangeError:
    case Runtime::kThrowReferenceError:
130
    case Runtime::kThrowAccessedUninitializedVariable:
131 132 133 134 135 136 137 138 139
    case Runtime::kThrowStackOverflow:
    case Runtime::kThrowStaticPrototypeError:
    case Runtime::kThrowSuperAlreadyCalledError:
    case Runtime::kThrowSuperNotCalled:
    case Runtime::kThrowSymbolAsyncIteratorInvalid:
    case Runtime::kThrowSymbolIteratorInvalid:
    case Runtime::kThrowThrowMethodMissing:
    case Runtime::kThrowTypeError:
    case Runtime::kThrowUnsupportedSuperError:
140
#if V8_ENABLE_WEBASSEMBLY
141 142
    case Runtime::kThrowWasmError:
    case Runtime::kThrowWasmStackOverflow:
143
#endif  // V8_ENABLE_WEBASSEMBLY
144 145 146 147 148 149
      return false;
    default:
      return true;
  }
}

150 151 152 153 154 155 156 157
bool Runtime::IsNonReturning(FunctionId id) {
  switch (id) {
    case Runtime::kThrowUnsupportedSuperError:
    case Runtime::kThrowConstructorNonCallableError:
    case Runtime::kThrowStaticPrototypeError:
    case Runtime::kThrowSuperAlreadyCalledError:
    case Runtime::kThrowSuperNotCalled:
    case Runtime::kReThrow:
158
    case Runtime::kReThrowWithMessage:
159 160 161 162 163 164 165
    case Runtime::kThrow:
    case Runtime::kThrowApplyNonFunction:
    case Runtime::kThrowCalledNonCallable:
    case Runtime::kThrowConstructedNonConstructable:
    case Runtime::kThrowConstructorReturnedNonObject:
    case Runtime::kThrowInvalidStringLength:
    case Runtime::kThrowInvalidTypedArrayAlignment:
166
    case Runtime::kThrowIteratorError:
167 168 169 170 171 172
    case Runtime::kThrowIteratorResultNotAnObject:
    case Runtime::kThrowThrowMethodMissing:
    case Runtime::kThrowSymbolIteratorInvalid:
    case Runtime::kThrowNotConstructor:
    case Runtime::kThrowRangeError:
    case Runtime::kThrowReferenceError:
173
    case Runtime::kThrowAccessedUninitializedVariable:
174 175 176 177
    case Runtime::kThrowStackOverflow:
    case Runtime::kThrowSymbolAsyncIteratorInvalid:
    case Runtime::kThrowTypeError:
    case Runtime::kThrowConstAssignError:
178
#if V8_ENABLE_WEBASSEMBLY
179 180
    case Runtime::kThrowWasmError:
    case Runtime::kThrowWasmStackOverflow:
181
#endif  // V8_ENABLE_WEBASSEMBLY
182 183 184 185 186 187
      return true;
    default:
      return false;
  }
}

188 189 190 191 192 193 194 195 196 197
bool Runtime::MayAllocate(FunctionId id) {
  switch (id) {
    case Runtime::kCompleteInobjectSlackTracking:
    case Runtime::kCompleteInobjectSlackTrackingForMap:
      return false;
    default:
      return true;
  }
}

Dan Elphick's avatar
Dan Elphick committed
198
bool Runtime::IsAllowListedForFuzzing(FunctionId id) {
199
  CHECK(FLAG_fuzzing);
200
  switch (id) {
Dan Elphick's avatar
Dan Elphick committed
201
    // Runtime functions allowlisted for all fuzzers. Only add functions that
202
    // help increase coverage.
203 204 205
    case Runtime::kArrayBufferDetach:
    case Runtime::kDeoptimizeFunction:
    case Runtime::kDeoptimizeNow:
206
    case Runtime::kDisableOptimizationFinalization:
207
    case Runtime::kEnableCodeLoggingForTesting:
208
    case Runtime::kFinalizeOptimization:
209 210 211
    case Runtime::kGetUndetectable:
    case Runtime::kNeverOptimizeFunction:
    case Runtime::kOptimizeFunctionOnNextCall:
212
    case Runtime::kOptimizeOsr:
213
    case Runtime::kPrepareFunctionForOptimization:
214
    case Runtime::kPretenureAllocationSite:
215 216
    case Runtime::kSetAllocationTimeout:
    case Runtime::kSimulateNewspaceFull:
217
    case Runtime::kWaitForBackgroundOptimization:
218 219
      return true;
    // Runtime functions only permitted for non-differential fuzzers.
220 221
    // This list may contain functions performing extra checks or returning
    // different values in the context of different flags passed to V8.
222
    case Runtime::kGetOptimizationStatus:
223
    case Runtime::kHeapObjectVerify:
224 225
    case Runtime::kIsBeingInterpreted:
      return !FLAG_allow_natives_for_differential_fuzzing;
226 227 228
    case Runtime::kVerifyType:
      return !FLAG_allow_natives_for_differential_fuzzing &&
             !FLAG_concurrent_recompilation;
229
    case Runtime::kBaselineOsr:
230
    case Runtime::kCompileBaseline:
231
      return ENABLE_SPARKPLUG;
232 233 234 235 236
    default:
      return false;
  }
}

237 238 239 240 241 242 243 244 245
const Runtime::Function* Runtime::FunctionForName(const unsigned char* name,
                                                  int length) {
  base::CallOnce(&initialize_function_name_map_once,
                 &InitializeIntrinsicFunctionNames);
  IntrinsicFunctionIdentifier identifier(name, length);
  base::HashMap::Entry* entry =
      kRuntimeFunctionNameMap->Lookup(&identifier, identifier.Hash());
  if (entry) {
    return reinterpret_cast<Function*>(entry->value);
246
  }
247
  return nullptr;
248 249 250
}


251
const Runtime::Function* Runtime::FunctionForEntry(Address entry) {
252
  for (size_t i = 0; i < arraysize(kIntrinsicFunctions); ++i) {
253 254 255 256
    if (entry == kIntrinsicFunctions[i].entry) {
      return &(kIntrinsicFunctions[i]);
    }
  }
257
  return nullptr;
258 259 260
}


261
const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
262 263
  return &(kIntrinsicFunctions[static_cast<int>(id)]);
}
264

265
const Runtime::Function* Runtime::RuntimeFunctionTable(Isolate* isolate) {
266 267 268 269 270 271
#ifdef USE_SIMULATOR
  // When running with the simulator we need to provide a table which has
  // redirected runtime entry addresses.
  if (!isolate->runtime_state()->redirected_intrinsic_functions()) {
    size_t function_count = arraysize(kIntrinsicFunctions);
    Function* redirected_functions = new Function[function_count];
272 273
    memcpy(redirected_functions, kIntrinsicFunctions,
           sizeof(kIntrinsicFunctions));
274
    for (size_t i = 0; i < function_count; i++) {
275 276
      ExternalReference redirected_entry =
          ExternalReference::Create(static_cast<Runtime::FunctionId>(i));
277
      redirected_functions[i].entry = redirected_entry.address();
278
    }
279 280
    isolate->runtime_state()->set_redirected_intrinsic_functions(
        redirected_functions);
281 282
  }

283 284 285 286 287
  return isolate->runtime_state()->redirected_intrinsic_functions();
#else
  return kIntrinsicFunctions;
#endif
}
288

289 290
std::ostream& operator<<(std::ostream& os, Runtime::FunctionId id) {
  return os << Runtime::FunctionForId(id)->name;
291
}
292

293

294 295
}  // namespace internal
}  // namespace v8