| 1 | // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 | // for details. All rights reserved. Use of this source code is governed by a |
| 3 | // BSD-style license that can be found in the LICENSE file. |
| 4 | |
| 5 | #ifndef RUNTIME_VM_RUNTIME_ENTRY_H_ |
| 6 | #define RUNTIME_VM_RUNTIME_ENTRY_H_ |
| 7 | |
| 8 | #include "vm/allocation.h" |
| 9 | #if !defined(DART_PRECOMPILED_RUNTIME) |
| 10 | #include "vm/compiler/runtime_api.h" |
| 11 | #endif |
| 12 | #include "vm/flags.h" |
| 13 | #include "vm/heap/safepoint.h" |
| 14 | #include "vm/log.h" |
| 15 | #include "vm/native_arguments.h" |
| 16 | #include "vm/runtime_entry_list.h" |
| 17 | |
| 18 | namespace dart { |
| 19 | |
| 20 | typedef void (*RuntimeFunction)(NativeArguments arguments); |
| 21 | |
| 22 | #if !defined(DART_PRECOMPILED_RUNTIME) |
| 23 | using BaseRuntimeEntry = compiler::RuntimeEntry; |
| 24 | #else |
| 25 | using BaseRuntimeEntry = ValueObject; |
| 26 | #endif |
| 27 | |
| 28 | // Class RuntimeEntry is used to encapsulate runtime functions, it includes |
| 29 | // the entry point for the runtime function and the number of arguments expected |
| 30 | // by the function. |
| 31 | class RuntimeEntry : public BaseRuntimeEntry { |
| 32 | public: |
| 33 | RuntimeEntry(const char* name, |
| 34 | RuntimeFunction function, |
| 35 | intptr_t argument_count, |
| 36 | bool is_leaf, |
| 37 | bool is_float) |
| 38 | : |
| 39 | #if !defined(DART_PRECOMPILED_RUNTIME) |
| 40 | compiler::RuntimeEntry(this, &CallInternal), |
| 41 | #endif |
| 42 | name_(name), |
| 43 | function_(function), |
| 44 | argument_count_(argument_count), |
| 45 | is_leaf_(is_leaf), |
| 46 | is_float_(is_float) { |
| 47 | } |
| 48 | |
| 49 | const char* name() const { return name_; } |
| 50 | RuntimeFunction function() const { return function_; } |
| 51 | intptr_t argument_count() const { return argument_count_; } |
| 52 | bool is_leaf() const { return is_leaf_; } |
| 53 | bool is_float() const { return is_float_; } |
| 54 | uword GetEntryPoint() const; |
| 55 | |
| 56 | // Generate code to call the runtime entry. |
| 57 | NOT_IN_PRECOMPILED(void Call(compiler::Assembler* assembler, |
| 58 | intptr_t argument_count) const); |
| 59 | |
| 60 | static uword InterpretCallEntry(); |
| 61 | |
| 62 | protected: |
| 63 | NOT_IN_PRECOMPILED(static void CallInternal(const RuntimeEntry* runtime_entry, |
| 64 | compiler::Assembler* assembler, |
| 65 | intptr_t argument_count)); |
| 66 | |
| 67 | private: |
| 68 | const char* const name_; |
| 69 | const RuntimeFunction function_; |
| 70 | const intptr_t argument_count_; |
| 71 | const bool is_leaf_; |
| 72 | const bool is_float_; |
| 73 | |
| 74 | DISALLOW_COPY_AND_ASSIGN(RuntimeEntry); |
| 75 | }; |
| 76 | |
| 77 | #ifdef DEBUG |
| 78 | #define TRACE_RUNTIME_CALL(format, name) \ |
| 79 | if (FLAG_trace_runtime_calls) { \ |
| 80 | THR_Print("Runtime call: " format "\n", name); \ |
| 81 | } |
| 82 | #else |
| 83 | #define TRACE_RUNTIME_CALL(format, name) \ |
| 84 | do { \ |
| 85 | } while (0) |
| 86 | #endif |
| 87 | |
| 88 | #if defined(USING_SIMULATOR) |
| 89 | #define CHECK_SIMULATOR_STACK_OVERFLOW() \ |
| 90 | if (!OSThread::Current()->HasStackHeadroom()) { \ |
| 91 | Exceptions::ThrowStackOverflow(); \ |
| 92 | } |
| 93 | #else |
| 94 | #define CHECK_SIMULATOR_STACK_OVERFLOW() |
| 95 | #endif // defined(USING_SIMULATOR) |
| 96 | |
| 97 | // Helper macros for declaring and defining runtime entries. |
| 98 | |
| 99 | #define DEFINE_RUNTIME_ENTRY(name, argument_count) \ |
| 100 | extern void DRT_##name(NativeArguments arguments); \ |
| 101 | extern const RuntimeEntry k##name##RuntimeEntry( \ |
| 102 | "DRT_" #name, &DRT_##name, argument_count, false, false); \ |
| 103 | static void DRT_Helper##name(Isolate* isolate, Thread* thread, Zone* zone, \ |
| 104 | NativeArguments arguments); \ |
| 105 | void DRT_##name(NativeArguments arguments) { \ |
| 106 | CHECK_STACK_ALIGNMENT; \ |
| 107 | /* Tell MemorySanitizer 'arguments' is initialized by generated code. */ \ |
| 108 | MSAN_UNPOISON(&arguments, sizeof(arguments)); \ |
| 109 | ASSERT(arguments.ArgCount() == argument_count); \ |
| 110 | TRACE_RUNTIME_CALL("%s", "" #name); \ |
| 111 | { \ |
| 112 | Thread* thread = arguments.thread(); \ |
| 113 | ASSERT(thread == Thread::Current()); \ |
| 114 | Isolate* isolate = thread->isolate(); \ |
| 115 | TransitionGeneratedToVM transition(thread); \ |
| 116 | StackZone zone(thread); \ |
| 117 | HANDLESCOPE(thread); \ |
| 118 | CHECK_SIMULATOR_STACK_OVERFLOW(); \ |
| 119 | DRT_Helper##name(isolate, thread, zone.GetZone(), arguments); \ |
| 120 | } \ |
| 121 | } \ |
| 122 | static void DRT_Helper##name(Isolate* isolate, Thread* thread, Zone* zone, \ |
| 123 | NativeArguments arguments) |
| 124 | |
| 125 | #define DECLARE_RUNTIME_ENTRY(name) \ |
| 126 | extern const RuntimeEntry k##name##RuntimeEntry; \ |
| 127 | extern void DRT_##name(NativeArguments arguments); |
| 128 | |
| 129 | #define DEFINE_LEAF_RUNTIME_ENTRY(type, name, argument_count, ...) \ |
| 130 | extern "C" type DLRT_##name(__VA_ARGS__); \ |
| 131 | extern const RuntimeEntry k##name##RuntimeEntry( \ |
| 132 | "DLRT_" #name, reinterpret_cast<RuntimeFunction>(&DLRT_##name), \ |
| 133 | argument_count, true, false); \ |
| 134 | type DLRT_##name(__VA_ARGS__) { \ |
| 135 | CHECK_STACK_ALIGNMENT; \ |
| 136 | NoSafepointScope no_safepoint_scope; |
| 137 | |
| 138 | #define END_LEAF_RUNTIME_ENTRY } |
| 139 | |
| 140 | // TODO(rmacnak): Fix alignment issue on simarm and use |
| 141 | // DEFINE_LEAF_RUNTIME_ENTRY instead. |
| 142 | #define DEFINE_RAW_LEAF_RUNTIME_ENTRY(name, argument_count, is_float, func) \ |
| 143 | extern const RuntimeEntry k##name##RuntimeEntry( \ |
| 144 | "DFLRT_" #name, func, argument_count, true, is_float) |
| 145 | |
| 146 | #define DECLARE_LEAF_RUNTIME_ENTRY(type, name, ...) \ |
| 147 | extern const RuntimeEntry k##name##RuntimeEntry; \ |
| 148 | extern "C" type DLRT_##name(__VA_ARGS__); |
| 149 | |
| 150 | // Declare all runtime functions here. |
| 151 | RUNTIME_ENTRY_LIST(DECLARE_RUNTIME_ENTRY) |
| 152 | LEAF_RUNTIME_ENTRY_LIST(DECLARE_LEAF_RUNTIME_ENTRY) |
| 153 | |
| 154 | // Expected to be called inside a safepoint. |
| 155 | extern "C" Thread* DLRT_GetThreadForNativeCallback(uword callback_id); |
| 156 | extern "C" Thread* DLRT_GetThreadForNativeCallbackTrampoline(uword callback_id); |
| 157 | |
| 158 | // For creating scoped handles in FFI trampolines. |
| 159 | extern "C" ApiLocalScope* DLRT_EnterHandleScope(Thread* thread); |
| 160 | extern "C" void DLRT_ExitHandleScope(Thread* thread); |
| 161 | extern "C" LocalHandle* DLRT_AllocateHandle(ApiLocalScope* scope); |
| 162 | |
| 163 | const char* DeoptReasonToCString(ICData::DeoptReasonId deopt_reason); |
| 164 | |
| 165 | void DeoptimizeAt(const Code& optimized_code, StackFrame* frame); |
| 166 | void DeoptimizeFunctionsOnStack(); |
| 167 | |
| 168 | double DartModulo(double a, double b); |
| 169 | |
| 170 | } // namespace dart |
| 171 | |
| 172 | #endif // RUNTIME_VM_RUNTIME_ENTRY_H_ |
| 173 | |