65bab52df5
- Add back Message.fromUri constructor. - Fix 'root' isolateId alias. - FATAL on missing source files when starting up the service isolate. Review URL: https://codereview.chromium.org//922163005 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@43814 260f80e4-7a28-3924-810f-c04153c831b5
386 lines
12 KiB
C++
386 lines
12 KiB
C++
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
#include "bin/vmservice_impl.h"
|
|
|
|
#include "include/dart_api.h"
|
|
|
|
#include "bin/builtin.h"
|
|
#include "bin/dartutils.h"
|
|
#include "bin/isolate_data.h"
|
|
#include "bin/platform.h"
|
|
#include "bin/thread.h"
|
|
#include "bin/utils.h"
|
|
#include "platform/json.h"
|
|
|
|
namespace dart {
|
|
namespace bin {
|
|
|
|
#define RETURN_ERROR_HANDLE(handle) \
|
|
if (Dart_IsError(handle)) { \
|
|
return handle; \
|
|
}
|
|
|
|
#define SHUTDOWN_ON_ERROR(handle) \
|
|
if (Dart_IsError(handle)) { \
|
|
error_msg_ = strdup(Dart_GetError(handle)); \
|
|
Dart_ExitScope(); \
|
|
Dart_ShutdownIsolate(); \
|
|
return false; \
|
|
}
|
|
|
|
#define kLibrarySourceNamePrefix "/vmservice"
|
|
static const char* kVMServiceIOLibraryScriptResourceName = "vmservice_io.dart";
|
|
|
|
struct ResourcesEntry {
|
|
const char* path_;
|
|
const char* resource_;
|
|
int length_;
|
|
};
|
|
|
|
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];
|
|
}
|
|
|
|
DISALLOW_ALLOCATION();
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(Resources);
|
|
};
|
|
|
|
|
|
void TriggerResourceLoad(Dart_NativeArguments args) {
|
|
Dart_Handle library = Dart_RootLibrary();
|
|
ASSERT(!Dart_IsError(library));
|
|
Dart_Handle result = VmService::LoadResources(library);
|
|
ASSERT(!Dart_IsError(result));
|
|
}
|
|
|
|
|
|
void NotifyServerState(Dart_NativeArguments args) {
|
|
Dart_EnterScope();
|
|
const char* ip_chars;
|
|
Dart_Handle ip_arg = Dart_GetNativeArgument(args, 0);
|
|
if (Dart_IsError(ip_arg)) {
|
|
VmService::SetServerIPAndPort("", 0);
|
|
Dart_ExitScope();
|
|
return;
|
|
}
|
|
Dart_Handle result = Dart_StringToCString(ip_arg, &ip_chars);
|
|
if (Dart_IsError(result)) {
|
|
VmService::SetServerIPAndPort("", 0);
|
|
Dart_ExitScope();
|
|
return;
|
|
}
|
|
Dart_Handle port_arg = Dart_GetNativeArgument(args, 1);
|
|
if (Dart_IsError(port_arg)) {
|
|
VmService::SetServerIPAndPort("", 0);
|
|
Dart_ExitScope();
|
|
return;
|
|
}
|
|
int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
|
|
VmService::SetServerIPAndPort(ip_chars, port);
|
|
Dart_ExitScope();
|
|
}
|
|
|
|
struct VmServiceIONativeEntry {
|
|
const char* name;
|
|
int num_arguments;
|
|
Dart_NativeFunction function;
|
|
};
|
|
|
|
|
|
static VmServiceIONativeEntry _VmServiceIONativeEntries[] = {
|
|
{"VMServiceIO_TriggerResourceLoad", 0, TriggerResourceLoad},
|
|
{"VMServiceIO_NotifyServerState", 2, NotifyServerState},
|
|
};
|
|
|
|
|
|
static Dart_NativeFunction VmServiceIONativeResolver(Dart_Handle name,
|
|
int num_arguments,
|
|
bool* auto_setup_scope) {
|
|
const char* function_name = NULL;
|
|
Dart_Handle result = Dart_StringToCString(name, &function_name);
|
|
ASSERT(!Dart_IsError(result));
|
|
ASSERT(function_name != NULL);
|
|
*auto_setup_scope = true;
|
|
intptr_t n =
|
|
sizeof(_VmServiceIONativeEntries) / sizeof(_VmServiceIONativeEntries[0]);
|
|
for (intptr_t i = 0; i < n; i++) {
|
|
VmServiceIONativeEntry entry = _VmServiceIONativeEntries[i];
|
|
if ((strcmp(function_name, entry.name) == 0) &&
|
|
(num_arguments == entry.num_arguments)) {
|
|
return entry.function;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
const char* VmService::error_msg_ = NULL;
|
|
char VmService::server_ip_[kServerIpStringBufferSize];
|
|
intptr_t VmService::server_port_ = 0;
|
|
|
|
bool VmService::Setup(const char* server_ip, intptr_t server_port) {
|
|
Dart_Isolate isolate = Dart_CurrentIsolate();
|
|
ASSERT(isolate != NULL);
|
|
SetServerIPAndPort("", 0);
|
|
|
|
Dart_Handle result;
|
|
|
|
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(NULL, true, builtin_lib);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
|
|
// Load main script.
|
|
Dart_SetLibraryTagHandler(LibraryTagHandler);
|
|
Dart_Handle library = LoadScript(kVMServiceIOLibraryScriptResourceName);
|
|
ASSERT(library != Dart_Null());
|
|
SHUTDOWN_ON_ERROR(library);
|
|
result = Dart_SetNativeResolver(library, VmServiceIONativeResolver, NULL);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
result = Dart_FinalizeLoading(false);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
|
|
// Make runnable.
|
|
Dart_ExitScope();
|
|
Dart_ExitIsolate();
|
|
bool retval = Dart_IsolateMakeRunnable(isolate);
|
|
if (!retval) {
|
|
Dart_EnterIsolate(isolate);
|
|
Dart_ShutdownIsolate();
|
|
error_msg_ = "Invalid isolate state - Unable to make it runnable.";
|
|
return false;
|
|
}
|
|
Dart_EnterIsolate(isolate);
|
|
Dart_EnterScope();
|
|
|
|
library = Dart_RootLibrary();
|
|
SHUTDOWN_ON_ERROR(library);
|
|
|
|
// Set HTTP server state.
|
|
DartUtils::SetStringField(library, "_ip", server_ip);
|
|
// If we have a port specified, start the server immediately.
|
|
bool auto_start = server_port >= 0;
|
|
if (server_port < 0) {
|
|
// Adjust server_port to port 0 which will result in the first available
|
|
// port when the HTTP server is started.
|
|
server_port = 0;
|
|
}
|
|
DartUtils::SetIntegerField(library, "_port", server_port);
|
|
result = Dart_SetField(library,
|
|
DartUtils::NewString("_autoStart"),
|
|
Dart_NewBoolean(auto_start));
|
|
SHUTDOWN_ON_ERROR(result);
|
|
|
|
// Are we running on Windows?
|
|
#if defined(TARGET_OS_WINDOWS)
|
|
Dart_Handle is_windows = Dart_True();
|
|
#else
|
|
Dart_Handle is_windows = Dart_False();
|
|
#endif
|
|
result =
|
|
Dart_SetField(library, DartUtils::NewString("_isWindows"), is_windows);
|
|
SHUTDOWN_ON_ERROR(result);
|
|
|
|
// Get _getWatchSignalInternal from dart:io.
|
|
Dart_Handle dart_io_str = Dart_NewStringFromCString(DartUtils::kIOLibURL);
|
|
SHUTDOWN_ON_ERROR(dart_io_str);
|
|
Dart_Handle io_lib = Dart_LookupLibrary(dart_io_str);
|
|
SHUTDOWN_ON_ERROR(io_lib);
|
|
Dart_Handle function_name =
|
|
Dart_NewStringFromCString("_getWatchSignalInternal");
|
|
SHUTDOWN_ON_ERROR(function_name);
|
|
Dart_Handle signal_watch = Dart_Invoke(io_lib, function_name, 0, NULL);
|
|
SHUTDOWN_ON_ERROR(signal_watch);
|
|
Dart_Handle field_name = Dart_NewStringFromCString("_signalWatch");
|
|
SHUTDOWN_ON_ERROR(field_name);
|
|
result =
|
|
Dart_SetField(library, field_name, signal_watch);
|
|
SHUTDOWN_ON_ERROR(field_name);
|
|
return true;
|
|
}
|
|
|
|
|
|
const char* VmService::GetErrorMessage() {
|
|
return error_msg_ == NULL ? "No error." : error_msg_;
|
|
}
|
|
|
|
|
|
void VmService::SetServerIPAndPort(const char* ip, intptr_t port) {
|
|
if (ip == NULL) {
|
|
ip = "";
|
|
}
|
|
strncpy(server_ip_, ip, kServerIpStringBufferSize);
|
|
server_ip_[kServerIpStringBufferSize - 1] = '\0';
|
|
server_port_ = 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(buffer, &vmservice_source);
|
|
if (r == Resources::kNoSuchInstance) {
|
|
FATAL1("vm-service: Could not find embedded source file: %s ", buffer);
|
|
}
|
|
ASSERT(r != Resources::kNoSuchInstance);
|
|
return Dart_NewStringFromCString(vmservice_source);
|
|
}
|
|
|
|
|
|
Dart_Handle VmService::LoadScript(const char* name) {
|
|
Dart_Handle url = Dart_NewStringFromCString("dart:vmservice_io");
|
|
Dart_Handle source = GetSource(name);
|
|
return Dart_LoadScript(url, source, 0, 0);
|
|
}
|
|
|
|
|
|
Dart_Handle VmService::LoadSource(Dart_Handle library, const char* name) {
|
|
Dart_Handle url = Dart_NewStringFromCString(name);
|
|
Dart_Handle source = GetSource(name);
|
|
return Dart_LoadSource(library, url, source, 0, 0);
|
|
}
|
|
|
|
|
|
Dart_Handle VmService::LoadResource(Dart_Handle library,
|
|
const char* resource_name) {
|
|
// Prepare for invoke call.
|
|
Dart_Handle name = Dart_NewStringFromCString(resource_name);
|
|
RETURN_ERROR_HANDLE(name);
|
|
const char* data_buffer = NULL;
|
|
int data_buffer_length = Resources::ResourceLookup(resource_name,
|
|
&data_buffer);
|
|
if (data_buffer_length == Resources::kNoSuchInstance) {
|
|
printf("Could not find %s %s\n", resource_name, resource_name);
|
|
}
|
|
ASSERT(data_buffer_length != Resources::kNoSuchInstance);
|
|
Dart_Handle data_list = Dart_NewTypedData(Dart_TypedData_kUint8,
|
|
data_buffer_length);
|
|
RETURN_ERROR_HANDLE(data_list);
|
|
Dart_TypedData_Type type = Dart_TypedData_kInvalid;
|
|
void* data_list_buffer = NULL;
|
|
intptr_t data_list_buffer_length = 0;
|
|
Dart_Handle result = Dart_TypedDataAcquireData(data_list, &type,
|
|
&data_list_buffer,
|
|
&data_list_buffer_length);
|
|
RETURN_ERROR_HANDLE(result);
|
|
ASSERT(data_buffer_length == data_list_buffer_length);
|
|
ASSERT(data_list_buffer != NULL);
|
|
ASSERT(type = Dart_TypedData_kUint8);
|
|
memmove(data_list_buffer, &data_buffer[0], data_buffer_length);
|
|
result = Dart_TypedDataReleaseData(data_list);
|
|
RETURN_ERROR_HANDLE(result);
|
|
|
|
// Make invoke call.
|
|
const intptr_t kNumArgs = 2;
|
|
Dart_Handle args[kNumArgs] = { name, data_list };
|
|
result = Dart_Invoke(library, Dart_NewStringFromCString("_addResource"),
|
|
kNumArgs, args);
|
|
return result;
|
|
}
|
|
|
|
|
|
Dart_Handle VmService::LoadResources(Dart_Handle library) {
|
|
Dart_Handle result = Dart_Null();
|
|
intptr_t prefixLen = strlen(kLibrarySourceNamePrefix);
|
|
for (intptr_t i = 0; Resources::Path(i) != NULL; i++) {
|
|
const char* path = Resources::Path(i);
|
|
// If it doesn't begin with kLibrarySourceNamePrefix it is a frontend
|
|
// resource.
|
|
if (strncmp(path, kLibrarySourceNamePrefix, prefixLen) != 0) {
|
|
result = LoadResource(library, path);
|
|
if (Dart_IsError(result)) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
|
|
Dart_Handle VmService::LibraryTagHandler(Dart_LibraryTag tag,
|
|
Dart_Handle library,
|
|
Dart_Handle url) {
|
|
if (!Dart_IsLibrary(library)) {
|
|
return Dart_NewApiError("not a library");
|
|
}
|
|
if (!Dart_IsString(url)) {
|
|
return Dart_NewApiError("url is not a string");
|
|
}
|
|
const char* url_string = NULL;
|
|
Dart_Handle result = Dart_StringToCString(url, &url_string);
|
|
if (Dart_IsError(result)) {
|
|
return result;
|
|
}
|
|
Dart_Handle library_url = Dart_LibraryUrl(library);
|
|
const char* library_url_string = NULL;
|
|
result = Dart_StringToCString(library_url, &library_url_string);
|
|
if (Dart_IsError(result)) {
|
|
return result;
|
|
}
|
|
if (tag == Dart_kImportTag) {
|
|
// Embedder handles all requests for external libraries.
|
|
return DartUtils::LibraryTagHandler(tag, library, url);
|
|
}
|
|
ASSERT((tag == Dart_kSourceTag) || (tag == Dart_kCanonicalizeUrl));
|
|
if (tag == Dart_kCanonicalizeUrl) {
|
|
// url is already canonicalized.
|
|
return url;
|
|
}
|
|
Dart_Handle source = GetSource(url_string);
|
|
if (Dart_IsError(source)) {
|
|
return source;
|
|
}
|
|
return Dart_LoadSource(library, url, source, 0, 0);
|
|
}
|
|
|
|
|
|
} // namespace bin
|
|
} // namespace dart
|