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