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