Files
sdk/runtime/vm/custom_isolate_test.cc
T
asiva@google.com ebbb7c4134 - Represent strings internally in UTF-16 format, this makes it
compatible with webkit and will allow for easy externalization of
  strings. One byte strings are retained for pure ASCII strings.
  (The language specification was changed recently to reflect this as
   follows "A string is a sequence of UTF-16 code units").
- Remove four byte string class and all references to it.
- Rename some of the string functions in Dart API to make them
  consistent and better describe the underlying functionality
  Dart_NewString => Dart_NewStringFromCString
  Dart_NewString8 => Dart_NewStringFromUTF8
  Dart_NewString16 => Dart_NewStringFromUTF16
  Dart_NewString32 => Dart_NewStringFromUTF32
  Dart_NewExternalString8 => Dart_NewExternalUTF8String
  Dart_NewExternalString16 => Dart_NewExternalUTF16String
  Dart_NewExternalString32 => Dart_NewExternalUTF32String
  Dart_StringGet8 => Dart_StringToUTF8
  Dart_StringGet16 => Dart_StringToUTF16
  Dart_StringToCString => Dart_StringToCString
  Dart_IsString8 => Removed
  Dart_IsString16 -> Removed
  Dart_StringToBytes -> Removed
  Dart_StringGet32 -> Removed
Review URL: https://codereview.chromium.org//11318018

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@14357 260f80e4-7a28-3924-810f-c04153c831b5
2012-10-31 17:56:46 +00:00

347 lines
8.9 KiB
C++

// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#include "include/dart_api.h"
#include "vm/unit_test.h"
// Custom Isolate Test.
//
// This mid-size test uses the Dart Embedding Api to create a custom
// isolate abstraction. Instead of having a dedicated thread for each
// isolate, as is the case normally, this implementation shares a
// single thread among the isolates using an event queue.
namespace dart {
// Only ia32 and x64 can run execution tests.
#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64)
static void native_echo(Dart_NativeArguments args);
static void CustomIsolateImpl_start(Dart_NativeArguments args);
static Dart_NativeFunction NativeLookup(Dart_Handle name, int argc);
static const char* kCustomIsolateScriptChars =
"#import('dart:isolate');\n"
"\n"
"ReceivePort mainPort;\n"
"\n"
"echo(arg) native \"native_echo\";\n"
"\n"
"class CustomIsolateImpl implements CustomIsolate {\n"
" CustomIsolateImpl(String entry) : _entry = entry{\n"
" echo('Constructing isolate');\n"
" }\n"
"\n"
" Future<SendPort> spawn() {\n"
" Completer<SendPort> completer = new Completer<SendPort>();\n"
" SendPort port = _start(_entry);\n"
" completer.complete(port);\n"
" return completer.future;\n"
" }\n"
"\n"
" static SendPort _start(entry)\n"
" native \"CustomIsolateImpl_start\";\n"
"\n"
" String _entry;\n"
"}\n"
"\n"
"interface CustomIsolate default CustomIsolateImpl {\n"
" CustomIsolate(String entry);\n"
"\n"
" Future<SendPort> spawn();\n"
"}\n"
"\n"
"isolateMain() {\n"
" echo('Running isolateMain');\n"
" mainPort.receive((message, SendPort replyTo) {\n"
" echo('Received: $message');\n"
" replyTo.send((message + 1), null);\n"
" });\n"
"}\n"
"\n"
"main() {\n"
" var isolate = new CustomIsolate(\"isolateMain\");\n"
" isolate.spawn().then((SendPort port) {\n"
" port.call(42).then((message) {\n"
" echo('Received: $message');\n"
" });\n"
" });\n"
" return 'success';\n"
"}\n";
// An entry in our event queue.
class Event {
protected:
explicit Event(Dart_Isolate isolate) : isolate_(isolate), next_(NULL) {}
public:
virtual ~Event() {}
virtual void Process() = 0;
Dart_Isolate isolate() const { return isolate_; }
private:
friend class EventQueue;
Dart_Isolate isolate_;
Event* next_;
};
// A simple event queue for our test.
class EventQueue {
public:
EventQueue() {
head_ = NULL;
}
void Add(Event* event) {
if (head_ == NULL) {
head_ = event;
tail_ = event;
} else {
tail_->next_ = event;
tail_ = event;
}
}
Event* Get() {
if (head_ == NULL) {
return NULL;
}
Event* tmp = head_;
head_ = head_->next_;
if (head_ == NULL) {
// Not necessary, but why not.
tail_ = NULL;
}
return tmp;
}
void RemoveEventsForIsolate(Dart_Isolate isolate) {
Event* cur = head_;
Event* prev = NULL;
while (cur != NULL) {
Event* next = cur->next_;
if (cur->isolate() == isolate) {
// Remove matching event.
if (prev != NULL) {
prev->next_ = next;
} else {
head_ = next;
}
delete cur;
} else {
// Advance.
prev = cur;
}
cur = next;
}
tail_ = prev;
}
private:
Event* head_;
Event* tail_;
};
EventQueue* event_queue;
// Start an isolate.
class StartEvent : public Event {
public:
StartEvent(Dart_Isolate isolate, const char* main)
: Event(isolate), main_(main) {}
virtual void Process();
private:
const char* main_;
};
void StartEvent::Process() {
OS::Print(">> StartEvent with isolate(%p)--\n", isolate());
Dart_EnterIsolate(isolate());
Dart_EnterScope();
Dart_Handle result;
// Reload all the test classes here.
//
// TODO(turnidge): Use the create isolate callback instead?
Dart_Handle lib = TestCase::LoadTestScript(kCustomIsolateScriptChars,
NativeLookup);
EXPECT_VALID(lib);
EXPECT_VALID(Dart_CompileAll());
Dart_Handle recv_port = Dart_GetReceivePort(Dart_GetMainPortId());
EXPECT_VALID(recv_port);
result = Dart_SetField(lib, NewString("mainPort"), recv_port);
EXPECT_VALID(result);
result = Dart_Invoke(lib, NewString(main_), 0, NULL);
EXPECT_VALID(result);
free(const_cast<char*>(main_));
main_ = NULL;
Dart_ExitScope();
Dart_ExitIsolate();
}
// Notify an isolate of a pending message.
class MessageEvent : public Event {
public:
explicit MessageEvent(Dart_Isolate isolate) : Event(isolate) {}
~MessageEvent() {
}
virtual void Process();
};
void MessageEvent::Process() {
OS::Print("$$ MessageEvent with isolate(%p)\n", isolate());
Dart_EnterIsolate(isolate());
Dart_EnterScope();
Dart_Handle result = Dart_HandleMessage();
EXPECT_VALID(result);
if (!Dart_HasLivePorts()) {
OS::Print("<< Shutting down isolate(%p)\n", isolate());
event_queue->RemoveEventsForIsolate(isolate());
Dart_ShutdownIsolate();
} else {
Dart_ExitScope();
Dart_ExitIsolate();
}
ASSERT(Dart_CurrentIsolate() == NULL);
}
static void NotifyMessage(Dart_Isolate dest_isolate) {
OS::Print("-- Notify isolate(%p) of pending message --\n", dest_isolate);
OS::Print("-- Adding MessageEvent to queue --\n");
event_queue->Add(new MessageEvent(dest_isolate));
}
static Dart_NativeFunction NativeLookup(Dart_Handle name, int argc) {
const char* name_str = NULL;
EXPECT(Dart_IsString(name));
EXPECT_VALID(Dart_StringToCString(name, &name_str));
if (strcmp(name_str, "native_echo") == 0) {
return &native_echo;
} else if (strcmp(name_str, "CustomIsolateImpl_start") == 0) {
return &CustomIsolateImpl_start;
}
return NULL;
}
const char* saved_echo = NULL;
static void native_echo(Dart_NativeArguments args) {
Dart_EnterScope();
Dart_Handle arg = Dart_GetNativeArgument(args, 0);
Dart_Handle toString = Dart_ToString(arg);
EXPECT_VALID(toString);
const char* c_str = NULL;
EXPECT_VALID(Dart_StringToCString(toString, &c_str));
if (saved_echo) {
free(const_cast<char*>(saved_echo));
}
saved_echo = strdup(c_str);
OS::Print("-- (isolate=%p) %s\n", Dart_CurrentIsolate(), c_str);
Dart_ExitScope();
}
static void CustomIsolateImpl_start(Dart_NativeArguments args) {
OS::Print("-- Enter: CustomIsolateImpl_start --\n");
// We would probably want to pass in the this pointer too, so we
// could associate the CustomIsolateImpl instance with the
// Dart_Isolate by storing it in a native field.
EXPECT_EQ(1, Dart_GetNativeArgumentCount(args));
Dart_Handle param = Dart_GetNativeArgument(args, 0);
EXPECT_VALID(param);
EXPECT(Dart_IsString(param));
const char* isolate_main = NULL;
EXPECT_VALID(Dart_StringToCString(param, &isolate_main));
isolate_main = strdup(isolate_main);
// Save current isolate.
Dart_Isolate saved_isolate = Dart_CurrentIsolate();
Dart_ExitIsolate();
// Create a new Dart_Isolate.
Dart_Isolate new_isolate = TestCase::CreateTestIsolate();
EXPECT(new_isolate != NULL);
Dart_SetMessageNotifyCallback(&NotifyMessage);
Dart_Port new_port = Dart_GetMainPortId();
OS::Print("-- Adding StartEvent to queue --\n");
event_queue->Add(new StartEvent(new_isolate, isolate_main));
// Restore the original isolate.
Dart_ExitIsolate();
Dart_EnterIsolate(saved_isolate);
Dart_EnterScope();
Dart_Handle send_port = Dart_NewSendPort(new_port);
EXPECT_VALID(send_port);
Dart_SetReturnValue(args, send_port);
OS::Print("-- Exit: CustomIsolateImpl_start --\n");
Dart_ExitScope();
}
UNIT_TEST_CASE(CustomIsolates) {
event_queue = new EventQueue();
Dart_Isolate dart_isolate = TestCase::CreateTestIsolate();
EXPECT(dart_isolate != NULL);
Dart_SetMessageNotifyCallback(&NotifyMessage);
Dart_EnterScope();
Dart_Handle result;
// Create a test library.
Dart_Handle lib = TestCase::LoadTestScript(kCustomIsolateScriptChars,
NativeLookup);
EXPECT_VALID(lib);
// Run main.
result = Dart_Invoke(lib, NewString("main"), 0, NULL);
EXPECT_VALID(result);
EXPECT(Dart_IsString(result));
const char* result_str = NULL;
EXPECT_VALID(Dart_StringToCString(result, &result_str));
EXPECT_STREQ("success", result_str);
Dart_ExitScope();
Dart_ExitIsolate();
OS::Print("-- Starting event loop --\n");
Event* event = event_queue->Get();
while (event) {
event->Process();
delete event;
event = event_queue->Get();
}
OS::Print("-- Finished event loop --\n");
EXPECT_STREQ("Received: 43", saved_echo);
free(const_cast<char*>(saved_echo));
delete event_queue;
}
#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64).
} // namespace dart