1// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include <memory>
6
7#include "platform/globals.h"
8
9#include "include/dart_tools_api.h"
10#include "vm/dart_api_impl.h"
11#include "vm/dart_entry.h"
12#include "vm/debugger.h"
13#include "vm/debugger_api_impl_test.h"
14#include "vm/globals.h"
15#include "vm/heap/safepoint.h"
16#include "vm/message_handler.h"
17#include "vm/object_id_ring.h"
18#include "vm/os.h"
19#include "vm/port.h"
20#include "vm/profiler.h"
21#include "vm/service.h"
22#include "vm/unit_test.h"
23
24namespace dart {
25
26// This flag is used in the Service_Flags test below.
27DEFINE_FLAG(bool, service_testing_flag, false, "Comment");
28
29#ifndef PRODUCT
30
31class ServiceTestMessageHandler : public MessageHandler {
32 public:
33 ServiceTestMessageHandler() : _msg(NULL) {}
34
35 ~ServiceTestMessageHandler() {
36 PortMap::ClosePorts(this);
37 free(_msg);
38 }
39
40 MessageStatus HandleMessage(std::unique_ptr<Message> message) {
41 if (_msg != NULL) {
42 free(_msg);
43 _msg = NULL;
44 }
45
46 // Parse the message.
47 Object& response_obj = Object::Handle();
48 if (message->IsRaw()) {
49 response_obj = message->raw_obj();
50 } else {
51 Thread* thread = Thread::Current();
52 MessageSnapshotReader reader(message.get(), thread);
53 response_obj = reader.ReadObject();
54 }
55 if (response_obj.IsString()) {
56 String& response = String::Handle();
57 response ^= response_obj.raw();
58 _msg = Utils::StrDup(response.ToCString());
59 } else {
60 ASSERT(response_obj.IsArray());
61 Array& response_array = Array::Handle();
62 response_array ^= response_obj.raw();
63 ASSERT(response_array.Length() == 1);
64 ExternalTypedData& response = ExternalTypedData::Handle();
65 response ^= response_array.At(0);
66 _msg = Utils::StrDup(reinterpret_cast<char*>(response.DataAddr(0)));
67 }
68
69 return kOK;
70 }
71
72 const char* msg() const { return _msg; }
73
74 virtual Isolate* isolate() const { return Isolate::Current(); }
75
76 private:
77 char* _msg;
78};
79
80static ArrayPtr Eval(Dart_Handle lib, const char* expr) {
81 const String& dummy_isolate_id = String::Handle(String::New("isolateId"));
82 Dart_Handle expr_val;
83 {
84 TransitionVMToNative transiton(Thread::Current());
85 expr_val = Dart_EvaluateStaticExpr(lib, NewString(expr));
86 EXPECT_VALID(expr_val);
87 }
88 Zone* zone = Thread::Current()->zone();
89 const GrowableObjectArray& value =
90 Api::UnwrapGrowableObjectArrayHandle(zone, expr_val);
91 const Array& result = Array::Handle(Array::MakeFixedLength(value));
92 GrowableObjectArray& growable = GrowableObjectArray::Handle();
93 growable ^= result.At(4);
94 // Append dummy isolate id to parameter values.
95 growable.Add(dummy_isolate_id);
96 Array& array = Array::Handle(Array::MakeFixedLength(growable));
97 result.SetAt(4, array);
98 growable ^= result.At(5);
99 // Append dummy isolate id to parameter values.
100 growable.Add(dummy_isolate_id);
101 array = Array::MakeFixedLength(growable);
102 result.SetAt(5, array);
103 return result.raw();
104}
105
106static ArrayPtr EvalF(Dart_Handle lib, const char* fmt, ...) {
107 va_list args;
108 va_start(args, fmt);
109 intptr_t len = Utils::VSNPrint(NULL, 0, fmt, args);
110 va_end(args);
111
112 char* buffer = Thread::Current()->zone()->Alloc<char>(len + 1);
113 va_list args2;
114 va_start(args2, fmt);
115 Utils::VSNPrint(buffer, (len + 1), fmt, args2);
116 va_end(args2);
117
118 return Eval(lib, buffer);
119}
120
121static FunctionPtr GetFunction(const Class& cls, const char* name) {
122 const Function& result = Function::Handle(
123 cls.LookupDynamicFunction(String::Handle(String::New(name))));
124 EXPECT(!result.IsNull());
125 return result.raw();
126}
127
128static ClassPtr GetClass(const Library& lib, const char* name) {
129 const Class& cls = Class::Handle(
130 lib.LookupClass(String::Handle(Symbols::New(Thread::Current(), name))));
131 EXPECT(!cls.IsNull()); // No ambiguity error expected.
132 return cls.raw();
133}
134
135static void HandleIsolateMessage(Isolate* isolate, const Array& msg) {
136 Service::HandleIsolateMessage(isolate, msg);
137}
138
139static void HandleRootMessage(const Array& message) {
140 Service::HandleRootMessage(message);
141}
142
143ISOLATE_UNIT_TEST_CASE(Service_IsolateStickyError) {
144 const char* kScript = "main() => throw 'HI THERE STICKY';\n";
145
146 Isolate* isolate = thread->isolate();
147 isolate->set_is_runnable(true);
148 Dart_Handle result;
149 {
150 TransitionVMToNative transition(thread);
151 Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
152 EXPECT_VALID(lib);
153 result = Dart_Invoke(lib, NewString("main"), 0, NULL);
154 EXPECT(Dart_IsUnhandledExceptionError(result));
155 EXPECT(!Dart_HasStickyError());
156 }
157 EXPECT(Thread::Current()->sticky_error() == Error::null());
158
159 {
160 JSONStream js;
161 isolate->PrintJSON(&js, false);
162 // No error property and no PauseExit state.
163 EXPECT_NOTSUBSTRING("\"error\":", js.ToCString());
164 EXPECT_NOTSUBSTRING("HI THERE STICKY", js.ToCString());
165 EXPECT_NOTSUBSTRING("PauseExit", js.ToCString());
166 }
167
168 {
169 // Set the sticky error.
170 TransitionVMToNative transition(thread);
171 Dart_SetStickyError(result);
172 Dart_SetPausedOnExit(true);
173 EXPECT(Dart_HasStickyError());
174 }
175
176 {
177 JSONStream js;
178 isolate->PrintJSON(&js, false);
179 // Error and PauseExit set.
180 EXPECT_SUBSTRING("\"error\":", js.ToCString());
181 EXPECT_SUBSTRING("HI THERE STICKY", js.ToCString());
182 EXPECT_SUBSTRING("PauseExit", js.ToCString());
183 }
184}
185
186ISOLATE_UNIT_TEST_CASE(Service_IdZones) {
187 Zone* zone = thread->zone();
188 Isolate* isolate = thread->isolate();
189 ObjectIdRing* ring = isolate->EnsureObjectIdRing();
190
191 const String& test_a = String::Handle(zone, String::New("a"));
192 const String& test_b = String::Handle(zone, String::New("b"));
193 const String& test_c = String::Handle(zone, String::New("c"));
194 const String& test_d = String::Handle(zone, String::New("d"));
195
196 // Both RingServiceIdZones share the same backing store and id space.
197
198 // Always allocate a new id.
199 RingServiceIdZone always_new_zone;
200 always_new_zone.Init(ring, ObjectIdRing::kAllocateId);
201 EXPECT_STREQ("objects/0", always_new_zone.GetServiceId(test_a));
202 EXPECT_STREQ("objects/1", always_new_zone.GetServiceId(test_a));
203 EXPECT_STREQ("objects/2", always_new_zone.GetServiceId(test_a));
204 EXPECT_STREQ("objects/3", always_new_zone.GetServiceId(test_b));
205 EXPECT_STREQ("objects/4", always_new_zone.GetServiceId(test_c));
206
207 // Reuse an existing id or allocate a new id.
208 RingServiceIdZone reuse_zone;
209 reuse_zone.Init(ring, ObjectIdRing::kReuseId);
210 EXPECT_STREQ("objects/0", reuse_zone.GetServiceId(test_a));
211 EXPECT_STREQ("objects/0", reuse_zone.GetServiceId(test_a));
212 EXPECT_STREQ("objects/3", reuse_zone.GetServiceId(test_b));
213 EXPECT_STREQ("objects/3", reuse_zone.GetServiceId(test_b));
214 EXPECT_STREQ("objects/4", reuse_zone.GetServiceId(test_c));
215 EXPECT_STREQ("objects/4", reuse_zone.GetServiceId(test_c));
216 EXPECT_STREQ("objects/5", reuse_zone.GetServiceId(test_d));
217 EXPECT_STREQ("objects/5", reuse_zone.GetServiceId(test_d));
218}
219
220ISOLATE_UNIT_TEST_CASE(Service_Code) {
221 const char* kScript =
222 "var port;\n" // Set to our mock port by C++.
223 "\n"
224 "class A {\n"
225 " var a;\n"
226 " dynamic b() {}\n"
227 " dynamic c() {\n"
228 " var d = () { b(); };\n"
229 " return d;\n"
230 " }\n"
231 "}\n"
232 "main() {\n"
233 " var z = new A();\n"
234 " var x = z.c();\n"
235 " x();\n"
236 "}";
237
238 Isolate* isolate = thread->isolate();
239 isolate->set_is_runnable(true);
240 Dart_Handle lib;
241 Library& vmlib = Library::Handle();
242 {
243 TransitionVMToNative transition(thread);
244 lib = TestCase::LoadTestScript(kScript, NULL);
245 EXPECT_VALID(lib);
246 EXPECT(!Dart_IsNull(lib));
247 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
248 EXPECT_VALID(result);
249 }
250 vmlib ^= Api::UnwrapHandle(lib);
251 EXPECT(!vmlib.IsNull());
252 const Class& class_a = Class::Handle(GetClass(vmlib, "A"));
253 EXPECT(!class_a.IsNull());
254 const Function& function_c = Function::Handle(GetFunction(class_a, "c"));
255 EXPECT(!function_c.IsNull());
256 const Code& code_c = Code::Handle(function_c.CurrentCode());
257 EXPECT(!code_c.IsNull());
258 // Use the entry of the code object as it's reference.
259 uword entry = code_c.PayloadStart();
260 int64_t compile_timestamp = code_c.compile_timestamp();
261 EXPECT_GT(code_c.Size(), 16);
262 uword last = entry + code_c.Size();
263
264 // Build a mock message handler and wrap it in a dart port.
265 ServiceTestMessageHandler handler;
266 Dart_Port port_id = PortMap::CreatePort(&handler);
267 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
268 {
269 TransitionVMToNative transition(thread);
270 EXPECT_VALID(port);
271 EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
272 }
273
274 Array& service_msg = Array::Handle();
275
276 // Request an invalid code object.
277 service_msg =
278 Eval(lib, "[0, port, '0', 'getObject', ['objectId'], ['code/0']]");
279 HandleIsolateMessage(isolate, service_msg);
280 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
281 EXPECT_SUBSTRING("\"error\"", handler.msg());
282
283 // The following test checks that a code object can be found only
284 // at compile_timestamp()-code.EntryPoint().
285 service_msg = EvalF(lib,
286 "[0, port, '0', 'getObject', "
287 "['objectId'], ['code/%" Px64 "-%" Px "']]",
288 compile_timestamp, entry);
289 HandleIsolateMessage(isolate, service_msg);
290 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
291 EXPECT_SUBSTRING("\"type\":\"Code\"", handler.msg());
292 {
293 // Only perform a partial match.
294 const intptr_t kBufferSize = 512;
295 char buffer[kBufferSize];
296 Utils::SNPrint(buffer, kBufferSize - 1,
297 "\"fixedId\":true,\"id\":\"code\\/%" Px64 "-%" Px "\",",
298 compile_timestamp, entry);
299 EXPECT_SUBSTRING(buffer, handler.msg());
300 }
301
302 // Request code object at compile_timestamp-code.EntryPoint() + 16
303 // Expect this to fail because the address is not the entry point.
304 uintptr_t address = entry + 16;
305 service_msg = EvalF(lib,
306 "[0, port, '0', 'getObject', "
307 "['objectId'], ['code/%" Px64 "-%" Px "']]",
308 compile_timestamp, address);
309 HandleIsolateMessage(isolate, service_msg);
310 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
311 EXPECT_SUBSTRING("\"error\"", handler.msg());
312
313 // Request code object at (compile_timestamp - 1)-code.EntryPoint()
314 // Expect this to fail because the timestamp is wrong.
315 address = entry;
316 service_msg = EvalF(lib,
317 "[0, port, '0', 'getObject', "
318 "['objectId'], ['code/%" Px64 "-%" Px "']]",
319 compile_timestamp - 1, address);
320 HandleIsolateMessage(isolate, service_msg);
321 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
322 EXPECT_SUBSTRING("\"error\"", handler.msg());
323
324 // Request native code at address. Expect the null code object back.
325 address = last;
326 service_msg = EvalF(lib,
327 "[0, port, '0', 'getObject', "
328 "['objectId'], ['code/native-%" Px "']]",
329 address);
330 HandleIsolateMessage(isolate, service_msg);
331 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
332 // TODO(turnidge): It is pretty broken to return an Instance here. Fix.
333 EXPECT_SUBSTRING("\"kind\":\"Null\"", handler.msg());
334
335 // Request malformed native code.
336 service_msg = EvalF(lib,
337 "[0, port, '0', 'getObject', ['objectId'], "
338 "['code/native%" Px "']]",
339 address);
340 HandleIsolateMessage(isolate, service_msg);
341 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
342 EXPECT_SUBSTRING("\"error\"", handler.msg());
343}
344
345ISOLATE_UNIT_TEST_CASE(Service_PcDescriptors) {
346 const char* kScript =
347 "var port;\n" // Set to our mock port by C++.
348 "\n"
349 "class A {\n"
350 " var a;\n"
351 " dynamic b() {}\n"
352 " dynamic c() {\n"
353 " var d = () { b(); };\n"
354 " return d;\n"
355 " }\n"
356 "}\n"
357 "main() {\n"
358 " var z = new A();\n"
359 " var x = z.c();\n"
360 " x();\n"
361 "}";
362
363 Isolate* isolate = thread->isolate();
364 isolate->set_is_runnable(true);
365 Dart_Handle lib;
366 Library& vmlib = Library::Handle();
367 {
368 TransitionVMToNative transition(thread);
369 lib = TestCase::LoadTestScript(kScript, NULL);
370 EXPECT_VALID(lib);
371 EXPECT(!Dart_IsNull(lib));
372 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
373 EXPECT_VALID(result);
374 }
375 vmlib ^= Api::UnwrapHandle(lib);
376 EXPECT(!vmlib.IsNull());
377 const Class& class_a = Class::Handle(GetClass(vmlib, "A"));
378 EXPECT(!class_a.IsNull());
379 const Function& function_c = Function::Handle(GetFunction(class_a, "c"));
380 EXPECT(!function_c.IsNull());
381 const Code& code_c = Code::Handle(function_c.CurrentCode());
382 EXPECT(!code_c.IsNull());
383
384 const PcDescriptors& descriptors =
385 PcDescriptors::Handle(code_c.pc_descriptors());
386 EXPECT(!descriptors.IsNull());
387 ObjectIdRing* ring = isolate->EnsureObjectIdRing();
388 intptr_t id = ring->GetIdForObject(descriptors.raw());
389
390 // Build a mock message handler and wrap it in a dart port.
391 ServiceTestMessageHandler handler;
392 Dart_Port port_id = PortMap::CreatePort(&handler);
393 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
394 {
395 TransitionVMToNative transition(thread);
396 EXPECT_VALID(port);
397 EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
398 }
399
400 Array& service_msg = Array::Handle();
401
402 // Fetch object.
403 service_msg = EvalF(lib,
404 "[0, port, '0', 'getObject', "
405 "['objectId'], ['objects/%" Pd "']]",
406 id);
407 HandleIsolateMessage(isolate, service_msg);
408 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
409 // Check type.
410 EXPECT_SUBSTRING("\"type\":\"Object\"", handler.msg());
411 EXPECT_SUBSTRING("\"_vmType\":\"PcDescriptors\"", handler.msg());
412 // Check for members array.
413 EXPECT_SUBSTRING("\"members\":[", handler.msg());
414}
415
416ISOLATE_UNIT_TEST_CASE(Service_LocalVarDescriptors) {
417 const char* kScript =
418 "var port;\n" // Set to our mock port by C++.
419 "\n"
420 "class A {\n"
421 " var a;\n"
422 " dynamic b() {}\n"
423 " dynamic c() {\n"
424 " var d = () { b(); };\n"
425 " return d;\n"
426 " }\n"
427 "}\n"
428 "main() {\n"
429 " var z = new A();\n"
430 " var x = z.c();\n"
431 " x();\n"
432 "}";
433
434 Isolate* isolate = thread->isolate();
435 isolate->set_is_runnable(true);
436 Dart_Handle lib;
437 Library& vmlib = Library::Handle();
438 {
439 TransitionVMToNative transition(thread);
440 lib = TestCase::LoadTestScript(kScript, NULL);
441 EXPECT_VALID(lib);
442 EXPECT(!Dart_IsNull(lib));
443 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
444 EXPECT_VALID(result);
445 }
446 vmlib ^= Api::UnwrapHandle(lib);
447 EXPECT(!vmlib.IsNull());
448 const Class& class_a = Class::Handle(GetClass(vmlib, "A"));
449 EXPECT(!class_a.IsNull());
450 const Function& function_c = Function::Handle(GetFunction(class_a, "c"));
451 EXPECT(!function_c.IsNull());
452 const Code& code_c = Code::Handle(function_c.CurrentCode());
453 EXPECT(!code_c.IsNull());
454
455 const LocalVarDescriptors& descriptors =
456 LocalVarDescriptors::Handle(code_c.GetLocalVarDescriptors());
457 // Generate an ID for this object.
458 ObjectIdRing* ring = isolate->EnsureObjectIdRing();
459 intptr_t id = ring->GetIdForObject(descriptors.raw());
460
461 // Build a mock message handler and wrap it in a dart port.
462 ServiceTestMessageHandler handler;
463 Dart_Port port_id = PortMap::CreatePort(&handler);
464 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
465 {
466 TransitionVMToNative transition(thread);
467 EXPECT_VALID(port);
468 EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
469 }
470
471 Array& service_msg = Array::Handle();
472
473 // Fetch object.
474 service_msg = EvalF(lib,
475 "[0, port, '0', 'getObject', "
476 "['objectId'], ['objects/%" Pd "']]",
477 id);
478 HandleIsolateMessage(isolate, service_msg);
479 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
480 // Check type.
481 EXPECT_SUBSTRING("\"type\":\"Object\"", handler.msg());
482 EXPECT_SUBSTRING("\"_vmType\":\"LocalVarDescriptors\"", handler.msg());
483 // Check for members array.
484 EXPECT_SUBSTRING("\"members\":[", handler.msg());
485}
486
487static void WeakHandleFinalizer(void* isolate_callback_data,
488 Dart_WeakPersistentHandle handle,
489 void* peer) {}
490
491ISOLATE_UNIT_TEST_CASE(Service_PersistentHandles) {
492 const char* kScript =
493 "var port;\n" // Set to our mock port by C++.
494 "\n"
495 "class A {\n"
496 " var a;\n"
497 "}\n"
498 "var global = new A();\n"
499 "main() {\n"
500 " return global;\n"
501 "}";
502
503 Isolate* isolate = thread->isolate();
504 isolate->set_is_runnable(true);
505
506 Dart_Handle lib;
507 Dart_PersistentHandle persistent_handle;
508 Dart_WeakPersistentHandle weak_persistent_handle;
509 {
510 TransitionVMToNative transition(thread);
511 lib = TestCase::LoadTestScript(kScript, NULL);
512 EXPECT_VALID(lib);
513 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
514 EXPECT_VALID(result);
515
516 // Create a persistent handle to global.
517 persistent_handle = Dart_NewPersistentHandle(result);
518
519 // Create a weak persistent handle to global.
520 weak_persistent_handle = Dart_NewWeakPersistentHandle(
521 result, reinterpret_cast<void*>(0xdeadbeef), 128, WeakHandleFinalizer);
522 }
523
524 // Build a mock message handler and wrap it in a dart port.
525 ServiceTestMessageHandler handler;
526 Dart_Port port_id = PortMap::CreatePort(&handler);
527 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
528 {
529 TransitionVMToNative transition(thread);
530 EXPECT_VALID(port);
531 EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
532 }
533
534 Array& service_msg = Array::Handle();
535
536 // Get persistent handles.
537 service_msg = Eval(lib, "[0, port, '0', '_getPersistentHandles', [], []]");
538 HandleIsolateMessage(isolate, service_msg);
539 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
540 // Look for a heart beat.
541 EXPECT_SUBSTRING("\"type\":\"_PersistentHandles\"", handler.msg());
542 EXPECT_SUBSTRING("\"peer\":\"0xdeadbeef\"", handler.msg());
543 EXPECT_SUBSTRING("\"name\":\"A\"", handler.msg());
544 EXPECT_SUBSTRING("\"externalSize\":\"128\"", handler.msg());
545
546 // Delete persistent handles.
547 {
548 TransitionVMToNative transition(thread);
549 Dart_DeletePersistentHandle(persistent_handle);
550 Dart_DeleteWeakPersistentHandle(weak_persistent_handle);
551 }
552
553 // Get persistent handles (again).
554 service_msg = Eval(lib, "[0, port, '0', '_getPersistentHandles', [], []]");
555 HandleIsolateMessage(isolate, service_msg);
556 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
557 EXPECT_SUBSTRING("\"type\":\"_PersistentHandles\"", handler.msg());
558 // Verify that old persistent handles are not present.
559 EXPECT_NOTSUBSTRING("\"peer\":\"0xdeadbeef\"", handler.msg());
560 EXPECT_NOTSUBSTRING("\"name\":\"A\"", handler.msg());
561 EXPECT_NOTSUBSTRING("\"externalSize\":\"128\"", handler.msg());
562}
563
564static bool alpha_callback(const char* name,
565 const char** option_keys,
566 const char** option_values,
567 intptr_t num_options,
568 void* user_data,
569 const char** result) {
570 *result = Utils::StrDup("alpha");
571 return true;
572}
573
574static bool beta_callback(const char* name,
575 const char** option_keys,
576 const char** option_values,
577 intptr_t num_options,
578 void* user_data,
579 const char** result) {
580 *result = Utils::StrDup("beta");
581 return false;
582}
583
584ISOLATE_UNIT_TEST_CASE(Service_EmbedderRootHandler) {
585 const char* kScript =
586 "var port;\n" // Set to our mock port by C++.
587 "\n"
588 "var x = 7;\n"
589 "main() {\n"
590 " x = x * x;\n"
591 " x = (x / 13).floor();\n"
592 "}";
593
594 Dart_Handle lib;
595 {
596 TransitionVMToNative transition(thread);
597
598 Dart_RegisterRootServiceRequestCallback("alpha", alpha_callback, NULL);
599 Dart_RegisterRootServiceRequestCallback("beta", beta_callback, NULL);
600
601 lib = TestCase::LoadTestScript(kScript, NULL);
602 EXPECT_VALID(lib);
603 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
604 EXPECT_VALID(result);
605 }
606
607 // Build a mock message handler and wrap it in a dart port.
608 ServiceTestMessageHandler handler;
609 Dart_Port port_id = PortMap::CreatePort(&handler);
610 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
611 {
612 TransitionVMToNative transition(thread);
613 EXPECT_VALID(port);
614 EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
615 }
616
617 Array& service_msg = Array::Handle();
618 service_msg = Eval(lib, "[0, port, '\"', 'alpha', [], []]");
619 HandleRootMessage(service_msg);
620 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
621 EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":alpha,\"id\":\"\\\"\"}",
622 handler.msg());
623 service_msg = Eval(lib, "[0, port, 1, 'beta', [], []]");
624 HandleRootMessage(service_msg);
625 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
626 EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"error\":beta,\"id\":1}", handler.msg());
627}
628
629ISOLATE_UNIT_TEST_CASE(Service_EmbedderIsolateHandler) {
630 const char* kScript =
631 "var port;\n" // Set to our mock port by C++.
632 "\n"
633 "var x = 7;\n"
634 "main() {\n"
635 " x = x * x;\n"
636 " x = (x / 13).floor();\n"
637 "}";
638
639 Dart_Handle lib;
640 {
641 TransitionVMToNative transition(thread);
642
643 Dart_RegisterIsolateServiceRequestCallback("alpha", alpha_callback, NULL);
644 Dart_RegisterIsolateServiceRequestCallback("beta", beta_callback, NULL);
645
646 lib = TestCase::LoadTestScript(kScript, NULL);
647 EXPECT_VALID(lib);
648 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
649 EXPECT_VALID(result);
650 }
651
652 // Build a mock message handler and wrap it in a dart port.
653 ServiceTestMessageHandler handler;
654 Dart_Port port_id = PortMap::CreatePort(&handler);
655 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
656 {
657 TransitionVMToNative transition(thread);
658 EXPECT_VALID(port);
659 EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
660 }
661
662 Isolate* isolate = thread->isolate();
663 Array& service_msg = Array::Handle();
664 service_msg = Eval(lib, "[0, port, '0', 'alpha', [], []]");
665 HandleIsolateMessage(isolate, service_msg);
666 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
667 EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":alpha,\"id\":\"0\"}",
668 handler.msg());
669 service_msg = Eval(lib, "[0, port, '0', 'beta', [], []]");
670 HandleIsolateMessage(isolate, service_msg);
671 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
672 EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"error\":beta,\"id\":\"0\"}",
673 handler.msg());
674}
675
676// TODO(zra): Remove when tests are ready to enable.
677#if !defined(TARGET_ARCH_ARM64)
678
679static void EnableProfiler() {
680 if (!FLAG_profiler) {
681 FLAG_profiler = true;
682 Profiler::Init();
683 }
684}
685
686ISOLATE_UNIT_TEST_CASE(Service_Profile) {
687 EnableProfiler();
688 const char* kScript =
689 "var port;\n" // Set to our mock port by C++.
690 "\n"
691 "var x = 7;\n"
692 "main() {\n"
693 " x = x * x;\n"
694 " x = (x / 13).floor();\n"
695 "}";
696
697 Isolate* isolate = thread->isolate();
698 isolate->set_is_runnable(true);
699 Dart_Handle lib;
700 {
701 TransitionVMToNative transition(thread);
702
703 lib = TestCase::LoadTestScript(kScript, NULL);
704 EXPECT_VALID(lib);
705 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
706 EXPECT_VALID(result);
707 }
708
709 // Build a mock message handler and wrap it in a dart port.
710 ServiceTestMessageHandler handler;
711 Dart_Port port_id = PortMap::CreatePort(&handler);
712 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
713 {
714 TransitionVMToNative transition(thread);
715 EXPECT_VALID(port);
716 EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
717 }
718
719 Array& service_msg = Array::Handle();
720 service_msg = Eval(lib, "[0, port, '0', 'getCpuSamples', [], []]");
721 HandleIsolateMessage(isolate, service_msg);
722 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
723 // Expect profile
724 EXPECT_SUBSTRING("\"type\":\"CpuSamples\"", handler.msg());
725}
726
727#endif // !defined(TARGET_ARCH_ARM64)
728
729#endif // !PRODUCT
730
731} // namespace dart
732