| // Copyright (c) 2013, 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. |
| |
| #include "include/dart_api.h" |
| |
| #include "platform/assert.h" |
| #include "vm/bigint_operations.h" |
| #include "vm/class_finalizer.h" |
| #include "vm/compiler.h" |
| #include "vm/dart.h" |
| #include "vm/dart_api_impl.h" |
| #include "vm/dart_api_message.h" |
| #include "vm/dart_api_state.h" |
| #include "vm/dart_entry.h" |
| #include "vm/debuginfo.h" |
| #include "vm/exceptions.h" |
| #include "vm/flags.h" |
| #include "vm/growable_array.h" |
| #include "vm/message.h" |
| #include "vm/native_entry.h" |
| #include "vm/native_message_handler.h" |
| #include "vm/object.h" |
| #include "vm/object_store.h" |
| #include "vm/port.h" |
| #include "vm/resolver.h" |
| #include "vm/stack_frame.h" |
| #include "vm/symbols.h" |
| #include "vm/timer.h" |
| #include "vm/unicode.h" |
| #include "vm/verifier.h" |
| #include "vm/version.h" |
| |
| namespace dart { |
| |
| DECLARE_FLAG(bool, print_class_table); |
| |
| ThreadLocalKey Api::api_native_key_ = Thread::kUnsetThreadLocalKey; |
| |
| |
| const char* CanonicalFunction(const char* func) { |
| if (strncmp(func, "dart::", 6) == 0) { |
| return func + 6; |
| } else { |
| return func; |
| } |
| } |
| |
| |
| #define RETURN_TYPE_ERROR(isolate, dart_handle, type) \ |
| do { \ |
| const Object& tmp = \ |
| Object::Handle(isolate, Api::UnwrapHandle((dart_handle))); \ |
| if (tmp.IsNull()) { \ |
| return Api::NewError("%s expects argument '%s' to be non-null.", \ |
| CURRENT_FUNC, #dart_handle); \ |
| } else if (tmp.IsError()) { \ |
| return dart_handle; \ |
| } else { \ |
| return Api::NewError("%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_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) |
| |
| |
| Dart_Handle Api::NewHandle(Isolate* isolate, RawObject* raw) { |
| LocalHandles* local_handles = Api::TopScope(isolate)->local_handles(); |
| ASSERT(local_handles != NULL); |
| LocalHandle* ref = local_handles->AllocateHandle(); |
| ref->set_raw(raw); |
| return reinterpret_cast<Dart_Handle>(ref); |
| } |
| |
| RawObject* Api::UnwrapHandle(Dart_Handle object) { |
| #if defined(DEBUG) |
| Isolate* isolate = Isolate::Current(); |
| ASSERT(isolate != NULL); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| ASSERT(state->IsValidLocalHandle(object) || |
| state->IsValidPersistentHandle(object) || |
| state->IsValidWeakPersistentHandle(object) || |
| state->IsValidPrologueWeakPersistentHandle(object)); |
| ASSERT(FinalizablePersistentHandle::raw_offset() == 0 && |
| PersistentHandle::raw_offset() == 0 && |
| LocalHandle::raw_offset() == 0); |
| #endif |
| return (reinterpret_cast<LocalHandle*>(object))->raw(); |
| } |
| |
| #define DEFINE_UNWRAP(type) \ |
| const type& Api::Unwrap##type##Handle(Isolate* iso, \ |
| Dart_Handle dart_handle) { \ |
| const Object& obj = Object::Handle(iso, Api::UnwrapHandle(dart_handle)); \ |
| if (obj.Is##type()) { \ |
| return type::Cast(obj); \ |
| } \ |
| return type::Handle(iso); \ |
| } |
| CLASS_LIST_FOR_HANDLES(DEFINE_UNWRAP) |
| #undef DEFINE_UNWRAP |
| |
| |
| LocalHandle* Api::UnwrapAsLocalHandle(const ApiState& state, |
| Dart_Handle object) { |
| ASSERT(state.IsValidLocalHandle(object)); |
| return reinterpret_cast<LocalHandle*>(object); |
| } |
| |
| |
| PersistentHandle* Api::UnwrapAsPersistentHandle(const ApiState& state, |
| Dart_Handle object) { |
| ASSERT(state.IsValidPersistentHandle(object)); |
| return reinterpret_cast<PersistentHandle*>(object); |
| } |
| |
| |
| FinalizablePersistentHandle* Api::UnwrapAsWeakPersistentHandle( |
| const ApiState& state, |
| Dart_Handle object) { |
| ASSERT(state.IsValidWeakPersistentHandle(object)); |
| return reinterpret_cast<FinalizablePersistentHandle*>(object); |
| } |
| |
| |
| FinalizablePersistentHandle* Api::UnwrapAsPrologueWeakPersistentHandle( |
| const ApiState& state, |
| Dart_Handle object) { |
| ASSERT(state.IsValidPrologueWeakPersistentHandle(object)); |
| return reinterpret_cast<FinalizablePersistentHandle*>(object); |
| } |
| |
| |
| Dart_Handle Api::CheckIsolateState(Isolate* isolate) { |
| if (ClassFinalizer::FinalizePendingClasses() && |
| isolate->object_store()->PreallocateObjects()) { |
| return Api::Success(isolate); |
| } |
| ASSERT(isolate->object_store()->sticky_error() != Object::null()); |
| return Api::NewHandle(isolate, isolate->object_store()->sticky_error()); |
| } |
| |
| |
| Dart_Isolate Api::CastIsolate(Isolate* isolate) { |
| return reinterpret_cast<Dart_Isolate>(isolate); |
| } |
| |
| |
| Dart_Handle Api::Success(Isolate* isolate) { |
| ASSERT(isolate != NULL); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| PersistentHandle* true_handle = state->True(); |
| return reinterpret_cast<Dart_Handle>(true_handle); |
| } |
| |
| |
| Dart_Handle Api::NewError(const char* format, ...) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| CHECK_CALLBACK_STATE(isolate); |
| |
| va_list args; |
| va_start(args, format); |
| intptr_t len = OS::VSNPrint(NULL, 0, format, args); |
| va_end(args); |
| |
| char* buffer = isolate->current_zone()->Alloc<char>(len + 1); |
| va_list args2; |
| va_start(args2, format); |
| OS::VSNPrint(buffer, (len + 1), format, args2); |
| va_end(args2); |
| |
| const String& message = String::Handle(isolate, String::New(buffer)); |
| return Api::NewHandle(isolate, ApiError::New(message)); |
| } |
| |
| |
| void Api::SetupAcquiredError(Isolate* isolate) { |
| ASSERT(isolate != NULL); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| state->SetupAcquiredError(); |
| } |
| |
| |
| Dart_Handle Api::AcquiredError(Isolate* isolate) { |
| ASSERT(isolate != NULL); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| PersistentHandle* acquired_error_handle = state->AcquiredError(); |
| return reinterpret_cast<Dart_Handle>(acquired_error_handle); |
| } |
| |
| |
| Dart_Handle Api::Null(Isolate* isolate) { |
| ASSERT(isolate != NULL); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| PersistentHandle* null_handle = state->Null(); |
| return reinterpret_cast<Dart_Handle>(null_handle); |
| } |
| |
| |
| Dart_Handle Api::True(Isolate* isolate) { |
| ASSERT(isolate != NULL); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| PersistentHandle* true_handle = state->True(); |
| return reinterpret_cast<Dart_Handle>(true_handle); |
| } |
| |
| |
| Dart_Handle Api::False(Isolate* isolate) { |
| ASSERT(isolate != NULL); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| PersistentHandle* false_handle = state->False(); |
| return reinterpret_cast<Dart_Handle>(false_handle); |
| } |
| |
| |
| ApiLocalScope* Api::TopScope(Isolate* isolate) { |
| ASSERT(isolate != NULL); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| ApiLocalScope* scope = state->top_scope(); |
| ASSERT(scope != NULL); |
| return scope; |
| } |
| |
| |
| void Api::InitOnce() { |
| ASSERT(api_native_key_ == Thread::kUnsetThreadLocalKey); |
| api_native_key_ = Thread::CreateThreadLocal(); |
| ASSERT(api_native_key_ != Thread::kUnsetThreadLocalKey); |
| } |
| |
| |
| bool Api::ExternalStringGetPeerHelper(Dart_Handle object, void** peer) { |
| NoGCScope no_gc_scope; |
| RawObject* raw_obj = Api::UnwrapHandle(object); |
| switch (Api::ClassId(object)) { |
| case kExternalOneByteStringCid: { |
| RawExternalOneByteString* raw_string = |
| reinterpret_cast<RawExternalOneByteString*>(raw_obj)->ptr(); |
| ExternalStringData<uint8_t>* data = raw_string->external_data_; |
| *peer = data->peer(); |
| return true; |
| } |
| case kExternalTwoByteStringCid: { |
| RawExternalTwoByteString* raw_string = |
| reinterpret_cast<RawExternalTwoByteString*>(raw_obj)->ptr(); |
| ExternalStringData<uint16_t>* data = raw_string->external_data_; |
| *peer = data->peer(); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| |
| // When we want to return a handle to a type to the user, we handle |
| // class-types differently than some other types. |
| static Dart_Handle TypeToHandle(Isolate* isolate, |
| const char* function_name, |
| const AbstractType& type) { |
| if (type.IsMalformed()) { |
| const Error& error = Error::Handle(type.malformed_error()); |
| return Api::NewError("%s: malformed type encountered: %s.", |
| function_name, error.ToErrorCString()); |
| } else if (type.HasResolvedTypeClass()) { |
| const Class& cls = Class::Handle(isolate, type.type_class()); |
| #if defined(DEBUG) |
| const Library& lib = Library::Handle(cls.library()); |
| if (lib.IsNull()) { |
| ASSERT(cls.IsDynamicClass() || cls.IsVoidClass()); |
| } |
| #endif |
| return Api::NewHandle(isolate, cls.raw()); |
| } else if (type.IsTypeParameter()) { |
| return Api::NewHandle(isolate, type.raw()); |
| } else { |
| return Api::NewError("%s: unexpected type '%s' encountered.", |
| function_name, type.ToCString()); |
| } |
| } |
| |
| |
| // --- Handles --- |
| |
| |
| DART_EXPORT bool Dart_IsError(Dart_Handle handle) { |
| return RawObject::IsErrorClassId(Api::ClassId(handle)); |
| } |
| |
| |
| DART_EXPORT bool Dart_IsApiError(Dart_Handle object) { |
| return Api::ClassId(object) == kApiErrorCid; |
| } |
| |
| |
| DART_EXPORT bool Dart_IsUnhandledExceptionError(Dart_Handle object) { |
| return Api::ClassId(object) == kUnhandledExceptionCid; |
| } |
| |
| |
| DART_EXPORT bool Dart_IsCompilationError(Dart_Handle object) { |
| return Api::ClassId(object) == kLanguageErrorCid; |
| } |
| |
| |
| DART_EXPORT bool Dart_IsFatalError(Dart_Handle object) { |
| return Api::ClassId(object) == kUnwindErrorCid; |
| } |
| |
| |
| DART_EXPORT const char* Dart_GetError(Dart_Handle handle) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle)); |
| if (obj.IsError()) { |
| const Error& error = Error::Cast(obj); |
| const char* str = error.ToErrorCString(); |
| intptr_t len = strlen(str) + 1; |
| char* str_copy = Api::TopScope(isolate)->zone()->Alloc<char>(len); |
| strncpy(str_copy, str, len); |
| // Strip a possible trailing '\n'. |
| if ((len > 1) && (str_copy[len - 2] == '\n')) { |
| str_copy[len - 2] = '\0'; |
| } |
| return str_copy; |
| } else { |
| return ""; |
| } |
| } |
| |
| |
| DART_EXPORT bool Dart_ErrorHasException(Dart_Handle handle) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle)); |
| return obj.IsUnhandledException(); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_ErrorGetException(Dart_Handle handle) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle)); |
| if (obj.IsUnhandledException()) { |
| const UnhandledException& error = UnhandledException::Cast(obj); |
| return Api::NewHandle(isolate, error.exception()); |
| } else if (obj.IsError()) { |
| return Api::NewError("This error is not an unhandled exception error."); |
| } else { |
| return Api::NewError("Can only get exceptions from error handles."); |
| } |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_ErrorGetStacktrace(Dart_Handle handle) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle)); |
| if (obj.IsUnhandledException()) { |
| const UnhandledException& error = UnhandledException::Cast(obj); |
| return Api::NewHandle(isolate, error.stacktrace()); |
| } else if (obj.IsError()) { |
| return Api::NewError("This error is not an unhandled exception error."); |
| } else { |
| return Api::NewError("Can only get stacktraces from error handles."); |
| } |
| } |
| |
| |
| // Deprecated. |
| // TODO(turnidge): Remove all uses and delete. |
| DART_EXPORT Dart_Handle Dart_Error(const char* format, ...) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| CHECK_CALLBACK_STATE(isolate); |
| |
| va_list args; |
| va_start(args, format); |
| intptr_t len = OS::VSNPrint(NULL, 0, format, args); |
| va_end(args); |
| |
| char* buffer = isolate->current_zone()->Alloc<char>(len + 1); |
| va_list args2; |
| va_start(args2, format); |
| OS::VSNPrint(buffer, (len + 1), format, args2); |
| va_end(args2); |
| |
| const String& message = String::Handle(isolate, String::New(buffer)); |
| return Api::NewHandle(isolate, ApiError::New(message)); |
| } |
| |
| |
| // TODO(turnidge): This clones Api::NewError. I need to use va_copy to |
| // fix this but not sure if it available on all of our builds. |
| DART_EXPORT Dart_Handle Dart_NewApiError(const char* format, ...) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| CHECK_CALLBACK_STATE(isolate); |
| |
| va_list args; |
| va_start(args, format); |
| intptr_t len = OS::VSNPrint(NULL, 0, format, args); |
| va_end(args); |
| |
| char* buffer = isolate->current_zone()->Alloc<char>(len + 1); |
| va_list args2; |
| va_start(args2, format); |
| OS::VSNPrint(buffer, (len + 1), format, args2); |
| va_end(args2); |
| |
| const String& message = String::Handle(isolate, String::New(buffer)); |
| return Api::NewHandle(isolate, ApiError::New(message)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewUnhandledExceptionError(Dart_Handle exception) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| CHECK_CALLBACK_STATE(isolate); |
| |
| const Instance& obj = Api::UnwrapInstanceHandle(isolate, exception); |
| if (obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, exception, Instance); |
| } |
| const Instance& stacktrace = Instance::Handle(isolate); |
| return Api::NewHandle(isolate, UnhandledException::New(obj, stacktrace)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_PropagateError(Dart_Handle handle) { |
| Isolate* isolate = Isolate::Current(); |
| { |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(handle)); |
| if (!obj.IsError()) { |
| return Api::NewError( |
| "%s expects argument 'handle' to be an error handle. " |
| "Did you forget to check Dart_IsError first?", |
| CURRENT_FUNC); |
| } |
| } |
| if (isolate->top_exit_frame_info() == 0) { |
| // There are no dart frames on the stack so it would be illegal to |
| // propagate an error here. |
| return Api::NewError("No Dart frames on stack, cannot propagate error."); |
| } |
| |
| // Unwind all the API scopes till the exit frame before propagating. |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| const Error* error; |
| { |
| // We need to preserve the error object across the destruction of zones |
| // when the ApiScopes are unwound. By using NoGCScope, we can ensure |
| // that GC won't touch the raw error object before creating a valid |
| // handle for it in the surviving zone. |
| NoGCScope no_gc; |
| RawError* raw_error = Api::UnwrapErrorHandle(isolate, handle).raw(); |
| state->UnwindScopes(isolate->top_exit_frame_info()); |
| error = &Error::Handle(isolate, raw_error); |
| } |
| Exceptions::PropagateError(*error); |
| UNREACHABLE(); |
| return Api::NewError("Cannot reach here. Internal error."); |
| } |
| |
| |
| DART_EXPORT void _Dart_ReportErrorHandle(const char* file, |
| int line, |
| const char* handle, |
| const char* message) { |
| fprintf(stderr, "%s:%d: error handle: '%s':\n '%s'\n", |
| file, line, handle, message); |
| OS::Abort(); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_ToString(Dart_Handle object) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object)); |
| if (obj.IsString()) { |
| return Api::NewHandle(isolate, obj.raw()); |
| } else if (obj.IsInstance()) { |
| CHECK_CALLBACK_STATE(isolate); |
| const Instance& receiver = Instance::Cast(obj); |
| return Api::NewHandle(isolate, DartLibraryCalls::ToString(receiver)); |
| } else { |
| CHECK_CALLBACK_STATE(isolate); |
| // This is a VM internal object. Call the C++ method of printing. |
| return Api::NewHandle(isolate, String::New(obj.ToCString())); |
| } |
| } |
| |
| |
| DART_EXPORT bool Dart_IdentityEquals(Dart_Handle obj1, Dart_Handle obj2) { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| NoGCScope ngc; |
| return Api::UnwrapHandle(obj1) == Api::UnwrapHandle(obj2); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewPersistentHandle(Dart_Handle object) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| const Object& old_ref = Object::Handle(isolate, Api::UnwrapHandle(object)); |
| PersistentHandle* new_ref = state->persistent_handles().AllocateHandle(); |
| new_ref->set_raw(old_ref); |
| return reinterpret_cast<Dart_Handle>(new_ref); |
| } |
| |
| static Dart_Handle AllocateFinalizableHandle( |
| Isolate* isolate, |
| FinalizablePersistentHandles* handles, |
| Dart_Handle object, |
| void* peer, |
| Dart_WeakPersistentHandleFinalizer callback) { |
| const Object& ref = Object::Handle(isolate, Api::UnwrapHandle(object)); |
| FinalizablePersistentHandle* finalizable_ref = handles->AllocateHandle(); |
| finalizable_ref->set_raw(ref); |
| finalizable_ref->set_peer(peer); |
| finalizable_ref->set_callback(callback); |
| return reinterpret_cast<Dart_Handle>(finalizable_ref); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewWeakPersistentHandle( |
| Dart_Handle object, |
| void* peer, |
| Dart_WeakPersistentHandleFinalizer callback) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| return AllocateFinalizableHandle(isolate, |
| &state->weak_persistent_handles(), |
| object, |
| peer, |
| callback); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewPrologueWeakPersistentHandle( |
| Dart_Handle object, |
| void* peer, |
| Dart_WeakPersistentHandleFinalizer callback) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| return AllocateFinalizableHandle(isolate, |
| &state->prologue_weak_persistent_handles(), |
| object, |
| peer, |
| callback); |
| } |
| |
| |
| DART_EXPORT void Dart_DeletePersistentHandle(Dart_Handle object) { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| if (state->IsValidPrologueWeakPersistentHandle(object)) { |
| FinalizablePersistentHandle* prologue_weak_ref = |
| Api::UnwrapAsPrologueWeakPersistentHandle(*state, object); |
| state->prologue_weak_persistent_handles().FreeHandle(prologue_weak_ref); |
| return; |
| } |
| if (state->IsValidWeakPersistentHandle(object)) { |
| FinalizablePersistentHandle* weak_ref = |
| Api::UnwrapAsWeakPersistentHandle(*state, object); |
| state->weak_persistent_handles().FreeHandle(weak_ref); |
| return; |
| } |
| PersistentHandle* ref = Api::UnwrapAsPersistentHandle(*state, object); |
| ASSERT(!state->IsProtectedHandle(ref)); |
| if (!state->IsProtectedHandle(ref)) { |
| state->persistent_handles().FreeHandle(ref); |
| } |
| } |
| |
| |
| DART_EXPORT bool Dart_IsWeakPersistentHandle(Dart_Handle object) { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| return state->IsValidWeakPersistentHandle(object); |
| } |
| |
| |
| DART_EXPORT bool Dart_IsPrologueWeakPersistentHandle(Dart_Handle object) { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| return state->IsValidPrologueWeakPersistentHandle(object); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewWeakReferenceSet(Dart_Handle* keys, |
| intptr_t num_keys, |
| Dart_Handle* values, |
| intptr_t num_values) { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| if (keys == NULL) { |
| RETURN_NULL_ERROR(keys); |
| } |
| if (num_keys <= 0) { |
| return Api::NewError( |
| "%s expects argument 'num_keys' to be greater than 0.", |
| CURRENT_FUNC); |
| } |
| if (values == NULL) { |
| RETURN_NULL_ERROR(values); |
| } |
| if (num_values <= 0) { |
| return Api::NewError( |
| "%s expects argument 'num_values' to be greater than 0.", |
| CURRENT_FUNC); |
| } |
| |
| WeakReferenceSet* reference_set = new WeakReferenceSet(keys, num_keys, |
| values, num_values); |
| state->DelayWeakReferenceSet(reference_set); |
| return Api::Success(isolate); |
| } |
| |
| |
| // --- Garbage Collection Callbacks -- |
| |
| |
| DART_EXPORT Dart_Handle Dart_AddGcPrologueCallback( |
| Dart_GcPrologueCallback callback) { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| GcPrologueCallbacks& callbacks = isolate->gc_prologue_callbacks(); |
| if (callbacks.Contains(callback)) { |
| return Api::NewError( |
| "%s permits only one instance of 'callback' to be present in the " |
| "prologue callback list.", |
| CURRENT_FUNC); |
| } |
| callbacks.Add(callback); |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_RemoveGcPrologueCallback( |
| Dart_GcPrologueCallback callback) { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| GcPrologueCallbacks& callbacks = isolate->gc_prologue_callbacks(); |
| if (!callbacks.Contains(callback)) { |
| return Api::NewError( |
| "%s expects 'callback' to be present in the prologue callback list.", |
| CURRENT_FUNC); |
| } |
| callbacks.Remove(callback); |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_AddGcEpilogueCallback( |
| Dart_GcEpilogueCallback callback) { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| GcEpilogueCallbacks& callbacks = isolate->gc_epilogue_callbacks(); |
| if (callbacks.Contains(callback)) { |
| return Api::NewError( |
| "%s permits only one instance of 'callback' to be present in the " |
| "epilogue callback list.", |
| CURRENT_FUNC); |
| } |
| callbacks.Add(callback); |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_RemoveGcEpilogueCallback( |
| Dart_GcEpilogueCallback callback) { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| GcEpilogueCallbacks& callbacks = isolate->gc_epilogue_callbacks(); |
| if (!callbacks.Contains(callback)) { |
| return Api::NewError( |
| "%s expects 'callback' to be present in the epilogue callback list.", |
| CURRENT_FUNC); |
| } |
| callbacks.Remove(callback); |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_HeapProfile(Dart_FileWriteCallback callback, |
| void* stream) { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| if (callback == NULL) { |
| RETURN_NULL_ERROR(callback); |
| } |
| isolate->heap()->Profile(callback, stream); |
| return Api::Success(isolate); |
| } |
| |
| // --- Initialization and Globals --- |
| |
| DART_EXPORT const char* Dart_VersionString() { |
| return Version::String(); |
| } |
| |
| DART_EXPORT bool Dart_Initialize( |
| Dart_IsolateCreateCallback create, |
| Dart_IsolateInterruptCallback interrupt, |
| Dart_IsolateUnhandledExceptionCallback unhandled, |
| Dart_IsolateShutdownCallback shutdown, |
| Dart_FileOpenCallback file_open, |
| Dart_FileWriteCallback file_write, |
| Dart_FileCloseCallback file_close) { |
| const char* err_msg = Dart::InitOnce(create, interrupt, unhandled, shutdown, |
| file_open, file_write, file_close); |
| if (err_msg != NULL) { |
| OS::PrintErr("Dart_Initialize: %s\n", err_msg); |
| return false; |
| } |
| return true; |
| } |
| |
| DART_EXPORT bool Dart_SetVMFlags(int argc, const char** argv) { |
| return Flags::ProcessCommandLineFlags(argc, argv); |
| } |
| |
| DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name) { |
| if (Flags::Lookup(flag_name) != NULL) { |
| return true; |
| } |
| return false; |
| } |
| |
| |
| // --- Isolates --- |
| |
| |
| static char* BuildIsolateName(const char* script_uri, |
| const char* main) { |
| if (script_uri == NULL) { |
| // Just use the main as the name. |
| if (main == NULL) { |
| return strdup("isolate"); |
| } else { |
| return strdup(main); |
| } |
| } |
| |
| // Skip past any slashes and backslashes in the script uri. |
| const char* last_slash = strrchr(script_uri, '/'); |
| if (last_slash != NULL) { |
| script_uri = last_slash + 1; |
| } |
| const char* last_backslash = strrchr(script_uri, '\\'); |
| if (last_backslash != NULL) { |
| script_uri = last_backslash + 1; |
| } |
| if (main == NULL) { |
| main = "main"; |
| } |
| |
| char* chars = NULL; |
| intptr_t len = OS::SNPrint(NULL, 0, "%s$%s", script_uri, main) + 1; |
| chars = reinterpret_cast<char*>(malloc(len)); |
| OS::SNPrint(chars, len, "%s$%s", script_uri, main); |
| return chars; |
| } |
| |
| |
| DART_EXPORT Dart_Isolate Dart_CreateIsolate(const char* script_uri, |
| const char* main, |
| const uint8_t* snapshot, |
| void* callback_data, |
| char** error) { |
| char* isolate_name = BuildIsolateName(script_uri, main); |
| Isolate* isolate = Dart::CreateIsolate(isolate_name); |
| free(isolate_name); |
| { |
| StackZone zone(isolate); |
| HANDLESCOPE(isolate); |
| const Error& error_obj = |
| Error::Handle(isolate, |
| Dart::InitializeIsolate(snapshot, callback_data)); |
| if (error_obj.IsNull()) { |
| START_TIMER(time_total_runtime); |
| return reinterpret_cast<Dart_Isolate>(isolate); |
| } |
| *error = strdup(error_obj.ToErrorCString()); |
| } |
| Dart::ShutdownIsolate(); |
| return reinterpret_cast<Dart_Isolate>(NULL); |
| } |
| |
| |
| DART_EXPORT void Dart_ShutdownIsolate() { |
| CHECK_ISOLATE(Isolate::Current()); |
| STOP_TIMER(time_total_runtime); |
| Dart::ShutdownIsolate(); |
| } |
| |
| |
| DART_EXPORT Dart_Isolate Dart_CurrentIsolate() { |
| return Api::CastIsolate(Isolate::Current()); |
| } |
| |
| |
| DART_EXPORT void* Dart_CurrentIsolateData() { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| return isolate->init_callback_data(); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_DebugName() { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| return Api::NewHandle(isolate, String::New(isolate->name())); |
| } |
| |
| |
| |
| DART_EXPORT void Dart_EnterIsolate(Dart_Isolate dart_isolate) { |
| CHECK_NO_ISOLATE(Isolate::Current()); |
| Isolate* isolate = reinterpret_cast<Isolate*>(dart_isolate); |
| Isolate::SetCurrent(isolate); |
| } |
| |
| |
| DART_EXPORT void Dart_ExitIsolate() { |
| CHECK_ISOLATE(Isolate::Current()); |
| Isolate::SetCurrent(NULL); |
| } |
| |
| |
| static uint8_t* ApiReallocate(uint8_t* ptr, |
| intptr_t old_size, |
| intptr_t new_size) { |
| return Api::TopScope(Isolate::Current())->zone()->Realloc<uint8_t>( |
| ptr, old_size, new_size); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_CreateSnapshot(uint8_t** buffer, |
| intptr_t* size) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| TIMERSCOPE(time_creating_snapshot); |
| if (buffer == NULL) { |
| RETURN_NULL_ERROR(buffer); |
| } |
| if (size == NULL) { |
| RETURN_NULL_ERROR(size); |
| } |
| Dart_Handle state = Api::CheckIsolateState(isolate); |
| if (::Dart_IsError(state)) { |
| return state; |
| } |
| // Since this is only a snapshot the root library should not be set. |
| isolate->object_store()->set_root_library(Library::Handle(isolate)); |
| FullSnapshotWriter writer(buffer, ApiReallocate); |
| writer.WriteFullSnapshot(); |
| *size = writer.BytesWritten(); |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_CreateScriptSnapshot(uint8_t** buffer, |
| intptr_t* size) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| TIMERSCOPE(time_creating_snapshot); |
| if (buffer == NULL) { |
| RETURN_NULL_ERROR(buffer); |
| } |
| if (size == NULL) { |
| RETURN_NULL_ERROR(size); |
| } |
| Dart_Handle state = Api::CheckIsolateState(isolate); |
| if (::Dart_IsError(state)) { |
| return state; |
| } |
| Library& library = |
| Library::Handle(isolate, isolate->object_store()->root_library()); |
| if (library.IsNull()) { |
| return |
| Api::NewError("%s expects the isolate to have a script loaded in it.", |
| CURRENT_FUNC); |
| } |
| ScriptSnapshotWriter writer(buffer, ApiReallocate); |
| writer.WriteScriptSnapshot(library); |
| *size = writer.BytesWritten(); |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT void Dart_InterruptIsolate(Dart_Isolate isolate) { |
| if (isolate == NULL) { |
| FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC); |
| } |
| Isolate* iso = reinterpret_cast<Isolate*>(isolate); |
| iso->ScheduleInterrupts(Isolate::kApiInterrupt); |
| } |
| |
| |
| DART_EXPORT bool Dart_IsolateMakeRunnable(Dart_Isolate isolate) { |
| CHECK_NO_ISOLATE(Isolate::Current()); |
| if (isolate == NULL) { |
| FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC); |
| } |
| Isolate* iso = reinterpret_cast<Isolate*>(isolate); |
| return iso->MakeRunnable(); |
| } |
| |
| |
| // --- Messages and Ports --- |
| |
| DART_EXPORT void Dart_SetMessageNotifyCallback( |
| Dart_MessageNotifyCallback message_notify_callback) { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| isolate->set_message_notify_callback(message_notify_callback); |
| } |
| |
| |
| struct RunLoopData { |
| Monitor* monitor; |
| bool done; |
| }; |
| |
| |
| static void RunLoopDone(uword param) { |
| RunLoopData* data = reinterpret_cast<RunLoopData*>(param); |
| ASSERT(data->monitor != NULL); |
| MonitorLocker ml(data->monitor); |
| data->done = true; |
| ml.Notify(); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_RunLoop() { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE_SCOPE(isolate); |
| CHECK_CALLBACK_STATE(isolate); |
| Monitor monitor; |
| MonitorLocker ml(&monitor); |
| { |
| SwitchIsolateScope switch_scope(NULL); |
| |
| RunLoopData data; |
| data.monitor = &monitor; |
| data.done = false; |
| isolate->message_handler()->Run( |
| Dart::thread_pool(), |
| NULL, RunLoopDone, reinterpret_cast<uword>(&data)); |
| while (!data.done) { |
| ml.Wait(); |
| } |
| } |
| if (isolate->object_store()->sticky_error() != Object::null()) { |
| Dart_Handle error = Api::NewHandle(isolate, |
| isolate->object_store()->sticky_error()); |
| isolate->object_store()->clear_sticky_error(); |
| return error; |
| } |
| if (FLAG_print_class_table) { |
| isolate->class_table()->Print(); |
| } |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_HandleMessage() { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE_SCOPE(isolate); |
| CHECK_CALLBACK_STATE(isolate); |
| if (!isolate->message_handler()->HandleNextMessage()) { |
| Dart_Handle error = Api::NewHandle(isolate, |
| isolate->object_store()->sticky_error()); |
| isolate->object_store()->clear_sticky_error(); |
| return error; |
| } |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT bool Dart_HasLivePorts() { |
| Isolate* isolate = Isolate::Current(); |
| ASSERT(isolate); |
| return isolate->message_handler()->HasLivePorts(); |
| } |
| |
| |
| static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) { |
| void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size); |
| return reinterpret_cast<uint8_t*>(new_ptr); |
| } |
| |
| |
| DART_EXPORT bool Dart_PostIntArray(Dart_Port port_id, |
| intptr_t len, |
| intptr_t* data) { |
| uint8_t* buffer = NULL; |
| ApiMessageWriter writer(&buffer, &allocator); |
| writer.WriteMessage(len, data); |
| |
| // Post the message at the given port. |
| return PortMap::PostMessage(new Message( |
| port_id, Message::kIllegalPort, buffer, writer.BytesWritten(), |
| Message::kNormalPriority)); |
| } |
| |
| |
| DART_EXPORT bool Dart_PostCObject(Dart_Port port_id, Dart_CObject* message) { |
| uint8_t* buffer = NULL; |
| ApiMessageWriter writer(&buffer, allocator); |
| bool success = writer.WriteCMessage(message); |
| |
| if (!success) return success; |
| |
| // Post the message at the given port. |
| return PortMap::PostMessage(new Message( |
| port_id, Message::kIllegalPort, buffer, writer.BytesWritten(), |
| Message::kNormalPriority)); |
| } |
| |
| |
| DART_EXPORT bool Dart_Post(Dart_Port port_id, Dart_Handle handle) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Object& object = Object::Handle(isolate, Api::UnwrapHandle(handle)); |
| uint8_t* data = NULL; |
| MessageWriter writer(&data, &allocator); |
| writer.WriteMessage(object); |
| intptr_t len = writer.BytesWritten(); |
| return PortMap::PostMessage(new Message( |
| port_id, Message::kIllegalPort, data, len, Message::kNormalPriority)); |
| } |
| |
| |
| DART_EXPORT Dart_Port Dart_NewNativePort(const char* name, |
| Dart_NativeMessageHandler handler, |
| bool handle_concurrently) { |
| if (name == NULL) { |
| name = "<UnnamedNativePort>"; |
| } |
| if (handler == NULL) { |
| OS::PrintErr("%s expects argument 'handler' to be non-null.\n", |
| CURRENT_FUNC); |
| return ILLEGAL_PORT; |
| } |
| // Start the native port without a current isolate. |
| IsolateSaver saver(Isolate::Current()); |
| Isolate::SetCurrent(NULL); |
| |
| NativeMessageHandler* nmh = new NativeMessageHandler(name, handler); |
| Dart_Port port_id = PortMap::CreatePort(nmh); |
| nmh->Run(Dart::thread_pool(), NULL, NULL, 0); |
| return port_id; |
| } |
| |
| |
| DART_EXPORT bool Dart_CloseNativePort(Dart_Port native_port_id) { |
| // Close the native port without a current isolate. |
| IsolateSaver saver(Isolate::Current()); |
| Isolate::SetCurrent(NULL); |
| |
| // TODO(turnidge): Check that the port is native before trying to close. |
| return PortMap::ClosePort(native_port_id); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| CHECK_CALLBACK_STATE(isolate); |
| return Api::NewHandle(isolate, DartLibraryCalls::NewSendPort(port_id)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_GetReceivePort(Dart_Port port_id) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| CHECK_CALLBACK_STATE(isolate); |
| |
| Library& isolate_lib = Library::Handle(isolate, Library::IsolateLibrary()); |
| ASSERT(!isolate_lib.IsNull()); |
| const String& class_name = String::Handle( |
| isolate, isolate_lib.PrivateName(Symbols::_ReceivePortImpl())); |
| // TODO(asiva): Symbols should contain private keys. |
| const String& function_name = |
| String::Handle(isolate_lib.PrivateName(Symbols::_get_or_create())); |
| const int kNumArguments = 1; |
| const Function& function = Function::Handle( |
| isolate, |
| Resolver::ResolveStatic(isolate_lib, |
| class_name, |
| function_name, |
| kNumArguments, |
| Object::empty_array(), |
| Resolver::kIsQualified)); |
| ASSERT(!function.IsNull()); |
| const Array& args = Array::Handle(isolate, Array::New(kNumArguments)); |
| args.SetAt(0, Integer::Handle(isolate, Integer::New(port_id))); |
| return Api::NewHandle(isolate, DartEntry::InvokeFunction(function, args)); |
| } |
| |
| |
| DART_EXPORT Dart_Port Dart_GetMainPortId() { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| return isolate->main_port(); |
| } |
| |
| // --- Scopes ---- |
| |
| |
| DART_EXPORT void Dart_EnterScope() { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| ApiLocalScope* new_scope = new ApiLocalScope(state->top_scope(), |
| isolate->top_exit_frame_info()); |
| ASSERT(new_scope != NULL); |
| state->set_top_scope(new_scope); // New scope is now the top scope. |
| } |
| |
| |
| DART_EXPORT void Dart_ExitScope() { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE_SCOPE(isolate); |
| ApiState* state = isolate->api_state(); |
| ApiLocalScope* scope = state->top_scope(); |
| |
| state->set_top_scope(scope->previous()); // Reset top scope to previous. |
| delete scope; // Free up the old scope which we have just exited. |
| } |
| |
| |
| DART_EXPORT uint8_t* Dart_ScopeAllocate(intptr_t size) { |
| Zone* zone; |
| Isolate* isolate = Isolate::Current(); |
| if (isolate != NULL) { |
| ApiState* state = isolate->api_state(); |
| if (state == NULL) return NULL; |
| ApiLocalScope* scope = state->top_scope(); |
| zone = scope->zone(); |
| } else { |
| ApiNativeScope* scope = ApiNativeScope::Current(); |
| if (scope == NULL) return NULL; |
| zone = scope->zone(); |
| } |
| return reinterpret_cast<uint8_t*>(zone->AllocUnsafe(size)); |
| } |
| |
| |
| // --- Objects ---- |
| |
| |
| DART_EXPORT Dart_Handle Dart_Null() { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE_SCOPE(isolate); |
| return Api::Null(isolate); |
| } |
| |
| |
| DART_EXPORT bool Dart_IsNull(Dart_Handle object) { |
| return Api::ClassId(object) == kNullCid; |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_ObjectEquals(Dart_Handle obj1, Dart_Handle obj2, |
| bool* value) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| CHECK_CALLBACK_STATE(isolate); |
| const Instance& expected = |
| Instance::CheckedHandle(isolate, Api::UnwrapHandle(obj1)); |
| const Instance& actual = |
| Instance::CheckedHandle(isolate, Api::UnwrapHandle(obj2)); |
| const Object& result = |
| Object::Handle(isolate, DartLibraryCalls::Equals(expected, actual)); |
| if (result.IsBool()) { |
| *value = Bool::Cast(result).value(); |
| return Api::Success(isolate); |
| } else if (result.IsError()) { |
| return Api::NewHandle(isolate, result.raw()); |
| } else { |
| return Api::NewError("Expected boolean result from =="); |
| } |
| } |
| |
| |
| // TODO(iposva): This call actually implements IsInstanceOfClass. |
| // Do we also need a real Dart_IsInstanceOf, which should take an instance |
| // rather than an object and a type rather than a class? |
| DART_EXPORT Dart_Handle Dart_ObjectIsType(Dart_Handle object, |
| Dart_Handle clazz, |
| bool* value) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| |
| const Class& cls = Api::UnwrapClassHandle(isolate, clazz); |
| if (cls.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, clazz, Class); |
| } |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object)); |
| if (obj.IsError()) { |
| return object; |
| } else if (!obj.IsNull() && !obj.IsInstance()) { |
| return Api::NewError( |
| "%s expects argument 'object' to be an instance of Object.", |
| CURRENT_FUNC); |
| } |
| // Finalize all classes. |
| Dart_Handle state = Api::CheckIsolateState(isolate); |
| if (::Dart_IsError(state)) { |
| return state; |
| } |
| if (obj.IsInstance()) { |
| CHECK_CALLBACK_STATE(isolate); |
| const Type& type = Type::Handle(isolate, |
| Type::NewNonParameterizedType(cls)); |
| Error& malformed_type_error = Error::Handle(isolate); |
| *value = Instance::Cast(obj).IsInstanceOf(type, |
| TypeArguments::Handle(isolate), |
| &malformed_type_error); |
| ASSERT(malformed_type_error.IsNull()); // Type was created from a class. |
| } else { |
| *value = false; |
| } |
| return Api::Success(isolate); |
| } |
| |
| |
| // --- Instances ---- |
| |
| |
| DART_EXPORT bool Dart_IsInstance(Dart_Handle object) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object)); |
| return obj.IsInstance(); |
| } |
| |
| |
| // TODO(turnidge): Technically, null has a class. Should we allow it? |
| DART_EXPORT Dart_Handle Dart_InstanceGetClass(Dart_Handle instance) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Instance& obj = Api::UnwrapInstanceHandle(isolate, instance); |
| if (obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, instance, Instance); |
| } |
| return Api::NewHandle(isolate, obj.clazz()); |
| } |
| |
| |
| // --- Numbers ---- |
| |
| |
| DART_EXPORT bool Dart_IsNumber(Dart_Handle object) { |
| return RawObject::IsNumberClassId(Api::ClassId(object)); |
| } |
| |
| |
| // --- Integers ---- |
| |
| |
| DART_EXPORT bool Dart_IsInteger(Dart_Handle object) { |
| return RawObject::IsIntegerClassId(Api::ClassId(object)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_IntegerFitsIntoInt64(Dart_Handle integer, |
| bool* fits) { |
| // Fast path for Smis and Mints. |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| intptr_t class_id = Api::ClassId(integer); |
| if (class_id == kSmiCid || class_id == kMintCid) { |
| *fits = true; |
| return Api::Success(isolate); |
| } |
| // Slow path for Mints and Bigints. |
| DARTSCOPE(isolate); |
| const Integer& int_obj = Api::UnwrapIntegerHandle(isolate, integer); |
| if (int_obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, integer, Integer); |
| } |
| ASSERT(!BigintOperations::FitsIntoMint(Bigint::Cast(int_obj))); |
| *fits = false; |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_IntegerFitsIntoUint64(Dart_Handle integer, |
| bool* fits) { |
| // Fast path for Smis. |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| if (Api::IsSmi(integer)) { |
| *fits = (Api::SmiValue(integer) >= 0); |
| return Api::Success(isolate); |
| } |
| // Slow path for Mints and Bigints. |
| DARTSCOPE(isolate); |
| const Integer& int_obj = Api::UnwrapIntegerHandle(isolate, integer); |
| if (int_obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, integer, Integer); |
| } |
| ASSERT(!int_obj.IsSmi()); |
| if (int_obj.IsMint()) { |
| *fits = !int_obj.IsNegative(); |
| } else { |
| *fits = BigintOperations::FitsIntoUint64(Bigint::Cast(int_obj)); |
| } |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value) { |
| // Fast path for Smis. |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| if (Smi::IsValid64(value)) { |
| NOHANDLESCOPE(isolate); |
| return Api::NewHandle(isolate, Smi::New(static_cast<intptr_t>(value))); |
| } |
| // Slow path for Mints and Bigints. |
| DARTSCOPE(isolate); |
| CHECK_CALLBACK_STATE(isolate); |
| return Api::NewHandle(isolate, Integer::New(value)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewIntegerFromHexCString(const char* str) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| CHECK_CALLBACK_STATE(isolate); |
| const String& str_obj = String::Handle(isolate, String::New(str)); |
| return Api::NewHandle(isolate, Integer::New(str_obj)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_IntegerToInt64(Dart_Handle integer, |
| int64_t* value) { |
| // Fast path for Smis. |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| if (Api::IsSmi(integer)) { |
| *value = Api::SmiValue(integer); |
| return Api::Success(isolate); |
| } |
| // Slow path for Mints and Bigints. |
| DARTSCOPE(isolate); |
| const Integer& int_obj = Api::UnwrapIntegerHandle(isolate, integer); |
| if (int_obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, integer, Integer); |
| } |
| ASSERT(!int_obj.IsSmi()); |
| if (int_obj.IsMint()) { |
| *value = int_obj.AsInt64Value(); |
| return Api::Success(isolate); |
| } else { |
| const Bigint& bigint = Bigint::Cast(int_obj); |
| if (BigintOperations::FitsIntoMint(bigint)) { |
| *value = BigintOperations::ToMint(bigint); |
| return Api::Success(isolate); |
| } |
| } |
| return Api::NewError("%s: Integer %s cannot be represented as an int64_t.", |
| CURRENT_FUNC, int_obj.ToCString()); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_IntegerToUint64(Dart_Handle integer, |
| uint64_t* value) { |
| // Fast path for Smis. |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE(isolate); |
| if (Api::IsSmi(integer)) { |
| intptr_t smi_value = Api::SmiValue(integer); |
| if (smi_value >= 0) { |
| *value = smi_value; |
| return Api::Success(isolate); |
| } |
| } |
| // Slow path for Mints and Bigints. |
| DARTSCOPE(isolate); |
| const Integer& int_obj = Api::UnwrapIntegerHandle(isolate, integer); |
| if (int_obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, integer, Integer); |
| } |
| ASSERT(!int_obj.IsSmi()); |
| if (int_obj.IsMint() && !int_obj.IsNegative()) { |
| *value = int_obj.AsInt64Value(); |
| return Api::Success(isolate); |
| } else { |
| const Bigint& bigint = Bigint::Cast(int_obj); |
| if (BigintOperations::FitsIntoUint64(bigint)) { |
| *value = BigintOperations::ToUint64(bigint); |
| return Api::Success(isolate); |
| } |
| } |
| return Api::NewError("%s: Integer %s cannot be represented as a uint64_t.", |
| CURRENT_FUNC, int_obj.ToCString()); |
| } |
| |
| |
| static uword BigintAllocate(intptr_t size) { |
| return Api::TopScope(Isolate::Current())->zone()->AllocUnsafe(size); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_IntegerToHexCString(Dart_Handle integer, |
| const char** value) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Integer& int_obj = Api::UnwrapIntegerHandle(isolate, integer); |
| if (int_obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, integer, Integer); |
| } |
| if (int_obj.IsSmi() || int_obj.IsMint()) { |
| const Bigint& bigint = Bigint::Handle(isolate, |
| BigintOperations::NewFromInt64(int_obj.AsInt64Value())); |
| *value = BigintOperations::ToHexCString(bigint, BigintAllocate); |
| } else { |
| *value = BigintOperations::ToHexCString(Bigint::Cast(int_obj), |
| BigintAllocate); |
| } |
| return Api::Success(isolate); |
| } |
| |
| |
| // --- Booleans ---- |
| |
| |
| DART_EXPORT Dart_Handle Dart_True() { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE_SCOPE(isolate); |
| return Api::True(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_False() { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE_SCOPE(isolate); |
| return Api::False(isolate); |
| } |
| |
| |
| DART_EXPORT bool Dart_IsBoolean(Dart_Handle object) { |
| return Api::ClassId(object) == kBoolCid; |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewBoolean(bool value) { |
| Isolate* isolate = Isolate::Current(); |
| CHECK_ISOLATE_SCOPE(isolate); |
| return value ? Api::True(isolate) : Api::False(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_BooleanValue(Dart_Handle boolean_obj, |
| bool* value) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Bool& obj = Api::UnwrapBoolHandle(isolate, boolean_obj); |
| if (obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, boolean_obj, Bool); |
| } |
| *value = obj.value(); |
| return Api::Success(isolate); |
| } |
| |
| |
| // --- Doubles --- |
| |
| |
| DART_EXPORT bool Dart_IsDouble(Dart_Handle object) { |
| return Api::ClassId(object) == kDoubleCid; |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewDouble(double value) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| CHECK_CALLBACK_STATE(isolate); |
| return Api::NewHandle(isolate, Double::New(value)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj, |
| double* value) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Double& obj = Api::UnwrapDoubleHandle(isolate, double_obj); |
| if (obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, double_obj, Double); |
| } |
| *value = obj.value(); |
| return Api::Success(isolate); |
| } |
| |
| |
| // --- Strings --- |
| |
| |
| DART_EXPORT bool Dart_IsString(Dart_Handle object) { |
| return RawObject::IsStringClassId(Api::ClassId(object)); |
| } |
| |
| |
| DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object) { |
| return RawObject::IsOneByteStringClassId(Api::ClassId(object)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_StringLength(Dart_Handle str, intptr_t* len) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const String& str_obj = Api::UnwrapStringHandle(isolate, str); |
| if (str_obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, str, String); |
| } |
| *len = str_obj.Length(); |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char* str) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| if (str == NULL) { |
| RETURN_NULL_ERROR(str); |
| } |
| CHECK_CALLBACK_STATE(isolate); |
| return Api::NewHandle(isolate, String::New(str)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewStringFromUTF8(const uint8_t* utf8_array, |
| intptr_t length) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| if (utf8_array == NULL && length != 0) { |
| RETURN_NULL_ERROR(utf8_array); |
| } |
| CHECK_LENGTH(length, String::kMaxElements); |
| if (!Utf8::IsValid(utf8_array, length)) { |
| return Api::NewError("%s expects argument 'str' to be valid UTF-8.", |
| CURRENT_FUNC); |
| } |
| CHECK_CALLBACK_STATE(isolate); |
| return Api::NewHandle(isolate, String::FromUTF8(utf8_array, length)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewStringFromUTF16(const uint16_t* utf16_array, |
| intptr_t length) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| if (utf16_array == NULL && length != 0) { |
| RETURN_NULL_ERROR(utf16_array); |
| } |
| CHECK_LENGTH(length, String::kMaxElements); |
| CHECK_CALLBACK_STATE(isolate); |
| return Api::NewHandle(isolate, String::FromUTF16(utf16_array, length)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const int32_t* utf32_array, |
| intptr_t length) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| if (utf32_array == NULL && length != 0) { |
| RETURN_NULL_ERROR(utf32_array); |
| } |
| CHECK_LENGTH(length, String::kMaxElements); |
| CHECK_CALLBACK_STATE(isolate); |
| return Api::NewHandle(isolate, String::FromUTF32(utf32_array, length)); |
| } |
| |
| |
| DART_EXPORT bool Dart_IsExternalString(Dart_Handle object) { |
| return RawObject::IsExternalStringClassId(Api::ClassId(object)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_ExternalStringGetPeer(Dart_Handle object, |
| void** peer) { |
| if (peer == NULL) { |
| RETURN_NULL_ERROR(peer); |
| } |
| |
| if (Api::ExternalStringGetPeerHelper(object, peer)) { |
| return Api::Success(Isolate::Current()); |
| } |
| |
| // It's not an external string, return appropriate error. |
| if (!RawObject::IsStringClassId(Api::ClassId(object))) { |
| RETURN_TYPE_ERROR(Isolate::Current(), object, String); |
| } else { |
| return |
| Api::NewError( |
| "%s expects argument 'object' to be an external String.", |
| CURRENT_FUNC); |
| } |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewExternalLatin1String( |
| const uint8_t* latin1_array, |
| intptr_t length, |
| void* peer, |
| Dart_PeerFinalizer cback) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| if (latin1_array == NULL && length != 0) { |
| RETURN_NULL_ERROR(latin1_array); |
| } |
| CHECK_LENGTH(length, String::kMaxElements); |
| CHECK_CALLBACK_STATE(isolate); |
| return Api::NewHandle(isolate, |
| String::NewExternal(latin1_array, length, peer, cback)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewExternalUTF16String(const uint16_t* utf16_array, |
| intptr_t length, |
| void* peer, |
| Dart_PeerFinalizer cback) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| if (utf16_array == NULL && length != 0) { |
| RETURN_NULL_ERROR(utf16_array); |
| } |
| CHECK_LENGTH(length, String::kMaxElements); |
| CHECK_CALLBACK_STATE(isolate); |
| return Api::NewHandle(isolate, |
| String::NewExternal(utf16_array, length, peer, cback)); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle object, |
| const char** cstr) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| if (cstr == NULL) { |
| RETURN_NULL_ERROR(cstr); |
| } |
| const String& str_obj = Api::UnwrapStringHandle(isolate, object); |
| if (str_obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, object, String); |
| } |
| intptr_t string_length = Utf8::Length(str_obj); |
| char* res = Api::TopScope(isolate)->zone()->Alloc<char>(string_length + 1); |
| if (res == NULL) { |
| return Api::NewError("Unable to allocate memory"); |
| } |
| const char* string_value = str_obj.ToCString(); |
| memmove(res, string_value, string_length + 1); |
| ASSERT(res[string_length] == '\0'); |
| *cstr = res; |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_StringToUTF8(Dart_Handle str, |
| uint8_t** utf8_array, |
| intptr_t* length) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| if (utf8_array == NULL) { |
| RETURN_NULL_ERROR(utf8_array); |
| } |
| if (length == NULL) { |
| RETURN_NULL_ERROR(length); |
| } |
| const String& str_obj = Api::UnwrapStringHandle(isolate, str); |
| if (str_obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, str, String); |
| } |
| intptr_t str_len = Utf8::Length(str_obj); |
| *utf8_array = Api::TopScope(isolate)->zone()->Alloc<uint8_t>(str_len); |
| if (*utf8_array == NULL) { |
| return Api::NewError("Unable to allocate memory"); |
| } |
| str_obj.ToUTF8(*utf8_array, str_len); |
| *length = str_len; |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_StringToLatin1(Dart_Handle str, |
| uint8_t* latin1_array, |
| intptr_t* length) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| if (latin1_array == NULL) { |
| RETURN_NULL_ERROR(latin1_array); |
| } |
| if (length == NULL) { |
| RETURN_NULL_ERROR(length); |
| } |
| const String& str_obj = Api::UnwrapStringHandle(isolate, str); |
| if (str_obj.IsNull() || !str_obj.IsOneByteString()) { |
| RETURN_TYPE_ERROR(isolate, str, String); |
| } |
| intptr_t str_len = str_obj.Length(); |
| intptr_t copy_len = (str_len > *length) ? *length : str_len; |
| |
| // We have already asserted that the string object is a Latin-1 string |
| // so we can copy the characters over using a simple loop. |
| for (intptr_t i = 0; i < copy_len; i++) { |
| latin1_array[i] = str_obj.CharAt(i); |
| } |
| *length = copy_len; |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_StringToUTF16(Dart_Handle str, |
| uint16_t* utf16_array, |
| intptr_t* length) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const String& str_obj = Api::UnwrapStringHandle(isolate, str); |
| if (str_obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, str, String); |
| } |
| intptr_t str_len = str_obj.Length(); |
| intptr_t copy_len = (str_len > *length) ? *length : str_len; |
| for (intptr_t i = 0; i < copy_len; i++) { |
| utf16_array[i] = static_cast<uint16_t>(str_obj.CharAt(i)); |
| } |
| *length = copy_len; |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_StringStorageSize(Dart_Handle str, |
| intptr_t* size) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const String& str_obj = Api::UnwrapStringHandle(isolate, str); |
| if (str_obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, str, String); |
| } |
| if (size == NULL) { |
| RETURN_NULL_ERROR(size); |
| } |
| *size = (str_obj.Length() * str_obj.CharSize()); |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_MakeExternalString(Dart_Handle str, |
| void* array, |
| intptr_t length, |
| void* peer, |
| Dart_PeerFinalizer cback) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const String& str_obj = Api::UnwrapStringHandle(isolate, str); |
| if (str_obj.IsExternal()) { |
| return str; // String is already an external string. |
| } |
| if (str_obj.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, str, String); |
| } |
| if (array == NULL) { |
| RETURN_NULL_ERROR(array); |
| } |
| intptr_t str_size = (str_obj.Length() * str_obj.CharSize()); |
| if ((length < str_size) || (length > String::kMaxElements)) { |
| return Api::NewError("Dart_MakeExternalString " |
| "expects argument length to be in the range" |
| "[%"Pd"..%"Pd"].", |
| str_size, String::kMaxElements); |
| } |
| if (str_obj.InVMHeap()) { |
| // Since the string object is read only we do not externalize |
| // the string but instead copy the contents of the string into the |
| // specified buffer and return a Null object. |
| // This ensures that the embedder does not have to call again |
| // to get at the contents. |
| intptr_t copy_len = str_obj.Length(); |
| if (str_obj.IsOneByteString()) { |
| ASSERT(length >= copy_len); |
| uint8_t* latin1_array = reinterpret_cast<uint8_t*>(array); |
| for (intptr_t i = 0; i < copy_len; i++) { |
| latin1_array[i] = static_cast<uint8_t>(str_obj.CharAt(i)); |
| } |
| } else { |
| ASSERT(str_obj.IsTwoByteString()); |
| ASSERT(length >= (copy_len * str_obj.CharSize())); |
| uint16_t* utf16_array = reinterpret_cast<uint16_t*>(array); |
| for (intptr_t i = 0; i < copy_len; i++) { |
| utf16_array[i] = static_cast<uint16_t>(str_obj.CharAt(i)); |
| } |
| } |
| return Api::Null(isolate); |
| } |
| return Api::NewHandle(isolate, |
| str_obj.MakeExternal(array, length, peer, cback)); |
| } |
| |
| |
| // --- Lists --- |
| |
| |
| static RawInstance* GetListInstance(Isolate* isolate, const Object& obj) { |
| if (obj.IsInstance()) { |
| const Instance& instance = Instance::Cast(obj); |
| const Class& obj_class = Class::Handle(isolate, obj.clazz()); |
| const Class& list_class = |
| Class::Handle(isolate, isolate->object_store()->list_class()); |
| Error& malformed_type_error = Error::Handle(isolate); |
| if (obj_class.IsSubtypeOf(TypeArguments::Handle(isolate), |
| list_class, |
| TypeArguments::Handle(isolate), |
| &malformed_type_error)) { |
| ASSERT(malformed_type_error.IsNull()); // Type is a raw List. |
| return instance.raw(); |
| } |
| } |
| return Instance::null(); |
| } |
| |
| |
| DART_EXPORT bool Dart_IsList(Dart_Handle object) { |
| if (RawObject::IsBuiltinListClassId(Api::ClassId(object))) { |
| return true; |
| } |
| |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(object)); |
| return GetListInstance(isolate, obj) != Instance::null(); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewList(intptr_t length) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| CHECK_LENGTH(length, Array::kMaxElements); |
| CHECK_CALLBACK_STATE(isolate); |
| return Api::NewHandle(isolate, Array::New(length)); |
| } |
| |
| |
| #define GET_LIST_LENGTH(isolate, type, obj, len) \ |
| type& array = type::Handle(isolate); \ |
| array ^= obj.raw(); \ |
| *len = array.Length(); \ |
| return Api::Success(isolate); \ |
| |
| |
| DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t* len) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(list)); |
| if (obj.IsError()) { |
| // Pass through errors. |
| return list; |
| } |
| if (obj.IsTypedData()) { |
| GET_LIST_LENGTH(isolate, TypedData, obj, len); |
| } |
| if (obj.IsArray()) { |
| GET_LIST_LENGTH(isolate, Array, obj, len); |
| } |
| if (obj.IsGrowableObjectArray()) { |
| GET_LIST_LENGTH(isolate, GrowableObjectArray, obj, len); |
| } |
| if (obj.IsExternalTypedData()) { |
| GET_LIST_LENGTH(isolate, ExternalTypedData, obj, len); |
| } |
| CHECK_CALLBACK_STATE(isolate); |
| |
| // Now check and handle a dart object that implements the List interface. |
| const Instance& instance = |
| Instance::Handle(isolate, GetListInstance(isolate, obj)); |
| if (instance.IsNull()) { |
| return Api::NewError("Object does not implement the List interface"); |
| } |
| const String& name = String::Handle(Field::GetterName(Symbols::Length())); |
| const Function& function = |
| Function::Handle(isolate, Resolver::ResolveDynamic(instance, name, 1, 0)); |
| if (function.IsNull()) { |
| return Api::NewError("List object does not have a 'length' field."); |
| } |
| |
| const int kNumArgs = 1; |
| const Array& args = Array::Handle(isolate, Array::New(kNumArgs)); |
| args.SetAt(0, instance); // Set up the receiver as the first argument. |
| const Object& retval = |
| Object::Handle(isolate, DartEntry::InvokeFunction(function, args)); |
| if (retval.IsSmi()) { |
| *len = Smi::Cast(retval).Value(); |
| return Api::Success(isolate); |
| } else if (retval.IsMint() || retval.IsBigint()) { |
| if (retval.IsMint()) { |
| int64_t mint_value = Mint::Cast(retval).value(); |
| if (mint_value >= kIntptrMin && mint_value <= kIntptrMax) { |
| *len = static_cast<intptr_t>(mint_value); |
| } |
| } else { |
| // Check for a non-canonical Mint range value. |
| ASSERT(retval.IsBigint()); |
| const Bigint& bigint = Bigint::Handle(); |
| if (BigintOperations::FitsIntoMint(bigint)) { |
| int64_t bigint_value = bigint.AsInt64Value(); |
| if (bigint_value >= kIntptrMin && bigint_value <= kIntptrMax) { |
| *len = static_cast<intptr_t>(bigint_value); |
| } |
| } |
| } |
| return Api::NewError("Length of List object is greater than the " |
| "maximum value that 'len' parameter can hold"); |
| } else if (retval.IsError()) { |
| return Api::NewHandle(isolate, retval.raw()); |
| } else { |
| return Api::NewError("Length of List object is not an integer"); |
| } |
| } |
| |
| |
| #define GET_LIST_ELEMENT(isolate, type, obj, index) \ |
| const type& array_obj = type::Cast(obj); \ |
| if ((index >= 0) && (index < array_obj.Length())) { \ |
| return Api::NewHandle(isolate, array_obj.At(index)); \ |
| } \ |
| return Api::NewError("Invalid index passed in to access list element"); \ |
| |
| |
| DART_EXPORT Dart_Handle Dart_ListGetAt(Dart_Handle list, intptr_t index) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(list)); |
| if (obj.IsArray()) { |
| GET_LIST_ELEMENT(isolate, Array, obj, index); |
| } else if (obj.IsGrowableObjectArray()) { |
| GET_LIST_ELEMENT(isolate, GrowableObjectArray, obj, index); |
| } else if (obj.IsError()) { |
| return list; |
| } else { |
| CHECK_CALLBACK_STATE(isolate); |
| |
| // Check and handle a dart object that implements the List interface. |
| const Instance& instance = |
| Instance::Handle(isolate, GetListInstance(isolate, obj)); |
| if (!instance.IsNull()) { |
| const Function& function = Function::Handle( |
| isolate, |
| Resolver::ResolveDynamic(instance, Symbols::IndexToken(), 2, 0)); |
| if (!function.IsNull()) { |
| const int kNumArgs = 2; |
| const Array& args = Array::Handle(isolate, Array::New(kNumArgs)); |
| const Integer& indexobj = Integer::Handle(isolate, Integer::New(index)); |
| args.SetAt(0, instance); |
| args.SetAt(1, indexobj); |
| return Api::NewHandle(isolate, DartEntry::InvokeFunction(function, |
| args)); |
| } |
| } |
| return Api::NewError("Object does not implement the 'List' interface"); |
| } |
| } |
| |
| |
| #define SET_LIST_ELEMENT(isolate, type, obj, index, value) \ |
| const type& array = type::Cast(obj); \ |
| const Object& value_obj = Object::Handle(isolate, Api::UnwrapHandle(value)); \ |
| if (!value_obj.IsNull() && !value_obj.IsInstance()) { \ |
| RETURN_TYPE_ERROR(isolate, value, Instance); \ |
| } \ |
| if ((index >= 0) && (index < array.Length())) { \ |
| array.SetAt(index, value_obj); \ |
| return Api::Success(isolate); \ |
| } \ |
| return Api::NewError("Invalid index passed in to set list element"); \ |
| |
| |
| DART_EXPORT Dart_Handle Dart_ListSetAt(Dart_Handle list, |
| intptr_t index, |
| Dart_Handle value) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(list)); |
| // If the list is immutable we call into Dart for the indexed setter to |
| // get the unsupported operation exception as the result. |
| if (obj.IsArray() && !obj.IsImmutableArray()) { |
| SET_LIST_ELEMENT(isolate, Array, obj, index, value); |
| } else if (obj.IsGrowableObjectArray()) { |
| SET_LIST_ELEMENT(isolate, GrowableObjectArray, obj, index, value); |
| } else if (obj.IsError()) { |
| return list; |
| } else { |
| CHECK_CALLBACK_STATE(isolate); |
| |
| // Check and handle a dart object that implements the List interface. |
| const Instance& instance = |
| Instance::Handle(isolate, GetListInstance(isolate, obj)); |
| if (!instance.IsNull()) { |
| const Function& function = Function::Handle( |
| isolate, |
| Resolver::ResolveDynamic(instance, |
| Symbols::AssignIndexToken(), |
| 3, |
| 0)); |
| if (!function.IsNull()) { |
| const Integer& index_obj = |
| Integer::Handle(isolate, Integer::New(index)); |
| const Object& value_obj = |
| Object::Handle(isolate, Api::UnwrapHandle(value)); |
| if (!value_obj.IsNull() && !value_obj.IsInstance()) { |
| RETURN_TYPE_ERROR(isolate, value, Instance); |
| } |
| const intptr_t kNumArgs = 3; |
| const Array& args = Array::Handle(isolate, Array::New(kNumArgs)); |
| args.SetAt(0, instance); |
| args.SetAt(1, index_obj); |
| args.SetAt(2, value_obj); |
| return Api::NewHandle(isolate, DartEntry::InvokeFunction(function, |
| args)); |
| } |
| } |
| return Api::NewError("Object does not implement the 'List' interface"); |
| } |
| } |
| |
| |
| static RawObject* ResolveConstructor(const char* current_func, |
| const Class& cls, |
| const String& class_name, |
| const String& dotted_name, |
| int num_args); |
| |
| |
| static RawObject* ThrowArgumentError(const char* exception_message) { |
| Isolate* isolate = Isolate::Current(); |
| // Lookup the class ArgumentError in dart:core. |
| const String& lib_url = String::Handle(String::New("dart:core")); |
| const String& class_name = String::Handle(String::New("ArgumentError")); |
| const Library& lib = |
| Library::Handle(isolate, Library::LookupLibrary(lib_url)); |
| if (lib.IsNull()) { |
| const String& message = String::Handle( |
| String::NewFormatted("%s: library '%s' not found.", |
| CURRENT_FUNC, lib_url.ToCString())); |
| return ApiError::New(message); |
| } |
| const Class& cls = Class::Handle(isolate, |
| lib.LookupClassAllowPrivate(class_name)); |
| if (cls.IsNull()) { |
| const String& message = String::Handle( |
| String::NewFormatted("%s: class '%s' not found in library '%s'.", |
| CURRENT_FUNC, class_name.ToCString(), |
| lib_url.ToCString())); |
| return ApiError::New(message); |
| } |
| Object& result = Object::Handle(isolate); |
| String& dot_name = String::Handle(String::New(".")); |
| String& constr_name = String::Handle(String::Concat(class_name, dot_name)); |
| result = ResolveConstructor(CURRENT_FUNC, cls, class_name, constr_name, 1); |
| if (result.IsError()) return result.raw(); |
| ASSERT(result.IsFunction()); |
| Function& constructor = Function::Handle(isolate); |
| constructor ^= result.raw(); |
| if (!constructor.IsConstructor()) { |
| const String& message = String::Handle( |
| String::NewFormatted("%s: class '%s' is not a constructor.", |
| CURRENT_FUNC, class_name.ToCString())); |
| return ApiError::New(message); |
| } |
| Instance& exception = Instance::Handle(isolate); |
| exception = Instance::New(cls); |
| const Array& args = Array::Handle(isolate, Array::New(3)); |
| args.SetAt(0, exception); |
| args.SetAt(1, |
| Smi::Handle(isolate, Smi::New(Function::kCtorPhaseAll))); |
| args.SetAt(2, String::Handle(String::New(exception_message))); |
| result = DartEntry::InvokeFunction(constructor, args); |
| if (result.IsError()) return result.raw(); |
| ASSERT(result.IsNull()); |
| |
| if (isolate->top_exit_frame_info() == 0) { |
| // There are no dart frames on the stack so it would be illegal to |
| // throw an exception here. |
| const String& message = String::Handle( |
| String::New("No Dart frames on stack, cannot throw exception")); |
| return ApiError::New(message); |
| } |
| // Unwind all the API scopes till the exit frame before throwing an |
| // exception. |
| ApiState* state = isolate->api_state(); |
| ASSERT(state != NULL); |
| const Instance* saved_exception; |
| { |
| NoGCScope no_gc; |
| RawInstance* raw_exception = exception.raw(); |
| state->UnwindScopes(isolate->top_exit_frame_info()); |
| saved_exception = &Instance::Handle(raw_exception); |
| } |
| Exceptions::Throw(*saved_exception); |
| const String& message = String::Handle( |
| String::New("Exception was not thrown, internal error")); |
| return ApiError::New(message); |
| } |
| |
| // TODO(sgjesse): value should always be smaller then 0xff. Add error handling. |
| #define GET_LIST_ELEMENT_AS_BYTES(isolate, type, obj, native_array, offset, \ |
| length) \ |
| const type& array = type::Cast(obj); \ |
| if (Utils::RangeCheck(offset, length, array.Length())) { \ |
| Object& element = Object::Handle(isolate); \ |
| for (int i = 0; i < length; i++) { \ |
| element = array.At(offset + i); \ |
| if (!element.IsInteger()) { \ |
| return Api::NewHandle( \ |
| isolate, ThrowArgumentError("List contains non-int elements")); \ |
| \ |
| } \ |
| const Integer& integer = Integer::Cast(element); \ |
| native_array[i] = static_cast<uint8_t>(integer.AsInt64Value() & 0xff); \ |
| ASSERT(integer.AsInt64Value() <= 0xff); \ |
| } \ |
| return Api::Success(isolate); \ |
| } \ |
| return Api::NewError("Invalid length passed in to access array elements"); \ |
| |
| |
| DART_EXPORT Dart_Handle Dart_ListGetAsBytes(Dart_Handle list, |
| intptr_t offset, |
| uint8_t* native_array, |
| intptr_t length) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(list)); |
| if (obj.IsTypedData()) { |
| const TypedData& array = TypedData::Cast(obj); |
| if (array.ElementSizeInBytes() == 1) { |
| if (Utils::RangeCheck(offset, length, array.Length())) { |
| NoGCScope no_gc; |
| memmove(native_array, |
| reinterpret_cast<uint8_t*>(array.DataAddr(offset)), |
| length); |
| return Api::Success(isolate); |
| } |
| return Api::NewError("Invalid length passed in to access list elements"); |
| } |
| } |
| if (obj.IsArray()) { |
| GET_LIST_ELEMENT_AS_BYTES(isolate, |
| Array, |
| obj, |
| native_array, |
| offset, |
| length); |
| } |
| if (obj.IsGrowableObjectArray()) { |
| GET_LIST_ELEMENT_AS_BYTES(isolate, |
| GrowableObjectArray, |
| obj, |
| native_array, |
| offset, |
| length); |
| } |
| if (obj.IsError()) { |
| return list; |
| } |
| CHECK_CALLBACK_STATE(isolate); |
| |
| // Check and handle a dart object that implements the List interface. |
| const Instance& instance = |
| Instance::Handle(isolate, GetListInstance(isolate, obj)); |
| if (!instance.IsNull()) { |
| const Function& function = Function::Handle( |
| isolate, |
| Resolver::ResolveDynamic(instance, Symbols::IndexToken(), 2, 0)); |
| if (!function.IsNull()) { |
| Object& result = Object::Handle(isolate); |
| Integer& intobj = Integer::Handle(isolate); |
| const int kNumArgs = 2; |
| const Array& args = Array::Handle(isolate, Array::New(kNumArgs)); |
| args.SetAt(0, instance); // Set up the receiver as the first argument. |
| for (int i = 0; i < length; i++) { |
| intobj = Integer::New(offset + i); |
| args.SetAt(1, intobj); |
| result = DartEntry::InvokeFunction(function, args); |
| if (result.IsError()) { |
| return Api::NewHandle(isolate, result.raw()); |
| } |
| if (!result.IsInteger()) { |
| return Api::NewError("%s expects the argument 'list' to be " |
| "a List of int", CURRENT_FUNC); |
| } |
| const Integer& integer_result = Integer::Cast(result); |
| ASSERT(integer_result.AsInt64Value() <= 0xff); |
| // TODO(hpayer): value should always be smaller then 0xff. Add error |
| // handling. |
| native_array[i] = |
| static_cast<uint8_t>(integer_result.AsInt64Value() & 0xff); |
| } |
| return Api::Success(isolate); |
| } |
| } |
| return Api::NewError("Object does not implement the 'List' interface"); |
| } |
| |
| |
| #define SET_LIST_ELEMENT_AS_BYTES(isolate, type, obj, native_array, offset, \ |
| length) \ |
| const type& array = type::Cast(obj); \ |
| Integer& integer = Integer::Handle(isolate); \ |
| if (Utils::RangeCheck(offset, length, array.Length())) { \ |
| for (int i = 0; i < length; i++) { \ |
| integer = Integer::New(native_array[i]); \ |
| array.SetAt(offset + i, integer); \ |
| } \ |
| return Api::Success(isolate); \ |
| } \ |
| return Api::NewError("Invalid length passed in to set array elements"); \ |
| |
| |
| DART_EXPORT Dart_Handle Dart_ListSetAsBytes(Dart_Handle list, |
| intptr_t offset, |
| uint8_t* native_array, |
| intptr_t length) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(list)); |
| if (obj.IsTypedData()) { |
| const TypedData& array = TypedData::Cast(obj); |
| if (array.ElementSizeInBytes() == 1) { |
| if (Utils::RangeCheck(offset, length, array.Length())) { |
| NoGCScope no_gc; |
| memmove(reinterpret_cast<uint8_t*>(array.DataAddr(offset)), |
| native_array, |
| length); |
| return Api::Success(isolate); |
| } |
| return Api::NewError("Invalid length passed in to access list elements"); |
| } |
| } |
| if (obj.IsArray() && !obj.IsImmutableArray()) { |
| // If the list is immutable we call into Dart for the indexed setter to |
| // get the unsupported operation exception as the result. |
| SET_LIST_ELEMENT_AS_BYTES(isolate, |
| Array, |
| obj, |
| native_array, |
| offset, |
| length); |
| } |
| if (obj.IsGrowableObjectArray()) { |
| SET_LIST_ELEMENT_AS_BYTES(isolate, |
| GrowableObjectArray, |
| obj, |
| native_array, |
| offset, |
| length); |
| } |
| if (obj.IsError()) { |
| return list; |
| } |
| CHECK_CALLBACK_STATE(isolate); |
| |
| // Check and handle a dart object that implements the List interface. |
| const Instance& instance = |
| Instance::Handle(isolate, GetListInstance(isolate, obj)); |
| if (!instance.IsNull()) { |
| const Function& function = Function::Handle( |
| isolate, |
| Resolver::ResolveDynamic(instance, |
| Symbols::AssignIndexToken(), |
| 3, |
| 0)); |
| if (!function.IsNull()) { |
| Integer& indexobj = Integer::Handle(isolate); |
| Integer& valueobj = Integer::Handle(isolate); |
| const int kNumArgs = 3; |
| const Array& args = Array::Handle(isolate, Array::New(kNumArgs)); |
| args.SetAt(0, instance); // Set up the receiver as the first argument. |
| for (int i = 0; i < length; i++) { |
| indexobj = Integer::New(offset + i); |
| valueobj = Integer::New(native_array[i]); |
| args.SetAt(1, indexobj); |
| args.SetAt(2, valueobj); |
| const Object& result = Object::Handle( |
| isolate, DartEntry::InvokeFunction(function, args)); |
| if (result.IsError()) { |
| return Api::NewHandle(isolate, result.raw()); |
| } |
| } |
| return Api::Success(isolate); |
| } |
| } |
| return Api::NewError("Object does not implement the 'List' interface"); |
| } |
| |
| |
| // --- Typed Data --- |
| |
| |
| // Helper method to get the type of a TypedData object. |
| static Dart_TypedData_Type GetType(intptr_t class_id) { |
| Dart_TypedData_Type type; |
| switch (class_id) { |
| case kByteDataViewCid : |
| type = kByteData; |
| break; |
| case kTypedDataInt8ArrayCid : |
| case kTypedDataInt8ArrayViewCid : |
| case kExternalTypedDataInt8ArrayCid : |
| type = kInt8; |
| break; |
| case kTypedDataUint8ArrayCid : |
| case kTypedDataUint8ArrayViewCid : |
| case kExternalTypedDataUint8ArrayCid : |
| type = kUint8; |
| break; |
| case kTypedDataUint8ClampedArrayCid : |
| case kTypedDataUint8ClampedArrayViewCid : |
| case kExternalTypedDataUint8ClampedArrayCid : |
| type = kUint8Clamped; |
| break; |
| case kTypedDataInt16ArrayCid : |
| case kTypedDataInt16ArrayViewCid : |
| case kExternalTypedDataInt16ArrayCid : |
| type = kInt16; |
| break; |
| case kTypedDataUint16ArrayCid : |
| case kTypedDataUint16ArrayViewCid : |
| case kExternalTypedDataUint16ArrayCid : |
| type = kUint16; |
| break; |
| case kTypedDataInt32ArrayCid : |
| case kTypedDataInt32ArrayViewCid : |
| case kExternalTypedDataInt32ArrayCid : |
| type = kInt32; |
| break; |
| case kTypedDataUint32ArrayCid : |
| case kTypedDataUint32ArrayViewCid : |
| case kExternalTypedDataUint32ArrayCid : |
| type = kUint32; |
| break; |
| case kTypedDataInt64ArrayCid : |
| case kTypedDataInt64ArrayViewCid : |
| case kExternalTypedDataInt64ArrayCid : |
| type = kInt64; |
| break; |
| case kTypedDataUint64ArrayCid : |
| case kTypedDataUint64ArrayViewCid : |
| case kExternalTypedDataUint64ArrayCid : |
| type = kUint64; |
| break; |
| case kTypedDataFloat32ArrayCid : |
| case kTypedDataFloat32ArrayViewCid : |
| case kExternalTypedDataFloat32ArrayCid : |
| type = kFloat32; |
| break; |
| case kTypedDataFloat64ArrayCid : |
| case kTypedDataFloat64ArrayViewCid : |
| case kExternalTypedDataFloat64ArrayCid : |
| type = kFloat64; |
| break; |
| case kTypedDataFloat32x4ArrayCid : |
| case kTypedDataFloat32x4ArrayViewCid : |
| case kExternalTypedDataFloat32x4ArrayCid : |
| type = kFloat32x4; |
| break; |
| default: |
| type = kInvalid; |
| break; |
| } |
| return type; |
| } |
| |
| |
| DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfTypedData(Dart_Handle object) { |
| intptr_t class_id = Api::ClassId(object); |
| if (RawObject::IsTypedDataClassId(class_id) || |
| RawObject::IsTypedDataViewClassId(class_id)) { |
| return GetType(class_id); |
| } |
| return kInvalid; |
| } |
| |
| |
| DART_EXPORT Dart_TypedData_Type Dart_GetTypeOfExternalTypedData( |
| Dart_Handle object) { |
| intptr_t class_id = Api::ClassId(object); |
| if (RawObject::IsExternalTypedDataClassId(class_id) || |
| RawObject::IsTypedDataViewClassId(class_id)) { |
| return GetType(class_id); |
| } |
| return kInvalid; |
| } |
| |
| |
| static RawObject* GetByteDataConstructor(Isolate* isolate, |
| const String& constructor_name, |
| intptr_t num_args) { |
| const Library& lib = |
| Library::Handle(isolate->object_store()->typed_data_library()); |
| ASSERT(!lib.IsNull()); |
| const Class& cls = |
| Class::Handle(isolate, lib.LookupClassAllowPrivate(Symbols::ByteData())); |
| ASSERT(!cls.IsNull()); |
| return ResolveConstructor(CURRENT_FUNC, |
| cls, |
| Symbols::ByteData(), |
| constructor_name, |
| num_args); |
| } |
| |
| |
| static Dart_Handle NewByteData(Isolate* isolate, intptr_t length) { |
| CHECK_LENGTH(length, TypedData::MaxElements(kTypedDataInt8ArrayCid)); |
| Object& result = Object::Handle(isolate); |
| result = GetByteDataConstructor(isolate, Symbols::ByteDataDot(), 1); |
| ASSERT(!result.IsNull()); |
| ASSERT(result.IsFunction()); |
| const Function& factory = Function::Cast(result); |
| ASSERT(!factory.IsConstructor()); |
| |
| // Create the argument list. |
| const Array& args = Array::Handle(isolate, Array::New(2)); |
| // Factories get type arguments. |
| args.SetAt(0, TypeArguments::Handle(isolate)); |
| args.SetAt(1, Smi::Handle(isolate, Smi::New(length))); |
| |
| // Invoke the constructor and return the new object. |
| result = DartEntry::InvokeFunction(factory, args); |
| ASSERT(result.IsInstance() || result.IsNull() || result.IsError()); |
| return Api::NewHandle(isolate, result.raw()); |
| } |
| |
| |
| static Dart_Handle NewTypedData(Isolate* isolate, |
| intptr_t cid, |
| intptr_t length) { |
| CHECK_LENGTH(length, TypedData::MaxElements(cid)); |
| return Api::NewHandle(isolate, TypedData::New(cid, length)); |
| } |
| |
| |
| static Dart_Handle NewExternalTypedData( |
| intptr_t cid, |
| void* data, |
| intptr_t length, |
| void* peer, |
| Dart_WeakPersistentHandleFinalizer callback) { |
| CHECK_LENGTH(length, ExternalTypedData::MaxElements(cid)); |
| const ExternalTypedData& obj = ExternalTypedData::Handle( |
| ExternalTypedData::New(cid, |
| reinterpret_cast<uint8_t*>(data), |
| length)); |
| return reinterpret_cast<Dart_Handle>(obj.AddFinalizer(peer, callback)); |
| } |
| |
| |
| static Dart_Handle NewExternalByteData(Isolate* isolate, |
| void* data, |
| intptr_t length, |
| void* peer, |
| Dart_WeakPersistentHandleFinalizer cb) { |
| Dart_Handle ext_data = NewExternalTypedData(kExternalTypedDataUint8ArrayCid, |
| data, |
| length, |
| peer, |
| cb); |
| if (::Dart_IsError(ext_data)) { |
| return ext_data; |
| } |
| Object& result = Object::Handle(isolate); |
| result = GetByteDataConstructor(isolate, Symbols::ByteDataDotview(), 3); |
| ASSERT(!result.IsNull()); |
| ASSERT(result.IsFunction()); |
| const Function& factory = Function::Cast(result); |
| ASSERT(!factory.IsConstructor()); |
| |
| // Create the argument list. |
| const intptr_t num_args = 3; |
| const Array& args = Array::Handle(isolate, Array::New(num_args + 1)); |
| // Factories get type arguments. |
| args.SetAt(0, TypeArguments::Handle(isolate)); |
| const ExternalTypedData& array = |
| Api::UnwrapExternalTypedDataHandle(isolate, ext_data); |
| args.SetAt(1, array); |
| Smi& smi = Smi::Handle(isolate); |
| smi = Smi::New(0); |
| args.SetAt(2, smi); |
| smi = Smi::New(length); |
| args.SetAt(3, smi); |
| |
| // Invoke the constructor and return the new object. |
| result = DartEntry::InvokeFunction(factory, args); |
| ASSERT(result.IsNull() || result.IsInstance() || result.IsError()); |
| return Api::NewHandle(isolate, result.raw()); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewTypedData(Dart_TypedData_Type type, |
| intptr_t length) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| CHECK_CALLBACK_STATE(isolate); |
| switch (type) { |
| case kByteData : |
| return NewByteData(isolate, length); |
| case kInt8 : |
| return NewTypedData(isolate, kTypedDataInt8ArrayCid, length); |
| case kUint8 : |
| return NewTypedData(isolate, kTypedDataUint8ArrayCid, length); |
| case kUint8Clamped : |
| return NewTypedData(isolate, kTypedDataUint8ClampedArrayCid, length); |
| case kInt16 : |
| return NewTypedData(isolate, kTypedDataInt16ArrayCid, length); |
| case kUint16 : |
| return NewTypedData(isolate, kTypedDataUint16ArrayCid, length); |
| case kInt32 : |
| return NewTypedData(isolate, kTypedDataInt32ArrayCid, length); |
| case kUint32 : |
| return NewTypedData(isolate, kTypedDataUint32ArrayCid, length); |
| case kInt64 : |
| return NewTypedData(isolate, kTypedDataInt64ArrayCid, length); |
| case kUint64 : |
| return NewTypedData(isolate, kTypedDataUint64ArrayCid, length); |
| case kFloat32 : |
| return NewTypedData(isolate, kTypedDataFloat32ArrayCid, length); |
| case kFloat64 : |
| return NewTypedData(isolate, kTypedDataFloat64ArrayCid, length); |
| case kFloat32x4: |
| return NewTypedData(isolate, kTypedDataFloat32x4ArrayCid, length); |
| default: |
| return Api::NewError("%s expects argument 'type' to be of 'TypedData'", |
| CURRENT_FUNC); |
| } |
| UNREACHABLE(); |
| return Api::Null(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_NewExternalTypedData( |
| Dart_TypedData_Type type, |
| void* data, |
| intptr_t length, |
| void* peer, |
| Dart_WeakPersistentHandleFinalizer callback) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| if (data == NULL && length != 0) { |
| RETURN_NULL_ERROR(data); |
| } |
| CHECK_CALLBACK_STATE(isolate); |
| switch (type) { |
| case kByteData: |
| return NewExternalByteData(isolate, data, length, peer, callback); |
| case kInt8: |
| return NewExternalTypedData(kExternalTypedDataInt8ArrayCid, |
| data, |
| length, |
| peer, |
| callback); |
| case kUint8: |
| return NewExternalTypedData(kExternalTypedDataUint8ArrayCid, |
| data, |
| length, |
| peer, |
| callback); |
| case kUint8Clamped: |
| return NewExternalTypedData(kExternalTypedDataUint8ClampedArrayCid, |
| data, |
| length, |
| peer, |
| callback); |
| case kInt16: |
| return NewExternalTypedData(kExternalTypedDataInt16ArrayCid, |
| data, |
| length, |
| peer, |
| callback); |
| case kUint16: |
| return NewExternalTypedData(kExternalTypedDataUint16ArrayCid, |
| data, |
| length, |
| peer, |
| callback); |
| case kInt32: |
| return NewExternalTypedData(kExternalTypedDataInt32ArrayCid, |
| data, |
| length, |
| peer, |
| callback); |
| case kUint32: |
| return NewExternalTypedData(kExternalTypedDataUint32ArrayCid, |
| data, |
| length, |
| peer, |
| callback); |
| case kInt64: |
| return NewExternalTypedData(kExternalTypedDataInt64ArrayCid, |
| data, |
| length, |
| peer, |
| callback); |
| case kUint64: |
| return NewExternalTypedData(kExternalTypedDataUint64ArrayCid, |
| data, |
| length, |
| peer, |
| callback); |
| case kFloat32: |
| return NewExternalTypedData(kExternalTypedDataFloat32ArrayCid, |
| data, |
| length, |
| peer, |
| callback); |
| case kFloat64: |
| return NewExternalTypedData(kExternalTypedDataFloat64ArrayCid, |
| data, |
| length, |
| peer, |
| callback); |
| case kFloat32x4: |
| return NewExternalTypedData(kExternalTypedDataFloat32x4ArrayCid, |
| data, |
| length, |
| peer, |
| callback); |
| default: |
| return Api::NewError("%s expects argument 'type' to be of" |
| " 'external TypedData'", CURRENT_FUNC); |
| } |
| UNREACHABLE(); |
| return Api::Null(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_ExternalTypedDataGetPeer(Dart_Handle object, |
| void** peer) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| const ExternalTypedData& array = |
| Api::UnwrapExternalTypedDataHandle(isolate, object); |
| if (array.IsNull()) { |
| RETURN_TYPE_ERROR(isolate, object, ExternalTypedData); |
| } |
| if (peer == NULL) { |
| RETURN_NULL_ERROR(peer); |
| } |
| *peer = array.GetPeer(); |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_TypedDataAcquireData(Dart_Handle object, |
| Dart_TypedData_Type* type, |
| void** data, |
| intptr_t* len) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| intptr_t class_id = Api::ClassId(object); |
| if (!RawObject::IsExternalTypedDataClassId(class_id) && |
| !RawObject::IsTypedDataViewClassId(class_id) && |
| !RawObject::IsTypedDataClassId(class_id)) { |
| RETURN_TYPE_ERROR(isolate, object, 'TypedData'); |
| } |
| if (type == NULL) { |
| RETURN_NULL_ERROR(type); |
| } |
| if (data == NULL) { |
| RETURN_NULL_ERROR(data); |
| } |
| if (len == NULL) { |
| RETURN_NULL_ERROR(len); |
| } |
| // Get the type of typed data object. |
| *type = GetType(class_id); |
| // If it is an external typed data object just return the data field. |
| if (RawObject::IsExternalTypedDataClassId(class_id)) { |
| const ExternalTypedData& obj = |
| Api::UnwrapExternalTypedDataHandle(isolate, object); |
| ASSERT(!obj.IsNull()); |
| *len = obj.Length(); |
| *data = obj.DataAddr(0); |
| } else if (RawObject::IsTypedDataClassId(class_id)) { |
| // Regular typed data object, set up some GC and API callback guards. |
| const TypedData& obj = Api::UnwrapTypedDataHandle(isolate, object); |
| ASSERT(!obj.IsNull()); |
| *len = obj.Length(); |
| isolate->IncrementNoGCScopeDepth(); |
| START_NO_CALLBACK_SCOPE(isolate); |
| *data = obj.DataAddr(0); |
| } else { |
| ASSERT(RawObject::IsTypedDataViewClassId(class_id)); |
| const Instance& view_obj = Api::UnwrapInstanceHandle(isolate, object); |
| ASSERT(!view_obj.IsNull()); |
| Smi& val = Smi::Handle(); |
| val ^= TypedDataView::Length(view_obj); |
| *len = val.Value(); |
| val ^= TypedDataView::OffsetInBytes(view_obj); |
| intptr_t offset_in_bytes = val.Value(); |
| const Instance& obj = Instance::Handle(TypedDataView::Data(view_obj)); |
| isolate->IncrementNoGCScopeDepth(); |
| START_NO_CALLBACK_SCOPE(isolate); |
| if (TypedData::IsTypedData(obj)) { |
| const TypedData& data_obj = TypedData::Cast(obj); |
| *data = data_obj.DataAddr(offset_in_bytes); |
| } else { |
| ASSERT(ExternalTypedData::IsExternalTypedData(obj)); |
| const ExternalTypedData& data_obj = ExternalTypedData::Cast(obj); |
| *data = data_obj.DataAddr(offset_in_bytes); |
| } |
| } |
| return Api::Success(isolate); |
| } |
| |
| |
| DART_EXPORT Dart_Handle Dart_TypedDataReleaseData(Dart_Handle object) { |
| Isolate* isolate = Isolate::Current(); |
| DARTSCOPE(isolate); |
| intptr_t class_id = Api::ClassId(object); |
| if (!RawObject::IsExternalTypedDataClassId(class_id) && |
| !RawObject::IsTypedDataViewClassId(class_id) && |
| !RawObject::IsTypedDataClassId(class_id |