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: