Do away with the PromiseQueue.

Instead of queuing messages with promises in them until the promises
are ready, send immediately. This is done by sending a port down which
the receiver sends a port which can be used to signal completion of
the outgoing promise.
Review URL: https://chromereviews.googleplex.com/3573013

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@427 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
benl@google.com
2011-10-14 11:18:12 +00:00
parent fc1b7603b3
commit c0a59669cf
15 changed files with 360 additions and 183 deletions
@@ -317,6 +317,7 @@ public class DartIsolateStubGenerator extends AbstractBackend {
final boolean isVoid = isVoid(returnTypeNode);
final boolean isSimple = isSimpleType(returnTypeNode);
final boolean isProxy = isProxyType(returnTypeNode);
final boolean isPromise = isPromise(returnTypeNode);
if (!isVoid) {
p("return ");
if (!isSimple) {
@@ -328,6 +329,16 @@ public class DartIsolateStubGenerator extends AbstractBackend {
p("Impl(");
}
}
if (isProxy) {
// Note that Promises are Proxies.
p("new PromiseProxy");
if (isPromise) {
printTypeArguments(returnTypeNode);
} else {
p("<SendPort>");
}
p("(");
}
p("this.");
if (isVoid) {
p("send");
@@ -353,6 +364,9 @@ public class DartIsolateStubGenerator extends AbstractBackend {
};
params.acceptList(func.getParams());
p("])");
if (isProxy) {
p(")");
}
if (!isSimple) {
p(")");
}
@@ -396,8 +410,23 @@ public class DartIsolateStubGenerator extends AbstractBackend {
printFunctionName(member);
p("\") {");
nl();
unpackParams(member);
callTarget((DartMethodDefinition)member);
int proxies = unpackParams(member);
String extra = "";
if (proxies != 0) {
p(" Promise done = new Promise();");
nl();
p(" done.waitFor(promises, " + proxies + ");");
nl();
p(" done.addCompleteHandler((_) {");
nl();
gatherProxies(member);
extra = " ";
}
callTarget((DartMethodDefinition)member, extra);
if (proxies != 0) {
p(" });");
nl();
}
p(" }");
first = false;
}
@@ -411,11 +440,11 @@ public class DartIsolateStubGenerator extends AbstractBackend {
nl();
}
private void callTarget(DartMethodDefinition member) {
private void callTarget(DartMethodDefinition member, String extra) {
if (isConstructor(member)) {
return;
}
p(" ");
p(extra + " ");
boolean isVoid = isVoid(member.getFunction().getReturnTypeNode());
if (!isVoid) {
printReturnType(member);
@@ -431,14 +460,14 @@ public class DartIsolateStubGenerator extends AbstractBackend {
nl();
String returnType = stringReturnType(member);
if (stubInterfaces.contains(returnType)) {
p(" SendPort port = Dispatcher.serve(new " + returnType + "$Dispatcher(");
p(extra + " SendPort port = Dispatcher.serve(new " + returnType + "$Dispatcher(");
printFunctionName(member);
p("));");
nl();
p(" reply(port);");
p(extra + " reply(port);");
nl();
} else if (!isVoid) {
p(" reply(");
p(extra + " reply(");
printFunctionName(member);
p(");");
nl();
@@ -521,9 +550,10 @@ public class DartIsolateStubGenerator extends AbstractBackend {
return strType.toString();
}
private void unpackParams(DartNode member) {
DartVisitor visitor = new DartVisitor() {
private int unpackParams(DartNode member) {
class UnpackVisitor extends DartVisitor {
private int pos;
int proxies;
@Override
public boolean visit(DartTypeNode x, DartContext ctx) {
@@ -541,6 +571,7 @@ public class DartIsolateStubGenerator extends AbstractBackend {
@Override
public boolean visit(DartMethodDefinition x, DartContext ctx) {
pos = 1;
proxies = 0;
for (DartParameter param : x.getFunction().getParams()) {
p(" ");
accept(param);
@@ -554,23 +585,85 @@ public class DartIsolateStubGenerator extends AbstractBackend {
public boolean visit(DartParameter x, DartContext ctx) {
boolean isSimpleType = isSimpleType(x.getTypeNode());
accept(x.getTypeNode());
p(" ");
accept(x.getName());
p(" = ");
if (!isSimpleType) {
p("new ");
if (isSimpleType) {
accept(x.getTypeNode());
p("Impl(new Promise<SendPort>.fromValue(");
p(" ");
accept(x.getName());
p(" = ");
} else {
if (proxies == 0) {
p("List<Promise<SendPort>> promises = new List<Promise<SendPort>>();");
nl();
p(" ");
}
p("promises.add(new PromiseProxy<SendPort>(new Promise<SendPort>.fromValue(");
++proxies;
//p("new ");
//accept(x.getTypeNode());
//p("Impl(new Promise<SendPort>.fromValue(");
}
p("message[" + pos + "]");
if (!isSimpleType) {
p("))");
p(")))");
}
p(";");
return false;
}
};
UnpackVisitor visitor = new UnpackVisitor();
visitor.accept(member);
return visitor.proxies;
}
private void gatherProxies(DartNode member) {
class GatherVisitor extends DartVisitor {
private int proxies;
@Override
public boolean visit(DartTypeNode x, DartContext ctx) {
accept(x.getIdentifier());
printTypeArguments(x);
return false;
}
@Override
public boolean visit(DartIdentifier x, DartContext ctx) {
p(x.getTargetName());
return false;
}
@Override
public boolean visit(DartMethodDefinition x, DartContext ctx) {
proxies = 0;
for (DartParameter param : x.getFunction().getParams()) {
accept(param);
}
return false;
}
@Override
public boolean visit(DartParameter x, DartContext ctx) {
boolean isSimpleType = isSimpleType(x.getTypeNode());
if (!isSimpleType) {
p(" ");
accept(x.getTypeNode());
p(" ");
accept(x.getName());
p(" = new ");
accept(x.getTypeNode());
p("Impl(promises[" + proxies + "]);");
++proxies;
nl();
}
return false;
}
};
GatherVisitor visitor = new GatherVisitor();
visitor.accept(member);
}
@@ -608,8 +701,14 @@ public class DartIsolateStubGenerator extends AbstractBackend {
* reply(port);
* } else if (command == "deposit") {
* int amount = message[1];
* Proxy<Purse> source = new Proxy<Purse>.forPort(message[2]);
* target.deposit(amount, source);
* Promise<SendPort> port =
* new PromiseProxy<SendPort>(new Promise<SendPort>.fromValue(message[2]));
* port.addCompletionHandler((_) {
* Purse$Proxy source = new Purse$ProxyImpl(port);
* target.deposit(amount, source);
* });
* //Proxy<Purse> source = new Proxy<Purse>.forPort(message[2]);
* //target.deposit(amount, source);
* } else {
* // TODO(kasperl,benl): Somehow throw an exception instead.
* reply("Exception: command not understood.");
+2 -15
View File
@@ -7,17 +7,8 @@ class SendPortImpl implements SendPort {
const SendPortImpl(this._workerId, this._isolateId, this._receivePortId);
void send(var message, [SendPort replyTo = null]) {
if (PromiseQueue.isEmpty()) {
this._sendNow(message, replyTo);
} else {
_enqueueSend(message, replyTo);
}
}
void _enqueueSend(var message, SendPort replyTo) {
PromiseQueue.enqueue(const []).then((ignored) {
this._sendNow(message, replyTo);
});
// TODO(kasperl): get rid of _sendNow.
this._sendNow(message, replyTo);
}
void _sendNow(var message, SendPort replyTo) native;
@@ -179,10 +170,6 @@ class IsolateNatives {
class _IsolateJsUtil {
static void _promiseQueueProcess() native {
PromiseQueue.process();
}
static void _startIsolate(Isolate isolate, SendPort replyTo) native {
ReceivePort port = new ReceivePort();
replyTo.send(_SPAWNED_SIGNAL, port.toSendPort());
-1
View File
@@ -66,7 +66,6 @@ function isolate$receiveMessage(port, isolate,
var message = isolate$deserializeMessage(serializedMessage);
var replyTo = isolate$deserializeMessage(serializedReplyTo);
native_ReceivePortImpl__invokeCallback(port, message, replyTo);
native__IsolateJsUtil__promiseQueueProcess();
});
}
@@ -275,6 +275,19 @@ class ProxyImpl {
_promise = port;
}
// Note that comparing proxies or using them in maps is illegal
// until they complete.
bool operator ==(var other) {
return (other is ProxyImpl) && _promise.value == other._promise.value;
}
int hashCode() => _promise.value.hashCode();
// TODO: consider making this extend Promise<SendPort> instead?
void addCompleteHandler(void completeHandler()) {
_promise.addCompleteHandler((_) => completeHandler());
}
static ReceivePort register(Dispatcher dispatcher) {
if (_dispatchers === null) {
_dispatchers = new Map<SendPort, Dispatcher>();
@@ -289,7 +302,7 @@ class ProxyImpl {
Dispatcher dispatcher = _dispatchers[_promise.value];
if (dispatcher !== null) return dispatcher.target;
}
throw "Cannot access object of non-local proxy.";
throw new Exception("Cannot access object of non-local proxy.");
}
void send(List message) {
@@ -315,39 +328,46 @@ class ProxyImpl {
});
}
bool operator ==(var other) {
return this === other;
}
// FIXME(benl): generate a more useful hashCode.
int hashCode() => 0;
// Marshal the [message] and pass it to the [process] callback
// function once this proxy and all proxies in the message are
// resolved.
Promise _marshal(List message, process(List marshalled)) {
final promises = new List<Promise>();
promises.add(_promise);
// function. Any promises are converted to a port which expects to
// receive a port from the other side down which the remote promise
// can be completed by sending the promise's completion value.
Promise _marshal(List message, process(List marshalled)) {
return _promise.then((SendPort port) {
List marshalled = new List(message.length);
var marshalled = new List(message.length);
for (int i = 0; i < marshalled.length; i++) {
var entry = message[i];
marshalled[i] = entry; // TODO(kasperl): We probably have to copy here.
if (entry is Proxy) {
promises.add(entry._promise);
} else if (entry is Promise) {
promises.add(entry);
}
}
return PromiseQueue.enqueue(promises).then((ignored) {
for (int i = 0; i < marshalled.length; i++) {
var entry = marshalled[i];
var entry = message[i];
if (entry is Proxy) {
marshalled[i] = entry._promise.value;
} else if (entry is Promise) {
marshalled[i] = entry.value;
entry = entry._promise;
}
// Obviously this will be true if [entry] was a Proxy.
if (entry is Promise) {
// Note that we could optimise this by just sending the value
// if the promise is already complete. Let's get this working
// first!
// This port will receive a SendPort that can be used to
// signal completion of this promise to the corresponding
// promise that the other end has created.
ReceivePort receiveCompleter = new ReceivePort.singleShot();
marshalled[i] = receiveCompleter.toSendPort();
Promise<SendPort> completer = new Promise<SendPort>();
receiveCompleter.receive((var msg, SendPort replyPort) {
completer.complete(msg[0]);
});
entry.addCompleteHandler((value) {
completer.addCompleteHandler((SendPort port) {
port.send([value], null);
});
});
} else {
// FIXME(kasperl, benl): this should probably be a copy?
marshalled[i] = entry;
}
if (marshalled[i] is ReceivePort) {
throw new Exception("Despite the documentation, you cannot send a ReceivePort");
}
}
return process(marshalled);
}).flatten();
@@ -357,60 +377,3 @@ class ProxyImpl {
static Map<SendPort, Dispatcher> _dispatchers;
}
class PromiseQueue {
// Enqueue an element that depends on a list of promises. The
// returned promise is resolved when all the input promises have
// been resolved.
static Promise enqueue(List<Promise> dependencies) {
if (_queue === null) {
_queue = new Queue<Function>();
}
// Keep track of how many unresolved promises we're waiting for.
int unresolved = dependencies.length;
void notifyResolved(ignored) {
assert(unresolved > 0);
unresolved--;
}
// Register a callback on each of the dependencies.
for (Promise promise in dependencies) {
promise.then(notifyResolved);
}
final Promise result = new Promise();
_queue.addLast(() {
if (unresolved > 0) return false;
// TODO(kasperl): It seems a bit weird to pass back null. Maybe
// the resulting promise should be a Promise<bool> that
// indicates whether or not we successfully got the enqueued
// element through the queue?
result.complete(null);
return true;
});
// Before returning the resulting promise, we make sure to process
// any fully resolved enqueued elements.
process();
return result;
}
static bool isEmpty() {
return (_queue === null) ? true : _queue.isEmpty();
}
static void process() {
if (_queue === null) {
return;
}
while (!_queue.isEmpty() && (_queue.first())()) {
_queue.removeFirst();
}
}
static Queue<Function> _queue;
}
+17
View File
@@ -143,3 +143,20 @@ class Dispatcher<T> {
T target;
}
// When a promise is sent across a port, it is converted to a
// Promise<SendPort> down which we must send a port to receive the
// completion value. Hand the Promise<SendPort> to this class to deal
// with it.
class PromiseProxy<T> extends PromiseImpl<T> {
PromiseProxy(Promise<SendPort> sendCompleter) {
ReceivePort completer = new ReceivePort.singleShot();
completer.receive((var msg, SendPort _) {
complete(msg[0]);
});
sendCompleter.addCompleteHandler((SendPort port) {
port.send([completer.toSendPort()], null);
});
}
}
+1 -12
View File
@@ -48,7 +48,6 @@ class ReceivePortImpl implements ReceivePort {
ReceivePort port = _portMap[id];
SendPort replyTo = (replyId == 0) ? null : new SendPortImpl(replyId);
(port._onMessage)(message, replyTo);
PromiseQueue.process();
}
// Call into the VM to close the VM maintained mappings.
@@ -89,17 +88,7 @@ class ReceivePortSingleShotImpl implements ReceivePort {
class SendPortImpl implements SendPort {
/*--- public interface ---*/
void send(var message, [SendPort replyTo = null]) {
if (PromiseQueue.isEmpty()) {
this._sendNow(message, replyTo);
} else {
_enqueueSend(message, replyTo);
}
}
void _enqueueSend(var message, SendPort replyTo) {
PromiseQueue.enqueue(const []).then((ignored) {
this._sendNow(message, replyTo);
});
this._sendNow(message, replyTo);
}
void _sendNow(var message, SendPort replyTo) {
+35 -15
View File
@@ -26,7 +26,7 @@ interface Purse {
int queryBalance();
Purse sproutPurse();
void deposit(int amount, Purse$Proxy source);
int deposit(int amount, Purse$Proxy source);
}
@@ -43,12 +43,14 @@ class PurseImpl implements Purse {
return _mint.createPurse(0);
}
void deposit(int amount, Purse$Proxy purse) {
int deposit(int amount, Purse$Proxy purse) {
Purse$ProxyImpl impl = purse.dynamic; // TODO: Get rid of this 'cast'.
PurseImpl source = impl.local;
if (source._balance < amount) throw "Not enough dough.";
_balance += amount;
source._balance -= amount;
print("Moved $amount, leaving ${source._balance}");
return _balance;
}
Mint _mint;
@@ -67,15 +69,25 @@ class MintMakerPromiseTest {
Purse$Proxy sprouted = purse.sproutPurse();
expectEquals(0, sprouted.queryBalance());
sprouted.deposit(5, purse);
expectEquals(0 + 5, sprouted.queryBalance());
expectEquals(100 - 5, purse.queryBalance());
Promise<int> balance = sprouted.deposit(5, purse);
expectEquals(0 + 5, balance);
// FIXME(benl): because we have no ordering constraints we have to
// manually order the messages or it all falls apart. We should
// implement E-ORDER.
balance.addCompleteHandler((_) {
expectEquals(0 + 5, sprouted.queryBalance());
expectEquals(100 - 5, purse.queryBalance());
sprouted.deposit(42, purse);
expectEquals(0 + 5 + 42, sprouted.queryBalance());
expectEquals(100 - 5 - 42, purse.queryBalance());
balance = sprouted.deposit(42, purse);
expectEquals(0 + 5 + 42, balance);
balance.addCompleteHandler((_) {
expectEquals(0 + 5 + 42, sprouted.queryBalance());
expectEquals(100 - 5 - 42, purse.queryBalance());
// FIXME(benl): once more we could "pass" by not running anything much.
expectDone(8);
});
});
expectDone(6);
}
static Mint$Proxy createMint() {
@@ -91,6 +103,7 @@ class MintMakerPromiseTest {
results = new List<Promise>();
}
results.add(promise.then((int actual) {
print("done $expected/$actual");
Expect.equals(expected, actual);
}));
}
@@ -102,6 +115,7 @@ class MintMakerPromiseTest {
Promise done = new Promise();
done.waitFor(results, results.length);
done.then((ignored) {
print("expectDone $n/${results.length}");
Expect.equals(n, results.length);
});
}
@@ -166,7 +180,7 @@ interface Purse$Proxy {
Promise<int> queryBalance();
Purse$Proxy sproutPurse();
void deposit(int amount, Purse$Proxy source); // Promise<int> amount.
Promise<int> deposit(int amount, Purse$Proxy source); // Promise<int> amount.
}
@@ -179,8 +193,8 @@ class Purse$ProxyImpl extends Proxy implements Purse$Proxy {
return this.call(["balance"]);
}
void deposit(int amount, Purse$Proxy source) {
this.send(["deposit", amount, source]);
Promise<int> deposit(int amount, Purse$Proxy source) {
return this.call(["deposit", amount, source]);
}
Purse$Proxy sproutPurse() {
@@ -196,14 +210,19 @@ class Purse$Dispatcher extends Dispatcher<Purse> {
void process(var message, void reply(var response)) {
String command = message[0];
print("command $command");
if (command == "balance") {
int balance = target.queryBalance();
reply(balance);
} else if (command == "deposit") {
int amount = message[1];
Promise<SendPort> port = new Promise<SendPort>.fromValue(message[2]);
Purse$Proxy source = new Purse$ProxyImpl(port);
target.deposit(amount, source);
Promise<SendPort> port =
new PromiseProxy<SendPort>(new Promise<SendPort>.fromValue(message[2]));
port.addCompleteHandler((_) {
Purse$Proxy source = new Purse$ProxyImpl(port);
int balance = target.deposit(amount, source);
reply(balance);
});
} else if (command == "sprout") {
Purse purse = target.sproutPurse();
SendPort port = Dispatcher.serve(new Purse$Dispatcher(purse));
@@ -212,6 +231,7 @@ class Purse$Dispatcher extends Dispatcher<Purse> {
// TODO: Send an exception back.
reply("Exception: Command not understood");
}
print("command $command done");
}
}
+34 -2
View File
@@ -12,12 +12,15 @@ class TestIsolate extends Isolate {
void main() {
int seed = 0;
this.port.receive((var message, SendPort replyTo) {
print("Got ${message[0]}");
if (seed == 0) {
seed = message[0];
} else {
Promise<int> response = new Promise<int>();
var proxy = new Proxy.forPort(replyTo);
print("send to proxy");
proxy.send([response]);
print("sent");
response.complete(seed + message[0]);
this.port.close();
}
@@ -29,16 +32,45 @@ class TestIsolate extends Isolate {
void test(TestExpectation expect) {
Proxy proxy = new Proxy.forIsolate(new TestIsolate());
proxy.send([42]); // Seed the isolate.
Promise promise = expect.completes(proxy.call([87])).then((int value) {
Promise<int> result = new PromiseProxy<int>(proxy.call([87]));
Promise promise = expect.completes(result).then((int value) {
print("expect 1: $value");
Expect.equals(42 + 87, value);
return 99;
});
expect.completes(promise).then((int value) {
print("expect 2: $value");
Expect.equals(99, value);
expect.succeeded();
});
}
void expandedTest(TestExpectation expect) {
Proxy proxy = new Proxy.forIsolate(new TestIsolate());
proxy.send([42]); // Seed the isolate.
Promise<SendPort> sendCompleter = proxy.call([87]);
Promise<int> result = new Promise<int>();
ReceivePort completer = new ReceivePort.singleShot();
completer.receive((var msg, SendPort _) {
print("test completer");
result.complete(msg[0]);
});
sendCompleter.addCompleteHandler((SendPort port) {
print("test send");
port.send([completer.toSendPort()], null);
});
Promise promise = expect.completes(result).then((int value) {
print("expect 1: $value");
Expect.equals(42 + 87, value);
return 99;
});
expect.completes(promise).then((int value) {
print("expect 2: $value");
Expect.equals(99, value);
expect.succeeded();
});
}
void main() {
runTests([test]);
runTests([test, expandedTest]);
}
+7 -3
View File
@@ -9,8 +9,8 @@
typedef void AsynchronousTestFunction(TestExpectation check);
void runTests(List tests) {
TestRunner runner = new TestRunner(new TestSuite(tests));
void runTests(List tests, [bool guarded = true]) {
TestRunner runner = new TestRunner(new TestSuite(tests), guarded);
TestResult result = new TestResult(runner);
runner.run(result);
}
@@ -87,6 +87,9 @@ class TestResult {
}
runGuarded(TestCase testCase, Function fn) {
if (!runner.guarded) {
return fn();
}
var result = null;
try {
result = fn();
@@ -113,7 +116,7 @@ class TestResult {
class TestRunner {
TestRunner(this.suite);
TestRunner(this.suite, this.guarded);
void run(TestResult result) {
if (waitForDoneCallback !== null) {
@@ -150,6 +153,7 @@ class TestRunner {
}
final TestSuite suite;
final bool guarded;
static Function waitForDoneCallback;
static Function doneCallback;
@@ -30,9 +30,61 @@ interface Mint factory MintImpl {
PowerfulPurse$Proxy promote(Purse$Proxy purse);
}
// Because promises can't be used as keys in maps until they have
// completed, provide a wrapper. Note that if any key promise fails to
// resolve, then get()'s return may also fail to resolve. Also,
// although the logic is fine, this can't be used for a
// ProxyMap. Perhaps both Proxy and Promise should inherit from
// Completable?
// NB: not tested and known to be buggy. Will fix in a future change.
class PromiseMap<S extends Promise, T> {
PromiseMap() {
_map = new Map<S, T>();
_incomplete = new Set<S>();
}
T add(S s, T t) {
_incomplete.add(s);
s.addCompleteHandler((_) {
_map[s] = t;
_incomplete.remove(s);
});
return t;
}
Promise<T> find(S s) {
T t = _map[s];
if (t != null)
return new Promise<T>.fromValue(t);
Promise<T> p = new Promise<T>();
int counter = _incomplete.length;
p.join(_incomplete, bool (S completed) {
if (completed != s) {
if (--counter == 0) {
p.complete(null);
return true;
}
return false;
}
p.complete(_map[s]);
return true;
});
return p;
}
Set<S> _incomplete;
Map<S, T> _map;
}
class MintImpl implements Mint {
MintImpl() { print('mint'); }
MintImpl() {
print('mint');
if (_power == null)
_power = new Map<Purse$Proxy, PowerfulPurse$Proxy>();
}
Purse$Proxy createPurse(int balance) {
print('createPurse');
@@ -42,17 +94,18 @@ class MintImpl implements Mint {
purse.init(thisProxy, balance);
Purse$Proxy weakPurse = purse.weak();
if (_power === null)
_power = new Map<Purse$Proxy, PowerfulPurse$Proxy>();
print('cP1');
print(weakPurse.hashCode());
_power[weakPurse] = purse;
print('cP2');
weakPurse.addCompleteHandler(() {
print('cP1');
_power[weakPurse] = purse;
print('cP2');
});
return weakPurse;
}
PowerfulPurse$Proxy promote(Purse$Proxy purse) {
print('promote');
// FIXME(benl): we should be using a PromiseMap here. But we get
// away with it in this test for now.
print('promote $purse/${_power[purse]}');
return _power[purse];
}
@@ -128,16 +181,16 @@ class MintMakerFullyIsolatedTest {
done.then((int) {
expectEquals(0 + 5, sprouted.queryBalance());
expectEquals(100 - 5, purse.queryBalance());
});
done = sprouted.deposit(42, purse);
expectEquals(42, done);
done.then((int) {
expectEquals(0 + 5 + 42, sprouted.queryBalance());
expectEquals(100 - 5 - 42, purse.queryBalance());
});
done = sprouted.deposit(42, purse);
expectEquals(5 + 42, done);
done.then((int) {
expectEquals(0 + 5 + 42, sprouted.queryBalance());
expectEquals(100 - 5 - 42, purse.queryBalance());
expectDone(8);
expectDone(8);
});
});
}
static List<Promise> results;
@@ -18,7 +18,7 @@ interface Purse factory PurseImpl {
int queryBalance();
Purse sproutPurse();
void deposit(int amount, Purse$Proxy source);
int deposit(int amount, Purse$Proxy source);
}
@@ -55,7 +55,7 @@ class PurseImpl implements Purse {
return _mint.createPurse(0);
}
void deposit(int amount, Purse$Proxy proxy) {
int deposit(int amount, Purse$Proxy proxy) {
if (amount < 0) throw "Ha ha";
// Because we are in the same isolate as the other purse, we can
// retrieve the proxy's local PurseImpl object and act on it
@@ -65,6 +65,7 @@ class PurseImpl implements Purse {
if (source._balance < amount) throw "Not enough dough.";
_balance += amount;
source._balance -= amount;
return _balance;
}
Mint _mint;
@@ -82,15 +83,22 @@ class MintMakerPromiseWithStubsTest {
Purse$Proxy sprouted = purse.sproutPurse();
expectEquals(0, sprouted.queryBalance());
sprouted.deposit(5, purse);
expectEquals(0 + 5, sprouted.queryBalance());
expectEquals(100 - 5, purse.queryBalance());
// FIXME(benl): We should not have to manually order the calls
// like this.
Promise<int> result = sprouted.deposit(5, purse);
expectEquals(5, result);
result.addCompleteHandler((_) {
expectEquals(0 + 5, sprouted.queryBalance());
expectEquals(100 - 5, purse.queryBalance());
sprouted.deposit(42, purse);
expectEquals(0 + 5 + 42, sprouted.queryBalance());
expectEquals(100 - 5 - 42, purse.queryBalance());
expectDone(6);
result = sprouted.deposit(42, purse);
expectEquals(5 + 42, result);
result.addCompleteHandler((_) {
expectEquals(0 + 5 + 42, sprouted.queryBalance());
expectEquals(100 - 5 - 42, purse.queryBalance());
expectDone(8);
});
});
}
static List<Promise> results;
@@ -100,6 +108,7 @@ class MintMakerPromiseWithStubsTest {
results = new List<Promise>();
}
results.add(promise.then((int actual) {
print("done $expected/$actual");
Expect.equals(expected, actual);
}));
}
+1 -3
View File
@@ -5,11 +5,9 @@
prefix stub-generator
[ $arch == ia32 ]
MintMakerFullyIsolatedTest: Skip # Bug 5283149
MintMakerPromiseWithStubsTest: Skip # Bug 5384756
MintMakerFullyIsolatedTest: Skip # issue 115
[ $arch == dartc ]
MintMakerFullyIsolatedTest: Fail # benl
[ $arch == x64 ]
*: Skip
+1
View File
@@ -79,6 +79,7 @@ class DartStubTestConfiguration(test_configuration.StandardTestConfiguration):
def ListTests(self, current_path, path, mode, arch):
dartc = self.context.GetDartC(mode, 'dartc')
if not os.access(dartc[0], os.X_OK):
print "Can't find dartc at", str(dartc) + ", skipping"
return []
tests = []
for root, dirs, files in os.walk(join(self.root, 'src')):
+2 -1
View File
@@ -612,7 +612,8 @@ class Context(object):
def GetDartC(self, mode, arch):
"""Returns the path to the Dart --> JS compiler."""
dartc = os.path.abspath(os.path.join(
self.GetBuildRoot(mode, arch), 'compiler', 'bin', 'dartc'))
utils.GetBaseDir(), 'compiler', self.GetBuildRoot(mode, arch),
'compiler', 'bin', 'dartc'))
if utils.IsWindows(): dartc += '.exe'
command = [dartc]
+5
View File
@@ -134,6 +134,9 @@ def GetBuildConf(mode, arch):
# instead of 'dartc'.
RUN_FROM_TOP_DIR = os.path.basename(os.path.abspath(os.curdir)) == 'dart'
ARCH_GUESS = GuessArchitecture()
BASE_DIR = os.path.abspath(os.path.join(os.curdir, '..'))
if RUN_FROM_TOP_DIR:
BASE_DIR = os.path.abspath(os.curdir)
def GetBuildRoot(target_os, mode=None, arch=None):
if arch == 'dartc' and RUN_FROM_TOP_DIR: arch = ARCH_GUESS
@@ -143,6 +146,8 @@ def GetBuildRoot(target_os, mode=None, arch=None):
else:
return BUILD_ROOT[target_os]
def GetBaseDir():
return BASE_DIR
def RewritePathSeparator(path, workspace):
# Paths in test files are always specified using '/'