| // 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 thread has an API scope. | |
| #define CHECK_API_SCOPE(thread) \ | |
| do { \ | |
| Thread* tmpT = (thread); \ | |
| 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 reinterpret_cast<Dart_Handle>(Roots::null_api_handle()); | |
| } | |
| // Gets a handle to True. | |
| static Dart_Handle True() { | |
| return reinterpret_cast<Dart_Handle>(Roots::true_api_handle()); | |
| } | |
| // Gets a handle to False. | |
| static Dart_Handle False() { | |
| return reinterpret_cast<Dart_Handle>(Roots::false_api_handle()); | |
| } | |
| // Gets a handle to EmptyString. | |
| static Dart_Handle EmptyString() { | |
| return reinterpret_cast<Dart_Handle>(Roots::empty_string_api_handle()); | |
| } | |
| // Gets the handle which holds the pre-created acquired error object. | |
| static Dart_Handle NoCallbacksError() { | |
| return reinterpret_cast<Dart_Handle>( | |
| Roots::no_callbacks_error_api_handle()); | |
| } | |
| // Gets the handle for unwind-is-in-progress error. | |
| static Dart_Handle UnwindInProgressError() { | |
| return reinterpret_cast<Dart_Handle>( | |
| Roots::unwind_in_progress_error_api_handle()); | |
| } | |
| static bool IsProtectedHandle(Dart_Handle object) { | |
| if (object == nullptr) return false; | |
| return Roots::IsReadOnlyApiHandle(reinterpret_cast<uword>(object)); | |
| } | |
| // 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); | |
| 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); | |
| void ThrowCantRunWithoutIsolateError(); | |
| } // namespace dart. | |
| #endif // RUNTIME_VM_DART_API_IMPL_H_ |