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
17namespace dart {
18
19class ApiLocalScope;
20class ApiState;
21class FinalizablePersistentHandle;
22class LocalHandle;
23class PersistentHandle;
24class ReusableObjectHandleScope;
25class ThreadRegistry;
26
27const 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
144class 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
349class IsolateGroupSource;
350
351// Creates a new isolate from [source] (which should come from an existing
352// isolate).
353Isolate* CreateWithinExistingIsolateGroup(IsolateGroup* group,
354 const char* name,
355 char** error);
356Isolate* CreateWithinExistingIsolateGroupAOT(IsolateGroup* group,
357 const char* name,
358 char** error);
359
360} // namespace dart.
361
362#endif // RUNTIME_VM_DART_API_IMPL_H_
363