ec36e02c28
replace it with the beginnings of a local (same isolate) IsolateMirror implementation. Removed old mirror tests and added two new mirror tests. Even though mirrors.cc is part of the vm, I chose to implement most of it using the dart embedding interface instead of our internal interfaces because the embedding interface was more convenient. mirrors.cc is basically all new in this CL -- don't pay any attention to diffs for that file. Added dart embedding functions required for the functionality in this CL: Dart_DebugName, Dart_GetNativeInstanceFieldCount, Dart_RootLibrary, Dart_RegisteredLibraryUrls, and Dart_LibraryName. Extended or modified some existing dart api functions, primarily to make them propagate error handles properly. Added tests for new dart embedding api functionality. Added the ability to determine if a port is local to the current isolate. Extended NotImplementedException to accept an optional string argument. I wanted to give more descriptive error messages. Review URL: https://chromiumcodereview.appspot.com//10416050 git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@8117 260f80e4-7a28-3924-810f-c04153c831b5
247 lines
6.0 KiB
C++
247 lines
6.0 KiB
C++
// Copyright (c) 2012, 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 "vm/port.h"
|
|
|
|
#include "platform/utils.h"
|
|
#include "vm/dart_api_impl.h"
|
|
#include "vm/isolate.h"
|
|
#include "vm/message_handler.h"
|
|
#include "vm/thread.h"
|
|
|
|
namespace dart {
|
|
|
|
DECLARE_FLAG(bool, trace_isolates);
|
|
|
|
Mutex* PortMap::mutex_ = NULL;
|
|
PortMap::Entry* PortMap::map_ = NULL;
|
|
MessageHandler* PortMap::deleted_entry_ = reinterpret_cast<MessageHandler*>(1);
|
|
intptr_t PortMap::capacity_ = 0;
|
|
intptr_t PortMap::used_ = 0;
|
|
intptr_t PortMap::deleted_ = 0;
|
|
Dart_Port PortMap::next_port_ = 7111;
|
|
|
|
|
|
intptr_t PortMap::FindPort(Dart_Port port) {
|
|
intptr_t index = port % capacity_;
|
|
intptr_t start_index = index;
|
|
Entry entry = map_[index];
|
|
while (entry.handler != NULL) {
|
|
if (entry.port == port) {
|
|
return index;
|
|
}
|
|
index = (index + 1) % capacity_;
|
|
// Prevent endless loops.
|
|
ASSERT(index != start_index);
|
|
entry = map_[index];
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
void PortMap::Rehash(intptr_t new_capacity) {
|
|
Entry* new_ports = new Entry[new_capacity];
|
|
memset(new_ports, 0, new_capacity * sizeof(Entry));
|
|
|
|
for (intptr_t i = 0; i < capacity_; i++) {
|
|
Entry entry = map_[i];
|
|
// Skip free and deleted entries.
|
|
if (entry.port != 0) {
|
|
intptr_t new_index = entry.port % new_capacity;
|
|
while (new_ports[new_index].port != 0) {
|
|
new_index = (new_index + 1) % new_capacity;
|
|
}
|
|
new_ports[new_index] = entry;
|
|
}
|
|
}
|
|
delete[] map_;
|
|
map_ = new_ports;
|
|
capacity_ = new_capacity;
|
|
deleted_ = 0;
|
|
}
|
|
|
|
|
|
Dart_Port PortMap::AllocatePort() {
|
|
Dart_Port result = next_port_;
|
|
|
|
do {
|
|
// TODO(iposva): Use an approved hashing function to have less predictable
|
|
// port ids, or make them not accessible from Dart code or both.
|
|
next_port_++;
|
|
} while (FindPort(next_port_) >= 0);
|
|
|
|
ASSERT(result != 0);
|
|
return result;
|
|
}
|
|
|
|
|
|
void PortMap::SetLive(Dart_Port port) {
|
|
MutexLocker ml(mutex_);
|
|
intptr_t index = FindPort(port);
|
|
ASSERT(index >= 0);
|
|
map_[index].live = true;
|
|
map_[index].handler->increment_live_ports();
|
|
}
|
|
|
|
|
|
void PortMap::MaintainInvariants() {
|
|
intptr_t empty = capacity_ - used_ - deleted_;
|
|
if (used_ > ((capacity_ / 4) * 3)) {
|
|
// Grow the port map.
|
|
Rehash(capacity_ * 2);
|
|
} else if (empty < deleted_) {
|
|
// Rehash without growing the table to flush the deleted slots out of the
|
|
// map.
|
|
Rehash(capacity_);
|
|
}
|
|
}
|
|
|
|
|
|
Dart_Port PortMap::CreatePort(MessageHandler* handler) {
|
|
ASSERT(handler != NULL);
|
|
MutexLocker ml(mutex_);
|
|
#if defined(DEBUG)
|
|
handler->CheckAccess();
|
|
#endif
|
|
|
|
Entry entry;
|
|
entry.port = AllocatePort();
|
|
entry.handler = handler;
|
|
entry.live = false;
|
|
|
|
// Search for the first unused slot. Make use of the knowledge that here is
|
|
// currently no port with this id in the port map.
|
|
ASSERT(FindPort(entry.port) < 0);
|
|
intptr_t index = entry.port % capacity_;
|
|
Entry cur = map_[index];
|
|
// Stop the search at the first found unused (free or deleted) slot.
|
|
while (cur.port != 0) {
|
|
index = (index + 1) % capacity_;
|
|
cur = map_[index];
|
|
}
|
|
|
|
// Insert the newly created port at the index.
|
|
ASSERT(index >= 0);
|
|
ASSERT(index < capacity_);
|
|
ASSERT(map_[index].port == 0);
|
|
ASSERT((map_[index].handler == NULL) ||
|
|
(map_[index].handler == deleted_entry_));
|
|
if (map_[index].handler == deleted_entry_) {
|
|
// Consuming a deleted entry.
|
|
deleted_--;
|
|
}
|
|
map_[index] = entry;
|
|
|
|
// Increment number of used slots and grow if necessary.
|
|
used_++;
|
|
MaintainInvariants();
|
|
|
|
return entry.port;
|
|
}
|
|
|
|
|
|
bool PortMap::ClosePort(Dart_Port port) {
|
|
MessageHandler* handler = NULL;
|
|
{
|
|
MutexLocker ml(mutex_);
|
|
intptr_t index = FindPort(port);
|
|
if (index < 0) {
|
|
return false;
|
|
}
|
|
ASSERT(index < capacity_);
|
|
ASSERT(map_[index].port != 0);
|
|
ASSERT(map_[index].handler != deleted_entry_);
|
|
ASSERT(map_[index].handler != NULL);
|
|
|
|
handler = map_[index].handler;
|
|
#if defined(DEBUG)
|
|
handler->CheckAccess();
|
|
#endif
|
|
// Before releasing the lock mark the slot in the map as deleted. This makes
|
|
// it possible to release the port map lock before flushing all of its
|
|
// pending messages below.
|
|
map_[index].port = 0;
|
|
map_[index].handler = deleted_entry_;
|
|
if (map_[index].live) {
|
|
handler->decrement_live_ports();
|
|
}
|
|
|
|
used_--;
|
|
deleted_++;
|
|
MaintainInvariants();
|
|
}
|
|
handler->ClosePort(port);
|
|
if (!handler->HasLivePorts() && handler->OwnedByPortMap()) {
|
|
delete handler;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
void PortMap::ClosePorts(MessageHandler* handler) {
|
|
{
|
|
MutexLocker ml(mutex_);
|
|
for (intptr_t i = 0; i < capacity_; i++) {
|
|
if (map_[i].handler == handler) {
|
|
// Mark the slot as deleted.
|
|
map_[i].port = 0;
|
|
map_[i].handler = deleted_entry_;
|
|
if (map_[i].live) {
|
|
handler->decrement_live_ports();
|
|
}
|
|
used_--;
|
|
deleted_++;
|
|
}
|
|
}
|
|
MaintainInvariants();
|
|
}
|
|
handler->CloseAllPorts();
|
|
}
|
|
|
|
|
|
bool PortMap::PostMessage(Message* message) {
|
|
MutexLocker ml(mutex_);
|
|
intptr_t index = FindPort(message->dest_port());
|
|
if (index < 0) {
|
|
delete message;
|
|
return false;
|
|
}
|
|
ASSERT(index >= 0);
|
|
ASSERT(index < capacity_);
|
|
MessageHandler* handler = map_[index].handler;
|
|
ASSERT(map_[index].port != 0);
|
|
ASSERT((handler != NULL) && (handler != deleted_entry_));
|
|
handler->PostMessage(message);
|
|
return true;
|
|
}
|
|
|
|
|
|
bool PortMap::IsLocalPort(Dart_Port id) {
|
|
MutexLocker ml(mutex_);
|
|
intptr_t index = FindPort(id);
|
|
if (index < 0) {
|
|
// Port does not exist.
|
|
return false;
|
|
}
|
|
|
|
MessageHandler* handler = map_[index].handler;
|
|
return handler->IsCurrentIsolate();
|
|
}
|
|
|
|
|
|
void PortMap::InitOnce() {
|
|
mutex_ = new Mutex();
|
|
|
|
static const intptr_t kInitialCapacity = 8;
|
|
// TODO(iposva): Verify whether we want to keep exponentially growing.
|
|
ASSERT(Utils::IsPowerOfTwo(kInitialCapacity));
|
|
map_ = new Entry[kInitialCapacity];
|
|
memset(map_, 0, kInitialCapacity * sizeof(Entry));
|
|
capacity_ = kInitialCapacity;
|
|
used_ = 0;
|
|
deleted_ = 0;
|
|
}
|
|
|
|
} // namespace dart
|