| Rubin Xu | 7bc1b61 | 2021-02-16 09:38:50 +0000 | [diff] [blame^] | 1 | // Copyright 2009 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 | #ifndef V8_EXECUTION_SIMULATOR_H_ |
| 6 | #define V8_EXECUTION_SIMULATOR_H_ |
| 7 | |
| 8 | #include "src/common/globals.h" |
| 9 | #include "src/objects/code.h" |
| 10 | |
| 11 | #if !defined(USE_SIMULATOR) |
| 12 | #include "src/utils/utils.h" |
| 13 | #endif |
| 14 | |
| 15 | #if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_X64 |
| 16 | // No simulator for ia32 or x64. |
| 17 | #elif V8_TARGET_ARCH_ARM64 |
| 18 | #include "src/execution/arm64/simulator-arm64.h" |
| 19 | #elif V8_TARGET_ARCH_ARM |
| 20 | #include "src/execution/arm/simulator-arm.h" |
| 21 | #elif V8_TARGET_ARCH_PPC || V8_TARGET_ARCH_PPC64 |
| 22 | #include "src/execution/ppc/simulator-ppc.h" |
| 23 | #elif V8_TARGET_ARCH_MIPS |
| 24 | #include "src/execution/mips/simulator-mips.h" |
| 25 | #elif V8_TARGET_ARCH_MIPS64 |
| 26 | #include "src/execution/mips64/simulator-mips64.h" |
| 27 | #elif V8_TARGET_ARCH_S390 |
| 28 | #include "src/execution/s390/simulator-s390.h" |
| 29 | #else |
| 30 | #error Unsupported target architecture. |
| 31 | #endif |
| 32 | |
| 33 | namespace v8 { |
| 34 | namespace internal { |
| 35 | |
| 36 | #if defined(USE_SIMULATOR) |
| 37 | // Running with a simulator. |
| 38 | |
| 39 | // The simulator has its own stack. Thus it has a different stack limit from |
| 40 | // the C-based native code. The JS-based limit normally points near the end of |
| 41 | // the simulator stack. When the C-based limit is exhausted we reflect that by |
| 42 | // lowering the JS-based limit as well, to make stack checks trigger. |
| 43 | class SimulatorStack : public v8::internal::AllStatic { |
| 44 | public: |
| 45 | static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate, |
| 46 | uintptr_t c_limit) { |
| 47 | return Simulator::current(isolate)->StackLimit(c_limit); |
| 48 | } |
| 49 | |
| 50 | // Returns the current stack address on the simulator stack frame. |
| 51 | // The returned address is comparable with JS stack address. |
| 52 | static inline uintptr_t RegisterJSStackComparableAddress( |
| 53 | v8::internal::Isolate* isolate) { |
| 54 | // The value of |kPlaceHolder| is actually not used. It just occupies a |
| 55 | // single word on the stack frame of the simulator. |
| 56 | const uintptr_t kPlaceHolder = 0x4A535350u; // "JSSP" in ASCII |
| 57 | return Simulator::current(isolate)->PushAddress(kPlaceHolder); |
| 58 | } |
| 59 | |
| 60 | static inline void UnregisterJSStackComparableAddress( |
| 61 | v8::internal::Isolate* isolate) { |
| 62 | Simulator::current(isolate)->PopAddress(); |
| 63 | } |
| 64 | }; |
| 65 | |
| 66 | #else // defined(USE_SIMULATOR) |
| 67 | // Running without a simulator on a native platform. |
| 68 | |
| 69 | // The stack limit beyond which we will throw stack overflow errors in |
| 70 | // generated code. Because generated code uses the C stack, we just use |
| 71 | // the C stack limit. |
| 72 | class SimulatorStack : public v8::internal::AllStatic { |
| 73 | public: |
| 74 | static inline uintptr_t JsLimitFromCLimit(v8::internal::Isolate* isolate, |
| 75 | uintptr_t c_limit) { |
| 76 | USE(isolate); |
| 77 | return c_limit; |
| 78 | } |
| 79 | |
| 80 | // Returns the current stack address on the native stack frame. |
| 81 | // The returned address is comparable with JS stack address. |
| 82 | static inline uintptr_t RegisterJSStackComparableAddress( |
| 83 | v8::internal::Isolate* isolate) { |
| 84 | USE(isolate); |
| 85 | return internal::GetCurrentStackPosition(); |
| 86 | } |
| 87 | |
| 88 | static inline void UnregisterJSStackComparableAddress( |
| 89 | v8::internal::Isolate* isolate) { |
| 90 | USE(isolate); |
| 91 | } |
| 92 | }; |
| 93 | |
| 94 | #endif // defined(USE_SIMULATOR) |
| 95 | |
| 96 | // Use this class either as {GeneratedCode<ret, arg1, arg2>} or |
| 97 | // {GeneratedCode<ret(arg1, arg2)>} (see specialization below). |
| 98 | template <typename Return, typename... Args> |
| 99 | class GeneratedCode { |
| 100 | public: |
| 101 | using Signature = Return(Args...); |
| 102 | |
| 103 | static GeneratedCode FromAddress(Isolate* isolate, Address addr) { |
| 104 | return GeneratedCode(isolate, reinterpret_cast<Signature*>(addr)); |
| 105 | } |
| 106 | |
| 107 | static GeneratedCode FromBuffer(Isolate* isolate, byte* buffer) { |
| 108 | return GeneratedCode(isolate, reinterpret_cast<Signature*>(buffer)); |
| 109 | } |
| 110 | |
| 111 | static GeneratedCode FromCode(Code code) { |
| 112 | return FromAddress(code.GetIsolate(), code.entry()); |
| 113 | } |
| 114 | |
| 115 | #ifdef USE_SIMULATOR |
| 116 | // Defined in simulator-base.h. |
| 117 | Return Call(Args... args) { |
| 118 | #if defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN) |
| 119 | FATAL("Generated code execution not possible during cross-compilation."); |
| 120 | #endif // defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN) |
| 121 | return Simulator::current(isolate_)->template Call<Return>( |
| 122 | reinterpret_cast<Address>(fn_ptr_), args...); |
| 123 | } |
| 124 | #else |
| 125 | |
| 126 | DISABLE_CFI_ICALL Return Call(Args... args) { |
| 127 | // When running without a simulator we call the entry directly. |
| 128 | #if defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN) |
| 129 | FATAL("Generated code execution not possible during cross-compilation."); |
| 130 | #endif // defined(V8_TARGET_OS_WIN) && !defined(V8_OS_WIN) |
| 131 | #if ABI_USES_FUNCTION_DESCRIPTORS |
| 132 | // AIX ABI requires function descriptors (FD). Artificially create a pseudo |
| 133 | // FD to ensure correct dispatch to generated code. The 'volatile' |
| 134 | // declaration is required to avoid the compiler from not observing the |
| 135 | // alias of the pseudo FD to the function pointer, and hence, optimizing the |
| 136 | // pseudo FD declaration/initialization away. |
| 137 | volatile Address function_desc[] = {reinterpret_cast<Address>(fn_ptr_), 0, |
| 138 | 0}; |
| 139 | Signature* fn = reinterpret_cast<Signature*>(function_desc); |
| 140 | return fn(args...); |
| 141 | #else |
| 142 | return fn_ptr_(args...); |
| 143 | #endif // ABI_USES_FUNCTION_DESCRIPTORS |
| 144 | } |
| 145 | #endif // USE_SIMULATOR |
| 146 | |
| 147 | private: |
| 148 | friend class GeneratedCode<Return(Args...)>; |
| 149 | Isolate* isolate_; |
| 150 | Signature* fn_ptr_; |
| 151 | GeneratedCode(Isolate* isolate, Signature* fn_ptr) |
| 152 | : isolate_(isolate), fn_ptr_(fn_ptr) {} |
| 153 | }; |
| 154 | |
| 155 | // Allow to use {GeneratedCode<ret(arg1, arg2)>} instead of |
| 156 | // {GeneratedCode<ret, arg1, arg2>}. |
| 157 | template <typename Return, typename... Args> |
| 158 | class GeneratedCode<Return(Args...)> : public GeneratedCode<Return, Args...> { |
| 159 | public: |
| 160 | // Automatically convert from {GeneratedCode<ret, arg1, arg2>} to |
| 161 | // {GeneratedCode<ret(arg1, arg2)>}. |
| 162 | GeneratedCode(GeneratedCode<Return, Args...> other) |
| 163 | : GeneratedCode<Return, Args...>(other.isolate_, other.fn_ptr_) {} |
| 164 | }; |
| 165 | |
| 166 | } // namespace internal |
| 167 | } // namespace v8 |
| 168 | |
| 169 | #endif // V8_EXECUTION_SIMULATOR_H_ |