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_DART_API_IMPL_H_ |
6 | #define RUNTIME_VM_DART_API_IMPL_H_ |
7 | |
8 | #include <memory> |
9 | |
10 | #include "vm/allocation.h" |
11 | #include "vm/heap/safepoint.h" |
12 | #include "vm/native_arguments.h" |
13 | #include "vm/object.h" |
14 | #include "vm/thread_registry.h" |
15 | #include "vm/timeline.h" |
16 | |
17 | namespace dart { |
18 | |
19 | class ApiLocalScope; |
20 | class ApiState; |
21 | class FinalizablePersistentHandle; |
22 | class LocalHandle; |
23 | class PersistentHandle; |
24 | class ReusableObjectHandleScope; |
25 | class ThreadRegistry; |
26 | |
27 | const char* CanonicalFunction(const char* func); |
28 | |
29 | #define CURRENT_FUNC CanonicalFunction(__FUNCTION__) |
30 | |
31 | // Checks that the current isolate group is not NULL. |
32 | #define CHECK_ISOLATE_GROUP(isolate_group) \ |
33 | do { \ |
34 | if ((isolate_group) == NULL) { \ |
35 | FATAL1( \ |
36 | "%s expects there to be a current isolate group. Did you " \ |
37 | "forget to call Dart_CreateIsolateGroup or Dart_EnterIsolate?", \ |
38 | CURRENT_FUNC); \ |
39 | } \ |
40 | } while (0) |
41 | |
42 | // Checks that the current isolate is not NULL. |
43 | #define CHECK_ISOLATE(isolate) \ |
44 | do { \ |
45 | if ((isolate) == NULL) { \ |
46 | FATAL1( \ |
47 | "%s expects there to be a current isolate. Did you " \ |
48 | "forget to call Dart_CreateIsolateGroup or Dart_EnterIsolate?", \ |
49 | CURRENT_FUNC); \ |
50 | } \ |
51 | } while (0) |
52 | |
53 | // Checks that the current isolate is NULL. |
54 | #define CHECK_NO_ISOLATE(isolate) \ |
55 | do { \ |
56 | if ((isolate) != NULL) { \ |
57 | FATAL1( \ |
58 | "%s expects there to be no current isolate. Did you " \ |
59 | "forget to call Dart_ExitIsolate?", \ |
60 | CURRENT_FUNC); \ |
61 | } \ |
62 | } while (0) |
63 | |
64 | // Checks that the current isolate is not NULL and that it has an API scope. |
65 | #define CHECK_API_SCOPE(thread) \ |
66 | do { \ |
67 | Thread* tmpT = (thread); \ |
68 | Isolate* tmpI = tmpT == NULL ? NULL : tmpT->isolate(); \ |
69 | CHECK_ISOLATE(tmpI); \ |
70 | if (tmpT->api_top_scope() == NULL) { \ |
71 | FATAL1( \ |
72 | "%s expects to find a current scope. Did you forget to call " \ |
73 | "Dart_EnterScope?", \ |
74 | CURRENT_FUNC); \ |
75 | } \ |
76 | } while (0); |
77 | |
78 | #define DARTSCOPE(thread) \ |
79 | Thread* T = (thread); \ |
80 | CHECK_API_SCOPE(T); \ |
81 | TransitionNativeToVM transition(T); \ |
82 | HANDLESCOPE(T); |
83 | |
84 | #define RETURN_TYPE_ERROR(zone, dart_handle, type) \ |
85 | do { \ |
86 | const Object& tmp = \ |
87 | Object::Handle(zone, Api::UnwrapHandle((dart_handle))); \ |
88 | if (tmp.IsNull()) { \ |
89 | return Api::NewArgumentError("%s expects argument '%s' to be non-null.", \ |
90 | CURRENT_FUNC, #dart_handle); \ |
91 | } else if (tmp.IsError()) { \ |
92 | return dart_handle; \ |
93 | } \ |
94 | return Api::NewArgumentError("%s expects argument '%s' to be of type %s.", \ |
95 | CURRENT_FUNC, #dart_handle, #type); \ |
96 | } while (0) |
97 | |
98 | #define RETURN_NULL_ERROR(parameter) \ |
99 | return Api::NewError("%s expects argument '%s' to be non-null.", \ |
100 | CURRENT_FUNC, #parameter) |
101 | |
102 | #define CHECK_NULL(parameter) \ |
103 | if (parameter == NULL) { \ |
104 | RETURN_NULL_ERROR(parameter); \ |
105 | } |
106 | |
107 | #define CHECK_LENGTH(length, max_elements) \ |
108 | do { \ |
109 | intptr_t len = (length); \ |
110 | intptr_t max = (max_elements); \ |
111 | if (len < 0 || len > max) { \ |
112 | return Api::NewError( \ |
113 | "%s expects argument '%s' to be in the range [0..%" Pd "].", \ |
114 | CURRENT_FUNC, #length, max); \ |
115 | } \ |
116 | } while (0) |
117 | |
118 | #ifdef SUPPORT_TIMELINE |
119 | #define API_TIMELINE_DURATION(thread) \ |
120 | TimelineBeginEndScope api_tbes(thread, Timeline::GetAPIStream(), CURRENT_FUNC) |
121 | #define API_TIMELINE_DURATION_BASIC(thread) \ |
122 | API_TIMELINE_DURATION(thread); \ |
123 | api_tbes.SetNumArguments(1); \ |
124 | api_tbes.CopyArgument(0, "mode", "basic"); |
125 | |
126 | #define API_TIMELINE_BEGIN_END(thread) \ |
127 | TimelineBeginEndScope api_tbes(thread, Timeline::GetAPIStream(), CURRENT_FUNC) |
128 | |
129 | #define API_TIMELINE_BEGIN_END_BASIC(thread) \ |
130 | API_TIMELINE_BEGIN_END(thread); \ |
131 | api_tbes.SetNumArguments(1); \ |
132 | api_tbes.CopyArgument(0, "mode", "basic"); |
133 | #else |
134 | #define API_TIMELINE_DURATION(thread) \ |
135 | do { \ |
136 | } while (false) |
137 | #define API_TIMELINE_DURATION_BASIC(thread) API_TIMELINE_DURATION(thread) |
138 | #define API_TIMELINE_BEGIN_END(thread) \ |
139 | do { \ |
140 | } while (false) |
141 | #define API_TIMELINE_BEGIN_END_BASIC(thread) API_TIMELINE_BEGIN_END(thread) |
142 | #endif // !PRODUCT |
143 | |
144 | class Api : AllStatic { |
145 | public: |
146 | // Create on the stack to provide a new throw-safe api scope. |
147 | class Scope : public ThreadStackResource { |
148 | public: |
149 | explicit Scope(Thread* thread) : ThreadStackResource(thread) { |
150 | thread->EnterApiScope(); |
151 | } |
152 | ~Scope() { thread()->ExitApiScope(); } |
153 | |
154 | private: |
155 | DISALLOW_COPY_AND_ASSIGN(Scope); |
156 | }; |
157 | |
158 | // Creates a new local handle. |
159 | static Dart_Handle NewHandle(Thread* thread, ObjectPtr raw); |
160 | |
161 | // Unwraps the raw object from the handle. |
162 | static ObjectPtr UnwrapHandle(Dart_Handle object); |
163 | |
164 | // Unwraps a raw Type from the handle. The handle will be null if |
165 | // the object was not of the requested Type. |
166 | #define DECLARE_UNWRAP(Type) \ |
167 | static const Type& Unwrap##Type##Handle(Zone* zone, Dart_Handle object); |
168 | CLASS_LIST_FOR_HANDLES(DECLARE_UNWRAP) |
169 | #undef DECLARE_UNWRAP |
170 | |
171 | // Unwraps the raw object from the handle using a reused handle. |
172 | static const String& UnwrapStringHandle( |
173 | const ReusableObjectHandleScope& reused, |
174 | Dart_Handle object); |
175 | static const Instance& UnwrapInstanceHandle( |
176 | const ReusableObjectHandleScope& reused, |
177 | Dart_Handle object); |
178 | |
179 | // Returns an Error handle if isolate is in an inconsistent state |
180 | // or there was an error while finalizing classes. |
181 | // Returns a Success handle when no error condition exists. |
182 | static Dart_Handle CheckAndFinalizePendingClasses(Thread* thread); |
183 | |
184 | // Casts the internal Isolate* type to the external Dart_Isolate type. |
185 | static Dart_Isolate CastIsolate(Isolate* isolate); |
186 | |
187 | // Casts the internal IsolateGroup* type to the external Dart_IsolateGroup |
188 | // type. |
189 | static Dart_IsolateGroup CastIsolateGroup(IsolateGroup* isolate); |
190 | |
191 | // Gets the handle used to designate successful return. |
192 | static Dart_Handle Success() { return Api::True(); } |
193 | |
194 | // Gets the handle which holds the pre-created acquired error object. |
195 | static Dart_Handle AcquiredError(IsolateGroup* isolate_group); |
196 | |
197 | // Returns true if the handle holds a Smi. |
198 | static bool IsSmi(Dart_Handle handle) { |
199 | // Important: we do not require current thread to be in VM state because |
200 | // we do not dereference the handle. |
201 | ObjectPtr raw = *(reinterpret_cast<ObjectPtr*>(handle)); |
202 | return !raw->IsHeapObject(); |
203 | } |
204 | |
205 | // Returns the value of a Smi. |
206 | static intptr_t SmiValue(Dart_Handle handle) { |
207 | // Important: we do not require current thread to be in VM state because |
208 | // we do not dereference the handle. |
209 | ObjectPtr value = *(reinterpret_cast<ObjectPtr*>(handle)); |
210 | return Smi::Value(static_cast<SmiPtr>(value)); |
211 | } |
212 | |
213 | // Returns true if the handle holds a Dart Instance. |
214 | static bool IsInstance(Dart_Handle handle) { |
215 | return (ClassId(handle) >= kInstanceCid); |
216 | } |
217 | |
218 | // Returns true if the handle is non-dangling. |
219 | static bool IsValid(Dart_Handle handle); |
220 | |
221 | // Returns true if the handle holds an Error. |
222 | static bool IsError(Dart_Handle handle) { |
223 | return IsErrorClassId(ClassId(handle)); |
224 | } |
225 | |
226 | static intptr_t ClassId(Dart_Handle handle) { |
227 | ObjectPtr raw = UnwrapHandle(handle); |
228 | if (!raw->IsHeapObject()) { |
229 | return kSmiCid; |
230 | } |
231 | return raw->GetClassId(); |
232 | } |
233 | |
234 | // Generates a handle used to designate an error return. |
235 | static Dart_Handle NewError(const char* format, ...) PRINTF_ATTRIBUTE(1, 2); |
236 | static Dart_Handle NewArgumentError(const char* format, ...) |
237 | PRINTF_ATTRIBUTE(1, 2); |
238 | |
239 | // Gets a handle to Null. |
240 | static Dart_Handle Null() { return null_handle_; } |
241 | |
242 | // Gets a handle to True. |
243 | static Dart_Handle True() { return true_handle_; } |
244 | |
245 | // Gets a handle to False. |
246 | static Dart_Handle False() { return false_handle_; } |
247 | |
248 | // Gets a handle to EmptyString. |
249 | static Dart_Handle EmptyString() { return empty_string_handle_; } |
250 | |
251 | // Retrieves the top ApiLocalScope. |
252 | static ApiLocalScope* TopScope(Thread* thread); |
253 | |
254 | // Performs initialization needed by the API. |
255 | static void Init(); |
256 | |
257 | // Allocates handles for objects in the VM isolate. |
258 | static void InitHandles(); |
259 | |
260 | // Cleanup |
261 | static void Cleanup(); |
262 | |
263 | // Helper function to get the peer value of an external string object. |
264 | static bool StringGetPeerHelper(NativeArguments* args, |
265 | int arg_index, |
266 | void** peer); |
267 | |
268 | // Helper function to get the native field from a native receiver argument. |
269 | static bool GetNativeReceiver(NativeArguments* args, intptr_t* value); |
270 | |
271 | // Helper function to get the boolean value of a Bool native argument. |
272 | static bool GetNativeBooleanArgument(NativeArguments* args, |
273 | int arg_index, |
274 | bool* value); |
275 | |
276 | // Helper function to get the integer value of a Integer native argument. |
277 | static bool GetNativeIntegerArgument(NativeArguments* args, |
278 | int arg_index, |
279 | int64_t* value); |
280 | |
281 | // Helper function to get the double value of a Double native argument. |
282 | static bool GetNativeDoubleArgument(NativeArguments* args, |
283 | int arg_index, |
284 | double* value); |
285 | |
286 | // Helper function to get the native fields of an Instance native argument. |
287 | static bool GetNativeFieldsOfArgument(NativeArguments* args, |
288 | int arg_index, |
289 | int num_fields, |
290 | intptr_t* field_values); |
291 | |
292 | // Helper function to set the return value of native functions. |
293 | static void SetReturnValue(NativeArguments* args, Dart_Handle retval) { |
294 | args->SetReturnUnsafe(UnwrapHandle(retval)); |
295 | } |
296 | static void SetSmiReturnValue(NativeArguments* args, intptr_t retval) { |
297 | args->SetReturnUnsafe(Smi::New(retval)); |
298 | } |
299 | static void SetIntegerReturnValue(NativeArguments* args, int64_t retval) { |
300 | args->SetReturnUnsafe(Integer::New(retval)); |
301 | } |
302 | static void SetDoubleReturnValue(NativeArguments* args, double retval) { |
303 | args->SetReturnUnsafe(Double::New(retval)); |
304 | } |
305 | static void SetWeakHandleReturnValue(NativeArguments* args, |
306 | Dart_WeakPersistentHandle retval); |
307 | |
308 | static StringPtr GetEnvironmentValue(Thread* thread, const String& name); |
309 | |
310 | static bool IsFfiEnabled() { |
311 | #if defined(TAGET_OS_FUCHSIA) |
312 | return false; |
313 | #else |
314 | return FLAG_enable_ffi; |
315 | #endif |
316 | } |
317 | |
318 | private: |
319 | static Dart_Handle InitNewHandle(Thread* thread, ObjectPtr raw); |
320 | |
321 | static StringPtr CallEnvironmentCallback(Thread* thread, const String& name); |
322 | |
323 | // Thread local key used by the API. Currently holds the current |
324 | // ApiNativeScope if any. |
325 | static ThreadLocalKey api_native_key_; |
326 | static Dart_Handle true_handle_; |
327 | static Dart_Handle false_handle_; |
328 | static Dart_Handle null_handle_; |
329 | static Dart_Handle empty_string_handle_; |
330 | |
331 | friend class ApiNativeScope; |
332 | }; |
333 | |
334 | // Start a scope in which no Dart API call backs are allowed. |
335 | #define START_NO_CALLBACK_SCOPE(thread) thread->IncrementNoCallbackScopeDepth() |
336 | |
337 | // End a no Dart API call backs Scope. |
338 | #define END_NO_CALLBACK_SCOPE(thread) thread->DecrementNoCallbackScopeDepth() |
339 | |
340 | #define CHECK_CALLBACK_STATE(thread) \ |
341 | if (thread->no_callback_scope_depth() != 0) { \ |
342 | return reinterpret_cast<Dart_Handle>( \ |
343 | Api::AcquiredError(thread->isolate_group())); \ |
344 | } |
345 | |
346 | #define ASSERT_CALLBACK_STATE(thread) \ |
347 | ASSERT(thread->no_callback_scope_depth() == 0) |
348 | |
349 | class IsolateGroupSource; |
350 | |
351 | // Creates a new isolate from [source] (which should come from an existing |
352 | // isolate). |
353 | Isolate* CreateWithinExistingIsolateGroup(IsolateGroup* group, |
354 | const char* name, |
355 | char** error); |
356 | Isolate* CreateWithinExistingIsolateGroupAOT(IsolateGroup* group, |
357 | const char* name, |
358 | char** error); |
359 | |
360 | } // namespace dart. |
361 | |
362 | #endif // RUNTIME_VM_DART_API_IMPL_H_ |
363 | |