| 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 |  | 
|---|