1// Copyright (c) 2012, 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#include <utility>
7
8#include "include/dart_native_api.h"
9#include "platform/assert.h"
10#include "platform/unicode.h"
11#include "vm/bootstrap_natives.h"
12#include "vm/class_finalizer.h"
13#include "vm/dart.h"
14#include "vm/dart_api_impl.h"
15#include "vm/dart_api_message.h"
16#include "vm/dart_entry.h"
17#include "vm/exceptions.h"
18#include "vm/hash_table.h"
19#include "vm/lockers.h"
20#include "vm/longjump.h"
21#include "vm/message_handler.h"
22#include "vm/object.h"
23#include "vm/object_store.h"
24#include "vm/port.h"
25#include "vm/resolver.h"
26#include "vm/service.h"
27#include "vm/snapshot.h"
28#include "vm/symbols.h"
29
30namespace dart {
31
32DEFINE_NATIVE_ENTRY(CapabilityImpl_factory, 0, 1) {
33 ASSERT(
34 TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)).IsNull());
35 uint64_t id = isolate->random()->NextUInt64();
36 return Capability::New(id);
37}
38
39DEFINE_NATIVE_ENTRY(CapabilityImpl_equals, 0, 2) {
40 GET_NON_NULL_NATIVE_ARGUMENT(Capability, recv, arguments->NativeArgAt(0));
41 GET_NON_NULL_NATIVE_ARGUMENT(Capability, other, arguments->NativeArgAt(1));
42 return (recv.Id() == other.Id()) ? Bool::True().raw() : Bool::False().raw();
43}
44
45DEFINE_NATIVE_ENTRY(CapabilityImpl_get_hashcode, 0, 1) {
46 GET_NON_NULL_NATIVE_ARGUMENT(Capability, cap, arguments->NativeArgAt(0));
47 int64_t id = cap.Id();
48 int32_t hi = static_cast<int32_t>(id >> 32);
49 int32_t lo = static_cast<int32_t>(id);
50 int32_t hash = (hi ^ lo) & kSmiMax;
51 return Smi::New(hash);
52}
53
54DEFINE_NATIVE_ENTRY(RawReceivePortImpl_factory, 0, 1) {
55 ASSERT(
56 TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)).IsNull());
57 Dart_Port port_id = PortMap::CreatePort(isolate->message_handler());
58 return ReceivePort::New(port_id, false /* not control port */);
59}
60
61DEFINE_NATIVE_ENTRY(RawReceivePortImpl_get_id, 0, 1) {
62 GET_NON_NULL_NATIVE_ARGUMENT(ReceivePort, port, arguments->NativeArgAt(0));
63 return Integer::New(port.Id());
64}
65
66DEFINE_NATIVE_ENTRY(RawReceivePortImpl_get_sendport, 0, 1) {
67 GET_NON_NULL_NATIVE_ARGUMENT(ReceivePort, port, arguments->NativeArgAt(0));
68 return port.send_port();
69}
70
71DEFINE_NATIVE_ENTRY(RawReceivePortImpl_closeInternal, 0, 1) {
72 GET_NON_NULL_NATIVE_ARGUMENT(ReceivePort, port, arguments->NativeArgAt(0));
73 Dart_Port id = port.Id();
74 PortMap::ClosePort(id);
75 return Integer::New(id);
76}
77
78DEFINE_NATIVE_ENTRY(SendPortImpl_get_id, 0, 1) {
79 GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
80 return Integer::New(port.Id());
81}
82
83DEFINE_NATIVE_ENTRY(SendPortImpl_get_hashcode, 0, 1) {
84 GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
85 int64_t id = port.Id();
86 int32_t hi = static_cast<int32_t>(id >> 32);
87 int32_t lo = static_cast<int32_t>(id);
88 int32_t hash = (hi ^ lo) & kSmiMax;
89 return Smi::New(hash);
90}
91
92DEFINE_NATIVE_ENTRY(SendPortImpl_sendInternal_, 0, 2) {
93 GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
94 // TODO(iposva): Allow for arbitrary messages to be sent.
95 GET_NON_NULL_NATIVE_ARGUMENT(Instance, obj, arguments->NativeArgAt(1));
96
97 const Dart_Port destination_port_id = port.Id();
98 const bool can_send_any_object = isolate->origin_id() == port.origin_id();
99
100 if (ApiObjectConverter::CanConvert(obj.raw())) {
101 PortMap::PostMessage(
102 Message::New(destination_port_id, obj.raw(), Message::kNormalPriority));
103 } else {
104 MessageWriter writer(can_send_any_object);
105 // TODO(turnidge): Throw an exception when the return value is false?
106 PortMap::PostMessage(writer.WriteMessage(obj, destination_port_id,
107 Message::kNormalPriority));
108 }
109 return Object::null();
110}
111
112class ObjectPtrSetTraitsLayout {
113 public:
114 static bool ReportStats() { return false; }
115 static const char* Name() { return "RawObjectPtrSetTraits"; }
116
117 static bool IsMatch(const ObjectPtr a, const ObjectPtr b) { return a == b; }
118
119 static uword Hash(const ObjectPtr obj) { return static_cast<uword>(obj); }
120};
121
122static ObjectPtr ValidateMessageObject(Zone* zone,
123 Isolate* isolate,
124 const Object& obj) {
125 TIMELINE_DURATION(Thread::Current(), Isolate, "ValidateMessageObject");
126
127 class SendMessageValidator : public ObjectPointerVisitor {
128 public:
129 SendMessageValidator(IsolateGroup* isolate_group,
130 WeakTable* visited,
131 MallocGrowableArray<ObjectPtr>* const working_set)
132 : ObjectPointerVisitor(isolate_group),
133 visited_(visited),
134 working_set_(working_set) {}
135
136 private:
137 void VisitPointers(ObjectPtr* from, ObjectPtr* to) {
138 for (ObjectPtr* raw = from; raw <= to; raw++) {
139 if (!(*raw)->IsHeapObject() || (*raw)->ptr()->IsCanonical()) {
140 continue;
141 }
142 if (visited_->GetValueExclusive(*raw) == 1) {
143 continue;
144 }
145 visited_->SetValueExclusive(*raw, 1);
146 working_set_->Add(*raw);
147 }
148 }
149
150 WeakTable* visited_;
151 MallocGrowableArray<ObjectPtr>* const working_set_;
152 };
153 if (!obj.raw()->IsHeapObject() || obj.raw()->ptr()->IsCanonical()) {
154 return obj.raw();
155 }
156 ClassTable* class_table = isolate->class_table();
157
158 Class& klass = Class::Handle(zone);
159 Closure& closure = Closure::Handle(zone);
160
161 MallocGrowableArray<ObjectPtr> working_set;
162 std::unique_ptr<WeakTable> visited(new WeakTable());
163
164 NoSafepointScope no_safepoint;
165 SendMessageValidator visitor(isolate->group(), visited.get(), &working_set);
166
167 visited->SetValueExclusive(obj.raw(), 1);
168 working_set.Add(obj.raw());
169
170 while (!working_set.is_empty()) {
171 ObjectPtr raw = working_set.RemoveLast();
172
173 if (visited->GetValueExclusive(raw) > 0) {
174 continue;
175 }
176 visited->SetValueExclusive(raw, 1);
177
178 const intptr_t cid = raw->GetClassId();
179 switch (cid) {
180 // List below matches the one in raw_object_snapshot.cc
181#define MESSAGE_SNAPSHOT_ILLEGAL(type) \
182 case k##type##Cid: \
183 return Exceptions::CreateUnhandledException( \
184 zone, Exceptions::kArgumentValue, \
185 "Illegal argument in isolate message : (object is a " #type ")");
186
187 MESSAGE_SNAPSHOT_ILLEGAL(DynamicLibrary);
188 MESSAGE_SNAPSHOT_ILLEGAL(MirrorReference);
189 MESSAGE_SNAPSHOT_ILLEGAL(Pointer);
190 MESSAGE_SNAPSHOT_ILLEGAL(ReceivePort);
191 MESSAGE_SNAPSHOT_ILLEGAL(RegExp);
192 MESSAGE_SNAPSHOT_ILLEGAL(StackTrace);
193 MESSAGE_SNAPSHOT_ILLEGAL(UserTag);
194
195 case kClosureCid: {
196 closure = Closure::RawCast(raw);
197 FunctionPtr func = closure.function();
198 // We only allow closure of top level methods or static functions in a
199 // class to be sent in isolate messages.
200 if (!Function::IsImplicitStaticClosureFunction(func)) {
201 return Exceptions::CreateUnhandledException(
202 zone, Exceptions::kArgumentValue, "Closures are not allowed");
203 }
204 break;
205 }
206 default:
207 if (cid >= kNumPredefinedCids) {
208 klass = class_table->At(cid);
209 if (klass.num_native_fields() != 0) {
210 return Exceptions::CreateUnhandledException(
211 zone, Exceptions::kArgumentValue,
212 "Objects that extend NativeWrapper are not allowed");
213 }
214 }
215 }
216 raw->ptr()->VisitPointers(&visitor);
217 }
218 isolate->set_forward_table_new(nullptr);
219 return obj.raw();
220}
221
222DEFINE_NATIVE_ENTRY(SendPortImpl_sendAndExitInternal_, 0, 2) {
223 GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
224 if (!PortMap::IsReceiverInThisIsolateGroup(port.Id(), isolate->group())) {
225 const auto& error =
226 String::Handle(String::New("sendAndExit is only supported across "
227 "isolates spawned via spawnFunction."));
228 Exceptions::ThrowArgumentError(error);
229 UNREACHABLE();
230 }
231
232 GET_NON_NULL_NATIVE_ARGUMENT(Instance, obj, arguments->NativeArgAt(1));
233
234 Object& validated_result = Object::Handle(zone);
235 Object& msg_obj = Object::Handle(zone, obj.raw());
236 validated_result = ValidateMessageObject(zone, isolate, msg_obj);
237 if (validated_result.IsUnhandledException()) {
238 Exceptions::PropagateError(Error::Cast(validated_result));
239 UNREACHABLE();
240 }
241 PersistentHandle* handle =
242 isolate->group()->api_state()->AllocatePersistentHandle();
243 handle->set_raw(msg_obj);
244 isolate->bequeath(std::unique_ptr<Bequest>(new Bequest(handle, port.Id())));
245 // TODO(aam): Ensure there are no dart api calls after this point as we want
246 // to ensure that validated message won't get tampered with.
247 Isolate::KillIfExists(isolate, Isolate::LibMsgId::kKillMsg);
248 // Drain interrupts before running so any IMMEDIATE operations on the current
249 // isolate happen synchronously.
250 const Error& error = Error::Handle(thread->HandleInterrupts());
251 RELEASE_ASSERT(error.IsUnwindError());
252 Exceptions::PropagateError(error);
253 // We will never execute dart code again in this isolate.
254 return Object::null();
255}
256
257static void ThrowIsolateSpawnException(const String& message) {
258 const Array& args = Array::Handle(Array::New(1));
259 args.SetAt(0, message);
260 Exceptions::ThrowByType(Exceptions::kIsolateSpawn, args);
261}
262
263class SpawnIsolateTask : public ThreadPool::Task {
264 public:
265 SpawnIsolateTask(Isolate* parent_isolate,
266 std::unique_ptr<IsolateSpawnState> state,
267 bool in_new_isolate_group)
268 : parent_isolate_(parent_isolate),
269 state_(std::move(state)),
270 in_new_isolate_group_(in_new_isolate_group) {
271 parent_isolate->IncrementSpawnCount();
272 }
273
274 ~SpawnIsolateTask() override {
275 if (parent_isolate_ != nullptr) {
276 parent_isolate_->DecrementSpawnCount();
277 }
278 }
279
280 void Run() override {
281 auto group = state_->isolate_group();
282
283 // The create isolate group call back is mandatory. If not provided we
284 // cannot spawn isolates.
285 Dart_IsolateGroupCreateCallback create_group_callback =
286 Isolate::CreateGroupCallback();
287 if (create_group_callback == nullptr) {
288 FailedSpawn("Isolate spawn is not supported by this Dart embedder\n");
289 return;
290 }
291
292 // The initialize callback is optional atm, we fall back to creating isolate
293 // groups if it was not provided.
294 Dart_InitializeIsolateCallback initialize_callback =
295 Isolate::InitializeCallback();
296
297 const char* name = (state_->debug_name() == NULL) ? state_->function_name()
298 : state_->debug_name();
299 ASSERT(name != NULL);
300
301 // Create a new isolate.
302 char* error = nullptr;
303 Isolate* isolate = nullptr;
304 if (!FLAG_enable_isolate_groups || group == nullptr ||
305 initialize_callback == nullptr || in_new_isolate_group_) {
306 // Make a copy of the state's isolate flags and hand it to the callback.
307 Dart_IsolateFlags api_flags = *(state_->isolate_flags());
308 isolate = reinterpret_cast<Isolate*>((create_group_callback)(
309 state_->script_url(), name, nullptr, state_->package_config(),
310 &api_flags, parent_isolate_->init_callback_data(), &error));
311 parent_isolate_->DecrementSpawnCount();
312 parent_isolate_ = nullptr;
313 } else {
314 if (initialize_callback == nullptr) {
315 FailedSpawn("Isolate spawn is not supported by this embedder.");
316 return;
317 }
318
319#if defined(DART_PRECOMPILED_RUNTIME)
320 isolate = CreateWithinExistingIsolateGroupAOT(group, name, &error);
321#else
322 isolate = CreateWithinExistingIsolateGroup(group, name, &error);
323#endif
324 parent_isolate_->DecrementSpawnCount();
325 parent_isolate_ = nullptr;
326 if (isolate == nullptr) {
327 FailedSpawn(error);
328 free(error);
329 return;
330 }
331
332 void* child_isolate_data = nullptr;
333 bool success = initialize_callback(&child_isolate_data, &error);
334 isolate->set_init_callback_data(child_isolate_data);
335 if (!success) {
336 Dart_ShutdownIsolate();
337 FailedSpawn(error);
338 free(error);
339 return;
340 }
341 Dart_ExitIsolate();
342 }
343
344 if (isolate == nullptr) {
345 FailedSpawn(error);
346 free(error);
347 return;
348 }
349
350 if (state_->origin_id() != ILLEGAL_PORT) {
351 // For isolates spawned using spawnFunction we set the origin_id
352 // to the origin_id of the parent isolate.
353 isolate->set_origin_id(state_->origin_id());
354 }
355 MutexLocker ml(isolate->mutex());
356 state_->set_isolate(isolate);
357 isolate->set_spawn_state(std::move(state_));
358 if (isolate->is_runnable()) {
359 isolate->Run();
360 }
361 }
362
363 private:
364 void FailedSpawn(const char* error) {
365 ReportError(error != nullptr
366 ? error
367 : "Unknown error occured during Isolate spawning.");
368 state_ = nullptr;
369 }
370
371 void ReportError(const char* error) {
372 Dart_CObject error_cobj;
373 error_cobj.type = Dart_CObject_kString;
374 error_cobj.value.as_string = const_cast<char*>(error);
375 if (!Dart_PostCObject(state_->parent_port(), &error_cobj)) {
376 // Perhaps the parent isolate died or closed the port before we
377 // could report the error. Ignore.
378 }
379 }
380
381 Isolate* parent_isolate_;
382 std::unique_ptr<IsolateSpawnState> state_;
383 bool in_new_isolate_group_;
384
385 DISALLOW_COPY_AND_ASSIGN(SpawnIsolateTask);
386};
387
388static const char* String2UTF8(const String& str) {
389 intptr_t len = Utf8::Length(str);
390 char* result = new char[len + 1];
391 str.ToUTF8(reinterpret_cast<uint8_t*>(result), len);
392 result[len] = 0;
393
394 return result;
395}
396
397DEFINE_NATIVE_ENTRY(Isolate_spawnFunction, 0, 11) {
398 GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
399 GET_NON_NULL_NATIVE_ARGUMENT(String, script_uri, arguments->NativeArgAt(1));
400 GET_NON_NULL_NATIVE_ARGUMENT(Instance, closure, arguments->NativeArgAt(2));
401 GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(3));
402 GET_NON_NULL_NATIVE_ARGUMENT(Bool, paused, arguments->NativeArgAt(4));
403 GET_NATIVE_ARGUMENT(Bool, fatalErrors, arguments->NativeArgAt(5));
404 GET_NATIVE_ARGUMENT(SendPort, onExit, arguments->NativeArgAt(6));
405 GET_NATIVE_ARGUMENT(SendPort, onError, arguments->NativeArgAt(7));
406 GET_NATIVE_ARGUMENT(String, packageConfig, arguments->NativeArgAt(8));
407 GET_NATIVE_ARGUMENT(Bool, newIsolateGroup, arguments->NativeArgAt(9));
408 GET_NATIVE_ARGUMENT(String, debugName, arguments->NativeArgAt(10));
409
410 if (closure.IsClosure()) {
411 Function& func = Function::Handle();
412 func = Closure::Cast(closure).function();
413 if (func.IsImplicitClosureFunction() && func.is_static()) {
414#if defined(DEBUG)
415 Context& ctx = Context::Handle();
416 ctx = Closure::Cast(closure).context();
417 ASSERT(ctx.IsNull());
418#endif
419 // Get the parent function so that we get the right function name.
420 func = func.parent_function();
421
422 bool fatal_errors = fatalErrors.IsNull() ? true : fatalErrors.value();
423 Dart_Port on_exit_port = onExit.IsNull() ? ILLEGAL_PORT : onExit.Id();
424 Dart_Port on_error_port = onError.IsNull() ? ILLEGAL_PORT : onError.Id();
425
426 // We first try to serialize the message. In case the message is not
427 // serializable this will throw an exception.
428 SerializedObjectBuffer message_buffer;
429 {
430 MessageWriter writer(/* can_send_any_object = */ true);
431 message_buffer.set_message(writer.WriteMessage(
432 message, ILLEGAL_PORT, Message::kNormalPriority));
433 }
434
435 const char* utf8_package_config =
436 packageConfig.IsNull() ? NULL : String2UTF8(packageConfig);
437 const char* utf8_debug_name =
438 debugName.IsNull() ? NULL : String2UTF8(debugName);
439
440 std::unique_ptr<IsolateSpawnState> state(new IsolateSpawnState(
441 port.Id(), isolate->origin_id(), String2UTF8(script_uri), func,
442 &message_buffer, utf8_package_config, paused.value(), fatal_errors,
443 on_exit_port, on_error_port, utf8_debug_name, isolate->group()));
444
445 // Since this is a call to Isolate.spawn, copy the parent isolate's code.
446 state->isolate_flags()->copy_parent_code = true;
447
448 const bool in_new_isolate_group = newIsolateGroup.value();
449 isolate->group()->thread_pool()->Run<SpawnIsolateTask>(
450 isolate, std::move(state), in_new_isolate_group);
451 return Object::null();
452 }
453 }
454 const String& msg = String::Handle(String::New(
455 "Isolate.spawn expects to be passed a static or top-level function"));
456 Exceptions::ThrowArgumentError(msg);
457 return Object::null();
458}
459
460static const char* CanonicalizeUri(Thread* thread,
461 const Library& library,
462 const String& uri,
463 char** error) {
464 const char* result = NULL;
465 Zone* zone = thread->zone();
466 Isolate* isolate = thread->isolate();
467 if (isolate->HasTagHandler()) {
468 const Object& obj = Object::Handle(
469 isolate->CallTagHandler(Dart_kCanonicalizeUrl, library, uri));
470 if (obj.IsString()) {
471 result = String2UTF8(String::Cast(obj));
472 } else if (obj.IsError()) {
473 Error& error_obj = Error::Handle();
474 error_obj ^= obj.raw();
475 *error = zone->PrintToString("Unable to canonicalize uri '%s': %s",
476 uri.ToCString(), error_obj.ToErrorCString());
477 } else {
478 *error = zone->PrintToString(
479 "Unable to canonicalize uri '%s': "
480 "library tag handler returned wrong type",
481 uri.ToCString());
482 }
483 } else {
484 *error = zone->PrintToString(
485 "Unable to canonicalize uri '%s': no library tag handler found.",
486 uri.ToCString());
487 }
488 return result;
489}
490
491DEFINE_NATIVE_ENTRY(Isolate_spawnUri, 0, 12) {
492 GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
493 GET_NON_NULL_NATIVE_ARGUMENT(String, uri, arguments->NativeArgAt(1));
494 GET_NON_NULL_NATIVE_ARGUMENT(Instance, args, arguments->NativeArgAt(2));
495 GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(3));
496 GET_NON_NULL_NATIVE_ARGUMENT(Bool, paused, arguments->NativeArgAt(4));
497 GET_NATIVE_ARGUMENT(SendPort, onExit, arguments->NativeArgAt(5));
498 GET_NATIVE_ARGUMENT(SendPort, onError, arguments->NativeArgAt(6));
499 GET_NATIVE_ARGUMENT(Bool, fatalErrors, arguments->NativeArgAt(7));
500 GET_NATIVE_ARGUMENT(Bool, checked, arguments->NativeArgAt(8));
501 GET_NATIVE_ARGUMENT(Array, environment, arguments->NativeArgAt(9));
502 GET_NATIVE_ARGUMENT(String, packageConfig, arguments->NativeArgAt(10));
503 GET_NATIVE_ARGUMENT(String, debugName, arguments->NativeArgAt(11));
504
505 bool fatal_errors = fatalErrors.IsNull() ? true : fatalErrors.value();
506 Dart_Port on_exit_port = onExit.IsNull() ? ILLEGAL_PORT : onExit.Id();
507 Dart_Port on_error_port = onError.IsNull() ? ILLEGAL_PORT : onError.Id();
508
509 // We first try to serialize the arguments and the message. In case the
510 // arguments or the message are not serializable this will throw an exception.
511 SerializedObjectBuffer arguments_buffer;
512 SerializedObjectBuffer message_buffer;
513 {
514 MessageWriter writer(/* can_send_any_object = */ false);
515 arguments_buffer.set_message(
516 writer.WriteMessage(args, ILLEGAL_PORT, Message::kNormalPriority));
517 }
518 {
519 MessageWriter writer(/* can_send_any_object = */ false);
520 message_buffer.set_message(
521 writer.WriteMessage(message, ILLEGAL_PORT, Message::kNormalPriority));
522 }
523
524 // Canonicalize the uri with respect to the current isolate.
525 const Library& root_lib =
526 Library::Handle(isolate->object_store()->root_library());
527 char* error = NULL;
528 const char* canonical_uri = CanonicalizeUri(thread, root_lib, uri, &error);
529 if (canonical_uri == NULL) {
530 const String& msg = String::Handle(String::New(error));
531 ThrowIsolateSpawnException(msg);
532 }
533
534 const char* utf8_package_config =
535 packageConfig.IsNull() ? NULL : String2UTF8(packageConfig);
536 const char* utf8_debug_name =
537 debugName.IsNull() ? NULL : String2UTF8(debugName);
538
539 std::unique_ptr<IsolateSpawnState> state(new IsolateSpawnState(
540 port.Id(), canonical_uri, utf8_package_config, &arguments_buffer,
541 &message_buffer, paused.value(), fatal_errors, on_exit_port,
542 on_error_port, utf8_debug_name, /*group=*/nullptr));
543
544 // If we were passed a value then override the default flags state for
545 // checked mode.
546 if (!checked.IsNull()) {
547 Dart_IsolateFlags* flags = state->isolate_flags();
548 flags->enable_asserts = checked.value();
549 }
550
551 // Since this is a call to Isolate.spawnUri, don't copy the parent's code.
552 state->isolate_flags()->copy_parent_code = false;
553
554 const bool in_new_isolate_group = false;
555 isolate->group()->thread_pool()->Run<SpawnIsolateTask>(
556 isolate, std::move(state), in_new_isolate_group);
557 return Object::null();
558}
559
560DEFINE_NATIVE_ENTRY(Isolate_getDebugName, 0, 1) {
561 GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
562 auto name = Isolate::LookupIsolateNameByPort(port.Id());
563 if (name == nullptr) {
564 return String::null();
565 }
566 return String::New(name.get());
567}
568
569DEFINE_NATIVE_ENTRY(Isolate_getPortAndCapabilitiesOfCurrentIsolate, 0, 0) {
570 const Array& result = Array::Handle(Array::New(3));
571 result.SetAt(0, SendPort::Handle(SendPort::New(isolate->main_port())));
572 result.SetAt(
573 1, Capability::Handle(Capability::New(isolate->pause_capability())));
574 result.SetAt(
575 2, Capability::Handle(Capability::New(isolate->terminate_capability())));
576 return result.raw();
577}
578
579DEFINE_NATIVE_ENTRY(Isolate_getCurrentRootUriStr, 0, 0) {
580 const Library& root_lib =
581 Library::Handle(zone, isolate->object_store()->root_library());
582 return root_lib.url();
583}
584
585DEFINE_NATIVE_ENTRY(Isolate_sendOOB, 0, 2) {
586 GET_NON_NULL_NATIVE_ARGUMENT(SendPort, port, arguments->NativeArgAt(0));
587 GET_NON_NULL_NATIVE_ARGUMENT(Array, msg, arguments->NativeArgAt(1));
588
589 // Make sure to route this request to the isolate library OOB mesage handler.
590 msg.SetAt(0, Smi::Handle(Smi::New(Message::kIsolateLibOOBMsg)));
591
592 MessageWriter writer(false);
593 PortMap::PostMessage(
594 writer.WriteMessage(msg, port.Id(), Message::kOOBPriority));
595
596 // Drain interrupts before running so any IMMEDIATE operations on the current
597 // isolate happen synchronously.
598 const Error& error = Error::Handle(thread->HandleInterrupts());
599 if (!error.IsNull()) {
600 Exceptions::PropagateError(error);
601 UNREACHABLE();
602 }
603
604 return Object::null();
605}
606
607static void ExternalTypedDataFinalizer(void* isolate_callback_data,
608 void* peer) {
609 free(peer);
610}
611
612static intptr_t GetTypedDataSizeOrThrow(const Instance& instance) {
613 // From the Dart side we are guaranteed that the type of [instance] is a
614 // subtype of TypedData.
615 if (instance.IsTypedDataBase()) {
616 return TypedDataBase::Cast(instance).LengthInBytes();
617 }
618
619 // This can happen if [instance] is `null` or an instance of a 3rd party class
620 // which implements [TypedData].
621 Exceptions::ThrowArgumentError(instance);
622}
623
624DEFINE_NATIVE_ENTRY(TransferableTypedData_factory, 0, 2) {
625 ASSERT(
626 TypeArguments::CheckedHandle(zone, arguments->NativeArgAt(0)).IsNull());
627
628 GET_NON_NULL_NATIVE_ARGUMENT(Instance, array_instance,
629 arguments->NativeArgAt(1));
630
631 Array& array = Array::Handle();
632 intptr_t array_length;
633 if (array_instance.IsGrowableObjectArray()) {
634 const auto& growable_array = GrowableObjectArray::Cast(array_instance);
635 array ^= growable_array.data();
636 array_length = growable_array.Length();
637 } else if (array_instance.IsArray()) {
638 array ^= Array::Cast(array_instance).raw();
639 array_length = array.Length();
640 } else {
641 Exceptions::ThrowArgumentError(array_instance);
642 UNREACHABLE();
643 }
644 Instance& instance = Instance::Handle();
645 uint64_t total_bytes = 0;
646 const uint64_t kMaxBytes = TypedData::MaxElements(kTypedDataUint8ArrayCid);
647 for (intptr_t i = 0; i < array_length; i++) {
648 instance ^= array.At(i);
649 total_bytes += static_cast<uintptr_t>(GetTypedDataSizeOrThrow(instance));
650 if (total_bytes > kMaxBytes) {
651 const Array& error_args = Array::Handle(Array::New(3));
652 error_args.SetAt(0, array);
653 error_args.SetAt(1, String::Handle(String::New("data")));
654 error_args.SetAt(
655 2, String::Handle(String::NewFormatted(
656 "Aggregated list exceeds max size %" Pu64 "", kMaxBytes)));
657 Exceptions::ThrowByType(Exceptions::kArgumentValue, error_args);
658 UNREACHABLE();
659 }
660 }
661
662 uint8_t* data = reinterpret_cast<uint8_t*>(malloc(total_bytes));
663 if (data == nullptr) {
664 const Instance& exception =
665 Instance::Handle(thread->isolate()->object_store()->out_of_memory());
666 Exceptions::Throw(thread, exception);
667 UNREACHABLE();
668 }
669 intptr_t offset = 0;
670 for (intptr_t i = 0; i < array_length; i++) {
671 instance ^= array.At(i);
672
673 {
674 NoSafepointScope no_safepoint;
675 const auto& typed_data = TypedDataBase::Cast(instance);
676 const intptr_t length_in_bytes = typed_data.LengthInBytes();
677
678 void* source = typed_data.DataAddr(0);
679 // The memory does not overlap.
680 memcpy(data + offset, source, length_in_bytes); // NOLINT
681 offset += length_in_bytes;
682 }
683 }
684 ASSERT(static_cast<uintptr_t>(offset) == total_bytes);
685 return TransferableTypedData::New(data, total_bytes);
686}
687
688DEFINE_NATIVE_ENTRY(TransferableTypedData_materialize, 0, 1) {
689 GET_NON_NULL_NATIVE_ARGUMENT(TransferableTypedData, t,
690 arguments->NativeArgAt(0));
691
692 void* peer;
693 {
694 NoSafepointScope no_safepoint;
695 peer = thread->heap()->GetPeer(t.raw());
696 // Assume that object's Peer is only used to track transferrability state.
697 ASSERT(peer != nullptr);
698 }
699
700 TransferableTypedDataPeer* tpeer =
701 reinterpret_cast<TransferableTypedDataPeer*>(peer);
702 const intptr_t length = tpeer->length();
703 uint8_t* data = tpeer->data();
704 if (data == nullptr) {
705 const auto& error = String::Handle(String::New(
706 "Attempt to materialize object that was transferred already."));
707 Exceptions::ThrowArgumentError(error);
708 UNREACHABLE();
709 }
710 tpeer->ClearData();
711
712 const ExternalTypedData& typed_data = ExternalTypedData::Handle(
713 ExternalTypedData::New(kExternalTypedDataUint8ArrayCid, data, length,
714 thread->heap()->SpaceForExternal(length)));
715 FinalizablePersistentHandle::New(thread->isolate(), typed_data,
716 /* peer= */ data,
717 &ExternalTypedDataFinalizer, length,
718 /*auto_delete=*/true);
719 return typed_data.raw();
720}
721
722} // namespace dart
723