|  | // Copyright (c) 2011, the Dart project authors.  Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | #ifndef RUNTIME_VM_DART_API_IMPL_H_ | 
|  | #define RUNTIME_VM_DART_API_IMPL_H_ | 
|  |  | 
|  | #include <memory> | 
|  |  | 
|  | #include "vm/allocation.h" | 
|  | #include "vm/heap/safepoint.h" | 
|  | #include "vm/native_arguments.h" | 
|  | #include "vm/object.h" | 
|  | #include "vm/timeline.h" | 
|  |  | 
|  | namespace dart { | 
|  |  | 
|  | class ApiLocalScope; | 
|  | class ApiState; | 
|  | class FinalizablePersistentHandle; | 
|  | class LocalHandle; | 
|  | class PersistentHandle; | 
|  | class ReusableObjectHandleScope; | 
|  | class ThreadRegistry; | 
|  |  | 
|  | const char* CanonicalFunction(const char* func); | 
|  |  | 
|  | #define CURRENT_FUNC CanonicalFunction(__FUNCTION__) | 
|  |  | 
|  | // Checks that the current isolate group is not nullptr. | 
|  | #define CHECK_ISOLATE_GROUP(isolate_group)                                     \ | 
|  | do {                                                                         \ | 
|  | if ((isolate_group) == nullptr) {                                          \ | 
|  | FATAL(                                                                   \ | 
|  | "%s expects there to be a current isolate group. Did you "           \ | 
|  | "forget to call Dart_CreateIsolateGroup or Dart_EnterIsolate?",      \ | 
|  | CURRENT_FUNC);                                                       \ | 
|  | }                                                                          \ | 
|  | } while (0) | 
|  |  | 
|  | // Checks that the current isolate is not nullptr. | 
|  | #define CHECK_ISOLATE(isolate)                                                 \ | 
|  | do {                                                                         \ | 
|  | if ((isolate) == nullptr) {                                                \ | 
|  | FATAL(                                                                   \ | 
|  | "%s expects there to be a current isolate. Did you "                 \ | 
|  | "forget to call Dart_CreateIsolateGroup or Dart_EnterIsolate?",      \ | 
|  | CURRENT_FUNC);                                                       \ | 
|  | }                                                                          \ | 
|  | } while (0) | 
|  |  | 
|  | // Checks that the current isolate is nullptr. | 
|  | #define CHECK_NO_ISOLATE(isolate)                                              \ | 
|  | do {                                                                         \ | 
|  | if ((isolate) != nullptr) {                                                \ | 
|  | FATAL(                                                                   \ | 
|  | "%s expects there to be no current isolate. Did you "                \ | 
|  | "forget to call Dart_ExitIsolate?",                                  \ | 
|  | CURRENT_FUNC);                                                       \ | 
|  | }                                                                          \ | 
|  | } while (0) | 
|  |  | 
|  | // Checks that the current isolate is not nullptr and that it has an API scope. | 
|  | #define CHECK_API_SCOPE(thread)                                                \ | 
|  | do {                                                                         \ | 
|  | Thread* tmpT = (thread);                                                   \ | 
|  | Isolate* tmpI = tmpT == nullptr ? nullptr : tmpT->isolate();               \ | 
|  | CHECK_ISOLATE(tmpI);                                                       \ | 
|  | if (tmpT->api_top_scope() == nullptr) {                                    \ | 
|  | FATAL(                                                                   \ | 
|  | "%s expects to find a current scope. Did you forget to call "        \ | 
|  | "Dart_EnterScope?",                                                  \ | 
|  | CURRENT_FUNC);                                                       \ | 
|  | }                                                                          \ | 
|  | } while (0); | 
|  |  | 
|  | #define DARTSCOPE(thread)                                                      \ | 
|  | Thread* T = (thread);                                                        \ | 
|  | CHECK_API_SCOPE(T);                                                          \ | 
|  | TransitionNativeToVM transition(T);                                          \ | 
|  | HANDLESCOPE(T); | 
|  |  | 
|  | #define RETURN_TYPE_ERROR(zone, dart_handle, type)                             \ | 
|  | do {                                                                         \ | 
|  | const Object& tmp =                                                        \ | 
|  | Object::Handle(zone, Api::UnwrapHandle((dart_handle)));                \ | 
|  | if (tmp.IsNull()) {                                                        \ | 
|  | return Api::NewArgumentError("%s expects argument '%s' to be non-null.", \ | 
|  | CURRENT_FUNC, #dart_handle);                \ | 
|  | } else if (tmp.IsError()) {                                                \ | 
|  | return dart_handle;                                                      \ | 
|  | }                                                                          \ | 
|  | return Api::NewArgumentError("%s expects argument '%s' to be of type %s.", \ | 
|  | CURRENT_FUNC, #dart_handle, #type);           \ | 
|  | } while (0) | 
|  |  | 
|  | #define RETURN_NULL_ERROR(parameter)                                           \ | 
|  | return Api::NewError("%s expects argument '%s' to be non-null.",             \ | 
|  | CURRENT_FUNC, #parameter) | 
|  |  | 
|  | #define CHECK_NULL(parameter)                                                  \ | 
|  | if (parameter == nullptr) {                                                  \ | 
|  | RETURN_NULL_ERROR(parameter);                                              \ | 
|  | } | 
|  |  | 
|  | #define CHECK_LENGTH(length, max_elements)                                     \ | 
|  | do {                                                                         \ | 
|  | intptr_t len = (length);                                                   \ | 
|  | intptr_t max = (max_elements);                                             \ | 
|  | if (len < 0 || len > max) {                                                \ | 
|  | return Api::NewError(                                                    \ | 
|  | "%s expects argument '%s' to be in the range [0..%" Pd "].",         \ | 
|  | CURRENT_FUNC, #length, max);                                         \ | 
|  | }                                                                          \ | 
|  | } while (0) | 
|  |  | 
|  | #ifdef SUPPORT_TIMELINE | 
|  | #define API_TIMELINE_DURATION(thread)                                          \ | 
|  | TimelineBeginEndScope api_tbes(thread, Timeline::GetAPIStream(), CURRENT_FUNC) | 
|  |  | 
|  | #define API_TIMELINE_BEGIN_END(thread)                                         \ | 
|  | TimelineBeginEndScope api_tbes(thread, Timeline::GetAPIStream(), CURRENT_FUNC) | 
|  |  | 
|  | #else | 
|  | #define API_TIMELINE_DURATION(thread)                                          \ | 
|  | do {                                                                         \ | 
|  | } while (false) | 
|  | #define API_TIMELINE_BEGIN_END(thread)                                         \ | 
|  | do {                                                                         \ | 
|  | } while (false) | 
|  | #endif  // SUPPORT_TIMELINE | 
|  |  | 
|  | class Api : AllStatic { | 
|  | public: | 
|  | // Create on the stack to provide a new throw-safe api scope. | 
|  | class Scope : public ThreadStackResource { | 
|  | public: | 
|  | explicit Scope(Thread* thread) : ThreadStackResource(thread) { | 
|  | thread->EnterApiScope(); | 
|  | } | 
|  | ~Scope() { thread()->ExitApiScope(); } | 
|  |  | 
|  | private: | 
|  | DISALLOW_COPY_AND_ASSIGN(Scope); | 
|  | }; | 
|  |  | 
|  | // Creates a new local handle. | 
|  | static Dart_Handle NewHandle(Thread* thread, ObjectPtr raw); | 
|  |  | 
|  | // Unwraps the raw object from the handle. | 
|  | static ObjectPtr UnwrapHandle(Dart_Handle object); | 
|  |  | 
|  | // Unwraps a raw Type from the handle.  The handle will be null if | 
|  | // the object was not of the requested Type. | 
|  | #define DECLARE_UNWRAP(Type)                                                   \ | 
|  | static const Type& Unwrap##Type##Handle(Zone* zone, Dart_Handle object); | 
|  | CLASS_LIST_FOR_HANDLES(DECLARE_UNWRAP) | 
|  | #undef DECLARE_UNWRAP | 
|  |  | 
|  | // Unwraps the raw object from the handle using a reused handle. | 
|  | static const String& UnwrapStringHandle( | 
|  | const ReusableObjectHandleScope& reused, | 
|  | Dart_Handle object); | 
|  | static const Instance& UnwrapInstanceHandle( | 
|  | const ReusableObjectHandleScope& reused, | 
|  | Dart_Handle object); | 
|  |  | 
|  | // Returns an Error handle if isolate is in an inconsistent state | 
|  | // or there was an error while finalizing classes. | 
|  | // Returns a Success handle when no error condition exists. | 
|  | static Dart_Handle CheckAndFinalizePendingClasses(Thread* thread); | 
|  |  | 
|  | // Casts the internal Isolate* type to the external Dart_Isolate type. | 
|  | static Dart_Isolate CastIsolate(Isolate* isolate); | 
|  |  | 
|  | // Casts the internal IsolateGroup* type to the external Dart_IsolateGroup | 
|  | // type. | 
|  | static Dart_IsolateGroup CastIsolateGroup(IsolateGroup* isolate_group); | 
|  |  | 
|  | // Gets the handle used to designate successful return. | 
|  | static Dart_Handle Success() { return Api::True(); } | 
|  |  | 
|  | // Returns true if the handle holds a Smi. | 
|  | static bool IsSmi(Dart_Handle handle) { | 
|  | // Important: we do not require current thread to be in VM state because | 
|  | // we do not dereference the handle. | 
|  | ObjectPtr raw = *(reinterpret_cast<ObjectPtr*>(handle)); | 
|  | return !raw->IsHeapObject(); | 
|  | } | 
|  |  | 
|  | // Returns the value of a Smi. | 
|  | static intptr_t SmiValue(Dart_Handle handle) { | 
|  | // Important: we do not require current thread to be in VM state because | 
|  | // we do not dereference the handle. | 
|  | ObjectPtr value = *(reinterpret_cast<ObjectPtr*>(handle)); | 
|  | return Smi::Value(static_cast<SmiPtr>(value)); | 
|  | } | 
|  |  | 
|  | // Returns true if the handle holds a Dart Instance. | 
|  | static bool IsInstance(Dart_Handle handle) { | 
|  | return !IsInternalOnlyClassId(ClassId(handle)); | 
|  | } | 
|  |  | 
|  | // Returns true if the handle is non-dangling. | 
|  | static bool IsValid(Dart_Handle handle); | 
|  |  | 
|  | // Returns true if the handle holds an Error. | 
|  | static bool IsError(Dart_Handle handle) { | 
|  | return IsErrorClassId(ClassId(handle)); | 
|  | } | 
|  |  | 
|  | static intptr_t ClassId(Dart_Handle handle) { | 
|  | return UnwrapHandle(handle)->GetClassId(); | 
|  | } | 
|  |  | 
|  | // Generates a handle used to designate an error return. | 
|  | static Dart_Handle NewError(const char* format, ...) PRINTF_ATTRIBUTE(1, 2); | 
|  | static Dart_Handle NewArgumentError(const char* format, ...) | 
|  | PRINTF_ATTRIBUTE(1, 2); | 
|  |  | 
|  | // Gets a handle to Null. | 
|  | static Dart_Handle Null() { return null_handle_; } | 
|  |  | 
|  | // Gets a handle to True. | 
|  | static Dart_Handle True() { return true_handle_; } | 
|  |  | 
|  | // Gets a handle to False. | 
|  | static Dart_Handle False() { return false_handle_; } | 
|  |  | 
|  | // Gets a handle to EmptyString. | 
|  | static Dart_Handle EmptyString() { return empty_string_handle_; } | 
|  |  | 
|  | // Gets the handle which holds the pre-created acquired error object. | 
|  | static Dart_Handle NoCallbacksError() { return no_callbacks_error_handle_; } | 
|  |  | 
|  | // Gets the handle for unwind-is-in-progress error. | 
|  | static Dart_Handle UnwindInProgressError() { | 
|  | return unwind_in_progress_error_handle_; | 
|  | } | 
|  |  | 
|  | static bool IsProtectedHandle(Dart_Handle object) { | 
|  | if (object == nullptr) return false; | 
|  | return (object == true_handle_) || (object == false_handle_) || | 
|  | (object == null_handle_) || (object == empty_string_handle_) || | 
|  | (object == no_callbacks_error_handle_) || | 
|  | (object == unwind_in_progress_error_handle_); | 
|  | } | 
|  |  | 
|  | // Retrieves the top ApiLocalScope. | 
|  | static ApiLocalScope* TopScope(Thread* thread); | 
|  |  | 
|  | // Performs initialization needed by the API. | 
|  | static void Init(); | 
|  |  | 
|  | // Allocates handles for objects in the VM isolate. | 
|  | static void InitHandles(); | 
|  |  | 
|  | // Cleanup | 
|  | static void Cleanup(); | 
|  |  | 
|  | // Helper function to get the peer value of an external string object. | 
|  | static bool StringGetPeerHelper(NativeArguments* args, | 
|  | int arg_index, | 
|  | void** peer); | 
|  |  | 
|  | // Helper function to get the native field from a native receiver argument. | 
|  | static bool GetNativeReceiver(NativeArguments* args, intptr_t* value); | 
|  |  | 
|  | // Helper function to get the boolean value of a Bool native argument. | 
|  | static bool GetNativeBooleanArgument(NativeArguments* args, | 
|  | int arg_index, | 
|  | bool* value); | 
|  |  | 
|  | // Helper function to get the integer value of a Integer native argument. | 
|  | static bool GetNativeIntegerArgument(NativeArguments* args, | 
|  | int arg_index, | 
|  | int64_t* value); | 
|  |  | 
|  | // Helper function to get the double value of a Double native argument. | 
|  | static bool GetNativeDoubleArgument(NativeArguments* args, | 
|  | int arg_index, | 
|  | double* value); | 
|  |  | 
|  | // Helper function to get the native fields of an Instance native argument. | 
|  | static bool GetNativeFieldsOfArgument(NativeArguments* args, | 
|  | int arg_index, | 
|  | int num_fields, | 
|  | intptr_t* field_values); | 
|  |  | 
|  | // Helper function to set the return value of native functions. | 
|  | static void SetReturnValue(NativeArguments* args, Dart_Handle retval) { | 
|  | args->SetReturnUnsafe(UnwrapHandle(retval)); | 
|  | } | 
|  | static void SetSmiReturnValue(NativeArguments* args, intptr_t retval) { | 
|  | args->SetReturnUnsafe(Smi::New(retval)); | 
|  | } | 
|  | static void SetIntegerReturnValue(NativeArguments* args, int64_t retval) { | 
|  | args->SetReturnUnsafe(Integer::New(retval)); | 
|  | } | 
|  | static void SetDoubleReturnValue(NativeArguments* args, double retval) { | 
|  | args->SetReturnUnsafe(Double::New(retval)); | 
|  | } | 
|  | static void SetWeakHandleReturnValue(NativeArguments* args, | 
|  | Dart_WeakPersistentHandle retval); | 
|  |  | 
|  | static StringPtr GetEnvironmentValue(Thread* thread, const String& name); | 
|  |  | 
|  | static bool IsFfiEnabled() { return FLAG_enable_ffi; } | 
|  |  | 
|  | private: | 
|  | static Dart_Handle InitNewHandle(Thread* thread, ObjectPtr raw); | 
|  |  | 
|  | static StringPtr CallEnvironmentCallback(Thread* thread, const String& name); | 
|  |  | 
|  | // Thread local key used by the API. Currently holds the current | 
|  | // ApiNativeScope if any. | 
|  | static ThreadLocalKey api_native_key_; | 
|  | static Dart_Handle true_handle_; | 
|  | static Dart_Handle false_handle_; | 
|  | static Dart_Handle null_handle_; | 
|  | static Dart_Handle empty_string_handle_; | 
|  | static Dart_Handle no_callbacks_error_handle_; | 
|  | static Dart_Handle unwind_in_progress_error_handle_; | 
|  |  | 
|  | friend class ApiNativeScope; | 
|  | }; | 
|  |  | 
|  | // Start a scope in which no Dart API call backs are allowed. | 
|  | #define START_NO_CALLBACK_SCOPE(thread) thread->IncrementNoCallbackScopeDepth() | 
|  |  | 
|  | // End a no Dart API call backs Scope. | 
|  | #define END_NO_CALLBACK_SCOPE(thread)                                          \ | 
|  | do {                                                                         \ | 
|  | thread->DecrementNoCallbackScopeDepth();                                   \ | 
|  | if (thread->no_callback_scope_depth() == 0) {                              \ | 
|  | thread->heap()->CheckExternalGC(thread);                                 \ | 
|  | }                                                                          \ | 
|  | } while (false) | 
|  |  | 
|  | #define CHECK_CALLBACK_STATE(thread)                                           \ | 
|  | if (thread->no_callback_scope_depth() != 0) {                                \ | 
|  | return reinterpret_cast<Dart_Handle>(Api::NoCallbacksError());             \ | 
|  | }                                                                            \ | 
|  | if (thread->is_unwind_in_progress()) {                                       \ | 
|  | return reinterpret_cast<Dart_Handle>(Api::UnwindInProgressError());        \ | 
|  | } | 
|  |  | 
|  | #define ASSERT_CALLBACK_STATE(thread)                                          \ | 
|  | ASSERT(thread->no_callback_scope_depth() == 0) | 
|  |  | 
|  | class IsolateGroupSource; | 
|  |  | 
|  | // Creates a new isolate from [source] (which should come from an existing | 
|  | // isolate). | 
|  | Isolate* CreateWithinExistingIsolateGroup(IsolateGroup* group, | 
|  | const char* name, | 
|  | char** error); | 
|  |  | 
|  | }  // namespace dart. | 
|  |  | 
|  | #endif  // RUNTIME_VM_DART_API_IMPL_H_ |