Skip to content

Commit

Permalink
Remove loop/for callbacks in favor of CF root/block
Browse files Browse the repository at this point in the history
Extended forinof test uses the callbacks with a custom for-of iterator.
  • Loading branch information
alexjordan committed Oct 2, 2019
1 parent de3dedd commit 001a676
Show file tree
Hide file tree
Showing 13 changed files with 251 additions and 183 deletions.
42 changes: 42 additions & 0 deletions src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*******************************************************************************
* Copyright 2019 Dynamic Analysis Group, Università della Svizzera Italiana (USI)
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
let obj = {
x:'valueX',
y:'valueY',
Expand All @@ -10,3 +26,29 @@ let arr = [41,42,43];

for (let val of arr) {
}

const itemA = 42;
class Foo {
constructor() {
this.itemB = 'bar';
}
[Symbol.iterator]() {
let moreToIterate = 2;
return {
next: () => {
if (moreToIterate) {
const ret = { value: moreToIterate == 2 ? itemA : this.itemB, done: false };
moreToIterate--;
return ret;
} else {
return { done: true }
}
}
}
}
}

let o = new Foo();

for (i of o) {
}
89 changes: 79 additions & 10 deletions src/ch.usi.inf.nodeprof/js/analysis/forinof/analysis.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,25 +16,94 @@
*******************************************************************************/
//DO NOT INSTRUMENT
(function (sandbox) {
const assert = require('assert');
function MyAnalysis() {

// last expression before for-in/for-of is the iteration object
let lastExprResult;
this.forObject = function (iid, isForIn) {
console.log('forObject@', J$.iidToLocation(iid), isForIn, lastExprResult);

// control flow tracking
let cfRoots = new Map;
let cfBlockStack = [];
// ignore control flow other that for-in/for-of
let ignoredIIDs = new Set;

// keep track of user-defined iterators
let iteratorFuncs = new Set;
let iteratorIIDs = new Set;
let nextFuncs = new Set;
let rwTrackStack = [];

function logLoc(cbName, iid, ...extra) {
if (ignoredIIDs.has(iid)) {
return;
}
console.log('%s@%s', cbName, J$.iidToLocation(iid), ...extra);
}
function storeIterator(obj) {
let proto = obj;
while (proto != null) {
let iterator = proto[Symbol.iterator];
if (iterator) {
iteratorFuncs.add(iterator);
}
proto = Object.getPrototypeOf(proto);
}
}
this.forObjectPost = function (iid, isForIn) {
console.log('forObjectPost@', J$.iidToLocation(iid), isForIn);

this.cfRootEnter = function (iid, type) {
if (type === J$.cf.IF) {
ignoredIIDs.add(iid);
}
logLoc('cfRootEnter', iid, type);
if (type === J$.cf.FOR_OF || type === J$.cf.FOR_IN) {
const o = lastExprResult;
console.log('iteration obj:', nextFuncs.has(o.next) ? '<iter w/ next()>' : o);
}
cfRoots.set(iid, type);
}
this.cfRootExit = function (iid, type) {
logLoc('cfRootExit', iid, type);
}
this.cfBlockEnter = function(iid) {
console.log('iterationEnter@', J$.iidToLocation(iid));
this.cfBlockEnter = function(iid, iidParent) {
cfBlockStack.push(iid);
}
this.cfBlockExit = function(iid) {
console.log('iterationExit@', J$.iidToLocation(iid));
this.cfBlockExit = function(iid, iidParent) {
assert(cfBlockStack.pop() === iid);
if (!ignoredIIDs.has(iidParent)) {
console.log('cfRoot %s @ %s', cfRoots.get(iidParent), J$.iidToLocation(iidParent));
console.log(' \\-cfBlock @ %s', J$.iidToLocation(iid));
}
}
this.read = function(iid, name, value) {
console.log('read@', J$.iidToLocation(iid), name);
if (rwTrackStack.length) {
console.log('read@', J$.iidToLocation(iid), name); // only inside iter-next()
}
}
this.write = function(iid, name, value) {
console.log('write@', J$.iidToLocation(iid), name);
if (rwTrackStack.length) {
console.log('write@', J$.iidToLocation(iid), name); // only inside iter-next()
}
}
this.functionEnter = function (iid, f, dis, args) {
if (iteratorFuncs.has(f)) {
console.log("functionEnter: %s / %s / %d", f.name, J$.iidToLocation(iid), arguments.length);
iteratorIIDs.add(iid);
}
if (nextFuncs.has(f) || rwTrackStack.length) {
rwTrackStack.push(iid); // stack length > 0 when inside next()
}
}
this.functionExit = function (iid, returnVal) {
if (iteratorIIDs.has(iid)) {
nextFuncs.add(returnVal.next);
}
rwTrackStack.pop();
}
this.invokeFun = function (iid, f, base, args, result, isConstructor, isMethod) {
if (typeof result === 'object') {
storeIterator(result);
}
}
this.endExpression = function (iid, type, result) {
lastExprResult = result;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,39 @@
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:1:66:4:2) obj
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:17:6:20) obj
forObject@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2) true { x: 'valueX', y: 'valueY' }
iterationEnter@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2)
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2) key
iterationExit@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2)
iterationEnter@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2)
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2) key
iterationExit@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2)
forObjectPost@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2) true
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:9:5:9:21) arr
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:17:11:20) arr
forObject@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2) false [ 41, 42, 43 ]
iterationEnter@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2)
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2) val
iterationExit@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2)
iterationEnter@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2)
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2) val
iterationExit@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2)
iterationEnter@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2)
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2) val
iterationExit@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2)
forObjectPost@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2) false
cfRootEnter@(src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:22:1:23:2) ForInIteration
iteration obj: { x: 'valueX', y: 'valueY' }
cfRoot ForInIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:22:1:23:2)
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:22:1:23:2)
cfRoot ForInIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:22:1:23:2)
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:22:1:23:2)
cfRootExit@(src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:22:1:23:2) ForInIteration
cfRootEnter@(src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2) ForOfIteration
iteration obj: [ 41, 42, 43 ]
cfRoot ForOfIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2)
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2)
cfRoot ForOfIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2)
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2)
cfRoot ForOfIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2)
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2)
cfRootExit@(src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:27:1:28:2) ForOfIteration
functionEnter: [Symbol.iterator] / (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:35:3:48:4) / 4
cfRootEnter@(src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:53:1:54:2) ForOfIteration
iteration obj: <iter w/ next()>
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:39:13:39:26) moreToIterate
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:40:32:40:45) moreToIterate
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:40:53:40:58) itemA
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:40:17:40:86) ret
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:41:11:41:26) moreToIterate
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:41:11:41:26) moreToIterate
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:42:18:42:21) ret
cfRoot ForOfIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:53:1:54:2)
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:53:1:54:2)
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:39:13:39:26) moreToIterate
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:40:32:40:45) moreToIterate
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:40:61:40:65) this
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:40:17:40:86) ret
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:41:11:41:26) moreToIterate
write@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:41:11:41:26) moreToIterate
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:42:18:42:21) ret
cfRoot ForOfIteration @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:53:1:54:2)
\-cfBlock @ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:53:1:54:2)
read@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:39:13:39:26) moreToIterate
cfRootExit@(src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:53:1:54:2) ForOfIteration
22 changes: 9 additions & 13 deletions src/ch.usi.inf.nodeprof/js/analysis/trivial/emptyTemplate.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,6 @@
this.declare = function (iid, name, type) {
};

/**
* forin or forof support
* the object being iterated can be known by checking the last expression's result (via endExpression)
**/
this.forObject = function (iid, isForIn) {
}
this.forObjectPost = function (iid, isForIn) {
}

/**
* This callback is called before a value is returned from a function using the <tt>return</tt> keyword.
*
Expand Down Expand Up @@ -201,13 +192,18 @@
this.awaitPost = function (iid, result, exceptionVal) {
}

// TODO incubation stage
this.cfBlockEnter = function(iid, iidParent) {
};
this.cfBlockExit = function(iid, iidParent) {
};
this.cfRootEnter = function (iid, type) {
};
this.cfRootExit = function (iid, type) {
};
}

if(false) {
// replaced with forObject including support for forin and forof
this.forinObject = function (iid, val) {
};

//not supported yet
this._throw = function (iid, val) {
};
Expand Down
8 changes: 7 additions & 1 deletion src/ch.usi.inf.nodeprof/js/jalangi.js
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,16 @@ J$={};
sandbox.disableAnalysis = function() {
return sandbox.adapter.instrumentationSwitch(false);
}
}catch (e){
} catch (e){
console.log("cannot load nodeprof jalangi adapter");
}

sandbox.cf = {
FOR_IN: "ForInIteration",
FOR_OF: "ForOfIteration",
IF: "Conditional"
}

sandbox.analyses=[];
sandbox.enabledCBs = [];
if(process.env.ENABLED_JALANGI_CBS && process.env.ENABLED_JALANGI_CBS.length > 0){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,25 @@
*******************************************************************************/
package ch.usi.inf.nodeprof.handlers;

import ch.usi.inf.nodeprof.utils.NodeProfUtil;
import ch.usi.inf.nodeprof.utils.SourceMapping;
import com.oracle.truffle.api.instrumentation.EventContext;

import ch.usi.inf.nodeprof.ProfiledTagEnum;
import com.oracle.truffle.js.nodes.JavaScriptNode;
import com.oracle.truffle.js.nodes.instrumentation.JSTags;

public abstract class CFBlockEventHandler extends BaseSingleTagEventHandler {
private final int parentIID;

public CFBlockEventHandler(EventContext context) {
super(context, ProfiledTagEnum.CF_BLOCK);
JavaScriptNode parent = (JavaScriptNode) NodeProfUtil.getParentSkipWrappers(context.getInstrumentedNode());
assert parent.hasTag(JSTags.ControlFlowRootTag.class);
this.parentIID = SourceMapping.getIIDForSourceSection(parent.getSourceSection());
}

public int getParentIID() {
return parentIID;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*******************************************************************************
* Copyright 2018 Dynamic Analysis Group, Università della Svizzera Italiana (USI)
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -16,9 +17,9 @@
package ch.usi.inf.nodeprof.handlers;

import com.oracle.truffle.api.instrumentation.EventContext;
import com.oracle.truffle.js.nodes.instrumentation.JSTags;

import ch.usi.inf.nodeprof.ProfiledTagEnum;
import com.oracle.truffle.js.nodes.instrumentation.JSTags;

public abstract class CFRootEventHandler extends BaseSingleTagEventHandler {

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

public String getCFRootType() {
return type;
}

public boolean isAsyncRoot() {
return this.type.equals(JSTags.ControlFlowRootTag.Type.AsyncFunction.name());
}
Expand Down

This file was deleted.

Loading

0 comments on commit 001a676

Please sign in to comment.