blob: 4ebdac973ee7547c4585bcacf97f0b2be436d2e5 [file] [log] [blame]
// 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 "include/dart_native_api.h"
#include "lib/stacktrace.h"
#include "platform/assert.h"
#include "vm/class_finalizer.h"
#include "vm/clustered_snapshot.h"
#include "vm/compilation_trace.h"
#include "vm/compiler/jit/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/debugger.h"
#include "vm/dwarf.h"
#include "vm/elf.h"
#if !defined(DART_PRECOMPILED_RUNTIME)
#include "vm/kernel_loader.h"
#endif
#include "platform/unicode.h"
#include "vm/compiler/aot/precompiler.h"
#include "vm/exceptions.h"
#include "vm/flags.h"
#include "vm/growable_array.h"
#include "vm/heap/verifier.h"
#include "vm/image_snapshot.h"
#include "vm/isolate_reload.h"
#include "vm/kernel_isolate.h"
#include "vm/lockers.h"
#include "vm/message.h"
#include "vm/message_handler.h"
#include "vm/native_entry.h"
#include "vm/native_symbol.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/os.h"
#include "vm/os_thread.h"
#include "vm/port.h"
#include "vm/profiler.h"
#include "vm/profiler_service.h"
#include "vm/program_visitor.h"
#include "vm/resolver.h"
#include "vm/reusable_handles.h"
#include "vm/service.h"
#include "vm/service_event.h"
#include "vm/service_isolate.h"
#include "vm/stack_frame.h"
#include "vm/symbols.h"
#include "vm/tags.h"
#include "vm/thread_registry.h"
#include "vm/uri.h"
#include "vm/version.h"
namespace dart {
// Facilitate quick access to the current zone once we have the current thread.
#define Z (T->zone())
DECLARE_FLAG(bool, print_class_table);
DECLARE_FLAG(bool, verify_handles);
#if defined(DART_NO_SNAPSHOT)
DEFINE_FLAG(bool,
check_function_fingerprints,
true,
"Check function fingerprints");
#endif // defined(DART_NO_SNAPSHOT).
DEFINE_FLAG(bool,
verify_acquired_data,
false,
"Verify correct API acquire/release of typed data.");
DEFINE_FLAG(bool,
dump_tables,
false,
"Dump common hash tables before snapshotting.");
#define CHECK_ERROR_HANDLE(error) \
{ \
RawError* err = (error); \
if (err != Error::null()) { \
return Api::NewHandle(T, err); \
} \
}
ThreadLocalKey Api::api_native_key_ = kUnsetThreadLocalKey;
Dart_Handle Api::true_handle_ = NULL;
Dart_Handle Api::false_handle_ = NULL;
Dart_Handle Api::null_handle_ = NULL;
Dart_Handle Api::empty_string_handle_ = NULL;
const char* CanonicalFunction(const char* func) {
if (strncmp(func, "dart::", 6) == 0) {
return func + 6;
} else {
return func;
}
}
#if defined(DEBUG)
// An object visitor which will iterate over all the function objects in the
// heap and check if the result type and parameter types are canonicalized
// or not. An assertion is raised if a type is not canonicalized.
class CheckFunctionTypesVisitor : public ObjectVisitor {
public:
explicit CheckFunctionTypesVisitor(Thread* thread)
: classHandle_(Class::Handle(thread->zone())),
funcHandle_(Function::Handle(thread->zone())),
typeHandle_(AbstractType::Handle(thread->zone())) {}
void VisitObject(RawObject* obj) {
if (obj->IsFunction()) {
funcHandle_ ^= obj;
classHandle_ ^= funcHandle_.Owner();
// Signature functions get created, but not canonicalized, when function
// types get instantiated during run time type tests.
if (funcHandle_.IsSignatureFunction()) {
return;
}
// Verify that the result type of a function is canonical or a
// TypeParameter.
typeHandle_ ^= funcHandle_.result_type();
ASSERT(typeHandle_.IsTypeParameter() || typeHandle_.IsCanonical());
// Verify that the types in the function signature are all canonical or
// a TypeParameter.
const intptr_t num_parameters = funcHandle_.NumParameters();
for (intptr_t i = 0; i < num_parameters; i++) {
typeHandle_ = funcHandle_.ParameterTypeAt(i);
ASSERT(typeHandle_.IsTypeParameter() || typeHandle_.IsCanonical());
}
}
}
private:
Class& classHandle_;
Function& funcHandle_;
AbstractType& typeHandle_;
};
#endif // #if defined(DEBUG).
static RawInstance* GetListInstance(Zone* zone, const Object& obj) {
if (obj.IsInstance()) {
const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
const Class& list_class =
Class::Handle(zone, core_lib.LookupClass(Symbols::List()));
ASSERT(!list_class.IsNull());
const Instance& instance = Instance::Cast(obj);
const Class& obj_class = Class::Handle(zone, obj.clazz());
if (Class::IsSubtypeOf(obj_class, Object::null_type_arguments(), list_class,
Object::null_type_arguments(), Heap::kNew)) {
return instance.raw();
}
}
return Instance::null();
}
static RawInstance* GetMapInstance(Zone* zone, const Object& obj) {
if (obj.IsInstance()) {
const Library& core_lib = Library::Handle(zone, Library::CoreLibrary());
const Class& map_class =
Class::Handle(core_lib.LookupClass(Symbols::Map()));
ASSERT(!map_class.IsNull());
const Instance& instance = Instance::Cast(obj);
const Class& obj_class = Class::Handle(zone, obj.clazz());
if (Class::IsSubtypeOf(obj_class, Object::null_type_arguments(), map_class,
Object::null_type_arguments(), Heap::kNew)) {
return instance.raw();
}
}
return Instance::null();
}
static bool IsCompiletimeErrorObject(Zone* zone, const Object& obj) {
#if defined(DART_PRECOMPILED_RUNTIME)
// All compile-time errors were handled at snapshot generation time and
// compiletime_error_class was removed.
return false;
#else
Isolate* I = Thread::Current()->isolate();
const Class& error_class =
Class::Handle(zone, I->object_store()->compiletime_error_class());
ASSERT(!error_class.IsNull());
return (obj.GetClassId() == error_class.id());
#endif
}
static bool GetNativeStringArgument(NativeArguments* arguments,
int arg_index,
Dart_Handle* str,
void** peer) {
ASSERT(peer != NULL);
if (Api::StringGetPeerHelper(arguments, arg_index, peer)) {
*str = NULL;
return true;
}
Thread* thread = arguments->thread();
ASSERT(thread == Thread::Current());
*peer = NULL;
REUSABLE_OBJECT_HANDLESCOPE(thread);
Object& obj = thread->ObjectHandle();
obj = arguments->NativeArgAt(arg_index);
if (RawObject::IsStringClassId(obj.GetClassId())) {
ASSERT(thread->api_top_scope() != NULL);
*str = Api::NewHandle(thread, obj.raw());
return true;
}
if (obj.IsNull()) {
*str = Api::Null();
return true;
}
return false;
}
static bool GetNativeIntegerArgument(NativeArguments* arguments,
int arg_index,
int64_t* value) {
ASSERT(value != NULL);
return Api::GetNativeIntegerArgument(arguments, arg_index, value);
}
static bool GetNativeUnsignedIntegerArgument(NativeArguments* arguments,
int arg_index,
uint64_t* value) {
ASSERT(value != NULL);
int64_t arg_value = 0;
if (Api::GetNativeIntegerArgument(arguments, arg_index, &arg_value)) {
*value = static_cast<uint64_t>(arg_value);
return true;
}
return false;
}
static bool GetNativeDoubleArgument(NativeArguments* arguments,
int arg_index,
double* value) {
ASSERT(value != NULL);
return Api::GetNativeDoubleArgument(arguments, arg_index, value);
}
static Dart_Handle GetNativeFieldsOfArgument(NativeArguments* arguments,
int arg_index,
int num_fields,
intptr_t* field_values,
const char* current_func) {
ASSERT(field_values != NULL);
if (Api::GetNativeFieldsOfArgument(arguments, arg_index, num_fields,
field_values)) {
return Api::Success();
}
Thread* thread = arguments->thread();
ASSERT(thread == Thread::Current());
REUSABLE_OBJECT_HANDLESCOPE(thread);
Object& obj = thread->ObjectHandle();
obj = arguments->NativeArgAt(arg_index);
if (obj.IsNull()) {
memset(field_values, 0, (num_fields * sizeof(field_values[0])));
return Api::Success();
}
// We did not succeed in extracting the native fields report the
// appropriate error.
if (!obj.IsInstance()) {
return Api::NewError(
"%s expects argument at index '%d' to be of"
" type Instance.",
current_func, arg_index);
}
const Instance& instance = Instance::Cast(obj);
int field_count = instance.NumNativeFields();
ASSERT(num_fields != field_count);
return Api::NewError("%s: expected %d 'num_fields' but was passed in %d.",
current_func, field_count, num_fields);
}
static RawObject* Send0Arg(const Instance& receiver, const String& selector) {
const intptr_t kTypeArgsLen = 0;
const intptr_t kNumArgs = 1;
ArgumentsDescriptor args_desc(
Array::Handle(ArgumentsDescriptor::New(kTypeArgsLen, kNumArgs)));
const Function& function =
Function::Handle(Resolver::ResolveDynamic(receiver, selector, args_desc));
if (function.IsNull()) {
return ApiError::New(String::Handle(String::New("")));
}
const Array& args = Array::Handle(Array::New(kNumArgs));
args.SetAt(0, receiver);
return DartEntry::InvokeFunction(function, args);
}
static RawObject* Send1Arg(const Instance& receiver,
const String& selector,
const Instance& argument) {
const intptr_t kTypeArgsLen = 0;
const intptr_t kNumArgs = 2;
ArgumentsDescriptor args_desc(
Array::Handle(ArgumentsDescriptor::New(kTypeArgsLen, kNumArgs)));
const Function& function =
Function::Handle(Resolver::ResolveDynamic(receiver, selector, args_desc));
if (function.IsNull()) {
return ApiError::New(String::Handle(String::New("")));
}
const Array& args = Array::Handle(Array::New(kNumArgs));
args.SetAt(0, receiver);
args.SetAt(1, argument);
return DartEntry::InvokeFunction(function, args);
}
static const char* GetErrorString(Thread* thread, const Object& obj) {
// This function requires an API scope to be present.
if (obj.IsError()) {
ASSERT(thread->api_top_scope() != NULL);
const Error& error = Error::Cast(obj);
const char* str = error.ToErrorCString();
intptr_t len = strlen(str) + 1;
char* str_copy = Api::TopScope(thread)->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_Handle Api::InitNewHandle(Thread* thread, RawObject* raw) {
LocalHandles* local_handles = Api::TopScope(thread)->local_handles();
ASSERT(local_handles != NULL);
LocalHandle* ref = local_handles->AllocateHandle();
ref->set_raw(raw);
return ref->apiHandle();
}
Dart_Handle Api::NewHandle(Thread* thread, RawObject* raw) {
if (raw == Object::null()) {
return Null();
}
if (raw == Bool::True().raw()) {
return True();
}
if (raw == Bool::False().raw()) {
return False();
}
ASSERT(thread->execution_state() == Thread::kThreadInVM);
return InitNewHandle(thread, raw);
}
RawObject* Api::UnwrapHandle(Dart_Handle object) {
#if defined(DEBUG)
Thread* thread = Thread::Current();
ASSERT(thread->execution_state() == Thread::kThreadInVM);
ASSERT(thread->IsMutatorThread());
ASSERT(thread->isolate() != NULL);
ASSERT(!FLAG_verify_handles || thread->IsValidLocalHandle(object) ||
thread->isolate()->api_state()->IsActivePersistentHandle(
reinterpret_cast<Dart_PersistentHandle>(object)) ||
Dart::IsReadOnlyApiHandle(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(Zone* zone, Dart_Handle dart_handle) { \
const Object& obj = Object::Handle(zone, Api::UnwrapHandle(dart_handle)); \
if (obj.Is##type()) { \
return type::Cast(obj); \
} \
return type::Handle(zone); \
}
CLASS_LIST_FOR_HANDLES(DEFINE_UNWRAP)
#undef DEFINE_UNWRAP
const String& Api::UnwrapStringHandle(const ReusableObjectHandleScope& reuse,
Dart_Handle dart_handle) {
Object& ref = reuse.Handle();
ref = Api::UnwrapHandle(dart_handle);
if (ref.IsString()) {
return String::Cast(ref);
}
return Object::null_string();
}
const Instance& Api::UnwrapInstanceHandle(
const ReusableObjectHandleScope& reuse,
Dart_Handle dart_handle) {
Object& ref = reuse.Handle();
ref = Api::UnwrapHandle(dart_handle);
if (ref.IsInstance()) {
return Instance::Cast(ref);
}
return Object::null_instance();
}
Dart_Handle Api::CheckAndFinalizePendingClasses(Thread* thread) {
Isolate* isolate = thread->isolate();
if (!isolate->AllowClassFinalization()) {
// Class finalization is blocked for the isolate. Do nothing.
return Api::Success();
}
if (ClassFinalizer::ProcessPendingClasses()) {
return Api::Success();
}
ASSERT(thread->sticky_error() != Object::null());
return Api::NewHandle(thread, thread->sticky_error());
}
Dart_Isolate Api::CastIsolate(Isolate* isolate) {
return reinterpret_cast<Dart_Isolate>(isolate);
}
Dart_Handle Api::NewError(const char* format, ...) {
Thread* T = Thread::Current();
CHECK_API_SCOPE(T);
CHECK_CALLBACK_STATE(T);
// Ensure we transition safepoint state to VM if we are not already in
// that state.
TransitionToVM transition(T);
HANDLESCOPE(T);
va_list args;
va_start(args, format);
intptr_t len = Utils::VSNPrint(NULL, 0, format, args);
va_end(args);
char* buffer = Z->Alloc<char>(len + 1);
va_list args2;
va_start(args2, format);
Utils::VSNPrint(buffer, (len + 1), format, args2);
va_end(args2);
const String& message = String::Handle(Z, String::New(buffer));
return Api::NewHandle(T, 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);
}
bool Api::IsValid(Dart_Handle handle) {
Isolate* isolate = Isolate::Current();
Thread* thread = Thread::Current();
ASSERT(thread->IsMutatorThread());
CHECK_ISOLATE(isolate);
// Check against all of the handles in the current isolate as well as the
// read-only handles.
return thread->IsValidHandle(handle) ||
isolate->api_state()->IsActivePersistentHandle(
reinterpret_cast<Dart_PersistentHandle>(handle)) ||
isolate->api_state()->IsActiveWeakPersistentHandle(
reinterpret_cast<Dart_WeakPersistentHandle>(handle)) ||
Dart::IsReadOnlyApiHandle(handle) ||
Dart::IsReadOnlyHandle(reinterpret_cast<uword>(handle));
}
ApiLocalScope* Api::TopScope(Thread* thread) {
ASSERT(thread != NULL);
ApiLocalScope* scope = thread->api_top_scope();
ASSERT(scope != NULL);
return scope;
}
void Api::Init() {
if (api_native_key_ == kUnsetThreadLocalKey) {
api_native_key_ = OSThread::CreateThreadLocal();
}
ASSERT(api_native_key_ != kUnsetThreadLocalKey);
}
static Dart_Handle InitNewReadOnlyApiHandle(RawObject* raw) {
ASSERT(raw->InVMIsolateHeap());
LocalHandle* ref = Dart::AllocateReadOnlyApiHandle();
ref->set_raw(raw);
return ref->apiHandle();
}
void Api::InitHandles() {
Isolate* isolate = Isolate::Current();
ASSERT(isolate != NULL);
ASSERT(isolate == Dart::vm_isolate());
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
ASSERT(true_handle_ == NULL);
true_handle_ = InitNewReadOnlyApiHandle(Bool::True().raw());
ASSERT(false_handle_ == NULL);
false_handle_ = InitNewReadOnlyApiHandle(Bool::False().raw());
ASSERT(null_handle_ == NULL);
null_handle_ = InitNewReadOnlyApiHandle(Object::null());
ASSERT(empty_string_handle_ == NULL);
empty_string_handle_ = InitNewReadOnlyApiHandle(Symbols::Empty().raw());
}
void Api::Cleanup() {
true_handle_ = NULL;
false_handle_ = NULL;
null_handle_ = NULL;
empty_string_handle_ = NULL;
}
bool Api::StringGetPeerHelper(NativeArguments* arguments,
int arg_index,
void** peer) {
NoSafepointScope no_safepoint_scope;
RawObject* raw_obj = arguments->NativeArgAt(arg_index);
if (!raw_obj->IsHeapObject()) {
return false;
}
intptr_t cid = raw_obj->GetClassId();
if (cid == kExternalOneByteStringCid) {
RawExternalOneByteString* raw_string =
reinterpret_cast<RawExternalOneByteString*>(raw_obj);
*peer = raw_string->ptr()->peer_;
return true;
}
if (cid == kOneByteStringCid || cid == kTwoByteStringCid) {
Isolate* isolate = arguments->thread()->isolate();
*peer = isolate->heap()->GetPeer(raw_obj);
return (*peer != 0);
}
if (cid == kExternalTwoByteStringCid) {
RawExternalTwoByteString* raw_string =
reinterpret_cast<RawExternalTwoByteString*>(raw_obj);
*peer = raw_string->ptr()->peer_;
return true;
}
return false;
}
bool Api::GetNativeReceiver(NativeArguments* arguments, intptr_t* value) {
NoSafepointScope no_safepoint_scope;
RawObject* raw_obj = arguments->NativeArg0();
if (raw_obj->IsHeapObject()) {
intptr_t cid = raw_obj->GetClassId();
if (cid >= kNumPredefinedCids) {
ASSERT(Instance::Cast(Object::Handle(raw_obj)).IsValidNativeIndex(0));
RawTypedData* native_fields = *reinterpret_cast<RawTypedData**>(
RawObject::ToAddr(raw_obj) + sizeof(RawObject));
if (native_fields == TypedData::null()) {
*value = 0;
} else {
*value = *bit_cast<intptr_t*, uint8_t*>(native_fields->ptr()->data());
}
return true;
}
}
return false;
}
bool Api::GetNativeBooleanArgument(NativeArguments* arguments,
int arg_index,
bool* value) {
NoSafepointScope no_safepoint_scope;
RawObject* raw_obj = arguments->NativeArgAt(arg_index);
if (raw_obj->IsHeapObject()) {
intptr_t cid = raw_obj->GetClassId();
if (cid == kBoolCid) {
*value = (raw_obj == Object::bool_true().raw());
return true;
}
if (cid == kNullCid) {
*value = false;
return true;
}
}
return false;
}
bool Api::GetNativeIntegerArgument(NativeArguments* arguments,
int arg_index,
int64_t* value) {
NoSafepointScope no_safepoint_scope;
RawObject* raw_obj = arguments->NativeArgAt(arg_index);
if (raw_obj->IsHeapObject()) {
intptr_t cid = raw_obj->GetClassId();
if (cid == kMintCid) {
*value = reinterpret_cast<RawMint*>(raw_obj)->ptr()->value_;
return true;
}
return false;
}
*value = Smi::Value(reinterpret_cast<RawSmi*>(raw_obj));
return true;
}
bool Api::GetNativeDoubleArgument(NativeArguments* arguments,
int arg_index,
double* value) {
NoSafepointScope no_safepoint_scope;
RawObject* raw_obj = arguments->NativeArgAt(arg_index);
if (raw_obj->IsHeapObject()) {
intptr_t cid = raw_obj->GetClassId();
if (cid == kDoubleCid) {
*value = reinterpret_cast<RawDouble*>(raw_obj)->ptr()->value_;
return true;
}
if (cid == kMintCid) {
*value = static_cast<double>(
reinterpret_cast<RawMint*>(raw_obj)->ptr()->value_);
return true;
}
return false;
}
*value = static_cast<double>(Smi::Value(reinterpret_cast<RawSmi*>(raw_obj)));
return true;
}
bool Api::GetNativeFieldsOfArgument(NativeArguments* arguments,
int arg_index,
int num_fields,
intptr_t* field_values) {
NoSafepointScope no_safepoint_scope;
RawObject* raw_obj = arguments->NativeArgAt(arg_index);
if (raw_obj->IsHeapObject()) {
intptr_t cid = raw_obj->GetClassId();
if (cid >= kNumPredefinedCids) {
RawTypedData* native_fields = *reinterpret_cast<RawTypedData**>(
RawObject::ToAddr(raw_obj) + sizeof(RawObject));
if (native_fields == TypedData::null()) {
memset(field_values, 0, (num_fields * sizeof(field_values[0])));
} else if (num_fields == Smi::Value(native_fields->ptr()->length_)) {
intptr_t* native_values =
bit_cast<intptr_t*, uint8_t*>(native_fields->ptr()->data());
memmove(field_values, native_values,
(num_fields * sizeof(field_values[0])));
}
return true;
}
}
return false;
}
void Api::SetWeakHandleReturnValue(NativeArguments* args,
Dart_WeakPersistentHandle retval) {
args->SetReturnUnsafe(FinalizablePersistentHandle::Cast(retval)->raw());
}
PersistentHandle* PersistentHandle::Cast(Dart_PersistentHandle handle) {
ASSERT(Isolate::Current()->api_state()->IsValidPersistentHandle(handle));
return reinterpret_cast<PersistentHandle*>(handle);
}
FinalizablePersistentHandle* FinalizablePersistentHandle::Cast(
Dart_WeakPersistentHandle handle) {
#if defined(DEBUG)
ApiState* state = Isolate::Current()->api_state();
ASSERT(state->IsValidWeakPersistentHandle(handle));
#endif
return reinterpret_cast<FinalizablePersistentHandle*>(handle);
}
void FinalizablePersistentHandle::Finalize(
Isolate* isolate,
FinalizablePersistentHandle* handle) {
if (!handle->raw()->IsHeapObject()) {
return; // Free handle.
}
Dart_WeakPersistentHandleFinalizer callback = handle->callback();
ASSERT(callback != NULL);
void* peer = handle->peer();
Dart_WeakPersistentHandle object = handle->apiHandle();
(*callback)(isolate->init_callback_data(), object, peer);
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
state->weak_persistent_handles().FreeHandle(handle);
}
// --- Handles ---
DART_EXPORT bool Dart_IsError(Dart_Handle handle) {
Thread* thread = Thread::Current();
TransitionNativeToVM transition(thread);
return Api::IsError(handle);
}
DART_EXPORT bool Dart_IsApiError(Dart_Handle object) {
Thread* thread = Thread::Current();
TransitionNativeToVM transition(thread);
return Api::ClassId(object) == kApiErrorCid;
}
DART_EXPORT bool Dart_IsUnhandledExceptionError(Dart_Handle object) {
Thread* thread = Thread::Current();
TransitionNativeToVM transition(thread);
return Api::ClassId(object) == kUnhandledExceptionCid;
}
DART_EXPORT bool Dart_IsCompilationError(Dart_Handle object) {
if (::Dart_IsUnhandledExceptionError(object)) {
DARTSCOPE(Thread::Current());
const UnhandledException& error =
UnhandledException::Cast(Object::Handle(Z, Api::UnwrapHandle(object)));
const Instance& exc = Instance::Handle(Z, error.exception());
return IsCompiletimeErrorObject(Z, exc);
}
Thread* thread = Thread::Current();
TransitionNativeToVM transition(thread);
return Api::ClassId(object) == kLanguageErrorCid;
}
DART_EXPORT bool Dart_IsFatalError(Dart_Handle object) {
Thread* thread = Thread::Current();
TransitionNativeToVM transition(thread);
return Api::ClassId(object) == kUnwindErrorCid;
}
DART_EXPORT const char* Dart_GetError(Dart_Handle handle) {
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
return GetErrorString(T, obj);
}
DART_EXPORT bool Dart_ErrorHasException(Dart_Handle handle) {
DARTSCOPE(Thread::Current());
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
return obj.IsUnhandledException();
}
DART_EXPORT Dart_Handle Dart_ErrorGetException(Dart_Handle handle) {
DARTSCOPE(Thread::Current());
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
if (obj.IsUnhandledException()) {
const UnhandledException& error = UnhandledException::Cast(obj);
return Api::NewHandle(T, 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) {
DARTSCOPE(Thread::Current());
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
if (obj.IsUnhandledException()) {
const UnhandledException& error = UnhandledException::Cast(obj);
return Api::NewHandle(T, 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.");
}
}
DART_EXPORT Dart_Handle Dart_NewApiError(const char* error) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
const String& message = String::Handle(Z, String::New(error));
return Api::NewHandle(T, ApiError::New(message));
}
DART_EXPORT Dart_Handle Dart_NewCompilationError(const char* error) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
const String& message = String::Handle(Z, String::New(error));
return Api::NewHandle(T, LanguageError::New(message));
}
DART_EXPORT Dart_Handle Dart_NewUnhandledExceptionError(Dart_Handle exception) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
Instance& obj = Instance::Handle(Z);
intptr_t class_id = Api::ClassId(exception);
if ((class_id == kApiErrorCid) || (class_id == kLanguageErrorCid)) {
const Object& excp = Object::Handle(Z, Api::UnwrapHandle(exception));
obj = String::New(GetErrorString(T, excp));
} else {
obj = Api::UnwrapInstanceHandle(Z, exception).raw();
if (obj.IsNull()) {
RETURN_TYPE_ERROR(Z, exception, Instance);
}
}
const StackTrace& stacktrace = StackTrace::Handle(Z);
return Api::NewHandle(T, UnhandledException::New(obj, stacktrace));
}
DART_EXPORT void Dart_PropagateError(Dart_Handle handle) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
const Object& obj = Object::Handle(thread->zone(), Api::UnwrapHandle(handle));
if (!obj.IsError()) {
FATAL1(
"%s expects argument 'handle' to be an error handle. "
"Did you forget to check Dart_IsError first?",
CURRENT_FUNC);
}
if (thread->top_exit_frame_info() == 0) {
// There are no dart frames on the stack so it would be illegal to
// propagate an error here.
FATAL("No Dart frames on stack, cannot propagate error.");
}
// Unwind all the API scopes till the exit frame before propagating.
const Error* error;
{
// We need to preserve the error object across the destruction of zones
// when the ApiScopes are unwound. By using NoSafepointScope, we can ensure
// that GC won't touch the raw error object before creating a valid
// handle for it in the surviving zone.
NoSafepointScope no_safepoint;
RawError* raw_error = Api::UnwrapErrorHandle(thread->zone(), handle).raw();
thread->UnwindScopes(thread->top_exit_frame_info());
// Note that thread's zone is different here than at the beginning of this
// function.
error = &Error::Handle(thread->zone(), raw_error);
}
Exceptions::PropagateError(*error);
UNREACHABLE();
}
DART_EXPORT Dart_Handle Dart_ToString(Dart_Handle object) {
DARTSCOPE(Thread::Current());
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
if (obj.IsString()) {
return Api::NewHandle(T, obj.raw());
} else if (obj.IsInstance()) {
CHECK_CALLBACK_STATE(T);
const Instance& receiver = Instance::Cast(obj);
return Api::NewHandle(T, DartLibraryCalls::ToString(receiver));
} else {
CHECK_CALLBACK_STATE(T);
// This is a VM internal object. Call the C++ method of printing.
return Api::NewHandle(T, String::New(obj.ToCString()));
}
}
DART_EXPORT bool Dart_IdentityEquals(Dart_Handle obj1, Dart_Handle obj2) {
DARTSCOPE(Thread::Current());
{
NoSafepointScope no_safepoint_scope;
if (Api::UnwrapHandle(obj1) == Api::UnwrapHandle(obj2)) {
return true;
}
}
const Object& object1 = Object::Handle(Z, Api::UnwrapHandle(obj1));
const Object& object2 = Object::Handle(Z, Api::UnwrapHandle(obj2));
if (object1.IsInstance() && object2.IsInstance()) {
return Instance::Cast(object1).IsIdenticalTo(Instance::Cast(object2));
}
return false;
}
DART_EXPORT Dart_Handle
Dart_HandleFromPersistent(Dart_PersistentHandle object) {
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
TransitionNativeToVM transition(thread);
NoSafepointScope no_safepoint_scope;
PersistentHandle* ref = PersistentHandle::Cast(object);
return Api::NewHandle(thread, ref->raw());
}
DART_EXPORT Dart_Handle
Dart_HandleFromWeakPersistent(Dart_WeakPersistentHandle object) {
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
TransitionNativeToVM transition(thread);
NoSafepointScope no_safepoint_scope;
FinalizablePersistentHandle* weak_ref =
FinalizablePersistentHandle::Cast(object);
return Api::NewHandle(thread, weak_ref->raw());
}
DART_EXPORT Dart_PersistentHandle Dart_NewPersistentHandle(Dart_Handle object) {
DARTSCOPE(Thread::Current());
Isolate* I = T->isolate();
ApiState* state = I->api_state();
ASSERT(state != NULL);
const Object& old_ref = Object::Handle(Z, Api::UnwrapHandle(object));
PersistentHandle* new_ref = state->persistent_handles().AllocateHandle();
new_ref->set_raw(old_ref);
return new_ref->apiHandle();
}
DART_EXPORT void Dart_SetPersistentHandle(Dart_PersistentHandle obj1,
Dart_Handle obj2) {
DARTSCOPE(Thread::Current());
Isolate* I = T->isolate();
ApiState* state = I->api_state();
ASSERT(state != NULL);
ASSERT(state->IsValidPersistentHandle(obj1));
const Object& obj2_ref = Object::Handle(Z, Api::UnwrapHandle(obj2));
PersistentHandle* obj1_ref = PersistentHandle::Cast(obj1);
obj1_ref->set_raw(obj2_ref);
}
static Dart_WeakPersistentHandle AllocateFinalizableHandle(
Thread* thread,
const Object& ref,
void* peer,
intptr_t external_allocation_size,
Dart_WeakPersistentHandleFinalizer callback) {
if (!ref.raw()->IsHeapObject()) {
return NULL;
}
FinalizablePersistentHandle* finalizable_ref =
FinalizablePersistentHandle::New(thread->isolate(), ref, peer, callback,
external_allocation_size);
return finalizable_ref->apiHandle();
}
static Dart_WeakPersistentHandle AllocateFinalizableHandle(
Thread* thread,
Dart_Handle object,
void* peer,
intptr_t external_allocation_size,
Dart_WeakPersistentHandleFinalizer callback) {
REUSABLE_OBJECT_HANDLESCOPE(thread);
Object& ref = thread->ObjectHandle();
ref = Api::UnwrapHandle(object);
return AllocateFinalizableHandle(thread, ref, peer, external_allocation_size,
callback);
}
DART_EXPORT Dart_WeakPersistentHandle
Dart_NewWeakPersistentHandle(Dart_Handle object,
void* peer,
intptr_t external_allocation_size,
Dart_WeakPersistentHandleFinalizer callback) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
if (callback == NULL) {
return NULL;
}
TransitionNativeToVM transition(thread);
return AllocateFinalizableHandle(thread, object, peer,
external_allocation_size, callback);
}
DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object) {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
NoSafepointScope no_safepoint_scope;
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
PersistentHandle* ref = PersistentHandle::Cast(object);
ASSERT(!state->IsProtectedHandle(ref));
if (!state->IsProtectedHandle(ref)) {
state->persistent_handles().FreeHandle(ref);
}
}
DART_EXPORT void Dart_DeleteWeakPersistentHandle(
Dart_Isolate current_isolate,
Dart_WeakPersistentHandle object) {
Isolate* isolate = reinterpret_cast<Isolate*>(current_isolate);
CHECK_ISOLATE(isolate);
NoSafepointScope no_safepoint_scope;
ASSERT(isolate == Isolate::Current());
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
FinalizablePersistentHandle* weak_ref =
FinalizablePersistentHandle::Cast(object);
weak_ref->EnsureFreeExternal(isolate);
state->weak_persistent_handles().FreeHandle(weak_ref);
}
// --- Initialization and Globals ---
DART_EXPORT const char* Dart_VersionString() {
return Version::String();
}
DART_EXPORT char* Dart_Initialize(Dart_InitializeParams* params) {
if (params == NULL) {
return strdup(
"Dart_Initialize: "
"Dart_InitializeParams is null.");
}
if (params->version != DART_INITIALIZE_PARAMS_CURRENT_VERSION) {
return strdup(
"Dart_Initialize: "
"Invalid Dart_InitializeParams version.");
}
return Dart::Init(params->vm_snapshot_data, params->vm_snapshot_instructions,
params->create, params->shutdown, params->cleanup,
params->thread_exit, params->file_open, params->file_read,
params->file_write, params->file_close,
params->entropy_source, params->get_service_assets,
params->start_kernel_isolate);
}
DART_EXPORT char* Dart_Cleanup() {
CHECK_NO_ISOLATE(Isolate::Current());
return Dart::Cleanup();
}
DART_EXPORT char* Dart_SetVMFlags(int argc, const char** argv) {
return Flags::ProcessCommandLineFlags(argc, argv);
}
DART_EXPORT bool Dart_IsVMFlagSet(const char* flag_name) {
return Flags::IsSet(flag_name);
}
#if !defined(PRODUCT)
#define VM_METRIC_API(type, variable, name, unit) \
DART_EXPORT int64_t Dart_VM##variable##Metric() { \
return vm_metric_##variable.value(); \
}
VM_METRIC_LIST(VM_METRIC_API);
#undef VM_METRIC_API
#define ISOLATE_METRIC_API(type, variable, name, unit) \
DART_EXPORT int64_t Dart_Isolate##variable##Metric(Dart_Isolate isolate) { \
if (isolate == NULL) { \
FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC); \
} \
Isolate* iso = reinterpret_cast<Isolate*>(isolate); \
return iso->Get##variable##Metric()->value(); \
}
ISOLATE_METRIC_LIST(ISOLATE_METRIC_API);
#undef ISOLATE_METRIC_API
#else // !defined(PRODUCT)
#define VM_METRIC_API(type, variable, name, unit) \
DART_EXPORT int64_t Dart_VM##variable##Metric() { return -1; }
VM_METRIC_LIST(VM_METRIC_API);
#undef VM_METRIC_API
#define ISOLATE_METRIC_API(type, variable, name, unit) \
DART_EXPORT int64_t Dart_Isolate##variable##Metric(Dart_Isolate isolate) { \
return -1; \
}
ISOLATE_METRIC_LIST(ISOLATE_METRIC_API);
#endif // !defined(PRODUCT)
// --- Isolates ---
static Dart_Isolate CreateIsolate(const char* script_uri,
const char* name,
const uint8_t* snapshot_data,
const uint8_t* snapshot_instructions,
const uint8_t* shared_data,
const uint8_t* shared_instructions,
const uint8_t* kernel_buffer,
intptr_t kernel_buffer_size,
Dart_IsolateFlags* flags,
void* callback_data,
char** error) {
CHECK_NO_ISOLATE(Isolate::Current());
// Setup default flags in case none were passed.
Dart_IsolateFlags api_flags;
if (flags == NULL) {
Isolate::FlagsInitialize(&api_flags);
flags = &api_flags;
}
Isolate* I = Dart::CreateIsolate((name == NULL) ? "isolate" : name, *flags);
if (I == NULL) {
if (error != NULL) {
*error = strdup("Isolate creation failed");
}
return reinterpret_cast<Dart_Isolate>(NULL);
}
Thread* T = Thread::Current();
bool success = false;
{
StackZone zone(T);
HANDLESCOPE(T);
// We enter an API scope here as InitializeIsolate could compile some
// bootstrap library files which call out to a tag handler that may create
// Api Handles when an error is encountered.
T->EnterApiScope();
const Error& error_obj = Error::Handle(
Z,
Dart::InitializeIsolate(snapshot_data, snapshot_instructions,
shared_data, shared_instructions, kernel_buffer,
kernel_buffer_size, callback_data));
if (error_obj.IsNull()) {
#if defined(DART_NO_SNAPSHOT) && !defined(PRODUCT)
if (FLAG_check_function_fingerprints && kernel_buffer == NULL) {
Library::CheckFunctionFingerprints();
}
#endif // defined(DART_NO_SNAPSHOT) && !defined(PRODUCT).
success = true;
} else if (error != NULL) {
*error = strdup(error_obj.ToErrorCString());
}
// We exit the API scope entered above.
T->ExitApiScope();
}
if (success) {
// A Thread structure has been associated to the thread, we do the
// safepoint transition explicitly here instead of using the
// TransitionXXX scope objects as the reverse transition happens
// outside this scope in Dart_ShutdownIsolate/Dart_ExitIsolate.
T->set_execution_state(Thread::kThreadInNative);
T->EnterSafepoint();
if (error != NULL) {
*error = NULL;
}
return Api::CastIsolate(I);
}
Dart::ShutdownIsolate();
return reinterpret_cast<Dart_Isolate>(NULL);
}
DART_EXPORT void Dart_IsolateFlagsInitialize(Dart_IsolateFlags* flags) {
Isolate::FlagsInitialize(flags);
}
DART_EXPORT Dart_Isolate
Dart_CreateIsolate(const char* script_uri,
const char* name,
const uint8_t* snapshot_data,
const uint8_t* snapshot_instructions,
const uint8_t* shared_data,
const uint8_t* shared_instructions,
Dart_IsolateFlags* flags,
void* callback_data,
char** error) {
API_TIMELINE_DURATION(Thread::Current());
return CreateIsolate(script_uri, name, snapshot_data, snapshot_instructions,
shared_data, shared_instructions, NULL, 0, flags,
callback_data, error);
}
DART_EXPORT Dart_Isolate
Dart_CreateIsolateFromKernel(const char* script_uri,
const char* name,
const uint8_t* kernel_buffer,
intptr_t kernel_buffer_size,
Dart_IsolateFlags* flags,
void* callback_data,
char** error) {
API_TIMELINE_DURATION(Thread::Current());
return CreateIsolate(script_uri, name, NULL, NULL, NULL, NULL, kernel_buffer,
kernel_buffer_size, flags, callback_data, error);
}
DART_EXPORT void Dart_ShutdownIsolate() {
Thread* T = Thread::Current();
Isolate* I = T->isolate();
CHECK_ISOLATE(I);
// The Thread structure is disassociated from the isolate, we do the
// safepoint transition explicitly here instead of using the TransitionXXX
// scope objects as the original transition happened outside this scope in
// Dart_EnterIsolate/Dart_CreateIsolate.
ASSERT(T->execution_state() == Thread::kThreadInNative);
T->ExitSafepoint();
T->set_execution_state(Thread::kThreadInVM);
I->WaitForOutstandingSpawns();
// Release any remaining API scopes.
ApiLocalScope* scope = T->api_top_scope();
while (scope != NULL) {
ApiLocalScope* previous = scope->previous();
delete scope;
scope = previous;
}
T->set_api_top_scope(NULL);
{
StackZone zone(T);
HandleScope handle_scope(T);
Dart::RunShutdownCallback();
}
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);
NoSafepointScope no_safepoint_scope;
return isolate->init_callback_data();
}
DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate) {
if (isolate == NULL) {
FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC);
}
// TODO(16615): Validate isolate parameter.
Isolate* iso = reinterpret_cast<Isolate*>(isolate);
return iso->init_callback_data();
}
DART_EXPORT Dart_Handle Dart_DebugName() {
DARTSCOPE(Thread::Current());
Isolate* I = T->isolate();
return Api::NewHandle(
T, String::NewFormatted("(%" Pd64 ") '%s'",
static_cast<int64_t>(I->main_port()), I->name()));
}
DART_EXPORT const char* Dart_IsolateServiceId(Dart_Isolate isolate) {
if (isolate == NULL) {
FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC);
}
Isolate* I = reinterpret_cast<Isolate*>(isolate);
int64_t main_port = static_cast<int64_t>(I->main_port());
return OS::SCreate(NULL, "isolates/%" Pd64, main_port);
}
DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate) {
CHECK_NO_ISOLATE(Isolate::Current());
// TODO(16615): Validate isolate parameter.
Isolate* iso = reinterpret_cast<Isolate*>(isolate);
if (!Thread::EnterIsolate(iso)) {
FATAL(
"Unable to Enter Isolate : "
"Multiple mutators entering an isolate / "
"Dart VM is shutting down");
}
// A Thread structure has been associated to the thread, we do the
// safepoint transition explicitly here instead of using the
// TransitionXXX scope objects as the reverse transition happens
// outside this scope in Dart_ExitIsolate/Dart_ShutdownIsolate.
Thread* T = Thread::Current();
T->set_execution_state(Thread::kThreadInNative);
T->EnterSafepoint();
}
DART_EXPORT void Dart_StartProfiling() {
#if !defined(PRODUCT)
if (!FLAG_profiler) {
FLAG_profiler = true;
Profiler::Init();
}
#endif // !defined(PRODUCT)
}
DART_EXPORT void Dart_StopProfiling() {
#if !defined(PRODUCT)
if (FLAG_profiler) {
Profiler::Cleanup();
FLAG_profiler = false;
}
#endif // !defined(PRODUCT)
}
DART_EXPORT void Dart_ThreadDisableProfiling() {
OSThread* os_thread = OSThread::Current();
if (os_thread == NULL) {
return;
}
os_thread->DisableThreadInterrupts();
}
DART_EXPORT void Dart_ThreadEnableProfiling() {
OSThread* os_thread = OSThread::Current();
if (os_thread == NULL) {
return;
}
os_thread->EnableThreadInterrupts();
}
DART_EXPORT void Dart_AddSymbols(const char* dso_name,
void* buffer,
intptr_t buffer_size) {
NativeSymbolResolver::AddSymbols(dso_name, buffer, buffer_size);
}
DART_EXPORT bool Dart_WriteProfileToTimeline(Dart_Port main_port,
char** error) {
#if defined(PRODUCT)
return false;
#else
if (!FLAG_profiler) {
if (error != NULL) {
*error = strdup("The profiler is not running.");
}
return false;
}
const intptr_t kBufferLength = 512;
char method[kBufferLength];
// clang-format off
intptr_t method_length = snprintf(method, kBufferLength, "{"
"\"jsonrpc\": \"2.0\","
"\"method\": \"_writeCpuProfileTimeline\","
"\"id\": \"\","
"\"params\": {"
" \"isolateId\": \"isolates/%" Pd64 "\","
" \"tags\": \"None\""
"}"
"}", main_port);
// clang-format on
ASSERT(method_length <= kBufferLength);
char* response = NULL;
intptr_t response_length;
bool success = Dart_InvokeVMServiceMethod(
reinterpret_cast<uint8_t*>(method), method_length,
reinterpret_cast<uint8_t**>(&response), &response_length,
error);
free(response);
return success;
#endif
}
DART_EXPORT bool Dart_ShouldPauseOnStart() {
#if defined(PRODUCT)
return false;
#else
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
NoSafepointScope no_safepoint_scope;
return isolate->message_handler()->should_pause_on_start();
#endif
}
DART_EXPORT void Dart_SetShouldPauseOnStart(bool should_pause) {
#if defined(PRODUCT)
if (should_pause) {
FATAL1("%s(true) is not supported in a PRODUCT build", CURRENT_FUNC);
}
#else
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
NoSafepointScope no_safepoint_scope;
if (isolate->is_runnable()) {
FATAL1("%s expects the current isolate to not be runnable yet.",
CURRENT_FUNC);
}
isolate->message_handler()->set_should_pause_on_start(should_pause);
#endif
}
DART_EXPORT bool Dart_IsPausedOnStart() {
#if defined(PRODUCT)
return false;
#else
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
NoSafepointScope no_safepoint_scope;
return isolate->message_handler()->is_paused_on_start();
#endif
}
DART_EXPORT void Dart_SetPausedOnStart(bool paused) {
#if defined(PRODUCT)
if (paused) {
FATAL1("%s(true) is not supported in a PRODUCT build", CURRENT_FUNC);
}
#else
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
NoSafepointScope no_safepoint_scope;
if (isolate->message_handler()->is_paused_on_start() != paused) {
isolate->message_handler()->PausedOnStart(paused);
}
#endif
}
DART_EXPORT bool Dart_ShouldPauseOnExit() {
#if defined(PRODUCT)
return false;
#else
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
NoSafepointScope no_safepoint_scope;
return isolate->message_handler()->should_pause_on_exit();
#endif
}
DART_EXPORT void Dart_SetShouldPauseOnExit(bool should_pause) {
#if defined(PRODUCT)
if (should_pause) {
FATAL1("%s(true) is not supported in a PRODUCT build", CURRENT_FUNC);
}
#else
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
NoSafepointScope no_safepoint_scope;
isolate->message_handler()->set_should_pause_on_exit(should_pause);
#endif
}
DART_EXPORT bool Dart_IsPausedOnExit() {
#if defined(PRODUCT)
return false;
#else
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
NoSafepointScope no_safepoint_scope;
return isolate->message_handler()->is_paused_on_exit();
#endif
}
DART_EXPORT void Dart_SetPausedOnExit(bool paused) {
#if defined(PRODUCT)
if (paused) {
FATAL1("%s(true) is not supported in a PRODUCT build", CURRENT_FUNC);
}
#else
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
NoSafepointScope no_safepoint_scope;
if (isolate->message_handler()->is_paused_on_exit() != paused) {
isolate->message_handler()->PausedOnExit(paused);
}
#endif
}
DART_EXPORT void Dart_SetStickyError(Dart_Handle error) {
Thread* thread = Thread::Current();
DARTSCOPE(thread);
Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
NoSafepointScope no_safepoint_scope;
const Error& error_handle = Api::UnwrapErrorHandle(Z, error);
if ((isolate->sticky_error() != Error::null()) &&
(error_handle.raw() != Object::null())) {
FATAL1("%s expects there to be no sticky error.", CURRENT_FUNC);
}
if (!error_handle.IsUnhandledException() &&
(error_handle.raw() != Object::null())) {
FATAL1("%s expects the error to be an unhandled exception error or null.",
CURRENT_FUNC);
}
isolate->SetStickyError(error_handle.raw());
}
DART_EXPORT bool Dart_HasStickyError() {
Thread* T = Thread::Current();
Isolate* isolate = T->isolate();
CHECK_ISOLATE(isolate);
NoSafepointScope no_safepoint_scope;
return isolate->sticky_error() != Error::null();
}
DART_EXPORT Dart_Handle Dart_GetStickyError() {
Thread* T = Thread::Current();
Isolate* I = T->isolate();
CHECK_ISOLATE(I);
NoSafepointScope no_safepoint_scope;
if (I->sticky_error() != Error::null()) {
TransitionNativeToVM transition(T);
Dart_Handle error = Api::NewHandle(T, I->sticky_error());
return error;
}
return Dart_Null();
}
DART_EXPORT void Dart_NotifyIdle(int64_t deadline) {
Thread* T = Thread::Current();
CHECK_ISOLATE(T->isolate());
API_TIMELINE_BEGIN_END(T);
TransitionNativeToVM transition(T);
T->isolate()->NotifyIdle(deadline);
}
DART_EXPORT void Dart_NotifyLowMemory() {
API_TIMELINE_BEGIN_END(Thread::Current());
Isolate::NotifyLowMemory();
}
DART_EXPORT void Dart_ExitIsolate() {
Thread* T = Thread::Current();
CHECK_ISOLATE(T->isolate());
// The Thread structure is disassociated from the isolate, we do the
// safepoint transition explicitly here instead of using the TransitionXXX
// scope objects as the original transition happened outside this scope in
// Dart_EnterIsolate/Dart_CreateIsolate.
ASSERT(T->execution_state() == Thread::kThreadInNative);
T->ExitSafepoint();
T->set_execution_state(Thread::kThreadInVM);
Thread::ExitIsolate();
}
static uint8_t* ApiReallocate(uint8_t* ptr,
intptr_t old_size,
intptr_t new_size) {
return Api::TopScope(Thread::Current())
->zone()
->Realloc<uint8_t>(ptr, old_size, new_size);
}
DART_EXPORT Dart_Handle
Dart_CreateSnapshot(uint8_t** vm_snapshot_data_buffer,
intptr_t* vm_snapshot_data_size,
uint8_t** isolate_snapshot_data_buffer,
intptr_t* isolate_snapshot_data_size) {
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
Isolate* I = T->isolate();
if (!FLAG_load_deferred_eagerly) {
return Api::NewError(
"Creating full snapshots requires --load_deferred_eagerly");
}
if (vm_snapshot_data_buffer != NULL && vm_snapshot_data_size == NULL) {
RETURN_NULL_ERROR(vm_snapshot_data_size);
}
CHECK_NULL(isolate_snapshot_data_buffer);
CHECK_NULL(isolate_snapshot_data_size);
// Finalize all classes if needed.
Dart_Handle state = Api::CheckAndFinalizePendingClasses(T);
if (Api::IsError(state)) {
return state;
}
BackgroundCompiler::Stop(I);
#if defined(DEBUG)
I->heap()->CollectAllGarbage();
{
HeapIterationScope iteration(T);
CheckFunctionTypesVisitor check_canonical(T);
iteration.IterateObjects(&check_canonical);
}
#endif // #if defined(DEBUG)
Symbols::Compact();
FullSnapshotWriter writer(Snapshot::kFull, vm_snapshot_data_buffer,
isolate_snapshot_data_buffer, ApiReallocate,
NULL /* vm_image_writer */,
NULL /* isolate_image_writer */);
writer.WriteFullSnapshot();
if (vm_snapshot_data_buffer != NULL) {
*vm_snapshot_data_size = writer.VmIsolateSnapshotSize();
}
*isolate_snapshot_data_size = writer.IsolateSnapshotSize();
return Api::Success();
}
DART_EXPORT bool Dart_IsKernel(const uint8_t* buffer, intptr_t buffer_size) {
if (buffer_size < 4) {
return false;
}
return (buffer[0] == 0x90) && (buffer[1] == 0xab) && (buffer[2] == 0xcd) &&
(buffer[3] == 0xef);
}
DART_EXPORT char* Dart_IsolateMakeRunnable(Dart_Isolate isolate) {
CHECK_NO_ISOLATE(Isolate::Current());
API_TIMELINE_DURATION(Thread::Current());
if (isolate == NULL) {
FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC);
}
// TODO(16615): Validate isolate parameter.
Isolate* iso = reinterpret_cast<Isolate*>(isolate);
const char* error;
if (iso->object_store()->root_library() == Library::null()) {
// The embedder should have called Dart_LoadScriptFromKernel by now.
error = "Missing root library";
} else {
error = iso->MakeRunnable();
}
if (error != NULL) {
return strdup(error);
}
return NULL;
}
// --- Messages and Ports ---
DART_EXPORT void Dart_SetMessageNotifyCallback(
Dart_MessageNotifyCallback message_notify_callback) {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
{
NoSafepointScope no_safepoint_scope;
isolate->set_message_notify_callback(message_notify_callback);
}
if (message_notify_callback != nullptr && isolate->HasPendingMessages()) {
::Dart_ExitIsolate();
// If a new handler gets installed and there are pending messages in the
// queue (e.g. OOB messages for doing vm service work) we need to notify
// the newly registered callback, otherwise the embedder might never get
// notified about the pending messages.
message_notify_callback(Api::CastIsolate(isolate));
::Dart_EnterIsolate(Api::CastIsolate(isolate));
}
}
DART_EXPORT Dart_MessageNotifyCallback Dart_GetMessageNotifyCallback() {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
NoSafepointScope no_safepoint_scope;
return isolate->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* I;
{
Thread* T = Thread::Current();
I = T->isolate();
CHECK_API_SCOPE(T);
CHECK_CALLBACK_STATE(T);
}
API_TIMELINE_BEGIN_END(Thread::Current());
// The message handler run loop does not expect to have a current isolate
// so we exit the isolate here and enter it again after the runloop is done.
::Dart_ExitIsolate();
{
Monitor monitor;
MonitorLocker ml(&monitor);
RunLoopData data;
data.monitor = &monitor;
data.done = false;
I->message_handler()->Run(Dart::thread_pool(), NULL, RunLoopDone,
reinterpret_cast<uword>(&data));
while (!data.done) {
ml.Wait();
}
}
::Dart_EnterIsolate(Api::CastIsolate(I));
if (I->sticky_error() != Object::null()) {
Thread* T = Thread::Current();
TransitionNativeToVM transition(T);
return Api::NewHandle(T, I->StealStickyError());
}
if (FLAG_print_class_table) {
HANDLESCOPE(Thread::Current());
I->class_table()->Print();
}
return Api::Success();
}
DART_EXPORT Dart_Handle Dart_HandleMessage() {
Thread* T = Thread::Current();
Isolate* I = T->isolate();
CHECK_API_SCOPE(T);
CHECK_CALLBACK_STATE(T);
API_TIMELINE_BEGIN_END_BASIC(T);
TransitionNativeToVM transition(T);
if (I->message_handler()->HandleNextMessage() != MessageHandler::kOK) {
return Api::NewHandle(T, T->StealStickyError());
}
return Api::Success();
}
DART_EXPORT Dart_Handle Dart_WaitForEvent(int64_t timeout_millis) {
Thread* T = Thread::Current();
Isolate* I = T->isolate();
CHECK_API_SCOPE(T);
CHECK_CALLBACK_STATE(T);
API_TIMELINE_BEGIN_END_BASIC(T);
TransitionNativeToVM transition(T);
if (I->message_notify_callback() != NULL) {
return Api::NewError("waitForEventSync is not supported by this embedder");
}
Object& result =
Object::Handle(Z, DartLibraryCalls::EnsureScheduleImmediate());
if (result.IsError()) {
return Api::NewHandle(T, result.raw());
}
// Drain the microtask queue. Propagate any errors to the entry frame.
result = DartLibraryCalls::DrainMicrotaskQueue();
if (result.IsError()) {
// Persist the error across unwiding scopes before propagating.
const Error* error;
{
NoSafepointScope no_safepoint;
RawError* raw_error = Error::Cast(result).raw();
T->UnwindScopes(T->top_exit_frame_info());
error = &Error::Handle(T->zone(), raw_error);
}
Exceptions::PropagateToEntry(*error);
UNREACHABLE();
return Api::NewError("Unreachable");
}
// Block to wait for messages and then handle them. Propagate any errors to
// the entry frame.
if (I->message_handler()->PauseAndHandleAllMessages(timeout_millis) !=
MessageHandler::kOK) {
// Persist the error across unwiding scopes before propagating.
const Error* error;
{
NoSafepointScope no_safepoint;
RawError* raw_error = T->StealStickyError();
T->UnwindScopes(T->top_exit_frame_info());
error = &Error::Handle(T->zone(), raw_error);
}
Exceptions::PropagateToEntry(*error);
UNREACHABLE();
return Api::NewError("Unreachable");
}
return Api::Success();
}
DART_EXPORT bool Dart_HandleServiceMessages() {
#if defined(PRODUCT)
return true;
#else
Thread* T = Thread::Current();
Isolate* I = T->isolate();
CHECK_API_SCOPE(T);
CHECK_CALLBACK_STATE(T);
API_TIMELINE_DURATION(T);
TransitionNativeToVM transition(T);
ASSERT(I->GetAndClearResumeRequest() == false);
MessageHandler::MessageStatus status =
I->message_handler()->HandleOOBMessages();
bool resume = I->GetAndClearResumeRequest();
return (status != MessageHandler::kOK) || resume;
#endif
}
DART_EXPORT bool Dart_HasServiceMessages() {
#if defined(PRODUCT)
return false;
#else
Isolate* isolate = Isolate::Current();
ASSERT(isolate);
NoSafepointScope no_safepoint_scope;
return isolate->message_handler()->HasOOBMessages();
#endif
}
DART_EXPORT bool Dart_HasLivePorts() {
Isolate* isolate = Isolate::Current();
ASSERT(isolate);
NoSafepointScope no_safepoint_scope;
return isolate->message_handler()->HasLivePorts();
}
DART_EXPORT bool Dart_Post(Dart_Port port_id, Dart_Handle handle) {
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
NoSafepointScope no_safepoint_scope;
if (port_id == ILLEGAL_PORT) {
return false;
}
// Smis and null can be sent without serialization.
RawObject* raw_obj = Api::UnwrapHandle(handle);
if (ApiObjectConverter::CanConvert(raw_obj)) {
return PortMap::PostMessage(
Message::New(port_id, raw_obj, Message::kNormalPriority));
}
const Object& object = Object::Handle(Z, raw_obj);
MessageWriter writer(false);
return PortMap::PostMessage(
writer.WriteMessage(object, port_id, Message::kNormalPriority));
}
DART_EXPORT Dart_Handle Dart_NewSendPort(Dart_Port port_id) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
if (port_id == ILLEGAL_PORT) {
return Api::NewError("%s: illegal port_id %" Pd64 ".", CURRENT_FUNC,
port_id);
}
return Api::NewHandle(T, SendPort::New(port_id));
}
DART_EXPORT Dart_Handle Dart_SendPortGetId(Dart_Handle port,
Dart_Port* port_id) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
API_TIMELINE_DURATION(T);
const SendPort& send_port = Api::UnwrapSendPortHandle(Z, port);
if (send_port.IsNull()) {
RETURN_TYPE_ERROR(Z, port, SendPort);
}
if (port_id == NULL) {
RETURN_NULL_ERROR(port_id);
}
*port_id = send_port.Id();
return Api::Success();
}
DART_EXPORT Dart_Port Dart_GetMainPortId() {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
return isolate->main_port();
}
// --- Scopes ----
DART_EXPORT void Dart_EnterScope() {
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
TransitionNativeToVM transition(thread);
thread->EnterApiScope();
}
DART_EXPORT void Dart_ExitScope() {
Thread* thread = Thread::Current();
CHECK_API_SCOPE(thread);
TransitionNativeToVM transition(thread);
thread->ExitApiScope();
}
DART_EXPORT uint8_t* Dart_ScopeAllocate(intptr_t size) {
Zone* zone;
Thread* thread = Thread::Current();
if (thread != NULL) {
ApiLocalScope* scope = thread->api_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() {
ASSERT(Isolate::Current() != NULL);
return Api::Null();
}
DART_EXPORT Dart_Handle Dart_EmptyString() {
ASSERT(Isolate::Current() != NULL);
return Api::EmptyString();
}
DART_EXPORT bool Dart_IsNull(Dart_Handle object) {
TransitionNativeToVM transition(Thread::Current());
return Api::UnwrapHandle(object) == Object::null();
}
DART_EXPORT Dart_Handle Dart_ObjectEquals(Dart_Handle obj1,
Dart_Handle obj2,
bool* value) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
const Instance& expected =
Instance::CheckedHandle(Z, Api::UnwrapHandle(obj1));
const Instance& actual = Instance::CheckedHandle(Z, Api::UnwrapHandle(obj2));
const Object& result =
Object::Handle(Z, DartLibraryCalls::Equals(expected, actual));
if (result.IsBool()) {
*value = Bool::Cast(result).value();
return Api::Success();
} else if (result.IsError()) {
return Api::NewHandle(T, 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?
DART_EXPORT Dart_Handle Dart_ObjectIsType(Dart_Handle object,
Dart_Handle type,
bool* value) {
DARTSCOPE(Thread::Current());
const Type& type_obj = Api::UnwrapTypeHandle(Z, type);
if (type_obj.IsNull()) {
*value = false;
RETURN_TYPE_ERROR(Z, type, Type);
}
if (!type_obj.IsFinalized()) {
return Api::NewError(
"%s expects argument 'type' to be a fully resolved type.",
CURRENT_FUNC);
}
if (object == Api::Null()) {
*value = false;
return Api::Success();
}
const Instance& instance = Api::UnwrapInstanceHandle(Z, object);
if (instance.IsNull()) {
*value = false;
RETURN_TYPE_ERROR(Z, object, Instance);
}
CHECK_CALLBACK_STATE(T);
*value = instance.IsInstanceOf(type_obj, Object::null_type_arguments(),
Object::null_type_arguments());
return Api::Success();
}
DART_EXPORT bool Dart_IsInstance(Dart_Handle object) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
REUSABLE_OBJECT_HANDLESCOPE(thread);
Object& ref = thread->ObjectHandle();
ref = Api::UnwrapHandle(object);
return ref.IsInstance();
}
DART_EXPORT bool Dart_IsNumber(Dart_Handle object) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return RawObject::IsNumberClassId(Api::ClassId(object));
}
DART_EXPORT bool Dart_IsInteger(Dart_Handle object) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return RawObject::IsIntegerClassId(Api::ClassId(object));
}
DART_EXPORT bool Dart_IsDouble(Dart_Handle object) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return Api::ClassId(object) == kDoubleCid;
}
DART_EXPORT bool Dart_IsBoolean(Dart_Handle object) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return Api::ClassId(object) == kBoolCid;
}
DART_EXPORT bool Dart_IsString(Dart_Handle object) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return RawObject::IsStringClassId(Api::ClassId(object));
}
DART_EXPORT bool Dart_IsStringLatin1(Dart_Handle object) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return RawObject::IsOneByteStringClassId(Api::ClassId(object));
}
DART_EXPORT bool Dart_IsExternalString(Dart_Handle object) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return RawObject::IsExternalStringClassId(Api::ClassId(object));
}
DART_EXPORT bool Dart_IsList(Dart_Handle object) {
DARTSCOPE(Thread::Current());
if (RawObject::IsBuiltinListClassId(Api::ClassId(object))) {
return true;
}
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
return GetListInstance(Z, obj) != Instance::null();
}
DART_EXPORT bool Dart_IsMap(Dart_Handle object) {
DARTSCOPE(Thread::Current());
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
return GetMapInstance(Z, obj) != Instance::null();
}
DART_EXPORT bool Dart_IsLibrary(Dart_Handle object) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return Api::ClassId(object) == kLibraryCid;
}
DART_EXPORT bool Dart_IsType(Dart_Handle handle) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return Api::ClassId(handle) == kTypeCid;
}
DART_EXPORT bool Dart_IsFunction(Dart_Handle handle) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return Api::ClassId(handle) == kFunctionCid;
}
DART_EXPORT bool Dart_IsVariable(Dart_Handle handle) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return Api::ClassId(handle) == kFieldCid;
}
DART_EXPORT bool Dart_IsTypeVariable(Dart_Handle handle) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return Api::ClassId(handle) == kTypeParameterCid;
}
DART_EXPORT bool Dart_IsClosure(Dart_Handle object) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return Api::ClassId(object) == kClosureCid;
}
DART_EXPORT bool Dart_IsTearOff(Dart_Handle object) {
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(object));
if (obj.IsClosure()) {
const Closure& closure = Closure::Cast(obj);
const Function& func = Function::Handle(Z, closure.function());
return func.IsImplicitClosureFunction();
}
return false;
}
DART_EXPORT bool Dart_IsTypedData(Dart_Handle handle) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
intptr_t cid = Api::ClassId(handle);
return RawObject::IsTypedDataClassId(cid) ||
RawObject::IsExternalTypedDataClassId(cid) ||
RawObject::IsTypedDataViewClassId(cid);
}
DART_EXPORT bool Dart_IsByteBuffer(Dart_Handle handle) {
Thread* thread = Thread::Current();
CHECK_ISOLATE(thread->isolate());
TransitionNativeToVM transition(thread);
return Api::ClassId(handle) == kByteBufferCid;
}
DART_EXPORT bool Dart_IsFuture(Dart_Handle handle) {
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
Isolate* I = T->isolate();
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(handle));
if (obj.IsInstance()) {
const Class& future_class =
Class::Handle(I->object_store()->future_class());
ASSERT(!future_class.IsNull());
const Class& obj_class = Class::Handle(Z, obj.clazz());
bool is_future = Class::IsSubtypeOf(
obj_class, Object::null_type_arguments(), future_class,
Object::null_type_arguments(), Heap::kNew);
return is_future;
}
return false;
}
// --- Instances ----
DART_EXPORT Dart_Handle Dart_InstanceGetType(Dart_Handle instance) {
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
Isolate* I = T->isolate();
const Object& obj = Object::Handle(Z, Api::UnwrapHandle(instance));
if (obj.IsNull()) {
return Api::NewHandle(T, I->object_store()->null_type());
}
if (!obj.IsInstance()) {
RETURN_TYPE_ERROR(Z, instance, Instance);
}
const AbstractType& type =
AbstractType::Handle(Instance::Cast(obj).GetType(Heap::kNew));
return Api::NewHandle(T, type.Canonicalize());
}
DART_EXPORT Dart_Handle Dart_FunctionName(Dart_Handle function) {
DARTSCOPE(Thread::Current());
const Function& func = Api::UnwrapFunctionHandle(Z, function);
if (func.IsNull()) {
RETURN_TYPE_ERROR(Z, function, Function);
}
return Api::NewHandle(T, func.UserVisibleName());
}
DART_EXPORT Dart_Handle Dart_ClassName(Dart_Handle cls_type) {
DARTSCOPE(Thread::Current());
const Type& type_obj = Api::UnwrapTypeHandle(Z, cls_type);
if (type_obj.IsNull()) {
RETURN_TYPE_ERROR(Z, cls_type, Type);
}
const Class& klass = Class::Handle(Z, type_obj.type_class());
if (klass.IsNull()) {
return Api::NewError(
"cls_type must be a Type object which represents a Class.");
}
return Api::NewHandle(T, klass.UserVisibleName());
}
DART_EXPORT Dart_Handle Dart_FunctionOwner(Dart_Handle function) {
DARTSCOPE(Thread::Current());
const Function& func = Api::UnwrapFunctionHandle(Z, function);
if (func.IsNull()) {
RETURN_TYPE_ERROR(Z, function, Function);
}
if (func.IsNonImplicitClosureFunction()) {
RawFunction* parent_function = func.parent_function();
return Api::NewHandle(T, parent_function);
}
const Class& owner = Class::Handle(Z, func.Owner());
ASSERT(!owner.IsNull());
if (owner.IsTopLevel()) {
// Top-level functions are implemented as members of a hidden class. We hide
// that class here and instead answer the library.
#if defined(DEBUG)
const Library& lib = Library::Handle(Z, owner.library());
if (lib.IsNull()) {
ASSERT(owner.IsDynamicClass() || owner.IsVoidClass());
}
#endif
return Api::NewHandle(T, owner.library());
} else {
return Api::NewHandle(T, owner.RareType());
}
}
DART_EXPORT Dart_Handle Dart_FunctionIsStatic(Dart_Handle function,
bool* is_static) {
DARTSCOPE(Thread::Current());
if (is_static == NULL) {
RETURN_NULL_ERROR(is_static);
}
const Function& func = Api::UnwrapFunctionHandle(Z, function);
if (func.IsNull()) {
RETURN_TYPE_ERROR(Z, function, Function);
}
*is_static = func.is_static();
return Api::Success();
}
DART_EXPORT Dart_Handle Dart_ClosureFunction(Dart_Handle closure) {
DARTSCOPE(Thread::Current());
const Instance& closure_obj = Api::UnwrapInstanceHandle(Z, closure);
if (closure_obj.IsNull() || !closure_obj.IsClosure()) {
RETURN_TYPE_ERROR(Z, closure, Instance);
}
ASSERT(ClassFinalizer::AllClassesFinalized());
RawFunction* rf = Closure::Cast(closure_obj).function();
return Api::NewHandle(T, rf);
}
DART_EXPORT Dart_Handle Dart_ClassLibrary(Dart_Handle cls_type) {
DARTSCOPE(Thread::Current());
const Type& type_obj = Api::UnwrapTypeHandle(Z, cls_type);
const Class& klass = Class::Handle(Z, type_obj.type_class());
if (klass.IsNull()) {
return Api::NewError(
"cls_type must be a Type object which represents a Class.");
}
const Library& library = Library::Handle(klass.library());
if (library.IsNull()) {
return Dart_Null();
}
return Api::NewHandle(Thread::Current(), library.raw());
}
// --- Numbers, Integers and Doubles ----
DART_EXPORT Dart_Handle Dart_IntegerFitsIntoInt64(Dart_Handle integer,
bool* fits) {
// Fast path for Smis and Mints.
Thread* thread = Thread::Current();
API_TIMELINE_DURATION(thread);
Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
if (Api::IsSmi(integer)) {
*fits = true;
return Api::Success();
}
// Slow path for mints and type error.
DARTSCOPE(thread);
if (Api::ClassId(integer) == kMintCid) {
*fits = true;
return Api::Success();
}
const Integer& int_obj = Api::UnwrapIntegerHandle(Z, integer);
ASSERT(int_obj.IsNull());
RETURN_TYPE_ERROR(Z, integer, Integer);
}
DART_EXPORT Dart_Handle Dart_IntegerFitsIntoUint64(Dart_Handle integer,
bool* fits) {
// Fast path for Smis.
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
API_TIMELINE_DURATION(thread);
if (Api::IsSmi(integer)) {
*fits = (Api::SmiValue(integer) >= 0);
return Api::Success();
}
// Slow path for Mints.
DARTSCOPE(thread);
const Integer& int_obj = Api::UnwrapIntegerHandle(Z, integer);
if (int_obj.IsNull()) {
RETURN_TYPE_ERROR(Z, integer, Integer);
}
ASSERT(int_obj.IsMint());
*fits = !int_obj.IsNegative();
return Api::Success();
}
DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value) {
// Fast path for Smis.
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
API_TIMELINE_DURATION(thread);
DARTSCOPE(thread);
CHECK_CALLBACK_STATE(thread);
return Api::NewHandle(thread, Integer::New(value));
}
DART_EXPORT Dart_Handle Dart_NewIntegerFromUint64(uint64_t value) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
API_TIMELINE_DURATION(T);
if (Integer::IsValueInRange(value)) {
return Api::NewHandle(T, Integer::NewFromUint64(value));
}
return Api::NewError("%s: Cannot create Dart integer from value %" Pu64,
CURRENT_FUNC, value);
}
DART_EXPORT Dart_Handle Dart_NewIntegerFromHexCString(const char* str) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
API_TIMELINE_DURATION(T);
const String& str_obj = String::Handle(Z, String::New(str));
RawInteger* integer = Integer::New(str_obj);
if (integer == Integer::null()) {
return Api::NewError("%s: Cannot create Dart integer from string %s",
CURRENT_FUNC, str);
}
return Api::NewHandle(T, integer);
}
DART_EXPORT Dart_Handle Dart_IntegerToInt64(Dart_Handle integer,
int64_t* value) {
// Fast path for Smis.
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
if (Api::IsSmi(integer)) {
*value = Api::SmiValue(integer);
return Api::Success();
}
// Slow path for Mints.
DARTSCOPE(thread);
const Integer& int_obj = Api::UnwrapIntegerHandle(Z, integer);
if (int_obj.IsNull()) {
RETURN_TYPE_ERROR(Z, integer, Integer);
}
ASSERT(int_obj.IsMint());
*value = int_obj.AsInt64Value();
return Api::Success();
}
DART_EXPORT Dart_Handle Dart_IntegerToUint64(Dart_Handle integer,
uint64_t* value) {
// Fast path for Smis.
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
CHECK_ISOLATE(isolate);
if (Api::IsSmi(integer)) {
intptr_t smi_value = Api::SmiValue(integer);
if (smi_value >= 0) {
*value = smi_value;
return Api::Success();
}
}
// Slow path for Mints.
DARTSCOPE(thread);
const Integer& int_obj = Api::UnwrapIntegerHandle(Z, integer);
if (int_obj.IsNull()) {
RETURN_TYPE_ERROR(Z, integer, Integer);
}
if (int_obj.IsSmi()) {
ASSERT(int_obj.IsNegative());
} else {
ASSERT(int_obj.IsMint());
if (!int_obj.IsNegative()) {
*value = int_obj.AsInt64Value();
return Api::Success();
}
}
return Api::NewError("%s: Integer %s cannot be represented as a uint64_t.",
CURRENT_FUNC, int_obj.ToCString());
}
DART_EXPORT Dart_Handle Dart_IntegerToHexCString(Dart_Handle integer,
const char** value) {
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
const Integer& int_obj = Api::UnwrapIntegerHandle(Z, integer);
if (int_obj.IsNull()) {
RETURN_TYPE_ERROR(Z, integer, Integer);
}
Zone* scope_zone = Api::TopScope(Thread::Current())->zone();
*value = int_obj.ToHexCString(scope_zone);
return Api::Success();
}
DART_EXPORT Dart_Handle Dart_NewDouble(double value) {
DARTSCOPE(Thread::Current());
CHECK_CALLBACK_STATE(T);
return Api::NewHandle(T, Double::New(value));
}
DART_EXPORT Dart_Handle Dart_DoubleValue(Dart_Handle double_obj,
double* value) {
DARTSCOPE(Thread::Current());
const Double& obj = Api::UnwrapDoubleHandle(Z, double_obj);
if (obj.IsNull()) {
RETURN_TYPE_ERROR(Z, double_obj, Double);
}
*value = obj.value();
return Api::Success();
}
DART_EXPORT Dart_Handle Dart_GetStaticMethodClosure(Dart_Handle library,
Dart_Handle cls_type,
Dart_Handle function_name) {
DARTSCOPE(Thread::Current());
const Library& lib = Api::UnwrapLibraryHandle(Z, library);
if (lib.IsNull()) {
RETURN_TYPE_ERROR(Z, library, Library);
}
const Type& type_obj = Api::UnwrapTypeHandle(Z, cls_type);
if (type_obj.IsNull()) {
RETURN_TYPE_ERROR(Z, cls_type, Type);
}
const Class& klass = Class::Handle(Z, type_obj.type_class());
if (klass.IsNull()) {
return Api::NewError(
"cls_type must be a Type object which represents a Class");
}
const String& func_name = Api::UnwrapStringHandle(Z, function_name);
if (func_name.IsNull()) {
RETURN_TYPE_ERROR(Z, function_name, String);
}
Function& func =
Function::Handle(Z, klass.LookupStaticFunctionAllowPrivate(func_name));
if (func.IsNull()) {
return Dart_Null();
}
if (!func.is_static()) {
return Api::NewError("function_name must refer to a static method.");
}
if (func.kind() != RawFunction::kRegularFunction) {
return Api::NewError(
"function_name must be the name of a regular function.");
}
func = func.ImplicitClosureFunction();
if (func.IsNull()) {
return Dart_Null();
}
return Api::NewHandle(T, func.ImplicitStaticClosure());
}
// --- Booleans ----
DART_EXPORT Dart_Handle Dart_True() {
ASSERT(Isolate::Current() != NULL);
return Api::True();
}
DART_EXPORT Dart_Handle Dart_False() {
ASSERT(Isolate::Current() != NULL);
return Api::False();
}
DART_EXPORT Dart_Handle Dart_NewBoolean(bool value) {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
return value ? Api::True() : Api::False();
}
DART_EXPORT Dart_Handle Dart_BooleanValue(Dart_Handle boolean_obj,
bool* value) {
DARTSCOPE(Thread::Current());
const Bool& obj = Api::UnwrapBoolHandle(Z, boolean_obj);
if (obj.IsNull()) {
RETURN_TYPE_ERROR(Z, boolean_obj, Bool);
}
*value = obj.value();
return Api::Success();
}
// --- Strings ---
DART_EXPORT Dart_Handle Dart_StringLength(Dart_Handle str, intptr_t* len) {
Thread* thread = Thread::Current();
DARTSCOPE(thread);
ReusableObjectHandleScope reused_obj_handle(thread);
const String& str_obj = Api::UnwrapStringHandle(reused_obj_handle, str);
if (str_obj.IsNull()) {
RETURN_TYPE_ERROR(thread->zone(), str, String);
}
*len = str_obj.Length();
return Api::Success();
}
DART_EXPORT Dart_Handle Dart_NewStringFromCString(const char* str) {
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
if (str == NULL) {
RETURN_NULL_ERROR(str);
}
CHECK_CALLBACK_STATE(T);
return Api::NewHandle(T, String::New(str));
}
DART_EXPORT Dart_Handle Dart_NewStringFromUTF8(const uint8_t* utf8_array,
intptr_t length) {
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
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(T);
return Api::NewHandle(T, String::FromUTF8(utf8_array, length));
}
DART_EXPORT Dart_Handle Dart_NewStringFromUTF16(const uint16_t* utf16_array,
intptr_t length) {
DARTSCOPE(Thread::Current());
if (utf16_array == NULL && length != 0) {
RETURN_NULL_ERROR(utf16_array);
}
CHECK_LENGTH(length, String::kMaxElements);
CHECK_CALLBACK_STATE(T);
return Api::NewHandle(T, String::FromUTF16(utf16_array, length));
}
DART_EXPORT Dart_Handle Dart_NewStringFromUTF32(const int32_t* utf32_array,
intptr_t length) {
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
if (utf32_array == NULL && length != 0) {
RETURN_NULL_ERROR(utf32_array);
}
CHECK_LENGTH(length, String::kMaxElements);
CHECK_CALLBACK_STATE(T);
return Api::NewHandle(T, String::FromUTF32(utf32_array, length));
}
DART_EXPORT Dart_Handle
Dart_NewExternalLatin1String(const uint8_t* latin1_array,
intptr_t length,
void* peer,
intptr_t external_allocation_size,
Dart_WeakPersistentHandleFinalizer callback) {
DARTSCOPE(Thread::Current());
API_TIMELINE_DURATION(T);
if (latin1_array == NULL && length != 0) {
RETURN_NULL_ERROR(latin1_array);
}
if (callback == NULL) {
RETURN_NULL_ERROR(callback);
}
CHECK_LENGTH(length, String::kMaxElements);
CHECK_CALLBACK_STATE(T);
return Api::NewHandle(
T,
String::NewExternal(latin1_array, length, peer, external_allocation_size,
callback, T->heap()->SpaceForExternal(length)));
}
DART_EXPORT Dart_Handle
Dart_NewExternalUTF16String(const uint16_t* utf16_array,
intptr_t length,
void* peer,
intptr_t external_allocation_size,
Dart_WeakPersistentHandleFinalizer callback) {
DARTSCOPE(Thread::Current());
if (utf16_array == NULL && length != 0) {