Skip to content

Commit 001a676

Browse files
committed
Remove loop/for callbacks in favor of CF root/block
Extended forinof test uses the callbacks with a custom for-of iterator.
1 parent de3dedd commit 001a676

File tree

13 files changed

+251
-183
lines changed

13 files changed

+251
-183
lines changed

src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,19 @@
1+
/*******************************************************************************
2+
* Copyright 2019 Dynamic Analysis Group, Università della Svizzera Italiana (USI)
3+
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*******************************************************************************/
117
let obj = {
218
x:'valueX',
319
y:'valueY',
@@ -10,3 +26,29 @@ let arr = [41,42,43];
1026

1127
for (let val of arr) {
1228
}
29+
30+
const itemA = 42;
31+
class Foo {
32+
constructor() {
33+
this.itemB = 'bar';
34+
}
35+
[Symbol.iterator]() {
36+
let moreToIterate = 2;
37+
return {
38+
next: () => {
39+
if (moreToIterate) {
40+
const ret = { value: moreToIterate == 2 ? itemA : this.itemB, done: false };
41+
moreToIterate--;
42+
return ret;
43+
} else {
44+
return { done: true }
45+
}
46+
}
47+
}
48+
}
49+
}
50+
51+
let o = new Foo();
52+
53+
for (i of o) {
54+
}

src/ch.usi.inf.nodeprof/js/analysis/forinof/analysis.js

Lines changed: 79 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,94 @@
1616
*******************************************************************************/
1717
//DO NOT INSTRUMENT
1818
(function (sandbox) {
19+
const assert = require('assert');
1920
function MyAnalysis() {
21+
22+
// last expression before for-in/for-of is the iteration object
2023
let lastExprResult;
21-
this.forObject = function (iid, isForIn) {
22-
console.log('forObject@', J$.iidToLocation(iid), isForIn, lastExprResult);
24+
25+
// control flow tracking
26+
let cfRoots = new Map;
27+
let cfBlockStack = [];
28+
// ignore control flow other that for-in/for-of
29+
let ignoredIIDs = new Set;
30+
31+
// keep track of user-defined iterators
32+
let iteratorFuncs = new Set;
33+
let iteratorIIDs = new Set;
34+
let nextFuncs = new Set;
35+
let rwTrackStack = [];
36+
37+
function logLoc(cbName, iid, ...extra) {
38+
if (ignoredIIDs.has(iid)) {
39+
return;
40+
}
41+
console.log('%s@%s', cbName, J$.iidToLocation(iid), ...extra);
42+
}
43+
function storeIterator(obj) {
44+
let proto = obj;
45+
while (proto != null) {
46+
let iterator = proto[Symbol.iterator];
47+
if (iterator) {
48+
iteratorFuncs.add(iterator);
49+
}
50+
proto = Object.getPrototypeOf(proto);
51+
}
2352
}
24-
this.forObjectPost = function (iid, isForIn) {
25-
console.log('forObjectPost@', J$.iidToLocation(iid), isForIn);
53+
54+
this.cfRootEnter = function (iid, type) {
55+
if (type === J$.cf.IF) {
56+
ignoredIIDs.add(iid);
57+
}
58+
logLoc('cfRootEnter', iid, type);
59+
if (type === J$.cf.FOR_OF || type === J$.cf.FOR_IN) {
60+
const o = lastExprResult;
61+
console.log('iteration obj:', nextFuncs.has(o.next) ? '<iter w/ next()>' : o);
62+
}
63+
cfRoots.set(iid, type);
64+
}
65+
this.cfRootExit = function (iid, type) {
66+
logLoc('cfRootExit', iid, type);
2667
}
27-
this.cfBlockEnter = function(iid) {
28-
console.log('iterationEnter@', J$.iidToLocation(iid));
68+
this.cfBlockEnter = function(iid, iidParent) {
69+
cfBlockStack.push(iid);
2970
}
30-
this.cfBlockExit = function(iid) {
31-
console.log('iterationExit@', J$.iidToLocation(iid));
71+
this.cfBlockExit = function(iid, iidParent) {
72+
assert(cfBlockStack.pop() === iid);
73+
if (!ignoredIIDs.has(iidParent)) {
74+
console.log('cfRoot %s @ %s', cfRoots.get(iidParent), J$.iidToLocation(iidParent));
75+
console.log(' \\-cfBlock @ %s', J$.iidToLocation(iid));
76+
}
3277
}
3378
this.read = function(iid, name, value) {
34-
console.log('read@', J$.iidToLocation(iid), name);
79+
if (rwTrackStack.length) {
80+
console.log('read@', J$.iidToLocation(iid), name); // only inside iter-next()
81+
}
3582
}
3683
this.write = function(iid, name, value) {
37-
console.log('write@', J$.iidToLocation(iid), name);
84+
if (rwTrackStack.length) {
85+
console.log('write@', J$.iidToLocation(iid), name); // only inside iter-next()
86+
}
87+
}
88+
this.functionEnter = function (iid, f, dis, args) {
89+
if (iteratorFuncs.has(f)) {
90+
console.log("functionEnter: %s / %s / %d", f.name, J$.iidToLocation(iid), arguments.length);
91+
iteratorIIDs.add(iid);
92+
}
93+
if (nextFuncs.has(f) || rwTrackStack.length) {
94+
rwTrackStack.push(iid); // stack length > 0 when inside next()
95+
}
96+
}
97+
this.functionExit = function (iid, returnVal) {
98+
if (iteratorIIDs.has(iid)) {
99+
nextFuncs.add(returnVal.next);
100+
}
101+
rwTrackStack.pop();
102+
}
103+
this.invokeFun = function (iid, f, base, args, result, isConstructor, isMethod) {
104+
if (typeof result === 'object') {
105+
storeIterator(result);
106+
}
38107
}
39108
this.endExpression = function (iid, type, result) {
40109
lastExprResult = result;
Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,39 @@
1-
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:1:66:4:2) obj
2-
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:17:6:20) obj
3-
forObject@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2) true { x: 'valueX', y: 'valueY' }
4-
iterationEnter@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2)
5-
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2) key
6-
iterationExit@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2)
7-
iterationEnter@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2)
8-
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2) key
9-
iterationExit@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2)
10-
forObjectPost@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2) true
11-
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:9:5:9:21) arr
12-
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:17:11:20) arr
13-
forObject@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2) false [ 41, 42, 43 ]
14-
iterationEnter@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2)
15-
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2) val
16-
iterationExit@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2)
17-
iterationEnter@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2)
18-
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2) val
19-
iterationExit@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2)
20-
iterationEnter@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2)
21-
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2) val
22-
iterationExit@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2)
23-
forObjectPost@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2) false
1+
cfRootEnter@(src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:22:1:23:2) ForInIteration
2+
iteration obj: { x: 'valueX', y: 'valueY' }
3+
cfRoot ForInIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:22:1:23:2)
4+
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:22:1:23:2)
5+
cfRoot ForInIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:22:1:23:2)
6+
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:22:1:23:2)
7+
cfRootExit@(src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:22:1:23:2) ForInIteration
8+
cfRootEnter@(src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2) ForOfIteration
9+
iteration obj: [ 41, 42, 43 ]
10+
cfRoot ForOfIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2)
11+
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2)
12+
cfRoot ForOfIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2)
13+
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2)
14+
cfRoot ForOfIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2)
15+
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2)
16+
cfRootExit@(src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2) ForOfIteration
17+
functionEnter: [Symbol.iterator] / (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:35:3:48:4) / 4
18+
cfRootEnter@(src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:53:1:54:2) ForOfIteration
19+
iteration obj: <iter w/ next()>
20+
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:39:13:39:26) moreToIterate
21+
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:40:32:40:45) moreToIterate
22+
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:40:53:40:58) itemA
23+
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:40:17:40:86) ret
24+
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:41:11:41:26) moreToIterate
25+
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:41:11:41:26) moreToIterate
26+
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:42:18:42:21) ret
27+
cfRoot ForOfIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:53:1:54:2)
28+
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:53:1:54:2)
29+
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:39:13:39:26) moreToIterate
30+
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:40:32:40:45) moreToIterate
31+
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:40:61:40:65) this
32+
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:40:17:40:86) ret
33+
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:41:11:41:26) moreToIterate
34+
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:41:11:41:26) moreToIterate
35+
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:42:18:42:21) ret
36+
cfRoot ForOfIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:53:1:54:2)
37+
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:53:1:54:2)
38+
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:39:13:39:26) moreToIterate
39+
cfRootExit@(src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:53:1:54:2) ForOfIteration

