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 | bool can_lazy_deopt) |
39 | : |
40 | #if !defined(DART_PRECOMPILED_RUNTIME) |
41 | compiler::RuntimeEntry(this), |
42 | #endif |
43 | name_(name), |
44 | function_(function), |
45 | argument_count_(argument_count), |
46 | is_leaf_(is_leaf), |
47 | is_float_(is_float), |
48 | can_lazy_deopt_(can_lazy_deopt) { |
49 | } |
50 | |
51 | const char* name() const { return name_; } |
52 | RuntimeFunction function() const { return function_; } |
53 | intptr_t argument_count() const { return argument_count_; } |
54 | bool is_leaf() const { return is_leaf_; } |
55 | bool is_float() const { return is_float_; } |
56 | bool can_lazy_deopt() const { return can_lazy_deopt_; } |
57 | uword GetEntryPoint() const; |
58 | |
59 | private: |
60 | const char* const name_; |
61 | const RuntimeFunction function_; |
62 | const intptr_t argument_count_; |
63 | const bool is_leaf_; |
64 | const bool is_float_; |
65 | const bool can_lazy_deopt_; |
66 | |
67 | DISALLOW_COPY_AND_ASSIGN(RuntimeEntry); |
68 | }; |
69 | |
70 | #ifdef DEBUG |
71 | #define TRACE_RUNTIME_CALL(format, name) \ |
72 | if (FLAG_trace_runtime_calls) { \ |
73 | THR_Print("Runtime call: " format "\n", name); \ |
74 | } |
75 | #else |
76 | #define TRACE_RUNTIME_CALL(format, name) \ |
77 | do { \ |
78 | } while (0) |
79 | #endif |
80 | |
81 | #if defined(USING_SIMULATOR) |
82 | #define CHECK_SIMULATOR_STACK_OVERFLOW() \ |
83 | if (!OSThread::Current()->HasStackHeadroom()) { \ |
84 | Exceptions::ThrowStackOverflow(); \ |
85 | } |
86 | #else |
87 | #define CHECK_SIMULATOR_STACK_OVERFLOW() |
88 | #endif // defined(USING_SIMULATOR) |
89 | |
90 | // Helper macros for declaring and defining runtime entries. |
91 | |
92 | #define DEFINE_RUNTIME_ENTRY_IMPL(name, argument_count, can_lazy_deopt) \ |
93 | extern void DRT_##name(NativeArguments arguments); \ |
94 | extern const RuntimeEntry k##name##RuntimeEntry("DRT_" #name, &DRT_##name, \ |
95 | argument_count, false, \ |
96 | false, can_lazy_deopt); \ |
97 | static void DRT_Helper##name(Isolate* isolate, Thread* thread, Zone* zone, \ |
98 | NativeArguments arguments); \ |
99 | void DRT_##name(NativeArguments arguments) { \ |
100 | CHECK_STACK_ALIGNMENT; \ |
101 | /* Tell MemorySanitizer 'arguments' is initialized by generated code. */ \ |
102 | MSAN_UNPOISON(&arguments, sizeof(arguments)); \ |
103 | ASSERT(arguments.ArgCount() == argument_count); \ |
104 | TRACE_RUNTIME_CALL("%s", "" #name); \ |
105 | { \ |
106 | Thread* thread = arguments.thread(); \ |
107 | ASSERT(thread == Thread::Current()); \ |
108 | RuntimeCallDeoptScope runtime_call_deopt_scope( \ |
109 | thread, can_lazy_deopt ? RuntimeCallDeoptAbility::kCanLazyDeopt \ |
110 | : RuntimeCallDeoptAbility::kCannotLazyDeopt); \ |
111 | Isolate* isolate = thread->isolate(); \ |
112 | TransitionGeneratedToVM transition(thread); \ |
113 | StackZone zone(thread); \ |
114 | CHECK_SIMULATOR_STACK_OVERFLOW(); \ |
115 | if (FLAG_deoptimize_on_runtime_call_every > 0) { \ |
116 | OnEveryRuntimeEntryCall(thread, "" #name, can_lazy_deopt); \ |
117 | } \ |
118 | DRT_Helper##name(isolate, thread, zone.GetZone(), arguments); \ |
119 | } \ |
120 | } \ |
121 | static void DRT_Helper##name(Isolate* isolate, Thread* thread, Zone* zone, \ |
122 | NativeArguments arguments) |
123 | |
124 | #define DEFINE_RUNTIME_ENTRY(name, argument_count) \ |
125 | DEFINE_RUNTIME_ENTRY_IMPL(name, argument_count, /*can_lazy_deopt=*/true) |
126 | |
127 | #define DEFINE_RUNTIME_ENTRY_NO_LAZY_DEOPT(name, argument_count) \ |
128 | DEFINE_RUNTIME_ENTRY_IMPL(name, argument_count, /*can_lazy_deopt=*/false) |
129 | |
130 | #define DECLARE_RUNTIME_ENTRY(name) \ |
131 | extern const RuntimeEntry k##name##RuntimeEntry; \ |
132 | extern void DRT_##name(NativeArguments arguments); |
133 | |
134 | #define DEFINE_LEAF_RUNTIME_ENTRY(type, name, argument_count, ...) \ |
135 | extern "C" type DLRT_##name(__VA_ARGS__); \ |
136 | extern const RuntimeEntry k##name##RuntimeEntry( \ |
137 | "DLRT_" #name, reinterpret_cast<RuntimeFunction>(&DLRT_##name), \ |
138 | argument_count, true, false, /*can_lazy_deopt=*/false); \ |
139 | type DLRT_##name(__VA_ARGS__) { \ |
140 | CHECK_STACK_ALIGNMENT; \ |
141 | NoSafepointScope no_safepoint_scope; |
142 | |
143 | #define END_LEAF_RUNTIME_ENTRY } |
144 | |
145 | // TODO(rmacnak): Fix alignment issue on simarm and use |
146 | // DEFINE_LEAF_RUNTIME_ENTRY instead. |
147 | #define DEFINE_RAW_LEAF_RUNTIME_ENTRY(name, argument_count, is_float, func) \ |
148 | extern const RuntimeEntry k##name##RuntimeEntry( \ |
149 | "DFLRT_" #name, func, argument_count, true, is_float, \ |
150 | /*can_lazy_deopt=*/false) |
151 | |
152 | #define DECLARE_LEAF_RUNTIME_ENTRY(type, name, ...) \ |
153 | extern const RuntimeEntry k##name##RuntimeEntry; \ |
154 | extern "C" type DLRT_##name(__VA_ARGS__); |
155 | |
156 | // Declare all runtime functions here. |
157 | RUNTIME_ENTRY_LIST(DECLARE_RUNTIME_ENTRY) |
158 | LEAF_RUNTIME_ENTRY_LIST(DECLARE_LEAF_RUNTIME_ENTRY) |
159 | |
160 | // Expected to be called inside a safepoint. |
161 | extern "C" Thread* DLRT_GetFfiCallbackMetadata(uword trampoline, |
162 | uword* out_entry_point, |
163 | uword* out_callback_kind); |
164 | |
165 | extern "C" void DLRT_ExitTemporaryIsolate(); |
166 | |
167 | // For creating scoped handles in FFI trampolines. |
168 | extern "C" ApiLocalScope* DLRT_EnterHandleScope(Thread* thread); |
169 | extern "C" void DLRT_ExitHandleScope(Thread* thread); |
170 | extern "C" LocalHandle* DLRT_AllocateHandle(ApiLocalScope* scope); |
171 | |
172 | const char* DeoptReasonToCString(ICData::DeoptReasonId deopt_reason); |
173 | |
174 | void OnEveryRuntimeEntryCall(Thread* thread, |
175 | const char* runtime_call_name, |
176 | bool can_lazy_deopt); |
177 | |
178 | void DeoptimizeAt(Thread* mutator_thread, |
179 | const Code& optimized_code, |
180 | StackFrame* frame); |
181 | void DeoptimizeFunctionsOnStack(); |
182 | |
183 | double DartModulo(double a, double b); |
184 | |
185 | } // namespace dart |
186 | |
187 | #endif // RUNTIME_VM_RUNTIME_ENTRY_H_ |
188 | |