Flutter Engine
The Flutter Engine
service_test.cc
Go to the documentation of this file.
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
10#include "vm/dart_api_impl.h"
11#include "vm/dart_entry.h"
12#include "vm/debugger.h"
14#include "vm/globals.h"
15#include "vm/heap/safepoint.h"
16#include "vm/message_handler.h"
17#include "vm/message_snapshot.h"
18#include "vm/object_id_ring.h"
19#include "vm/os.h"
20#include "vm/port.h"
21#include "vm/profiler.h"
22#include "vm/resolver.h"
23#include "vm/service.h"
24#include "vm/unit_test.h"
25
26namespace dart {
27
28// This flag is used in the Service_Flags test below.
29DEFINE_FLAG(bool, service_testing_flag, false, "Comment");
30
31#ifndef PRODUCT
32
34 public:
35 ServiceTestMessageHandler() : _msg(nullptr) {}
36
39 free(_msg);
40 }
41
42 MessageStatus HandleMessage(std::unique_ptr<Message> message) {
43 if (_msg != nullptr) {
44 free(_msg);
45 _msg = nullptr;
46 }
47
48 // Parse the message.
49 Object& response_obj = Object::Handle();
50 if (message->IsRaw()) {
51 response_obj = message->raw_obj();
52 } else {
54 response_obj = ReadMessage(thread, message.get());
55 }
56 if (response_obj.IsString()) {
57 String& response = String::Handle();
58 response ^= response_obj.ptr();
59 _msg = Utils::StrDup(response.ToCString());
60 } else {
61 ASSERT(response_obj.IsArray());
62 Array& response_array = Array::Handle();
63 response_array ^= response_obj.ptr();
64 ASSERT(response_array.Length() == 1);
66 response ^= response_array.At(0);
67 _msg = Utils::StrDup(reinterpret_cast<char*>(response.DataAddr(0)));
68 }
69
70 return kOK;
71 }
72
73 const char* msg() const { return _msg; }
74
75 virtual Isolate* isolate() const { return Isolate::Current(); }
76
77 private:
78 char* _msg;
79};
80
81static ArrayPtr Eval(Dart_Handle lib, const char* expr) {
82 const String& dummy_isolate_id = String::Handle(String::New("isolateId"));
83 Dart_Handle expr_val;
84 {
86 expr_val = Dart_EvaluateStaticExpr(lib, NewString(expr));
87 EXPECT_VALID(expr_val);
88 }
89 Zone* zone = Thread::Current()->zone();
91 Api::UnwrapGrowableObjectArrayHandle(zone, expr_val);
94 growable ^= result.At(4);
95 // Append dummy isolate id to parameter values.
96 growable.Add(dummy_isolate_id);
97 Array& array = Array::Handle(Array::MakeFixedLength(growable));
98 result.SetAt(4, array);
99 growable ^= result.At(5);
100 // Append dummy isolate id to parameter values.
101 growable.Add(dummy_isolate_id);
102 array = Array::MakeFixedLength(growable);
103 result.SetAt(5, array);
104 return result.ptr();
105}
106
107static ArrayPtr EvalF(Dart_Handle lib, const char* fmt, ...) {
108 va_list measure_args;
109 va_start(measure_args, fmt);
110 intptr_t len = Utils::VSNPrint(nullptr, 0, fmt, measure_args);
111 va_end(measure_args);
112
113 char* buffer = Thread::Current()->zone()->Alloc<char>(len + 1);
114 va_list print_args;
115 va_start(print_args, fmt);
116 Utils::VSNPrint(buffer, (len + 1), fmt, print_args);
117 va_end(print_args);
118
119 return Eval(lib, buffer);
120}
121
122static FunctionPtr GetFunction(const Class& cls, const char* name) {
125 EXPECT(!result.IsNull());
126 return result.ptr();
127}
128
129static ClassPtr GetClass(const Library& lib, const char* name) {
130 const Class& cls = Class::Handle(
131 lib.LookupClass(String::Handle(Symbols::New(Thread::Current(), name))));
132 EXPECT(!cls.IsNull()); // No ambiguity error expected.
133 return cls.ptr();
134}
135
136static void HandleIsolateMessage(Isolate* isolate, const Array& msg) {
137 Service::HandleIsolateMessage(isolate, msg);
138}
139
140static void HandleRootMessage(const Array& message) {
142}
143
144ISOLATE_UNIT_TEST_CASE(Service_IsolateStickyError) {
145 const char* kScript = "main() => throw 'HI THERE STICKY';\n";
146
147 Isolate* isolate = thread->isolate();
148 isolate->set_is_runnable(true);
150 {
151 TransitionVMToNative transition(thread);
152 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
153 EXPECT_VALID(lib);
154 result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
157 }
158 EXPECT(Thread::Current()->sticky_error() == Error::null());
159
160 {
162 isolate->PrintJSON(&js, false);
163 // No error property and no PauseExit state.
164 EXPECT_NOTSUBSTRING("\"error\":", js.ToCString());
165 EXPECT_NOTSUBSTRING("HI THERE STICKY", js.ToCString());
166 EXPECT_NOTSUBSTRING("PauseExit", js.ToCString());
167 }
168
169 {
170 // Set the sticky error.
171 TransitionVMToNative transition(thread);
175 }
176
177 {
179 isolate->PrintJSON(&js, false);
180 // Error and PauseExit set.
181 EXPECT_SUBSTRING("\"error\":", js.ToCString());
182 EXPECT_SUBSTRING("HI THERE STICKY", js.ToCString());
183 EXPECT_SUBSTRING("PauseExit", js.ToCString());
184 }
185}
186
187ISOLATE_UNIT_TEST_CASE(Service_IdZones) {
188 Zone* zone = thread->zone();
189 Isolate* isolate = thread->isolate();
190 ObjectIdRing* ring = isolate->EnsureObjectIdRing();
191
192 const String& test_a = String::Handle(zone, String::New("a"));
193 const String& test_b = String::Handle(zone, String::New("b"));
194 const String& test_c = String::Handle(zone, String::New("c"));
195 const String& test_d = String::Handle(zone, String::New("d"));
196
197 // Both RingServiceIdZones share the same backing store and id space.
198
199 // Always allocate a new id.
200 RingServiceIdZone always_new_zone;
201 always_new_zone.Init(ring, ObjectIdRing::kAllocateId);
202 EXPECT_STREQ("objects/0", always_new_zone.GetServiceId(test_a));
203 EXPECT_STREQ("objects/1", always_new_zone.GetServiceId(test_a));
204 EXPECT_STREQ("objects/2", always_new_zone.GetServiceId(test_a));
205 EXPECT_STREQ("objects/3", always_new_zone.GetServiceId(test_b));
206 EXPECT_STREQ("objects/4", always_new_zone.GetServiceId(test_c));
207
208 // Reuse an existing id or allocate a new id.
209 RingServiceIdZone reuse_zone;
210 reuse_zone.Init(ring, ObjectIdRing::kReuseId);
211 EXPECT_STREQ("objects/0", reuse_zone.GetServiceId(test_a));
212 EXPECT_STREQ("objects/0", reuse_zone.GetServiceId(test_a));
213 EXPECT_STREQ("objects/3", reuse_zone.GetServiceId(test_b));
214 EXPECT_STREQ("objects/3", reuse_zone.GetServiceId(test_b));
215 EXPECT_STREQ("objects/4", reuse_zone.GetServiceId(test_c));
216 EXPECT_STREQ("objects/4", reuse_zone.GetServiceId(test_c));
217 EXPECT_STREQ("objects/5", reuse_zone.GetServiceId(test_d));
218 EXPECT_STREQ("objects/5", reuse_zone.GetServiceId(test_d));
219}
220
222 const char* kScript =
223 "var port;\n" // Set to our mock port by C++.
224 "\n"
225 "class A {\n"
226 " var a;\n"
227 " dynamic b() {}\n"
228 " dynamic c() {\n"
229 " var d = () { b(); };\n"
230 " return d;\n"
231 " }\n"
232 "}\n"
233 "main() {\n"
234 " var z = new A();\n"
235 " var x = z.c();\n"
236 " x();\n"
237 "}";
238
239 Isolate* isolate = thread->isolate();
240 isolate->set_is_runnable(true);
241 Dart_Handle lib;
242 Library& vmlib = Library::Handle();
243 {
244 TransitionVMToNative transition(thread);
245 lib = TestCase::LoadTestScript(kScript, nullptr);
246 EXPECT_VALID(lib);
247 EXPECT(!Dart_IsNull(lib));
248 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
250 }
251 vmlib ^= Api::UnwrapHandle(lib);
252 EXPECT(!vmlib.IsNull());
253 const Class& class_a = Class::Handle(GetClass(vmlib, "A"));
254 EXPECT(!class_a.IsNull());
255 const Function& function_c = Function::Handle(GetFunction(class_a, "c"));
256 EXPECT(!function_c.IsNull());
257 const Code& code_c = Code::Handle(function_c.CurrentCode());
258 EXPECT(!code_c.IsNull());
259 // Use the entry of the code object as it's reference.
260 uword entry = code_c.PayloadStart();
261 int64_t compile_timestamp = code_c.compile_timestamp();
262 EXPECT_GT(code_c.Size(), 16u);
263 uword last = entry + code_c.Size();
264
265 // Build a mock message handler and wrap it in a dart port.
267 Dart_Port port_id = PortMap::CreatePort(&handler);
268 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
269 {
270 TransitionVMToNative transition(thread);
273 }
274
275 Array& service_msg = Array::Handle();
276
277 // Request an invalid code object.
278 service_msg =
279 Eval(lib, "[0, port, '0', 'getObject', ['objectId'], ['code/0']]");
280 HandleIsolateMessage(isolate, service_msg);
281 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
282 EXPECT_SUBSTRING("\"error\"", handler.msg());
283
284 // The following test checks that a code object can be found only
285 // at compile_timestamp()-code.EntryPoint().
286 service_msg = EvalF(lib,
287 "[0, port, '0', 'getObject', "
288 "['objectId'], ['code/%" Px64 "-%" Px "']]",
289 compile_timestamp, entry);
290 HandleIsolateMessage(isolate, service_msg);
291 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
292 EXPECT_SUBSTRING("\"type\":\"Code\"", handler.msg());
293 {
294 // Only perform a partial match.
295 const intptr_t kBufferSize = 512;
296 char buffer[kBufferSize];
298 "\"fixedId\":true,\"id\":\"code\\/%" Px64 "-%" Px "\",",
299 compile_timestamp, entry);
300 EXPECT_SUBSTRING(buffer, handler.msg());
301 }
302
303 // Request code object at compile_timestamp-code.EntryPoint() + 16
304 // Expect this to fail because the address is not the entry point.
305 uintptr_t address = entry + 16;
306 service_msg = EvalF(lib,
307 "[0, port, '0', 'getObject', "
308 "['objectId'], ['code/%" Px64 "-%" Px "']]",
309 compile_timestamp, address);
310 HandleIsolateMessage(isolate, service_msg);
311 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
312 EXPECT_SUBSTRING("\"error\"", handler.msg());
313
314 // Request code object at (compile_timestamp - 1)-code.EntryPoint()
315 // Expect this to fail because the timestamp is wrong.
316 address = entry;
317 service_msg = EvalF(lib,
318 "[0, port, '0', 'getObject', "
319 "['objectId'], ['code/%" Px64 "-%" Px "']]",
320 compile_timestamp - 1, address);
321 HandleIsolateMessage(isolate, service_msg);
322 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
323 EXPECT_SUBSTRING("\"error\"", handler.msg());
324
325 // Request native code at address. Expect the null code object back.
326 address = last;
327 service_msg = EvalF(lib,
328 "[0, port, '0', 'getObject', "
329 "['objectId'], ['code/native-%" Px "']]",
330 address);
331 HandleIsolateMessage(isolate, service_msg);
332 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
333 // TODO(turnidge): It is pretty broken to return an Instance here. Fix.
334 EXPECT_SUBSTRING("\"kind\":\"Null\"", handler.msg());
335
336 // Request malformed native code.
337 service_msg = EvalF(lib,
338 "[0, port, '0', 'getObject', ['objectId'], "
339 "['code/native%" Px "']]",
340 address);
341 HandleIsolateMessage(isolate, service_msg);
342 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
343 EXPECT_SUBSTRING("\"error\"", handler.msg());
344}
345
346ISOLATE_UNIT_TEST_CASE(Service_PcDescriptors) {
347 const char* kScript =
348 "var port;\n" // Set to our mock port by C++.
349 "\n"
350 "class A {\n"
351 " var a;\n"
352 " dynamic b() {}\n"
353 " dynamic c() {\n"
354 " var d = () { b(); };\n"
355 " return d;\n"
356 " }\n"
357 "}\n"
358 "main() {\n"
359 " var z = new A();\n"
360 " var x = z.c();\n"
361 " x();\n"
362 "}";
363
364 Isolate* isolate = thread->isolate();
365 isolate->set_is_runnable(true);
366 Dart_Handle lib;
367 Library& vmlib = Library::Handle();
368 {
369 TransitionVMToNative transition(thread);
370 lib = TestCase::LoadTestScript(kScript, nullptr);
371 EXPECT_VALID(lib);
372 EXPECT(!Dart_IsNull(lib));
373 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
375 }
376 vmlib ^= Api::UnwrapHandle(lib);
377 EXPECT(!vmlib.IsNull());
378 const Class& class_a = Class::Handle(GetClass(vmlib, "A"));
379 EXPECT(!class_a.IsNull());
380 const Function& function_c = Function::Handle(GetFunction(class_a, "c"));
381 EXPECT(!function_c.IsNull());
382 const Code& code_c = Code::Handle(function_c.CurrentCode());
383 EXPECT(!code_c.IsNull());
384
385 const PcDescriptors& descriptors =
387 EXPECT(!descriptors.IsNull());
388 ObjectIdRing* ring = isolate->EnsureObjectIdRing();
389 intptr_t id = ring->GetIdForObject(descriptors.ptr());
390
391 // Build a mock message handler and wrap it in a dart port.
393 Dart_Port port_id = PortMap::CreatePort(&handler);
394 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
395 {
396 TransitionVMToNative transition(thread);
399 }
400
401 Array& service_msg = Array::Handle();
402
403 // Fetch object.
404 service_msg = EvalF(lib,
405 "[0, port, '0', 'getObject', "
406 "['objectId'], ['objects/%" Pd "']]",
407 id);
408 HandleIsolateMessage(isolate, service_msg);
409 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
410 // Check type.
411 EXPECT_SUBSTRING("\"type\":\"Object\"", handler.msg());
412 EXPECT_SUBSTRING("\"_vmType\":\"PcDescriptors\"", handler.msg());
413 // Check for members array.
414 EXPECT_SUBSTRING("\"members\":[", handler.msg());
415}
416
417ISOLATE_UNIT_TEST_CASE(Service_LocalVarDescriptors) {
418 const char* kScript =
419 "var port;\n" // Set to our mock port by C++.
420 "\n"
421 "class A {\n"
422 " var a;\n"
423 " dynamic b() {}\n"
424 " dynamic c() {\n"
425 " var d = () { b(); };\n"
426 " return d;\n"
427 " }\n"
428 "}\n"
429 "main() {\n"
430 " var z = new A();\n"
431 " var x = z.c();\n"
432 " x();\n"
433 "}";
434
435 Isolate* isolate = thread->isolate();
436 isolate->set_is_runnable(true);
437 Dart_Handle lib;
438 Library& vmlib = Library::Handle();
439 {
440 TransitionVMToNative transition(thread);
441 lib = TestCase::LoadTestScript(kScript, nullptr);
442 EXPECT_VALID(lib);
443 EXPECT(!Dart_IsNull(lib));
444 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
446 }
447 vmlib ^= Api::UnwrapHandle(lib);
448 EXPECT(!vmlib.IsNull());
449 const Class& class_a = Class::Handle(GetClass(vmlib, "A"));
450 EXPECT(!class_a.IsNull());
451 const Function& function_c = Function::Handle(GetFunction(class_a, "c"));
452 EXPECT(!function_c.IsNull());
453 const Code& code_c = Code::Handle(function_c.CurrentCode());
454 EXPECT(!code_c.IsNull());
455
456 const LocalVarDescriptors& descriptors =
458 // Generate an ID for this object.
459 ObjectIdRing* ring = isolate->EnsureObjectIdRing();
460 intptr_t id = ring->GetIdForObject(descriptors.ptr());
461
462 // Build a mock message handler and wrap it in a dart port.
464 Dart_Port port_id = PortMap::CreatePort(&handler);
465 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
466 {
467 TransitionVMToNative transition(thread);
470 }
471
472 Array& service_msg = Array::Handle();
473
474 // Fetch object.
475 service_msg = EvalF(lib,
476 "[0, port, '0', 'getObject', "
477 "['objectId'], ['objects/%" Pd "']]",
478 id);
479 HandleIsolateMessage(isolate, service_msg);
480 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
481 // Check type.
482 EXPECT_SUBSTRING("\"type\":\"Object\"", handler.msg());
483 EXPECT_SUBSTRING("\"_vmType\":\"LocalVarDescriptors\"", handler.msg());
484 // Check for members array.
485 EXPECT_SUBSTRING("\"members\":[", handler.msg());
486}
487
488static void WeakHandleFinalizer(void* isolate_callback_data, void* peer) {}
489
490ISOLATE_UNIT_TEST_CASE(Service_PersistentHandles) {
491 const char* kScript =
492 "var port;\n" // Set to our mock port by C++.
493 "\n"
494 "class A {\n"
495 " var a;\n"
496 "}\n"
497 "var global = new A();\n"
498 "main() {\n"
499 " return global;\n"
500 "}";
501
502 Isolate* isolate = thread->isolate();
503 isolate->set_is_runnable(true);
504
505 Dart_Handle lib;
506 Dart_PersistentHandle persistent_handle;
507 Dart_WeakPersistentHandle weak_persistent_handle;
508 {
509 TransitionVMToNative transition(thread);
510 lib = TestCase::LoadTestScript(kScript, nullptr);
511 EXPECT_VALID(lib);
512 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
514
515 // Create a persistent handle to global.
516 persistent_handle = Dart_NewPersistentHandle(result);
517
518 // Create a weak persistent handle to global.
519 weak_persistent_handle = Dart_NewWeakPersistentHandle(
520 result, reinterpret_cast<void*>(0xdeadbeef), 128, WeakHandleFinalizer);
521 }
522
523 // Build a mock message handler and wrap it in a dart port.
525 Dart_Port port_id = PortMap::CreatePort(&handler);
526 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
527 {
528 TransitionVMToNative transition(thread);
531 }
532
533 Array& service_msg = Array::Handle();
534
535 // Get persistent handles.
536 service_msg = Eval(lib, "[0, port, '0', '_getPersistentHandles', [], []]");
537 HandleIsolateMessage(isolate, service_msg);
538 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
539 // Look for a heart beat.
540 EXPECT_SUBSTRING("\"type\":\"_PersistentHandles\"", handler.msg());
541 EXPECT_SUBSTRING("\"peer\":\"0xdeadbeef\"", handler.msg());
542 EXPECT_SUBSTRING("\"name\":\"A\"", handler.msg());
543 EXPECT_SUBSTRING("\"externalSize\":\"128\"", handler.msg());
544
545 // Delete persistent handles.
546 {
547 TransitionVMToNative transition(thread);
548 Dart_DeletePersistentHandle(persistent_handle);
549 Dart_DeleteWeakPersistentHandle(weak_persistent_handle);
550 }
551
552 // Get persistent handles (again).
553 service_msg = Eval(lib, "[0, port, '0', '_getPersistentHandles', [], []]");
554 HandleIsolateMessage(isolate, service_msg);
555 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
556 EXPECT_SUBSTRING("\"type\":\"_PersistentHandles\"", handler.msg());
557 // Verify that old persistent handles are not present.
558 EXPECT_NOTSUBSTRING("\"peer\":\"0xdeadbeef\"", handler.msg());
559 EXPECT_NOTSUBSTRING("\"name\":\"A\"", handler.msg());
560 EXPECT_NOTSUBSTRING("\"externalSize\":\"128\"", handler.msg());
561}
562
563static bool alpha_callback(const char* name,
564 const char** option_keys,
565 const char** option_values,
566 intptr_t num_options,
567 void* user_data,
568 const char** result) {
569 *result = Utils::StrDup("alpha");
570 return true;
571}
572
573static bool beta_callback(const char* name,
574 const char** option_keys,
575 const char** option_values,
576 intptr_t num_options,
577 void* user_data,
578 const char** result) {
579 *result = Utils::StrDup("beta");
580 return false;
581}
582
583ISOLATE_UNIT_TEST_CASE(Service_EmbedderRootHandler) {
584 const char* kScript =
585 "var port;\n" // Set to our mock port by C++.
586 "\n"
587 "var x = 7;\n"
588 "main() {\n"
589 " x = x * x;\n"
590 " x = (x / 13).floor();\n"
591 "}";
592
593 Dart_Handle lib;
594 {
595 TransitionVMToNative transition(thread);
596
599
600 lib = TestCase::LoadTestScript(kScript, nullptr);
601 EXPECT_VALID(lib);
602 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
604 }
605
606 // Build a mock message handler and wrap it in a dart port.
608 Dart_Port port_id = PortMap::CreatePort(&handler);
609 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
610 {
611 TransitionVMToNative transition(thread);
614 }
615
616 Array& service_msg = Array::Handle();
617 service_msg = Eval(lib, "[0, port, '\"', 'alpha', [], []]");
618 HandleRootMessage(service_msg);
619 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
620 EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"result\":alpha,\"id\":\"\\\"\"}",
621 handler.msg());
622 service_msg = Eval(lib, "[0, port, 1, 'beta', [], []]");
623 HandleRootMessage(service_msg);
624 EXPECT_EQ(MessageHandler::kOK, handler.HandleNextMessage());
625 EXPECT_STREQ("{\"jsonrpc\":\"2.0\", \"error\":beta,\"id\":1}", handler.msg());
626}
627
628ISOLATE_UNIT_TEST_CASE(Service_EmbedderIsolateHandler) {
629 const char* kScript =
630 "var port;\n" // Set to our mock port by C++.
631 "\n"
632 "var x = 7;\n"
633 "main() {\n"
634 " x = x * x;\n"
635 " x = (x / 13).floor();\n"
636 "}";
637
638 Dart_Handle lib;
639 {
640 TransitionVMToNative transition(thread);
641
643 nullptr);
645
646 lib = TestCase::LoadTestScript(kScript, nullptr);
647 EXPECT_VALID(lib);
648 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
650 }
651
652 // Build a mock message handler and wrap it in a dart port.
654 Dart_Port port_id = PortMap::CreatePort(&handler);
655 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
656 {
657 TransitionVMToNative transition(thread);
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;
683 }
684}
685
686ISOLATE_UNIT_TEST_CASE(Service_Profile) {
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, nullptr);
704 EXPECT_VALID(lib);
705 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
707 }
708
709 // Build a mock message handler and wrap it in a dart port.
711 Dart_Port port_id = PortMap::CreatePort(&handler);
712 Dart_Handle port = Api::NewHandle(thread, SendPort::New(port_id));
713 {
714 TransitionVMToNative transition(thread);
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
729ISOLATE_UNIT_TEST_CASE(Service_ParseJSONArray) {
730 {
731 const auto& elements =
733 EXPECT_EQ(-1, ParseJSONArray(thread, "", elements));
734 EXPECT_EQ(-1, ParseJSONArray(thread, "[", elements));
735 }
736
737 {
738 const auto& elements =
740 EXPECT_EQ(0, ParseJSONArray(thread, "[]", elements));
741 EXPECT_EQ(0, elements.Length());
742 }
743
744 {
745 const auto& elements =
747 EXPECT_EQ(0, ParseJSONArray(thread, "[a]", elements));
748 EXPECT_EQ(1, elements.Length());
749 auto& element = String::Handle();
750 element ^= elements.At(0);
751 EXPECT(element.Equals("a"));
752 }
753
754 {
755 const auto& elements =
757 EXPECT_EQ(0, ParseJSONArray(thread, "[abc, def]", elements));
758 EXPECT_EQ(2, elements.Length());
759 auto& element = String::Handle();
760 element ^= elements.At(0);
761 EXPECT(element.Equals("abc"));
762 element ^= elements.At(1);
763 EXPECT(element.Equals("def"));
764 }
765
766 {
767 const auto& elements =
769 EXPECT_EQ(0, ParseJSONArray(thread, "[abc, def, ghi]", elements));
770 EXPECT_EQ(3, elements.Length());
771 auto& element = String::Handle();
772 element ^= elements.At(0);
773 EXPECT(element.Equals("abc"));
774 element ^= elements.At(1);
775 EXPECT(element.Equals("def"));
776 element ^= elements.At(2);
777 EXPECT(element.Equals("ghi"));
778 }
779
780 {
781 const auto& elements =
783 EXPECT_EQ(0, ParseJSONArray(thread, "[abc, , ghi]", elements));
784 EXPECT_EQ(3, elements.Length());
785 auto& element = String::Handle();
786 element ^= elements.At(0);
787 EXPECT(element.Equals("abc"));
788 element ^= elements.At(1);
789 EXPECT(element.Equals(""));
790 element ^= elements.At(2);
791 EXPECT(element.Equals("ghi"));
792 }
793}
794
795#endif // !PRODUCT
796
797} // namespace dart
static const size_t kBufferSize
Definition: SkString.cpp:27
#define EXPECT(type, expectedAlignment, expectedSize)
static Dart_Handle NewHandle(Thread *thread, ObjectPtr raw)
static ObjectPtr UnwrapHandle(Dart_Handle object)
ObjectPtr At(intptr_t index) const
Definition: object.h:10875
intptr_t Length() const
Definition: object.h:10829
static ArrayPtr MakeFixedLength(const GrowableObjectArray &growable_array, bool unique=false)
Definition: object.cc:24935
uword Size() const
Definition: object.h:6903
PcDescriptorsPtr pc_descriptors() const
Definition: object.h:6927
LocalVarDescriptorsPtr GetLocalVarDescriptors() const
Definition: object.cc:17625
uword PayloadStart() const
Definition: object.h:6850
int64_t compile_timestamp() const
Definition: object.h:7230
CodePtr CurrentCode() const
Definition: object.h:3177
void Add(const Object &value, Heap::Space space=Heap::kNew) const
Definition: object.cc:24991
static GrowableObjectArrayPtr New(Heap::Space space=Heap::kNew)
Definition: object.h:11144
static Isolate * Current()
Definition: isolate.h:986
void PrintJSON(JSONStream *stream, bool ref=true)
Definition: isolate.cc:3084
void set_is_runnable(bool value)
Definition: isolate.h:1096
ObjectIdRing * EnsureObjectIdRing()
Definition: isolate.cc:3014
Thread * thread() const
MessageStatus HandleNextMessage()
int32_t GetIdForObject(ObjectPtr raw_obj, IdPolicy policy=kAllocateId)
static ObjectPtr null()
Definition: object.h:433
ObjectPtr ptr() const
Definition: object.h:332
bool IsNull() const
Definition: object.h:363
static Object & Handle()
Definition: object.h:407
static void ClosePorts(MessageHandler *handler)
Definition: port.cc:128
static Dart_Port CreatePort(MessageHandler *handler)
Definition: port.cc:55
static void Init()
Definition: profiler.cc:573
static FunctionPtr ResolveDynamicFunction(Zone *zone, const Class &receiver_class, const String &function_name)
Definition: resolver.cc:176
void Init(ObjectIdRing *ring, ObjectIdRing::IdPolicy policy)
Definition: service.cc:374
virtual char * GetServiceId(const Object &obj)
Definition: service.cc:380
static SendPortPtr New(Dart_Port id, Heap::Space space=Heap::kNew)
Definition: object.cc:25812
MessageStatus HandleMessage(std::unique_ptr< Message > message)
Definition: service_test.cc:42
const char * msg() const
Definition: service_test.cc:73
virtual Isolate * isolate() const
Definition: service_test.cc:75
static ErrorPtr HandleRootMessage(const Array &message)
Definition: service.cc:1059
static ErrorPtr HandleIsolateMessage(Isolate *isolate, const Array &message)
Definition: service.cc:1069
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition: object.cc:23698
static const char * ToCString(Thread *thread, StringPtr ptr)
Definition: object.cc:24126
static StringPtr New(Thread *thread, const char *cstr)
Definition: symbols.h:723
static Dart_Handle LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri=RESOLVED_USER_TEST_URI, bool finalize=true, bool allow_compile_errors=false)
Definition: unit_test.cc:436
Zone * zone() const
Definition: thread_state.h:37
static Thread * Current()
Definition: thread.h:362
void * DataAddr(intptr_t byte_offset) const
Definition: object.h:11571
static int SNPrint(char *str, size_t size, const char *format,...) PRINTF_ATTRIBUTE(3
static char * StrDup(const char *s)
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
ElementType * Alloc(intptr_t length)
int64_t Dart_Port
Definition: dart_api.h:1525
struct _Dart_Handle * Dart_Handle
Definition: dart_api.h:258
Dart_Handle Dart_PersistentHandle
Definition: dart_api.h:259
struct _Dart_WeakPersistentHandle * Dart_WeakPersistentHandle
Definition: dart_api.h:260
#define ASSERT(E)
uint8_t value
GAsyncResult * result
Win32Message message
va_start(args, format)
va_end(args)
Definition: dart_vm.cc:33
DART_EXPORT Dart_WeakPersistentHandle Dart_NewWeakPersistentHandle(Dart_Handle object, void *peer, intptr_t external_allocation_size, Dart_HandleFinalizer callback)
ObjectPtr ReadMessage(Thread *thread, Message *message)
static ArrayPtr EvalF(Dart_Handle lib, const char *fmt,...)
const char *const name
Dart_Handle Dart_EvaluateStaticExpr(Dart_Handle lib_handle, Dart_Handle expr_in)
static void HandleIsolateMessage(Isolate *isolate, const Array &msg)
DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
DART_EXPORT bool Dart_HasStickyError()
DART_EXPORT bool Dart_IsUnhandledExceptionError(Dart_Handle object)
static ArrayPtr Eval(Dart_Handle lib, const char *expr)
Definition: service_test.cc:81
FunctionPtr GetFunction(const Library &lib, const char *name)
uintptr_t uword
Definition: globals.h:501
DART_EXPORT void Dart_RegisterRootServiceRequestCallback(const char *name, Dart_ServiceRequestCallback callback, void *user_data)
DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object)
DART_EXPORT void Dart_DeleteWeakPersistentHandle(Dart_WeakPersistentHandle object)
ISOLATE_UNIT_TEST_CASE(StackAllocatedDestruction)
DEFINE_FLAG(bool, print_cluster_information, false, "Print information about clusters written to snapshot")
static void WeakHandleFinalizer(void *isolate_callback_data, void *peer)
static void EnableProfiler()
ClassPtr GetClass(const Library &lib, const char *name)
DART_EXPORT Dart_Handle Dart_SetField(Dart_Handle container, Dart_Handle name, Dart_Handle value)
Dart_Handle NewString(const char *str)
DART_EXPORT void Dart_SetPausedOnExit(bool paused)
DART_EXPORT bool Dart_IsNull(Dart_Handle object)
DART_EXPORT void Dart_SetStickyError(Dart_Handle error)
DART_EXPORT void Dart_RegisterIsolateServiceRequestCallback(const char *name, Dart_ServiceRequestCallback callback, void *user_data)
static bool beta_callback(const char *name, const char **option_keys, const char **option_values, intptr_t num_options, void *user_data, const char **result)
intptr_t ParseJSONArray(Thread *thread, const char *str, const GrowableObjectArray &elements)
Definition: service.cc:3660
static bool alpha_callback(const char *name, const char **option_keys, const char **option_values, intptr_t num_options, void *user_data, const char **result)
static void HandleRootMessage(const Array &message)
DART_EXPORT Dart_PersistentHandle Dart_NewPersistentHandle(Dart_Handle object)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service port
Definition: switches.h:87
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
static SkString fmt(SkColor4f c)
Definition: p3.cpp:43
#define Px
Definition: globals.h:410
#define Px64
Definition: globals.h:418
#define Pd
Definition: globals.h:408
void * user_data
#define EXPECT_VALID(handle)
Definition: unit_test.h:643