src/ch.usi.inf.nodeprof/js/analysis/trivial/emptyTemplate.js

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -165,15 +165,6 @@
165165
this.declare = function (iid, name, type) {
166166
};
167167

168-
/**
169-
* forin or forof support
170-
* the object being iterated can be known by checking the last expression's result (via endExpression)
171-
**/
172-
this.forObject = function (iid, isForIn) {
173-
}
174-
this.forObjectPost = function (iid, isForIn) {
175-
}
176-
177168
/**
178169
* This callback is called before a value is returned from a function using the <tt>return</tt> keyword.
179170
*
@@ -201,13 +192,18 @@
201192
this.awaitPost = function (iid, result, exceptionVal) {
202193
}
203194

195+
// TODO incubation stage
196+
this.cfBlockEnter = function(iid, iidParent) {
197+
};
198+
this.cfBlockExit = function(iid, iidParent) {
199+
};
200+
this.cfRootEnter = function (iid, type) {
201+
};
202+
this.cfRootExit = function (iid, type) {
203+
};
204204
}
205205

206206
if(false) {
207-
// replaced with forObject including support for forin and forof
208-
this.forinObject = function (iid, val) {
209-
};
210-
211207
//not supported yet
212208
this._throw = function (iid, val) {
213209
};

src/ch.usi.inf.nodeprof/js/jalangi.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,16 @@ J$={};
6161
sandbox.disableAnalysis = function() {
6262
return sandbox.adapter.instrumentationSwitch(false);
6363
}
64-
}catch (e){
64+
} catch (e){
6565
console.log("cannot load nodeprof jalangi adapter");
6666
}
6767

68+
sandbox.cf = {
69+
FOR_IN: "ForInIteration",
70+
FOR_OF: "ForOfIteration",
71+
IF: "Conditional"
72+
}
73+
6874
sandbox.analyses=[];
6975
sandbox.enabledCBs = [];
7076
if(process.env.ENABLED_JALANGI_CBS && process.env.ENABLED_JALANGI_CBS.length > 0){

src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/CFBlockEventHandler.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,25 @@
1515
*******************************************************************************/
1616
package ch.usi.inf.nodeprof.handlers;
1717

