From ec36e02c287d39d4a090db2de186e6243980e763 Mon Sep 17 00:00:00 2001 From: "turnidge@google.com" Date: Wed, 30 May 2012 17:07:19 +0000 Subject: [PATCH] Remove the partially completed code for remote IsolateMirrors and replace it with the beginnings of a local (same isolate) IsolateMirror implementation. Removed old mirror tests and added two new mirror tests. Even though mirrors.cc is part of the vm, I chose to implement most of it using the dart embedding interface instead of our internal interfaces because the embedding interface was more convenient. mirrors.cc is basically all new in this CL -- don't pay any attention to diffs for that file. Added dart embedding functions required for the functionality in this CL: Dart_DebugName, Dart_GetNativeInstanceFieldCount, Dart_RootLibrary, Dart_RegisteredLibraryUrls, and Dart_LibraryName. Extended or modified some existing dart api functions, primarily to make them propagate error handles properly. Added tests for new dart embedding api functionality. Added the ability to determine if a port is local to the current isolate. Extended NotImplementedException to accept an optional string argument. I wanted to give more descriptive error messages. Review URL: https://chromiumcodereview.appspot.com//10416050 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8117 260f80e4-7a28-3924-810f-c04153c831b5 --- corelib/src/exceptions.dart | 7 +- lib/mirrors/mirrors.dart | 122 ++++- runtime/include/dart_api.h | 33 +- runtime/include/dart_debugger_api.h | 3 + runtime/lib/mirrors.cc | 424 ++++++++++++------ runtime/lib/mirrors_impl.dart | 131 ++++-- runtime/platform/assert.h | 19 + .../vm/dart/isolate_mirror_busy_test.dart | 33 -- .../vm/dart/isolate_mirror_idle_test.dart | 31 -- .../vm/dart/isolate_mirror_local_test.dart | 55 +++ .../vm/dart/isolate_mirror_remote_test.dart | 32 ++ .../vm/dart/isolate_mirror_self_test.dart | 25 -- runtime/tests/vm/vm.status | 5 - runtime/vm/bootstrap_natives.h | 5 +- runtime/vm/dart_api_impl.cc | 61 ++- runtime/vm/dart_api_impl_test.cc | 104 ++++- runtime/vm/dart_entry.h | 2 +- runtime/vm/debugger_api_impl_test.cc | 30 ++ runtime/vm/isolate.cc | 9 +- runtime/vm/message_handler.h | 3 + runtime/vm/object.cc | 3 + runtime/vm/port.cc | 13 + runtime/vm/port.h | 3 + 23 files changed, 877 insertions(+), 276 deletions(-) delete mode 100644 runtime/tests/vm/dart/isolate_mirror_busy_test.dart delete mode 100644 runtime/tests/vm/dart/isolate_mirror_idle_test.dart create mode 100644 runtime/tests/vm/dart/isolate_mirror_local_test.dart create mode 100644 runtime/tests/vm/dart/isolate_mirror_remote_test.dart delete mode 100644 runtime/tests/vm/dart/isolate_mirror_self_test.dart diff --git a/corelib/src/exceptions.dart b/corelib/src/exceptions.dart index 8e2bf6a4a08..48ede27290e 100644 --- a/corelib/src/exceptions.dart +++ b/corelib/src/exceptions.dart @@ -159,8 +159,11 @@ class UnsupportedOperationException implements Exception { class NotImplementedException implements Exception { - const NotImplementedException(); - String toString() => "NotImplementedException"; + const NotImplementedException([String this._message]); + String toString() => (this._message !== null + ? "NotImplementedException: $_message" + : "NotImplementedException"); + final String _message; } diff --git a/lib/mirrors/mirrors.dart b/lib/mirrors/mirrors.dart index 910c09185bf..d6d0d21d87c 100644 --- a/lib/mirrors/mirrors.dart +++ b/lib/mirrors/mirrors.dart @@ -6,13 +6,123 @@ // The dart:mirrors library provides reflective access for Dart program. // -// TODO(turnidge): Complete this api. This is a placeholder. - -interface IsolateMirror { - // A name used to refer to an isolate in debugging messages. - final String debugName; -} +// TODO(turnidge): Finish implementing this api. +/** + * Creates an [IsolateMirror] on the isolate which is listening on + * the [SendPort]. + */ Future isolateMirrorOf(SendPort port) { return _Mirrors.isolateMirrorOf(port); } + +/** + * A [Mirror] reflects some Dart language entity. + * + * Every [Mirror] originates from some [IsolateMirror]. + */ +interface Mirror { + /** + * The isolate of orgin for this [Mirror]. + */ + final IsolateMirror isolate; +} + +/** + * An [IsolateMirror] reflects an isolate. + */ +interface IsolateMirror extends Mirror { + /** + * A unique name used to refer to an isolate in debugging messages. + */ + final String debugName; + + /** + * A mirror on the root library of the reflectee. + */ + final LibraryMirror rootLibrary; + + /** + * An immutable map from from library names to mirrors for all + * libraries loaded in the reflectee. + */ + final Map libraries; +} + + +/** + * An [ObjectMirror] is a common superinterface of [InstanceMirror], + * [InterfaceMirror], and [LibraryMirror] that represents their shared + * functionality. + * + * For the purposes of the mirrors api, these types are all + * object-like, in that they support method invocation and field + * access. Real Dart objects are represented by the [InstanceMirror] + * type. + * + * See [InstanceMirror], [InterfaceMirror], and [LibraryMirror]. + */ +interface ObjectMirror extends Mirror { + /** + * Invokes the named function and returns a mirror on the result. + * + * TODO(turnidge): Properly document. + * + * TODO(turnidge): what to do if invoke causes the death of the reflectee? + */ + Future invoke(String memberName, + List positionalArguments, + [Map namedArguments]); +} + +/** + * An [InstanceMirror] reflects an instance of a Dart language object. + */ +interface InstanceMirror extends ObjectMirror { + /** + * If the [InstanceMirror] refers to a simple type, we provide + * access to the actual value here. Simple types are... + * + * TODO(turnidge): Properly document. + * + * TODO(turnidge): How best to represent a null simple value versus + * the absence of a simple value? + */ + final simpleValue; +} + +/** + * An [InterfaceMirror] reflects a Dart language class or interface. + */ +interface InterfaceMirror extends ObjectMirror { +} + +/** + * A [LibraryMirror] reflects a Dart language library, providing + * access to the variables, functions, classes, and interfaces of the + * library. + */ +interface LibraryMirror extends ObjectMirror { + /** + * The name of the library, as provided in the [#library] declaration. + */ + final String simpleName; + + /** + * The url of the library. + * + * TODO(turnidge): Document where this url comes from. Will this + * value be sensible? + */ + final String url; +} + +/** + * A [MirrorException] is used to indicate errors within the mirrors + * framework. + */ +class MirrorException implements Exception { + const MirrorException(String this._message); + String toString() => "MirrorException: '$_message'"; + final String _message; +} diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h index c610c5e0235..7453f24c8a2 100755 --- a/runtime/include/dart_api.h +++ b/runtime/include/dart_api.h @@ -534,6 +534,14 @@ DART_EXPORT void Dart_ShutdownIsolate(); */ DART_EXPORT Dart_Isolate Dart_CurrentIsolate(); +/** + * Returns the debugging name for the current isolate. + * + * This name is unique to each isolate and should only be used to make + * debugging messages more comprehensible. + */ +DART_EXPORT Dart_Handle Dart_DebugName(); + /** * Enters an isolate. After calling this function, * the current isolate will be set to the provided isolate. @@ -1114,6 +1122,8 @@ DART_EXPORT Dart_Handle Dart_StringLength(Dart_Handle str, intptr_t* length); * an error handle. */ DART_EXPORT Dart_Handle Dart_NewString(const char* str); +// TODO(turnidge): Document what happens when we run out of memory +// during this call. /** * Returns a String built from an array of 8-bit codepoints. @@ -1787,6 +1797,7 @@ DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle* arguments); +// TODO(turnidge): Document how to invoke operators. /** * Gets the value of a field. @@ -1842,6 +1853,12 @@ DART_EXPORT Dart_Handle Dart_CreateNativeWrapperClass(Dart_Handle library, Dart_Handle class_name, int field_count); +/** + * Gets the number of native instance fields in an object. + */ +DART_EXPORT Dart_Handle Dart_GetNativeInstanceFieldCount(Dart_Handle obj, + int* count); + /** * Gets the value of a native field. * @@ -2016,9 +2033,11 @@ DART_EXPORT Dart_Handle Dart_LoadScriptFromSnapshot(const uint8_t* buffer); /** * Gets the library for the root script for the current isolate. * - * \return Returns the Library object corresponding to the root script - * if it has been set by a successful call to Dart_LoadScript or - * Dart_LoadScriptFromSnapshot. Otherwise returns Dart_Null(). + * If the root script has not yet been set for the current isolate, + * this function returns Dart_Null(). This function never returns an + * error handle. + * + * \return Returns the root Library for the current isolate or Dart_Null(). */ DART_EXPORT Dart_Handle Dart_RootLibrary(); @@ -2049,6 +2068,14 @@ DART_EXPORT Dart_Handle Dart_GetClass(Dart_Handle library, // TODO(turnidge): Consider returning Dart_Null() when the class is // not found to distinguish that from a true error case. +/** + * Returns the name of a library as declared in the #library directive. + */ +DART_EXPORT Dart_Handle Dart_LibraryName(Dart_Handle library); + +/** + * Returns the url from which a library was loaded. + */ DART_EXPORT Dart_Handle Dart_LibraryUrl(Dart_Handle library); DART_EXPORT Dart_Handle Dart_LookupLibrary(Dart_Handle url); diff --git a/runtime/include/dart_debugger_api.h b/runtime/include/dart_debugger_api.h index 7f81d787be9..50c8ae936ed 100755 --- a/runtime/include/dart_debugger_api.h +++ b/runtime/include/dart_debugger_api.h @@ -54,6 +54,9 @@ DART_EXPORT Dart_Handle Dart_GetCachedObject(intptr_t obj_id); * \return A handle to a list of string handles. */ DART_EXPORT Dart_Handle Dart_GetLibraryURLs(); +// TODO(turnidge): The embedding and debugger apis are not consistent +// in how they capitalize url. One uses 'Url' and the other 'URL'. +// They should be the same. /** diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc index 16a58ddaaa3..2b9844cbe03 100644 --- a/runtime/lib/mirrors.cc +++ b/runtime/lib/mirrors.cc @@ -5,6 +5,8 @@ #include "vm/bootstrap_natives.h" #include "platform/json.h" +#include "include/dart_api.h" +#include "include/dart_debugger_api.h" #include "vm/dart_entry.h" #include "vm/exceptions.h" #include "vm/message.h" @@ -13,149 +15,321 @@ namespace dart { -static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) { - void* new_ptr = realloc(reinterpret_cast(ptr), new_size); - return reinterpret_cast(new_ptr); -} - - -DEFINE_NATIVE_ENTRY(Mirrors_send, 3) { +DEFINE_NATIVE_ENTRY(Mirrors_isLocalPort, 1) { GET_NATIVE_ARGUMENT(Instance, port, arguments->At(0)); - GET_NATIVE_ARGUMENT(Instance, message, arguments->At(1)); - GET_NATIVE_ARGUMENT(Instance, replyTo, arguments->At(2)); - // Get the send port id. - Object& result = Object::Handle(); - result = DartLibraryCalls::PortGetId(port); - if (result.IsError()) { - Exceptions::PropagateError(result); + // Get the port id from the SendPort instance. + const Object& id_obj = Object::Handle(DartLibraryCalls::PortGetId(port)); + if (id_obj.IsError()) { + Exceptions::PropagateError(id_obj); + UNREACHABLE(); } - - Integer& value = Integer::Handle(); - value ^= result.raw(); - int64_t send_port_id = value.AsInt64Value(); - - // Get the reply port id. - result = DartLibraryCalls::PortGetId(replyTo); - if (result.IsError()) { - Exceptions::PropagateError(result); - } - value ^= result.raw(); - int64_t reply_port_id = value.AsInt64Value(); - - // Construct the message. - uint8_t* data = NULL; - SnapshotWriter writer(Snapshot::kMessage, &data, &allocator); - writer.WriteObject(message.raw()); - writer.FinalizeBuffer(); - - // Post the message. - bool retval = PortMap::PostMessage(new Message( - send_port_id, reply_port_id, data, Message::kOOBPriority)); - const Bool& retval_obj = Bool::Handle(Bool::Get(retval)); - arguments->SetReturn(retval_obj); + ASSERT(id_obj.IsSmi() || id_obj.IsMint()); + Integer& id = Integer::Handle(); + id ^= id_obj.raw(); + Dart_Port port_id = static_cast(id.AsInt64Value()); + const Bool& is_local = Bool::Handle(Bool::Get(PortMap::IsLocalPort(port_id))); + arguments->SetReturn(is_local); } -static bool JSONGetString(JSONReader* reader, - const char** value_chars, - int* value_len) { - if (reader->Type() != JSONReader::kString) { - return false; - } - *value_chars = reader->ValueChars(); - *value_len = reader->ValueLen(); - return true; +// TODO(turnidge): Add Map support to the dart embedding api instead +// of implementing it here. +static Dart_Handle CoreLib() { + Dart_Handle core_lib_name = Dart_NewString("dart:core"); + return Dart_LookupLibrary(core_lib_name); } -DEFINE_NATIVE_ENTRY(Mirrors_processResponse, 3) { - GET_NATIVE_ARGUMENT(Instance, port, arguments->At(0)); - GET_NATIVE_ARGUMENT(String, command, arguments->At(1)); - GET_NATIVE_ARGUMENT(String, response, arguments->At(2)); +static Dart_Handle MapNew() { + Dart_Handle cls = Dart_GetClass(CoreLib(), Dart_NewString("Map")); + if (Dart_IsError(cls)) { + return cls; + } + return Dart_New(cls, Dart_Null(), 0, NULL); +} - const char* json_text = response.ToCString(); - if (command.Equals("isolateMirrorOf")) { - JSONReader reader(json_text); - const char* debug_name = ""; - int debug_name_len = 0; - if (!reader.Seek("ok") || !reader.IsTrue() || - !reader.Seek("debugName") || - !JSONGetString(&reader, &debug_name, &debug_name_len)) { - // TODO(turnidge): Use an exception class instead of a String. - Exceptions::Throw(Instance::Handle(String::NewFormatted( - "Error while processing mirror request."))); - UNREACHABLE(); + +static Dart_Handle MapAdd(Dart_Handle map, Dart_Handle key, Dart_Handle value) { + const int kNumArgs = 2; + Dart_Handle args[kNumArgs]; + args[0] = key; + args[1] = value; + return Dart_Invoke(map, Dart_NewString("[]="), kNumArgs, args); +} + + +static Dart_Handle MapGet(Dart_Handle map, Dart_Handle key) { + const int kNumArgs = 1; + Dart_Handle args[kNumArgs]; + args[0] = key; + return Dart_Invoke(map, Dart_NewString("[]"), kNumArgs, args); +} + + +static Dart_Handle MirrorLib() { + Dart_Handle mirror_lib_name = Dart_NewString("dart:mirrors"); + return Dart_LookupLibrary(mirror_lib_name); +} + + +static Dart_Handle IsMirror(Dart_Handle object, bool* is_mirror) { + Dart_Handle cls_name = Dart_NewString("Mirror"); + Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name); + if (Dart_IsError(cls)) { + return cls; + } + Dart_Handle result = Dart_ObjectIsType(object, cls, is_mirror); + if (Dart_IsError(result)) { + return result; + } + return Dart_True(); // Indicates success. Result is in is_mirror. +} + + +static bool IsSimpleValue(Dart_Handle object) { + return (Dart_IsNull(object) || + Dart_IsNumber(object) || + Dart_IsString(object) || + Dart_IsBoolean(object)); +} + + +static void FreeVMReference(Dart_Handle weak_ref, void* data) { + Dart_Handle perm_handle = reinterpret_cast(data); + Dart_DeletePersistentHandle(perm_handle); + Dart_DeletePersistentHandle(weak_ref); +} + + +static Dart_Handle CreateVMReference(Dart_Handle handle) { + // Create the VMReference object. + Dart_Handle cls_name = Dart_NewString("VMReference"); + Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name); + if (Dart_IsError(cls)) { + return cls; + } + Dart_Handle vm_ref = Dart_New(cls, Dart_Null(), 0, NULL); + if (Dart_IsError(vm_ref)) { + return vm_ref; + } + + // Allocate a persistent handle. + Dart_Handle perm_handle = Dart_NewPersistentHandle(handle); + if (Dart_IsError(perm_handle)) { + return perm_handle; + } + + // Store the persistent handle in the VMReference. + intptr_t perm_handle_value = reinterpret_cast(perm_handle); + Dart_Handle result = + Dart_SetNativeInstanceField(vm_ref, 0, perm_handle_value); + if (Dart_IsError(result)) { + Dart_DeletePersistentHandle(perm_handle); + return result; + } + + // Create a weak reference. We use the callback to be informed when + // the VMReference is collected, so we can release the persistent + // handle. + void* perm_handle_data = reinterpret_cast(perm_handle); + Dart_Handle weak_ref = + Dart_NewWeakPersistentHandle(vm_ref, perm_handle_data, FreeVMReference); + if (Dart_IsError(weak_ref)) { + Dart_DeletePersistentHandle(perm_handle); + return weak_ref; + } + + // Success. + return vm_ref; +} + + +static Dart_Handle UnwrapVMReference(Dart_Handle vm_ref) { + // Retrieve the persistent handle from the VMReference + intptr_t perm_handle_value = 0; + Dart_Handle result = + Dart_GetNativeInstanceField(vm_ref, 0, &perm_handle_value); + if (Dart_IsError(result)) { + return result; + } + Dart_Handle perm_handle = reinterpret_cast(perm_handle_value); + ASSERT(!Dart_IsError(perm_handle)); + return perm_handle; +} + + +static Dart_Handle UnwrapMirror(Dart_Handle mirror) { + Dart_Handle field_name = Dart_NewString("_reference"); + Dart_Handle vm_ref = Dart_GetField(mirror, field_name); + if (Dart_IsError(vm_ref)) { + return vm_ref; + } + return UnwrapVMReference(vm_ref); +} + + +static Dart_Handle UnwrapArgList(Dart_Handle arg_list, + GrowableArray* arg_array) { + intptr_t len = 0; + Dart_Handle result = Dart_ListLength(arg_list, &len); + if (Dart_IsError(result)) { + return result; + } + for (int i = 0; i < len; i++) { + Dart_Handle arg = Dart_ListGetAt(arg_list, i); + if (Dart_IsError(arg)) { + return arg; + } + bool is_mirror = false; + result = IsMirror(arg, &is_mirror); + if (Dart_IsError(result)) { + return result; + } + if (is_mirror) { + arg_array->Add(UnwrapMirror(arg)); + } else { + // Simple value. + ASSERT(IsSimpleValue(arg)); + arg_array->Add(arg); } - - // Create and return a new instance of _IsolateMirrorImpl. - Library& lib = Library::Handle(Library::MirrorsLibrary()); - const String& public_class_name = - String::Handle(String::NewSymbol("_IsolateMirrorImpl")); - const String& class_name = - String::Handle(lib.PrivateName(public_class_name)); - const String& function_name = - String::Handle(String::NewSymbol("_make")); - const int kNumArgs = 2; - const Array& kNoArgNames = Array::Handle(); - const Function& function = Function::Handle( - Resolver::ResolveStatic(lib, - class_name, - function_name, - kNumArgs, - kNoArgNames, - Resolver::kIsQualified)); - ASSERT(!function.IsNull()); - GrowableArray args(kNumArgs); - args.Add(&port); - const String& debug_name_str = String::Handle( - String::NewFormatted("%.*s", debug_name_len, debug_name)); - args.Add(&debug_name_str); - const Object& result = Object::Handle( - DartEntry::InvokeStatic(function, args, kNoArgNames)); - arguments->SetReturn(result); } + return Dart_True(); } +static Dart_Handle CreateLibraryMirror(Dart_Handle lib) { + Dart_Handle cls_name = Dart_NewString("_LocalLibraryMirrorImpl"); + Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name); + if (Dart_IsError(cls)) { + return cls; + } + const int kNumArgs = 3; + Dart_Handle args[kNumArgs]; + args[0] = CreateVMReference(lib); + args[1] = Dart_LibraryName(lib); + args[2] = Dart_LibraryUrl(lib); + return Dart_New(cls, Dart_Null(), kNumArgs, args); +} + + +static Dart_Handle CreateLibrariesMap() { + // TODO(turnidge): This should be an immutable map. + Dart_Handle map = MapNew(); + + Dart_Handle lib_urls = Dart_GetLibraryURLs(); + if (Dart_IsError(lib_urls)) { + return lib_urls; + } + intptr_t len; + Dart_Handle result = Dart_ListLength(lib_urls, &len); + if (Dart_IsError(result)) { + return result; + } + for (int i = 0; i < len; i++) { + Dart_Handle lib_url = Dart_ListGetAt(lib_urls, i); + Dart_Handle lib = Dart_LookupLibrary(lib_url); + if (Dart_IsError(lib)) { + return lib; + } + Dart_Handle lib_key = Dart_LibraryName(lib); + Dart_Handle lib_mirror = CreateLibraryMirror(lib); + if (Dart_IsError(lib_mirror)) { + return lib_mirror; + } + // TODO(turnidge): Check for duplicate library names. + result = MapAdd(map, lib_key, lib_mirror); + } + return map; +} + + +static Dart_Handle CreateLocalIsolateMirror() { + Dart_Handle cls_name = Dart_NewString("_LocalIsolateMirrorImpl"); + Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name); + if (Dart_IsError(cls)) { + return cls; + } + + Dart_Handle libraries = CreateLibrariesMap(); + if (Dart_IsError(libraries)) { + return libraries; + } + + // Lookup the root_lib_mirror from the library list to canonicalize it. + Dart_Handle root_lib_name = Dart_LibraryName(Dart_RootLibrary()); + Dart_Handle root_lib_mirror = MapGet(libraries, root_lib_name); + if (Dart_IsError(root_lib_mirror)) { + return root_lib_mirror; + } + + const int kNumArgs = 3; + Dart_Handle args[kNumArgs]; + args[0] = Dart_DebugName(); + args[1] = root_lib_mirror; + args[2] = libraries; + Dart_Handle mirror = Dart_New(cls, Dart_Null(), kNumArgs, args); + return mirror; +} + + +static Dart_Handle CreateLocalInstanceMirror(Dart_Handle instance) { + // ASSERT(Dart_IsInstance(instance)); + Dart_Handle cls_name = Dart_NewString("_LocalInstanceMirrorImpl"); + Dart_Handle cls = Dart_GetClass(MirrorLib(), cls_name); + if (Dart_IsError(cls)) { + return cls; + } + const int kNumArgs = 2; + Dart_Handle args[kNumArgs]; + args[0] = CreateVMReference(instance); + if (IsSimpleValue(instance)) { + args[1] = instance; + } else { + args[1] = Dart_Null(); + } + Dart_Handle mirror = Dart_New(cls, Dart_Null(), kNumArgs, args); + return mirror; +} + + +void NATIVE_ENTRY_FUNCTION(Mirrors_makeLocalIsolateMirror)( + Dart_NativeArguments args) { + Dart_Handle mirror = CreateLocalIsolateMirror(); + if (Dart_IsError(mirror)) { + Dart_PropagateError(mirror); + } + Dart_SetReturnValue(args, mirror); +} + +void NATIVE_ENTRY_FUNCTION(LocalObjectMirrorImpl_invoke)( + Dart_NativeArguments args) { + Dart_Handle mirror = Dart_GetNativeArgument(args, 0); + Dart_Handle member = Dart_GetNativeArgument(args, 1); + Dart_Handle raw_invoke_args = Dart_GetNativeArgument(args, 2); + + Dart_Handle reflectee = UnwrapMirror(mirror); + GrowableArray invoke_args; + Dart_Handle result = UnwrapArgList(raw_invoke_args, &invoke_args); + if (Dart_IsError(result)) { + Dart_PropagateError(result); + } + result = + Dart_Invoke(reflectee, member, invoke_args.length(), invoke_args.data()); + if (Dart_IsError(result)) { + Dart_PropagateError(result); + } + Dart_Handle wrapped_result = CreateLocalInstanceMirror(result); + if (Dart_IsError(wrapped_result)) { + Dart_PropagateError(wrapped_result); + } + Dart_SetReturnValue(args, wrapped_result); +} + void HandleMirrorsMessage(Isolate* isolate, Dart_Port reply_port, const Instance& message) { - TextBuffer buffer(64); - if (!message.IsString()) { - buffer.Printf( - "{ \"ok\": false, \"error\": \"Malformed mirrors request\" }"); - } else { - String& json_string = String::Handle(); - json_string ^= message.raw(); - const char* json_text = json_string.ToCString(); - JSONReader reader(json_text); - - if (reader.Seek("command")) { - if (reader.IsStringLiteral("isolateMirrorOf")) { - buffer.Printf("{ \"ok\": true, \"debugName\": \"%s\" }", - isolate->name()); - } else { - const char* command = ""; - int command_len = 0; - JSONGetString(&reader, &command, &command_len); - buffer.Printf( - "{ \"ok\": false, \"error\": \"Command '%.*s' not recognized\" }", - command_len, command); - } - } else { - buffer.Printf( - "{ \"ok\": false, \"error\": \"Field 'command' not found\" }"); - } - } - - Dart_CObject reply; - reply.type = Dart_CObject::kString; - reply.value.as_string = buffer.buf(); - if (!Dart_PostCObject(reply_port, &reply)) { - OS::PrintErr("Unable to post mirrors reply"); - return; - } + UNIMPLEMENTED(); } } // namespace dart diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart index ac24fb5b54c..2d0ebfe2ff8 100644 --- a/runtime/lib/mirrors_impl.dart +++ b/runtime/lib/mirrors_impl.dart @@ -4,36 +4,115 @@ // VM-specific implementation of the dart:mirrors library. -class _IsolateMirrorImpl implements IsolateMirror { - _IsolateMirrorImpl(this.port, this.debugName) {} - - final SendPort port; - final String debugName; - - static _make(SendPort port, String debugName) { - return new _IsolateMirrorImpl(port, debugName); - } +// These values are allowed to be passed directly over the wire. +bool isSimpleValue(var value) { + return (value === null || value is num || value is String || value is bool); } -class _Mirrors { - static Future isolateMirrorOf(SendPort port) { - Completer completer = new Completer(); - String request = '{ "command": "isolateMirrorOf" }'; - ReceivePort rp = new ReceivePort(); - if (!send(port, request, rp.toSendPort())) { - throw new Exception("Unable to send mirror request to port $port"); +abstract class _LocalMirrorImpl implements Mirror { + // Local mirrors always return the same IsolateMirror. This field + // is more interesting once we implement remote mirrors. + IsolateMirror get isolate() { return Mirrors.localIsolateMirror(); } +} + +class _LocalIsolateMirrorImpl extends _LocalMirrorImpl + implements IsolateMirror { + _LocalIsolateMirrorImpl(this.debugName, this.rootLibrary, this.libraries) {} + + final String debugName; + final LibraryMirror rootLibrary; + final Map libraries; +} + +// A VMReference is used to hold a reference to a VM-internal object, +// which can include things like libraries, classes, etc. +class VMReference extends NativeFieldWrapperClass1 { +} + +abstract class _LocalVMObjectMirrorImpl extends _LocalMirrorImpl { + _LocalVMObjectMirrorImpl(this._reference) {} + + // For now, all VMObjects hold a VMReference. We could consider + // storing the Object reference itself here if the object is a Dart + // language objects (except for objects of type VMReference, of + // course). + VMReference _reference; +} + +abstract class _LocalObjectMirrorImpl extends _LocalVMObjectMirrorImpl + implements ObjectMirror { + _LocalObjectMirrorImpl(ref) : super(ref) {} + + Future invoke(String memberName, + List positionalArguments, + [Map namedArguments]) { + if (namedArguments !== null) { + throw new NotImplementedException('named arguments not implemented'); } - rp.receive((message, _) { - rp.close(); - completer.complete(_Mirrors.processResponse( - port, "isolateMirrorOf", message)); - }); + // Walk the arguments and make sure they are legal. + for (int i = 0; i < positionalArguments.length; i++) { + var arg = positionalArguments[i]; + if (arg is Mirror) { + throw new MirrorException( + 'positional argument $i ($arg) was not an InstanceMirror'); + } + if (!isSimpleValue(arg)) { + throw new MirrorException( + 'positional argument $i ($arg) was not a simple value'); + } + } + Completer completer = new Completer(); + completer.complete( + _invoke(this, memberName, positionalArguments)); return completer.future; } - static bool send(SendPort port, String request, SendPort replyTo) - native "Mirrors_send"; - - static processResponse(SendPort port, String command, String response) - native "Mirrors_processResponse"; + static _invoke(ref, memberName, positionalArguments) + native 'LocalObjectMirrorImpl_invoke'; +} + +class _LocalInstanceMirrorImpl extends _LocalObjectMirrorImpl + implements InstanceMirror { + _LocalInstanceMirrorImpl(ref, this.simpleValue) : super(ref) {} + + final simpleValue; +} + +class _LocalLibraryMirrorImpl extends _LocalObjectMirrorImpl + implements LibraryMirror { + _LocalLibraryMirrorImpl(ref, this.simpleName, this.url) : super(ref) {} + + final String simpleName; + final String url; +} + +class _Mirrors { + // Does a port refer to our local isolate? + static bool isLocalPort(SendPort port) native 'Mirrors_isLocalPort'; + + static IsolateMirror _localIsolateMirror; + + // The IsolateMirror for the current isolate. + static IsolateMirror localIsolateMirror() { + if (_localIsolateMirror === null) { + _localIsolateMirror = makeLocalIsolateMirror(); + } + return _localIsolateMirror; + } + + // Creates a new local IsolateMirror. + static bool makeLocalIsolateMirror() + native 'Mirrors_makeLocalIsolateMirror'; + + static Future isolateMirrorOf(SendPort port) { + Completer completer = new Completer(); + if (isLocalPort(port)) { + // Make a local isolate mirror. + completer.complete(localIsolateMirror()); + } else { + // Make a remote isolate mirror. + throw new NotImplementedException('Remote mirrors not yet implemented'); + } + return completer.future; + } } diff --git a/runtime/platform/assert.h b/runtime/platform/assert.h index 3d39bab4eee..70a5dee9699 100644 --- a/runtime/platform/assert.h +++ b/runtime/platform/assert.h @@ -51,6 +51,9 @@ class DynamicAssertionHelper { template void IsSubstring(const E& needle, const A& haystack); + template + void IsNotSubstring(const E& needle, const A& haystack); + template void LessThan(const E& left, const A& right); @@ -157,6 +160,19 @@ void DynamicAssertionHelper::IsSubstring(const E& needle, const A& haystack) { } +template +void DynamicAssertionHelper::IsNotSubstring(const E& needle, + const A& haystack) { + std::stringstream ess, ass; + ess << needle; + ass << haystack; + std::string es = ess.str(), as = ass.str(); + if (as.find(es) == std::string::npos) return; + Fail("expected <\"%s\"> to not be a substring of <\"%s\">", + es.c_str(), as.c_str()); +} + + template void DynamicAssertionHelper::LessThan(const E& left, const A& right) { if (left < right) return; @@ -276,6 +292,9 @@ void DynamicAssertionHelper::NotNull(const T p) { #define EXPECT_SUBSTRING(needle, haystack) \ dart::Expect(__FILE__, __LINE__).IsSubstring((needle), (haystack)) +#define EXPECT_NOTSUBSTRING(needle, haystack) \ + dart::Expect(__FILE__, __LINE__).IsNotSubstring((needle), (haystack)) + #define EXPECT_LT(left, right) \ dart::Expect(__FILE__, __LINE__).LessThan((left), (right)) diff --git a/runtime/tests/vm/dart/isolate_mirror_busy_test.dart b/runtime/tests/vm/dart/isolate_mirror_busy_test.dart deleted file mode 100644 index 2aebbdb0df7..00000000000 --- a/runtime/tests/vm/dart/isolate_mirror_busy_test.dart +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2012, 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. -// -// Dart test program for checking implemention of IsolateMirror. - -#library('isolate_mirror_busy_test'); - -#import('dart:isolate'); -#import('dart:mirrors'); - -class BusyIsolate extends Isolate { - void busy() { - // TODO(turnidge): Get rid of this function once we check for - // interrupts on backwards branches. - } - void main() { - while (true) { - busy(); - } - } -} - -void testIsolateMirror(port) { - isolateMirrorOf(port).then((IsolateMirror mirror) { - Expect.isTrue(mirror.debugName.contains("BusyIsolate")); - }); -} - -void main() { - // Test that I can reflect on a busy isolate. - new BusyIsolate().spawn().then(testIsolateMirror); -} diff --git a/runtime/tests/vm/dart/isolate_mirror_idle_test.dart b/runtime/tests/vm/dart/isolate_mirror_idle_test.dart deleted file mode 100644 index 4d6b04dbf09..00000000000 --- a/runtime/tests/vm/dart/isolate_mirror_idle_test.dart +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) 2012, 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. -// -// Dart test program for checking implemention of IsolateMirror. - -#library('isolate_mirror_idle_test'); - -#import('dart:isolate'); -#import('dart:mirrors'); - -class IdleIsolate extends Isolate { - void main() { - // This isolate goes idle waiting for a message which never arrives. - port.receive((message, replyTo) { - print("IdleIsolate received $message"); - Expect.isTrue(false); - }); - } -} - -void testIsolateMirror(port) { - isolateMirrorOf(port).then((IsolateMirror mirror) { - Expect.isTrue(mirror.debugName.contains("IdleIsolate")); - }); -} - -void main() { - // Test that I can reflect on a busy isolate. - new IdleIsolate().spawn().then(testIsolateMirror); -} diff --git a/runtime/tests/vm/dart/isolate_mirror_local_test.dart b/runtime/tests/vm/dart/isolate_mirror_local_test.dart new file mode 100644 index 00000000000..cd54f56c673 --- /dev/null +++ b/runtime/tests/vm/dart/isolate_mirror_local_test.dart @@ -0,0 +1,55 @@ +// Copyright (c) 2012, 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. +// +// Dart test program for checking implemention of IsolateMirror when +// inspecting the current isolate. + +#library('isolate_mirror_local_test'); + +#import('dart:isolate'); +#import('dart:mirrors'); + +ReceivePort rp; +int global_var = 0; + +// This function will be invoked reflectively. +int function(int x) { + global_var = x; + return x + 1; +} + +void testRootLibraryMirror(LibraryMirror lib_mirror) { + Expect.equals('isolate_mirror_local_test', lib_mirror.simpleName); + Expect.isTrue(lib_mirror.url.contains('isolate_mirror_local_test.dart')); + + // Test library invocation. + Expect.equals(0, global_var); + lib_mirror.invoke('function', [ 123 ]).then( + (InstanceMirror retval) { + Expect.equals(123, global_var); + Expect.equals(124, retval.simpleValue); + rp.close(); + }); +} + +void testLibrariesMap(Map libraries) { + // Just look for a couple of well-known libs. + LibraryMirror core_lib = libraries['dart:core']; + Expect.isTrue(core_lib is LibraryMirror); + + LibraryMirror mirror_lib = libraries['dart:mirrors']; + Expect.isTrue(mirror_lib is LibraryMirror); +} + +void testIsolateMirror(IsolateMirror mirror) { + Expect.isTrue(mirror.debugName.contains('main')); + testRootLibraryMirror(mirror.rootLibrary); + testLibrariesMap(mirror.libraries); +} + +void main() { + // Test that an isolate can reflect on itself. + rp = new ReceivePort(); + isolateMirrorOf(rp.toSendPort()).then(testIsolateMirror); +} diff --git a/runtime/tests/vm/dart/isolate_mirror_remote_test.dart b/runtime/tests/vm/dart/isolate_mirror_remote_test.dart new file mode 100644 index 00000000000..05b56922f7b --- /dev/null +++ b/runtime/tests/vm/dart/isolate_mirror_remote_test.dart @@ -0,0 +1,32 @@ +// Copyright (c) 2012, 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. +// +// Dart test program for checking implemention of IsolateMirror when +// inspecting a remote isolate. + +#library('isolate_mirror_local_test'); + +#import('dart:isolate'); +#import('dart:mirrors'); + +void isolateMain() { + port.receive( + (msg, replyPort) { + Expect.fail('Received unexpected message $msg in remote isolate.'); + }); +} + +void testIsolateMirror(IsolateMirror mirror) { + Expect.fail('Should not reach here. Remote isolates not implemented.'); +} + +void main() { + SendPort sp = spawnFunction(isolateMain); + try { + isolateMirrorOf(sp).then(testIsolateMirror); + Expect.fail('Should not reach here. Remote isolates not implemented.'); + } catch (var exception) { + Expect.isTrue(exception is NotImplementedException); + } +} diff --git a/runtime/tests/vm/dart/isolate_mirror_self_test.dart b/runtime/tests/vm/dart/isolate_mirror_self_test.dart deleted file mode 100644 index 18c8b33158b..00000000000 --- a/runtime/tests/vm/dart/isolate_mirror_self_test.dart +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) 2012, 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. -// -// Dart test program for checking implemention of IsolateMirror. - -#library('isolate_mirror_self_test'); - -#import('dart:isolate'); -#import('dart:mirrors'); - -ReceivePort rp; - -void testIsolateMirror(port) { - isolateMirrorOf(port).then((IsolateMirror mirror) { - Expect.isTrue(mirror.debugName.contains("main")); - rp.close(); - }); -} - -void main() { - // Test that I can reflect on myself. - rp = new ReceivePort(); - testIsolateMirror(rp.toSendPort()); -} diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status index c4ebd317df8..bbc440354fd 100644 --- a/runtime/tests/vm/vm.status +++ b/runtime/tests/vm/vm.status @@ -2,9 +2,6 @@ # 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. -# NOTE(turnidge): These tests (and the code they cover) is going away soon. -dart/isolate_mirror*: Skip - # When a spawned isolate throws an uncaught exception, we terminate the vm. cc/RunLoop_ExceptionChild: Fail @@ -16,11 +13,9 @@ cc/IsolateInterrupt: Skip [ $system == windows ] cc/Dart2JSCompileAll: Skip -dart/isolate_mirror_self_test: Skip # TODO(turnidge): Fix this [ $runtime == drt ] dart/import_map_test: Skip -dart/isolate_mirror_self_test: Skip # TODO(turnidge,antonm): investigate [ $compiler == dart2js || $compiler == frog || $compiler == dartc ] dart/import_map_test: Skip # compilers not aware of import maps. diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h index 985e019a99f..332c7e24b33 100644 --- a/runtime/vm/bootstrap_natives.h +++ b/runtime/vm/bootstrap_natives.h @@ -183,8 +183,9 @@ namespace dart { V(isolate_getPortInternal, 0) \ V(isolate_spawnFunction, 1) \ V(isolate_spawnUri, 1) \ - V(Mirrors_processResponse, 3) \ - V(Mirrors_send, 3) \ + V(Mirrors_isLocalPort, 1) \ + V(Mirrors_makeLocalIsolateMirror, 0) \ + V(LocalObjectMirrorImpl_invoke, 3) \ V(GrowableObjectArray_allocate, 2) \ V(GrowableObjectArray_getIndexed, 2) \ V(GrowableObjectArray_setIndexed, 3) \ diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc index f68597def0c..807955a1b73 100644 --- a/runtime/vm/dart_api_impl.cc +++ b/runtime/vm/dart_api_impl.cc @@ -699,6 +699,14 @@ DART_EXPORT Dart_Isolate Dart_CurrentIsolate() { } +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(dart_isolate); @@ -2496,6 +2504,10 @@ DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, const Array& kNoArgNames = Array::Handle(isolate); const Object& obj = Object::Handle(isolate, Api::UnwrapHandle(target)); + if (obj.IsError()) { + return target; + } + if (obj.IsNull() || obj.IsInstance()) { Instance& instance = Instance::Handle(isolate); instance ^= obj.raw(); @@ -2894,20 +2906,35 @@ DART_EXPORT Dart_Handle Dart_CreateNativeWrapperClass(Dart_Handle library, } +DART_EXPORT Dart_Handle Dart_GetNativeInstanceFieldCount(Dart_Handle obj, + int* count) { + Isolate* isolate = Isolate::Current(); + DARTSCOPE(isolate); + const Instance& instance = Api::UnwrapInstanceHandle(isolate, obj); + if (instance.IsNull()) { + RETURN_TYPE_ERROR(isolate, obj, Instance); + } + const Class& cls = Class::Handle(isolate, instance.clazz()); + *count = cls.num_native_fields(); + return Api::Success(isolate); +} + + DART_EXPORT Dart_Handle Dart_GetNativeInstanceField(Dart_Handle obj, int index, intptr_t* value) { Isolate* isolate = Isolate::Current(); DARTSCOPE(isolate); - const Instance& object = Api::UnwrapInstanceHandle(isolate, obj); - if (object.IsNull()) { + const Instance& instance = Api::UnwrapInstanceHandle(isolate, obj); + if (instance.IsNull()) { RETURN_TYPE_ERROR(isolate, obj, Instance); } - if (!object.IsValidNativeIndex(index)) { + if (!instance.IsValidNativeIndex(index)) { return Api::NewError( - "Invalid index passed in to access native instance field"); + "%s: invalid index %d passed in to access native instance field", + CURRENT_FUNC, index); } - *value = object.GetNativeField(index); + *value = instance.GetNativeField(index); return Api::Success(isolate); } @@ -2917,15 +2944,16 @@ DART_EXPORT Dart_Handle Dart_SetNativeInstanceField(Dart_Handle obj, intptr_t value) { Isolate* isolate = Isolate::Current(); DARTSCOPE(isolate); - const Instance& object = Api::UnwrapInstanceHandle(isolate, obj); - if (object.IsNull()) { + const Instance& instance = Api::UnwrapInstanceHandle(isolate, obj); + if (instance.IsNull()) { RETURN_TYPE_ERROR(isolate, obj, Instance); } - if (!object.IsValidNativeIndex(index)) { + if (!instance.IsValidNativeIndex(index)) { return Api::NewError( - "Invalid index passed in to set native instance field"); + "%s: invalid index %d passed in to set native instance field", + CURRENT_FUNC, index); } - object.SetNativeField(index, value); + instance.SetNativeField(index, value); return Api::Success(isolate); } @@ -3193,6 +3221,19 @@ DART_EXPORT Dart_Handle Dart_GetClass(Dart_Handle library, } +DART_EXPORT Dart_Handle Dart_LibraryName(Dart_Handle library) { + Isolate* isolate = Isolate::Current(); + DARTSCOPE(isolate); + const Library& lib = Api::UnwrapLibraryHandle(isolate, library); + if (lib.IsNull()) { + RETURN_TYPE_ERROR(isolate, library, Library); + } + const String& name = String::Handle(isolate, lib.name()); + ASSERT(!name.IsNull()); + return Api::NewHandle(isolate, name.raw()); +} + + DART_EXPORT Dart_Handle Dart_LibraryUrl(Dart_Handle library) { Isolate* isolate = Isolate::Current(); DARTSCOPE(isolate); diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc index 002c2339429..4798bdefdd6 100644 --- a/runtime/vm/dart_api_impl_test.cc +++ b/runtime/vm/dart_api_impl_test.cc @@ -2157,6 +2157,13 @@ UNIT_TEST_CASE(Isolates) { } +TEST_CASE(DebugName) { + Dart_Handle debug_name = Dart_DebugName(); + EXPECT_VALID(debug_name); + EXPECT(Dart_IsString(debug_name)); +} + + static void MyMessageNotifyCallback(Dart_Isolate dest_isolate) { } @@ -2698,7 +2705,10 @@ static void TestNativeFields(Dart_Handle retobj) { const int kNativeFld2 = 2; const int kNativeFld3 = 3; const int kNativeFld4 = 4; + int field_count = 0; intptr_t field_value = 0; + EXPECT_VALID(Dart_GetNativeInstanceFieldCount(retobj, &field_count)); + EXPECT_EQ(4, field_count); result = Dart_GetNativeInstanceField(retobj, kNativeFld4, &field_value); EXPECT(Dart_IsError(result)); result = Dart_GetNativeInstanceField(retobj, kNativeFld0, &field_value); @@ -2775,6 +2785,18 @@ TEST_CASE(NativeFieldAccess) { // Now access and set various instance fields of the returned object. TestNativeFields(retobj); + + // Test that accessing an error handle propagates the error. + Dart_Handle error = Api::NewError("myerror"); + intptr_t field_value = 0; + + result = Dart_GetNativeInstanceField(error, 0, &field_value); + EXPECT(Dart_IsError(result)); + EXPECT_STREQ("myerror", Dart_GetError(result)); + + result = Dart_SetNativeInstanceField(error, 0, 1); + EXPECT(Dart_IsError(result)); + EXPECT_STREQ("myerror", Dart_GetError(result)); } @@ -3300,33 +3322,45 @@ TEST_CASE(Invoke_FunnyArgs) { "test(arg) => 'hello $arg';\n"; Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL); + Dart_Handle func_name = Dart_NewString("test"); Dart_Handle args[1]; const char* str; // Make sure that valid args yield valid results. args[0] = Dart_NewString("!!!"); - Dart_Handle result = Dart_Invoke(lib, Dart_NewString("test"), 1, args); + Dart_Handle result = Dart_Invoke(lib, func_name, 1, args); EXPECT_VALID(result); result = Dart_StringToCString(result, &str); EXPECT_STREQ("hello !!!", str); // Make sure that null is legal. args[0] = Dart_Null(); - result = Dart_Invoke(lib, Dart_NewString("test"), 1, args); + result = Dart_Invoke(lib, func_name, 1, args); EXPECT_VALID(result); result = Dart_StringToCString(result, &str); EXPECT_STREQ("hello null", str); - // Pass a non-instance handle. + // Pass an error handle as the target. The error is propagated. + result = Dart_Invoke(Api::NewError("myerror"), + func_name, 1, args); + EXPECT(Dart_IsError(result)); + EXPECT_STREQ("myerror", Dart_GetError(result)); + + // Pass an error handle as the function name. The error is propagated. + result = Dart_Invoke(lib, Api::NewError("myerror"), 1, args); + EXPECT(Dart_IsError(result)); + EXPECT_STREQ("myerror", Dart_GetError(result)); + + // Pass a non-instance handle as a parameter.. args[0] = lib; - result = Dart_Invoke(lib, Dart_NewString("test"), 1, args); + result = Dart_Invoke(lib, func_name, 1, args); EXPECT(Dart_IsError(result)); EXPECT_STREQ("Dart_Invoke expects argument 0 to be an instance of Object.", Dart_GetError(result)); - // Pass an error handle. The error is contagious. + // Pass an error handle as a parameter. The error is propagated. args[0] = Api::NewError("myerror"); - result = Dart_Invoke(lib, Dart_NewString("test"), 1, args); + result = Dart_Invoke(lib, func_name, 1, args); EXPECT(Dart_IsError(result)); EXPECT_STREQ("myerror", Dart_GetError(result)); } @@ -3750,6 +3784,31 @@ TEST_CASE(LoadScript) { } +TEST_CASE(RootLibrary) { + const char* kScriptChars = + "main() {" + " return 12345;" + "}"; + + Dart_Handle root_lib = Dart_RootLibrary(); + EXPECT_VALID(root_lib); + EXPECT(Dart_IsNull(root_lib)); + + // Load a script. + Dart_Handle url = Dart_NewString(TestCase::url()); + Dart_Handle source = Dart_NewString(kScriptChars); + EXPECT_VALID(Dart_LoadScript(url, source)); + + root_lib = Dart_RootLibrary(); + Dart_Handle lib_name = Dart_LibraryName(root_lib); + EXPECT_VALID(lib_name); + EXPECT(!Dart_IsNull(root_lib)); + const char* name_cstr = ""; + EXPECT_VALID(Dart_StringToCString(lib_name, &name_cstr)); + EXPECT_STREQ(TestCase::url(), name_cstr); +} + + static const char* var_mapping[] = { "GOOGLE3", ".", "ABC", "lala", @@ -3919,6 +3978,39 @@ TEST_CASE(LookupLibrary) { } +TEST_CASE(LibraryName) { + const char* kLibrary1Chars = + "#library('library1_name');"; + Dart_Handle url = Dart_NewString("library1_url"); + Dart_Handle source = Dart_NewString(kLibrary1Chars); + Dart_Handle lib = Dart_LoadLibrary(url, source); + Dart_Handle error = Dart_Error("incoming error"); + EXPECT_VALID(lib); + + Dart_Handle result = Dart_LibraryName(Dart_Null()); + EXPECT(Dart_IsError(result)); + EXPECT_STREQ("Dart_LibraryName expects argument 'library' to be non-null.", + Dart_GetError(result)); + + result = Dart_LibraryName(Dart_True()); + EXPECT(Dart_IsError(result)); + EXPECT_STREQ( + "Dart_LibraryName expects argument 'library' to be of type Library.", + Dart_GetError(result)); + + result = Dart_LibraryName(error); + EXPECT(Dart_IsError(result)); + EXPECT_STREQ("incoming error", Dart_GetError(result)); + + result = Dart_LibraryName(lib); + EXPECT_VALID(result); + EXPECT(Dart_IsString(result)); + const char* cstr = NULL; + EXPECT_VALID(Dart_StringToCString(result, &cstr)); + EXPECT_STREQ("library1_name", cstr); +} + + TEST_CASE(LibraryUrl) { const char* kLibrary1Chars = "#library('library1_name');"; diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h index dae66d3cc2c..fef2395db46 100644 --- a/runtime/vm/dart_entry.h +++ b/runtime/vm/dart_entry.h @@ -90,7 +90,7 @@ class DartLibraryCalls : public AllStatic { // Gets the _id field of a SendPort/ReceivePort. // - // Returns null on success, a RawError on failure. + // Returns the value of _id on success, a RawError on failure. static RawObject* PortGetId(const Instance& port); }; diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc index 46c0f2ea6ce..1c2a00d562b 100644 --- a/runtime/vm/debugger_api_impl_test.cc +++ b/runtime/vm/debugger_api_impl_test.cc @@ -975,6 +975,36 @@ TEST_CASE(Debug_LookupSourceLine) { EXPECT_STREQ(kScriptChars, source_chars); } + +TEST_CASE(GetLibraryURLs) { + const char* kScriptChars = + "main() {" + " return 12345;" + "}"; + + Dart_Handle lib_list = Dart_GetLibraryURLs(); + EXPECT_VALID(lib_list); + EXPECT(Dart_IsList(lib_list)); + Dart_Handle list_as_string = Dart_ToString(lib_list); + const char* list_cstr = ""; + EXPECT_VALID(Dart_StringToCString(list_as_string, &list_cstr)); + EXPECT_NOTSUBSTRING(TestCase::url(), list_cstr); + + // Load a script. + Dart_Handle url = Dart_NewString(TestCase::url()); + Dart_Handle source = Dart_NewString(kScriptChars); + EXPECT_VALID(Dart_LoadScript(url, source)); + + lib_list = Dart_GetLibraryURLs(); + EXPECT_VALID(lib_list); + EXPECT(Dart_IsList(lib_list)); + list_as_string = Dart_ToString(lib_list); + list_cstr = ""; + EXPECT_VALID(Dart_StringToCString(list_as_string, &list_cstr)); + EXPECT_SUBSTRING(TestCase::url(), list_cstr); +} + + #endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64). } // namespace dart diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc index ce70a9a5c4f..0c5a0d3b970 100644 --- a/runtime/vm/isolate.cc +++ b/runtime/vm/isolate.cc @@ -46,6 +46,8 @@ class IsolateMessageHandler : public MessageHandler { // Check that it is safe to access this handler. void CheckAccess(); #endif + bool IsCurrentIsolate() const; + private: Isolate* isolate_; }; @@ -120,11 +122,16 @@ bool IsolateMessageHandler::HandleMessage(Message* message) { #if defined(DEBUG) void IsolateMessageHandler::CheckAccess() { - ASSERT(isolate_ == Isolate::Current()); + ASSERT(IsCurrentIsolate()); } #endif +bool IsolateMessageHandler::IsCurrentIsolate() const { + return (isolate_ == Isolate::Current()); +} + + #if defined(DEBUG) // static void BaseIsolate::AssertCurrent(BaseIsolate* isolate) { diff --git a/runtime/vm/message_handler.h b/runtime/vm/message_handler.h index acbca5b27ec..e7f1a45218f 100644 --- a/runtime/vm/message_handler.h +++ b/runtime/vm/message_handler.h @@ -69,6 +69,9 @@ class MessageHandler { // ------------ START PortMap API ------------ // These functions should only be called from the PortMap. + // Does this message handler correspond to the current isolate? + virtual bool IsCurrentIsolate() const { return false; } + // Posts a message on this handler's message queue. void PostMessage(Message* message); diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc index 5420ed216d5..c55f6525283 100644 --- a/runtime/vm/object.cc +++ b/runtime/vm/object.cc @@ -5434,6 +5434,9 @@ void Library::InitMirrorsLibrary(Isolate* isolate) { lib.Register(); const Library& isolate_lib = Library::Handle(Library::IsolateLibrary()); lib.AddImport(isolate_lib); + const Library& wrappers_lib = + Library::Handle(Library::NativeWrappersLibrary()); + lib.AddImport(wrappers_lib); isolate->object_store()->set_mirrors_library(lib); } diff --git a/runtime/vm/port.cc b/runtime/vm/port.cc index 5bcc6bcc78b..b86684e9ecf 100644 --- a/runtime/vm/port.cc +++ b/runtime/vm/port.cc @@ -217,6 +217,19 @@ bool PortMap::PostMessage(Message* message) { } +bool PortMap::IsLocalPort(Dart_Port id) { + MutexLocker ml(mutex_); + intptr_t index = FindPort(id); + if (index < 0) { + // Port does not exist. + return false; + } + + MessageHandler* handler = map_[index].handler; + return handler->IsCurrentIsolate(); +} + + void PortMap::InitOnce() { mutex_ = new Mutex(); diff --git a/runtime/vm/port.h b/runtime/vm/port.h index be777bdf155..cb3abe81c16 100644 --- a/runtime/vm/port.h +++ b/runtime/vm/port.h @@ -40,6 +40,9 @@ class PortMap: public AllStatic { // Claims ownership of 'message'. static bool PostMessage(Message* message); + // Returns whether a port is local to the current isolate. + static bool IsLocalPort(Dart_Port id); + static void InitOnce(); private: