package com.oracle.truffle.js.test.instrumentation;
import org.junit.Test;
import com.oracle.truffle.js.nodes.instrumentation.JSTags.FunctionCallTag;
import com.oracle.truffle.js.nodes.instrumentation.JSTags.ReadVariableTag;
import com.oracle.truffle.js.nodes.instrumentation.JSTags.WriteElementTag;
import com.oracle.truffle.js.nodes.instrumentation.JSTags.WriteVariableTag;
import com.oracle.truffle.js.runtime.objects.Undefined;
public class ResumableNodesTest extends FineGrainedAccessTest {
@Test
public void asyncAwait() {
String src = "function res() {" +
" var local2 = 20;" +
" return new Promise(resolve => {" +
" resolve(local2);" +
" });" +
"};" +
"async function asyncCall() {" +
" var local = 2;" +
" return await res() + await res() + local;" +
"};" +
"asyncCall();";
evalWithTags(src, new Class[]{WriteVariableTag.class,
ReadVariableTag.class});
assertVariableWrite("local", 2);
assertVariableWrite("local2", 20);
assertVariableWrite("resolve");
assertVariableRead("resolve");
assertVariableRead("local2", 20);
assertVariableWrite("local2", 20);
assertVariableWrite("resolve");
assertVariableRead("resolve");
assertVariableRead("local2", 20);
assertVariableRead("local", 2);
}
@Test
public void generatorYield() {
String src = "function* foo(index) {" +
" var local = 1;" +
" while (index < 3) {" +
" yield (local + index++);" +
" };" +
"};" +
"var val = 0;" +
"var iterator = foo(val);" +
"iterator.next().value;" +
"iterator.next().value;";
evalWithTags(src, new Class[]{WriteVariableTag.class,
ReadVariableTag.class});
assertVariableWrite("local", 1);
assertVariableRead("index", 0);
assertVariableRead("local", 1);
assertVariableInc("index", 0);
assertVariableRead("index", 1);
assertVariableRead("local", 1);
assertVariableInc("index", 1);
}
@Test
public void generatorYieldInCall() {
String src = "function dummy(arg) {" +
" return {};" +
"};" +
"function crash() {" +
" return 'Crash';" +
"};" +
"function* myGen() {" +
" const c = crash();" +
" const boom = dummy(" +
" yield c" +
" );" +
"};" +
"a = myGen();" +
"a.next();" +
"a.next();" +
"a.next();";
evalWithTags(src, new Class[]{FunctionCallTag.class});
enter(FunctionCallTag.class, (e, call) -> {
call.input(assertUndefinedInput);
call.input(assertJSFunctionInputWithName("myGen"));
}).exit();
enter(FunctionCallTag.class, (e, call) -> {
call.input(assertJSObjectInput);
call.input(assertJSFunctionInputWithName("next"));
enter(FunctionCallTag.class, (e2, call2) -> {
call2.input(assertJSObjectInput);
call2.input(assertJSFunctionInputWithName("crash"));
}).exit();
}).exit();
enter(FunctionCallTag.class, (e, call) -> {
call.input(assertJSObjectInput);
call.input(assertJSFunctionInputWithName("next"));
enter(FunctionCallTag.class, (e2, call2) -> {
call2.input(assertJSObjectInput);
call2.input(assertJSFunctionInputWithName("dummy"));
call2.input(assertUndefinedInput);
}).exit();
}).exit();
enter(FunctionCallTag.class, (e, call) -> {
call.input(assertJSObjectInput);
call.input(assertJSFunctionInputWithName("next"));
}).exit();
}
@Test
public void generatorYieldWritesElement() {
String src = "var ret = [];" +
"function *next() {" +
" ret[0] = yield 1;" +
" yield next;" +
"};" +
"for(const val of next()) {" +
" val;" +
"}";
evalWithTags(src, new Class[]{WriteElementTag.class});
enter(WriteElementTag.class, (e, w) -> {
w.input(assertJSArrayInput);
w.input(0);
w.input(Undefined.instance);
}).exit(assertReturnValue(Undefined.instance));
}
protected void assertVariableInc(String name, int value) {
enter(WriteVariableTag.class, (e, var) -> {
assertAttribute(e, NAME, name);
enter(ReadVariableTag.class, (e1) -> {
assertAttribute(e, NAME, name);
}).exit(assertReturnValue(value));
var.input(value + 1);
}).exit();
}
protected void assertVariableRead(String name, Object value) {
enter(ReadVariableTag.class, (e) -> {
assertAttribute(e, NAME, name);
}).exit(assertReturnValue(value));
}
protected void assertVariableRead(String name) {
enter(ReadVariableTag.class, (e) -> {
assertAttribute(e, NAME, name);
}).exit();
}
protected void assertVariableWrite(String name, Object value) {
enter(WriteVariableTag.class, (e, var) -> {
assertAttribute(e, NAME, name);
var.input(value);
}).exit();
}
protected void assertVariableWrite(String name) {
enter(WriteVariableTag.class, (e, var) -> {
assertAttribute(e, NAME, name);
var.input();
}).exit();
}
}