18+
import ch.usi.inf.nodeprof.utils.NodeProfUtil;
19+
import ch.usi.inf.nodeprof.utils.SourceMapping;
1820
import com.oracle.truffle.api.instrumentation.EventContext;
1921

2022
import ch.usi.inf.nodeprof.ProfiledTagEnum;
23+
import com.oracle.truffle.js.nodes.JavaScriptNode;
24+
import com.oracle.truffle.js.nodes.instrumentation.JSTags;
2125

2226
public abstract class CFBlockEventHandler extends BaseSingleTagEventHandler {
27+
private final int parentIID;
28+
2329
public CFBlockEventHandler(EventContext context) {
2430
super(context, ProfiledTagEnum.CF_BLOCK);
31+
JavaScriptNode parent = (JavaScriptNode) NodeProfUtil.getParentSkipWrappers(context.getInstrumentedNode());
32+
assert parent.hasTag(JSTags.ControlFlowRootTag.class);
33+
this.parentIID = SourceMapping.getIIDForSourceSection(parent.getSourceSection());
34+
}
35+
36+
public int getParentIID() {
37+
return parentIID;
2538
}
2639
}

src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/CFRootEventHandler.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/*******************************************************************************
22
* Copyright 2018 Dynamic Analysis Group, Università della Svizzera Italiana (USI)
3+
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
34
*
45
* Licensed under the Apache License, Version 2.0 (the "License");
56
* you may not use this file except in compliance with the License.
@@ -16,9 +17,9 @@
1617
package ch.usi.inf.nodeprof.handlers;
1718

1819
import com.oracle.truffle.api.instrumentation.EventContext;
19-
import com.oracle.truffle.js.nodes.instrumentation.JSTags;
2020

2121
import ch.usi.inf.nodeprof.ProfiledTagEnum;
22+
import com.oracle.truffle.js.nodes.instrumentation.JSTags;
2223

2324
public abstract class CFRootEventHandler extends BaseSingleTagEventHandler {
2425

@@ -29,6 +30,10 @@ public CFRootEventHandler(EventContext context) {
2930
this.type = (String) getAttribute("type");
3031
}
3132

33+
public String getCFRootType() {
34+
return type;
35+
}
36+
3237
public boolean isAsyncRoot() {
3338
return this.type.equals(JSTags.ControlFlowRootTag.Type.AsyncFunction.name());
3439
}

src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/LoopEventHandler.java

Lines changed: 0 additions & 42 deletions
This file was deleted.

0 commit comments

Comments
 (0)