Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API change: replace loop and forObject callbacks with cfRoot/cfBlock #51

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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) {
}
88 changes: 86 additions & 2 deletions src/ch.usi.inf.nodeprof/js/analysis/forinof/analysis.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +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.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, iidParent) {
cfBlockStack.push(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) {
if (rwTrackStack.length) {
console.log('read@', J$.iidToLocation(iid), name); // only inside iter-next()
}
}
this.write = function(iid, name, value) {
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,2 +1,39 @@
forObject@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:6:1:7:2) true { x: 'valueX', y: 'valueY' }
forObject@ (src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js:11:1:12:2) false [ 41, 42, 43 ]
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
25 changes: 16 additions & 9 deletions src/ch.usi.inf.nodeprof/js/analysis/trivial/emptyTemplate.js
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,13 @@
};

/**
* 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 callback is called before a value is returned from a function using the <tt>return</tt> keyword.
*
* @param {number} iid - Static unique instruction identifier of this callback
* @param {*} val - Value to be returned
*/
this._return = function (iid, val) {
};

/**
* This callback is called before a value is returned from a function using the <tt>return</tt> keyword.
Expand All @@ -190,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 @@ -26,9 +26,9 @@
public enum ProfiledTagEnum {
UNARY(JSTags.UnaryOperationTag.class, -1), // have multiple case
BINARY(JSTags.BinaryOperationTag.class, 2),
CF_BRANCH(JSTags.ControlFlowBranchTag.class, -1), // to be checked
CF_BLOCK(JSTags.ControlFlowBlockTag.class, -1), // to be checked
CF_ROOT(JSTags.ControlFlowRootTag.class, 0), // to be checked
CF_BRANCH(JSTags.ControlFlowBranchTag.class, -1), // have multiple case
CF_BLOCK(JSTags.ControlFlowBlockTag.class, 0),
CF_ROOT(JSTags.ControlFlowRootTag.class, 0),
EVAL(JSTags.EvalCallTag.class, 2),
DECLARE(JSTags.DeclareTag.class, 0),
VAR_READ(JSTags.ReadVariableTag.class, 0),
Expand All @@ -42,7 +42,7 @@ public enum ProfiledTagEnum {
BUILTIN(JSTags.BuiltinRootTag.class, 0),
LITERAL(JSTags.LiteralTag.class, 0),
STATEMENT(StandardTags.StatementTag.class, 0),
NEW(JSTags.ObjectAllocationTag.class, -1),
NEW(JSTags.ObjectAllocationTag.class, -1), // any number of inputs for arguments
EXPRESSION(StandardTags.ExpressionTag.class, 0);

// the corresponding JSTags class
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,28 +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 com.oracle.truffle.js.nodes.instrumentation.JSTags;

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

/**
* Abstract event handler for loop events
*/
public abstract class LoopEventHandler extends BaseSingleTagEventHandler {
public LoopEventHandler(EventContext context) {
super(context, ProfiledTagEnum.CF_ROOT);
}

public String getLoopType() {
return (String) getAttribute("type");
}
public abstract class CFBlockEventHandler extends BaseSingleTagEventHandler {
private final int parentIID;

public boolean isForIn() {
return getLoopType().equals(JSTags.ControlFlowRootTag.Type.ForInIteration.name());
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 boolean isForOf() {
return getLoopType().equals(JSTags.ControlFlowRootTag.Type.ForOfIteration.name());
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
Loading