| Index: runtime/bin/vmservice_impl.cc
|
| diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
|
| index 9e738cdfe883e783fea8ac8d966ababec00cf923..b35c67e00ed72a974a17a9be38bdfd6fb11efb87 100644
|
| --- a/runtime/bin/vmservice_impl.cc
|
| +++ b/runtime/bin/vmservice_impl.cc
|
| @@ -9,25 +9,11 @@
|
| #include "bin/builtin.h"
|
| #include "bin/dartutils.h"
|
| #include "bin/isolate_data.h"
|
| -#include "bin/resources.h"
|
| #include "bin/thread.h"
|
|
|
| -#include "vm/dart_api_impl.h"
|
| -#include "vm/dart_entry.h"
|
| -#include "vm/isolate.h"
|
| -#include "vm/message.h"
|
| -#include "vm/native_entry.h"
|
| -#include "vm/native_arguments.h"
|
| -#include "vm/object.h"
|
| -#include "vm/port.h"
|
| -#include "vm/snapshot.h"
|
| -
|
| namespace dart {
|
| namespace bin {
|
|
|
| -// snapshot_buffer points to a snapshot if we link in a snapshot otherwise
|
| -// it is initialized to NULL.
|
| -extern const uint8_t* snapshot_buffer;
|
| #define RETURN_ERROR_HANDLE(handle) \
|
| if (Dart_IsError(handle)) { \
|
| return handle; \
|
| @@ -41,143 +27,110 @@ extern const uint8_t* snapshot_buffer;
|
| return false; \
|
| }
|
|
|
| -#define kLibraryResourceNamePrefix "/vmservice"
|
| -static const char* kVMServiceIOLibraryScriptResourceName =
|
| - kLibraryResourceNamePrefix "/vmservice_io.dart";
|
| -static const char* kVMServiceLibraryName =
|
| - kLibraryResourceNamePrefix "/vmservice.dart";
|
| -
|
| +#define kLibrarySourceNamePrefix "/vmservice"
|
| +static const char* kVMServiceIOLibraryScriptResourceName = "vmservice_io.dart";
|
| #define kClientResourceNamePrefix "/vmservice/client/deployed/web"
|
|
|
| -Dart_Isolate VmService::isolate_ = NULL;
|
| -Dart_Port VmService::port_ = ILLEGAL_PORT;
|
| -dart::Monitor* VmService::monitor_ = NULL;
|
| -const char* VmService::error_msg_ = NULL;
|
| +struct ResourcesEntry {
|
| + const char* path_;
|
| + const char* resource_;
|
| + int length_;
|
| +};
|
|
|
| -// These must be kept in sync with vmservice/constants.dart
|
| -#define VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID 1
|
| -#define VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID 2
|
| +extern ResourcesEntry __service_bin_resources_[];
|
| +
|
| +class Resources {
|
| + public:
|
| + static const int kNoSuchInstance = -1;
|
| + static int ResourceLookup(const char* path, const char** resource) {
|
| + ResourcesEntry* table = ResourcesTable();
|
| + for (int i = 0; table[i].path_ != NULL; i++) {
|
| + const ResourcesEntry& entry = table[i];
|
| + if (strcmp(path, entry.path_) == 0) {
|
| + *resource = entry.resource_;
|
| + ASSERT(entry.length_ > 0);
|
| + return entry.length_;
|
| + }
|
| + }
|
| + return kNoSuchInstance;
|
| + }
|
|
|
| + static const char* Path(int idx) {
|
| + ASSERT(idx >= 0);
|
| + ResourcesEntry* entry = At(idx);
|
| + if (entry == NULL) {
|
| + return NULL;
|
| + }
|
| + ASSERT(entry->path_ != NULL);
|
| + return entry->path_;
|
| + }
|
| +
|
| + private:
|
| + static ResourcesEntry* At(int idx) {
|
| + ASSERT(idx >= 0);
|
| + ResourcesEntry* table = ResourcesTable();
|
| + for (int i = 0; table[i].path_ != NULL; i++) {
|
| + if (idx == i) {
|
| + return &table[i];
|
| + }
|
| + }
|
| + return NULL;
|
| + }
|
| + static ResourcesEntry* ResourcesTable() {
|
| + return &__service_bin_resources_[0];
|
| + }
|
|
|
| -static Dart_NativeFunction VmServiceNativeResolver(Dart_Handle name,
|
| - int num_arguments,
|
| - bool* auto_setup_scope);
|
| + DISALLOW_ALLOCATION();
|
| + DISALLOW_IMPLICIT_CONSTRUCTORS(Resources);
|
| +};
|
|
|
| +const char* VmService::error_msg_ = NULL;
|
|
|
| bool VmService::Start(intptr_t server_port) {
|
| - monitor_ = new dart::Monitor();
|
| - ASSERT(monitor_ != NULL);
|
| - error_msg_ = NULL;
|
| -
|
| -
|
| - {
|
| - // Take lock before spawning new thread.
|
| - MonitorLocker ml(monitor_);
|
| - // Spawn new thread.
|
| - dart::Thread::Start(ThreadMain, server_port);
|
| - // Wait until service is running on spawned thread.
|
| - ml.Wait();
|
| + bool r = _Start(server_port);
|
| + if (!r) {
|
| + return r;
|
| }
|
| - return port_ != ILLEGAL_PORT;
|
| + // Start processing messages in a new thread.
|
| + dart::Thread::Start(ThreadMain, NULL);
|
| + return true;
|
| }
|
|
|
|
|
| bool VmService::_Start(intptr_t server_port) {
|
| - ASSERT(isolate_ == NULL);
|
| - char* error = NULL;
|
| - const char* script_uri = "vmservice:";
|
| - IsolateData* isolate_data = new IsolateData(script_uri);
|
| - isolate_ = Dart_CreateIsolate(script_uri, "main", snapshot_buffer,
|
| - isolate_data,
|
| - &error);
|
| - if (isolate_ == NULL) {
|
| - error_msg_ = error;
|
| + ASSERT(Dart_CurrentIsolate() == NULL);
|
| + Dart_Isolate isolate = Dart_GetServiceIsolate(NULL);
|
| + if (isolate == NULL) {
|
| + error_msg_ = "Internal error.";
|
| return false;
|
| }
|
| -
|
| + Dart_EnterIsolate(isolate);
|
| Dart_EnterScope();
|
| -
|
| - if (snapshot_buffer != NULL) {
|
| - // Setup the native resolver as the snapshot does not carry it.
|
| - Builtin::SetNativeResolver(Builtin::kBuiltinLibrary);
|
| - Builtin::SetNativeResolver(Builtin::kIOLibrary);
|
| - }
|
| -
|
| - // Set up the library tag handler for this isolate.
|
| - Dart_Handle result = Dart_SetLibraryTagHandler(LibraryTagHandler);
|
| - SHUTDOWN_ON_ERROR(result);
|
| -
|
| - // Load the specified application script into the newly created isolate.
|
| -
|
| - // Prepare builtin and its dependent libraries for use to resolve URIs.
|
| - // The builtin library is part of the core snapshot and would already be
|
| - // available here in the case of script snapshot loading.
|
| - Dart_Handle builtin_lib =
|
| - Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
|
| - SHUTDOWN_ON_ERROR(builtin_lib);
|
| -
|
| - // Prepare for script loading by setting up the 'print' and 'timer'
|
| - // closures and setting up 'package root' for URI resolution.
|
| - result = DartUtils::PrepareForScriptLoading("", builtin_lib);
|
| - SHUTDOWN_ON_ERROR(result);
|
| -
|
| - {
|
| - // Load source into service isolate.
|
| - Dart_Handle library = LoadScript(kVMServiceIOLibraryScriptResourceName);
|
| - SHUTDOWN_ON_ERROR(library);
|
| - }
|
| -
|
| - // Make the isolate runnable so that it is ready to handle messages.
|
| + // Install our own library tag handler.
|
| + Dart_SetLibraryTagHandler(LibraryTagHandler);
|
| + Dart_Handle result;
|
| + Dart_Handle library = LoadScript(kVMServiceIOLibraryScriptResourceName);
|
| + // Expect a library.
|
| + ASSERT(library != Dart_Null());
|
| + SHUTDOWN_ON_ERROR(library);
|
| Dart_ExitScope();
|
| Dart_ExitIsolate();
|
| -
|
| - bool retval = Dart_IsolateMakeRunnable(isolate_);
|
| + bool retval = Dart_IsolateMakeRunnable(isolate);
|
| if (!retval) {
|
| - Dart_EnterIsolate(isolate_);
|
| + Dart_EnterIsolate(isolate);
|
| Dart_ShutdownIsolate();
|
| error_msg_ = "Invalid isolate state - Unable to make it runnable.";
|
| return false;
|
| }
|
|
|
| - Dart_EnterIsolate(isolate_);
|
| + Dart_EnterIsolate(isolate);
|
| Dart_EnterScope();
|
| -
|
| -
|
| - Dart_Handle library = Dart_RootLibrary();
|
| + library = Dart_RootLibrary();
|
| // Set requested TCP port.
|
| DartUtils::SetIntegerField(library, "_port", server_port);
|
| result = Dart_Invoke(library, DartUtils::NewString("main"), 0, NULL);
|
| SHUTDOWN_ON_ERROR(result);
|
| -
|
| - // Retrieve the ReceivePort that the service is waiting on. The _receivePort
|
| - // variable is setup in the call to main.
|
| - Dart_Handle receivePort = Dart_GetField(library,
|
| - DartUtils::NewString("_receivePort"));
|
| - SHUTDOWN_ON_ERROR(receivePort);
|
| -
|
| - {
|
| - // Extract the Dart_Port from the receive port.
|
| - HANDLESCOPE(Isolate::Current());
|
| - const Object& unwrapped_rp = Object::Handle(Api::UnwrapHandle(receivePort));
|
| - const Instance& rp = Instance::Cast(unwrapped_rp);
|
| - // Extract ReceivePort port id.
|
| - const Object& rp_id_obj = Object::Handle(DartLibraryCalls::PortGetId(rp));
|
| - if (rp_id_obj.IsError()) {
|
| - const Error& error = Error::Cast(rp_id_obj);
|
| - error_msg_ = strdup(error.ToErrorCString());
|
| - Dart_ExitScope();
|
| - Dart_ShutdownIsolate();
|
| - return false;
|
| - }
|
| - ASSERT(rp_id_obj.IsSmi() || rp_id_obj.IsMint());
|
| - Integer& id = Integer::Handle();
|
| - id ^= rp_id_obj.raw();
|
| - port_ = static_cast<Dart_Port>(id.AsInt64Value());
|
| - }
|
| -
|
| - Dart_Handle library_name = Dart_NewStringFromCString(kVMServiceLibraryName);
|
| - library = Dart_LookupLibrary(library_name);
|
| - SHUTDOWN_ON_ERROR(library);
|
| + // Load resources.
|
| result = LoadResources(library);
|
| SHUTDOWN_ON_ERROR(result);
|
|
|
| @@ -188,36 +141,24 @@ bool VmService::_Start(intptr_t server_port) {
|
| }
|
|
|
|
|
| -void VmService::_Stop() {
|
| - port_ = ILLEGAL_PORT;
|
| -}
|
| -
|
| -
|
| const char* VmService::GetErrorMessage() {
|
| return error_msg_ == NULL ? "No error." : error_msg_;
|
| }
|
|
|
|
|
| -Dart_Port VmService::port() {
|
| - return port_;
|
| -}
|
| -
|
| -
|
| -bool VmService::IsRunning() {
|
| - return port_ != ILLEGAL_PORT;
|
| -}
|
| -
|
| -
|
| Dart_Handle VmService::GetSource(const char* name) {
|
| + const intptr_t kBufferSize = 512;
|
| + char buffer[kBufferSize];
|
| + snprintf(&buffer[0], kBufferSize-1, "%s/%s", kLibrarySourceNamePrefix, name);
|
| const char* vmservice_source = NULL;
|
| - int r = Resources::ResourceLookup(name, &vmservice_source);
|
| + int r = Resources::ResourceLookup(buffer, &vmservice_source);
|
| ASSERT(r != Resources::kNoSuchInstance);
|
| return Dart_NewStringFromCString(vmservice_source);
|
| }
|
|
|
|
|
| Dart_Handle VmService::LoadScript(const char* name) {
|
| - Dart_Handle url = Dart_NewStringFromCString(name);
|
| + Dart_Handle url = Dart_NewStringFromCString("dart:vmservice_io");
|
| Dart_Handle source = GetSource(name);
|
| return Dart_LoadScript(url, source, 0, 0);
|
| }
|
| @@ -230,18 +171,6 @@ Dart_Handle VmService::LoadSource(Dart_Handle library, const char* name) {
|
| }
|
|
|
|
|
| -Dart_Handle VmService::LoadSources(Dart_Handle library, const char* names[]) {
|
| - Dart_Handle result = Dart_Null();
|
| - for (int i = 0; names[i] != NULL; i++) {
|
| - result = LoadSource(library, names[i]);
|
| - if (Dart_IsError(result)) {
|
| - break;
|
| - }
|
| - }
|
| - return result;
|
| -}
|
| -
|
| -
|
| Dart_Handle VmService::LoadResource(Dart_Handle library,
|
| const char* resource_name,
|
| const char* prefix) {
|
| @@ -285,8 +214,8 @@ Dart_Handle VmService::LoadResource(Dart_Handle library,
|
| Dart_Handle VmService::LoadResources(Dart_Handle library) {
|
| Dart_Handle result = Dart_Null();
|
| intptr_t prefixLen = strlen(kClientResourceNamePrefix);
|
| - for (intptr_t i = 0; i < Resources::get_resource_count(); i++) {
|
| - const char* path = Resources::get_resource_path(i);
|
| + for (intptr_t i = 0; Resources::Path(i) != NULL; i++) {
|
| + const char* path = Resources::Path(i);
|
| if (!strncmp(path, kClientResourceNamePrefix, prefixLen)) {
|
| result = LoadResource(library, path, kClientResourceNamePrefix);
|
| if (Dart_IsError(result)) {
|
| @@ -298,19 +227,6 @@ Dart_Handle VmService::LoadResources(Dart_Handle library) {
|
| }
|
|
|
|
|
| -static bool IsVMServiceURL(const char* url) {
|
| - static const intptr_t kLibraryResourceNamePrefixLen =
|
| - strlen(kLibraryResourceNamePrefix);
|
| - return 0 == strncmp(kLibraryResourceNamePrefix, url,
|
| - kLibraryResourceNamePrefixLen);
|
| -}
|
| -
|
| -
|
| -static bool IsVMServiceLibrary(const char* url) {
|
| - return 0 == strcmp(kVMServiceLibraryName, url);
|
| -}
|
| -
|
| -
|
| Dart_Handle VmService::LibraryTagHandler(Dart_LibraryTag tag,
|
| Dart_Handle library,
|
| Dart_Handle url) {
|
| @@ -331,224 +247,37 @@ Dart_Handle VmService::LibraryTagHandler(Dart_LibraryTag tag,
|
| if (Dart_IsError(result)) {
|
| return result;
|
| }
|
| - bool is_vm_service_url = IsVMServiceURL(url_string);
|
| - if (!is_vm_service_url) {
|
| - // Pass to DartUtils.
|
| + if (tag == Dart_kImportTag) {
|
| + // Embedder handles all requests for external libraries.
|
| return DartUtils::LibraryTagHandler(tag, library, url);
|
| }
|
| - switch (tag) {
|
| - case Dart_kCanonicalizeUrl:
|
| - // The URL is already canonicalized.
|
| - return url;
|
| - break;
|
| - case Dart_kImportTag: {
|
| - Dart_Handle source = GetSource(url_string);
|
| - if (Dart_IsError(source)) {
|
| - return source;
|
| - }
|
| - Dart_Handle lib = Dart_LoadLibrary(url, source);
|
| - if (Dart_IsError(lib)) {
|
| - return lib;
|
| - }
|
| - if (IsVMServiceLibrary(url_string)) {
|
| - // Install native resolver for this library.
|
| - result = Dart_SetNativeResolver(lib, VmServiceNativeResolver);
|
| - if (Dart_IsError(result)) {
|
| - return result;
|
| - }
|
| - }
|
| - return lib;
|
| - }
|
| - break;
|
| - case Dart_kSourceTag: {
|
| - Dart_Handle source = GetSource(url_string);
|
| - if (Dart_IsError(source)) {
|
| - return source;
|
| - }
|
| - return Dart_LoadSource(library, url, source);
|
| - }
|
| - break;
|
| - default:
|
| - UNIMPLEMENTED();
|
| - break;
|
| + ASSERT((tag == Dart_kSourceTag) || (tag == Dart_kCanonicalizeUrl));
|
| + if (tag == Dart_kCanonicalizeUrl) {
|
| + // url is already canonicalized.
|
| + return url;
|
| }
|
| - UNREACHABLE();
|
| - return result;
|
| + Dart_Handle source = GetSource(url_string);
|
| + if (Dart_IsError(source)) {
|
| + return source;
|
| + }
|
| + return Dart_LoadSource(library, url, source);
|
| }
|
|
|
|
|
| void VmService::ThreadMain(uword parameters) {
|
| ASSERT(Dart_CurrentIsolate() == NULL);
|
| - ASSERT(isolate_ == NULL);
|
| -
|
| - intptr_t server_port = static_cast<intptr_t>(parameters);
|
| - ASSERT(server_port >= 0);
|
| -
|
| - // Lock scope.
|
| - {
|
| - MonitorLocker ml(monitor_);
|
| - bool r = _Start(server_port);
|
| - if (!r) {
|
| - port_ = ILLEGAL_PORT;
|
| - monitor_->Notify();
|
| - return;
|
| - }
|
| -
|
| - Dart_EnterIsolate(isolate_);
|
| - Dart_EnterScope();
|
| -
|
| - Dart_Handle receievePort = Dart_GetReceivePort(port_);
|
| - ASSERT(!Dart_IsError(receievePort));
|
| - monitor_->Notify();
|
| - }
|
| -
|
| - // Keep handling messages until the last active receive port is closed.
|
| + Dart_Isolate service_isolate = Dart_GetServiceIsolate(NULL);
|
| + Dart_EnterIsolate(service_isolate);
|
| + Dart_EnterScope();
|
| Dart_Handle result = Dart_RunLoop();
|
| if (Dart_IsError(result)) {
|
| - printf("VmService has exited with an error:\n%s\n", Dart_GetError(result));
|
| + printf("Service exited with an error:\n%s\n", Dart_GetError(result));
|
| }
|
| -
|
| - _Stop();
|
| -
|
| Dart_ExitScope();
|
| Dart_ExitIsolate();
|
| }
|
|
|
|
|
| -static Dart_Handle MakeServiceControlMessage(Dart_Port port_id, intptr_t code,
|
| - Dart_Handle name) {
|
| - Dart_Handle result;
|
| - Dart_Handle list = Dart_NewList(4);
|
| - ASSERT(!Dart_IsError(list));
|
| - Dart_Handle code_handle = Dart_NewInteger(code);
|
| - ASSERT(!Dart_IsError(code_handle));
|
| - result = Dart_ListSetAt(list, 0, code_handle);
|
| - ASSERT(!Dart_IsError(result));
|
| - Dart_Handle port_id_handle = Dart_NewInteger(port_id);
|
| - ASSERT(!Dart_IsError(port_id_handle));
|
| - result = Dart_ListSetAt(list, 1, port_id_handle);
|
| - ASSERT(!Dart_IsError(result));
|
| - Dart_Handle sendPort = Dart_NewSendPort(port_id);
|
| - ASSERT(!Dart_IsError(sendPort));
|
| - result = Dart_ListSetAt(list, 2, sendPort);
|
| - ASSERT(!Dart_IsError(result));
|
| - result = Dart_ListSetAt(list, 3, name);
|
| - ASSERT(!Dart_IsError(result));
|
| - return list;
|
| -}
|
| -
|
| -
|
| -bool VmService::SendIsolateStartupMessage() {
|
| - if (!IsRunning()) {
|
| - return false;
|
| - }
|
| - Isolate* isolate = Isolate::Current();
|
| - ASSERT(isolate != NULL);
|
| - HANDLESCOPE(isolate);
|
| - Dart_Handle name = Api::NewHandle(isolate, String::New(isolate->name()));
|
| - ASSERT(!Dart_IsError(name));
|
| - Dart_Handle list =
|
| - MakeServiceControlMessage(Dart_GetMainPortId(),
|
| - VM_SERVICE_ISOLATE_STARTUP_MESSAGE_ID,
|
| - name);
|
| - ASSERT(!Dart_IsError(list));
|
| - return Dart_Post(port_, list);
|
| -}
|
| -
|
| -
|
| -bool VmService::SendIsolateShutdownMessage() {
|
| - if (!IsRunning()) {
|
| - return false;
|
| - }
|
| - Isolate* isolate = Isolate::Current();
|
| - ASSERT(isolate != NULL);
|
| - HANDLESCOPE(isolate);
|
| - Dart_Handle list =
|
| - MakeServiceControlMessage(Dart_GetMainPortId(),
|
| - VM_SERVICE_ISOLATE_SHUTDOWN_MESSAGE_ID,
|
| - Dart_Null());
|
| - ASSERT(!Dart_IsError(list));
|
| - return Dart_Post(port_, list);
|
| -}
|
| -
|
| -
|
| -void VmService::VmServiceShutdownCallback(void* callback_data) {
|
| - ASSERT(Dart_CurrentIsolate() != NULL);
|
| - Dart_EnterScope();
|
| - VmService::SendIsolateShutdownMessage();
|
| - Dart_ExitScope();
|
| -}
|
| -
|
| -
|
| -static uint8_t* allocator(uint8_t* ptr, intptr_t old_size, intptr_t new_size) {
|
| - void* new_ptr = realloc(reinterpret_cast<void*>(ptr), new_size);
|
| - return reinterpret_cast<uint8_t*>(new_ptr);
|
| -}
|
| -
|
| -
|
| -static void SendServiceMessage(Dart_NativeArguments args) {
|
| - NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
|
| - Isolate* isolate = arguments->isolate();
|
| - StackZone zone(isolate);
|
| - HANDLESCOPE(isolate);
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Instance, sp, arguments->NativeArgAt(0));
|
| - GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(1));
|
| -
|
| - // Extract SendPort port id.
|
| - const Object& sp_id_obj = Object::Handle(DartLibraryCalls::PortGetId(sp));
|
| - if (sp_id_obj.IsError()) {
|
| - Exceptions::PropagateError(Error::Cast(sp_id_obj));
|
| - }
|
| - Integer& id = Integer::Handle();
|
| - id ^= sp_id_obj.raw();
|
| - Dart_Port sp_id = static_cast<Dart_Port>(id.AsInt64Value());
|
| - ASSERT(sp_id != ILLEGAL_PORT);
|
| -
|
| - // Serialize message.
|
| - uint8_t* data = NULL;
|
| - MessageWriter writer(&data, &allocator);
|
| - writer.WriteMessage(message);
|
| -
|
| - // TODO(turnidge): Throw an exception when the return value is false?
|
| - PortMap::PostMessage(new Message(sp_id, data, writer.BytesWritten(),
|
| - Message::kOOBPriority));
|
| -}
|
| -
|
| -
|
| -struct VmServiceNativeEntry {
|
| - const char* name;
|
| - int num_arguments;
|
| - Dart_NativeFunction function;
|
| -};
|
| -
|
| -
|
| -static VmServiceNativeEntry _VmServiceNativeEntries[] = {
|
| - {"VMService_SendServiceMessage", 2, SendServiceMessage}
|
| -};
|
| -
|
| -
|
| -static Dart_NativeFunction VmServiceNativeResolver(Dart_Handle name,
|
| - int num_arguments,
|
| - bool* auto_setup_scope) {
|
| - const Object& obj = Object::Handle(Api::UnwrapHandle(name));
|
| - if (!obj.IsString()) {
|
| - return NULL;
|
| - }
|
| - const char* function_name = obj.ToCString();
|
| - ASSERT(function_name != NULL);
|
| - ASSERT(auto_setup_scope != NULL);
|
| - *auto_setup_scope = true;
|
| - intptr_t n =
|
| - sizeof(_VmServiceNativeEntries) / sizeof(_VmServiceNativeEntries[0]);
|
| - for (intptr_t i = 0; i < n; i++) {
|
| - VmServiceNativeEntry entry = _VmServiceNativeEntries[i];
|
| - if (!strcmp(function_name, entry.name) &&
|
| - (num_arguments == entry.num_arguments)) {
|
| - return entry.function;
|
| - }
|
| - }
|
| - return NULL;
|
| -}
|
|
|
| } // namespace bin
|
| } // namespace dart
|
|
|