diff --git a/src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js b/src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js index 127ac8ca..9171e725 100644 --- a/src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js +++ b/src/ch.usi.inf.nodeprof.test/js/minitests/forinof.js @@ -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', @@ -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) { +} diff --git a/src/ch.usi.inf.nodeprof/js/analysis/forinof/analysis.js b/src/ch.usi.inf.nodeprof/js/analysis/forinof/analysis.js index 57c58376..142a16c2 100644 --- a/src/ch.usi.inf.nodeprof/js/analysis/forinof/analysis.js +++ b/src/ch.usi.inf.nodeprof/js/analysis/forinof/analysis.js @@ -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) ? '' : 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; diff --git a/src/ch.usi.inf.nodeprof/js/analysis/forinof/minitests.forinof.js.expected b/src/ch.usi.inf.nodeprof/js/analysis/forinof/minitests.forinof.js.expected index 8399d7aa..765175ad 100644 --- a/src/ch.usi.inf.nodeprof/js/analysis/forinof/minitests.forinof.js.expected +++ b/src/ch.usi.inf.nodeprof/js/analysis/forinof/minitests.forinof.js.expected @@ -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: +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 diff --git a/src/ch.usi.inf.nodeprof/js/analysis/trivial/emptyTemplate.js b/src/ch.usi.inf.nodeprof/js/analysis/trivial/emptyTemplate.js index b06b1dfc..1c41bae7 100644 --- a/src/ch.usi.inf.nodeprof/js/analysis/trivial/emptyTemplate.js +++ b/src/ch.usi.inf.nodeprof/js/analysis/trivial/emptyTemplate.js @@ -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 return 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 return keyword. @@ -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) { }; diff --git a/src/ch.usi.inf.nodeprof/js/jalangi.js b/src/ch.usi.inf.nodeprof/js/jalangi.js index 6ab0fc20..b5fc6468 100644 --- a/src/ch.usi.inf.nodeprof/js/jalangi.js +++ b/src/ch.usi.inf.nodeprof/js/jalangi.js @@ -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){ diff --git a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/ProfiledTagEnum.java b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/ProfiledTagEnum.java index 1765d1e5..90642b49 100644 --- a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/ProfiledTagEnum.java +++ b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/ProfiledTagEnum.java @@ -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), @@ -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 diff --git a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/LoopEventHandler.java b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/CFBlockEventHandler.java similarity index 59% rename from src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/LoopEventHandler.java rename to src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/CFBlockEventHandler.java index f835e52b..848e496e 100644 --- a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/LoopEventHandler.java +++ b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/CFBlockEventHandler.java @@ -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; } } diff --git a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/CFRootEventHandler.java b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/CFRootEventHandler.java index f7abb2dd..edd78d5b 100644 --- a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/CFRootEventHandler.java +++ b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/CFRootEventHandler.java @@ -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. @@ -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 { @@ -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()); } diff --git a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/JalangiAnalysis.java b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/JalangiAnalysis.java index b57bcd90..b00b9eb5 100644 --- a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/JalangiAnalysis.java +++ b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/JalangiAnalysis.java @@ -36,17 +36,17 @@ import ch.usi.inf.nodeprof.jalangi.factory.BinaryFactory; import ch.usi.inf.nodeprof.jalangi.factory.ReturnFactory; import ch.usi.inf.nodeprof.jalangi.factory.BuiltinFactory; +import ch.usi.inf.nodeprof.jalangi.factory.CFBlockFactory; import ch.usi.inf.nodeprof.jalangi.factory.ConditionalFactory; import ch.usi.inf.nodeprof.jalangi.factory.DeclareFactory; import ch.usi.inf.nodeprof.jalangi.factory.EvalFactory; import ch.usi.inf.nodeprof.jalangi.factory.EvalFunctionFactory; import ch.usi.inf.nodeprof.jalangi.factory.ExpressionFactory; -import ch.usi.inf.nodeprof.jalangi.factory.ForObjectFactory; import ch.usi.inf.nodeprof.jalangi.factory.GetElementFactory; import ch.usi.inf.nodeprof.jalangi.factory.GetFieldFactory; import ch.usi.inf.nodeprof.jalangi.factory.InvokeFactory; import ch.usi.inf.nodeprof.jalangi.factory.LiteralFactory; -import ch.usi.inf.nodeprof.jalangi.factory.LoopFactory; +import ch.usi.inf.nodeprof.jalangi.factory.CFRootFactory; import ch.usi.inf.nodeprof.jalangi.factory.PutElementFactory; import ch.usi.inf.nodeprof.jalangi.factory.PutFieldFactory; import ch.usi.inf.nodeprof.jalangi.factory.ReadFactory; @@ -124,16 +124,20 @@ public class JalangiAnalysis { put("asyncFunctionEnter", EnumSet.of(CF_ROOT)); put("asyncFunctionExit", EnumSet.of(CF_ROOT)); + put("awaitPre", EnumSet.of(CF_BRANCH)); + put("awaitPost", EnumSet.of(CF_BRANCH)); - put("forObject", EnumSet.of(CF_ROOT)); + put("cfRootEnter", EnumSet.of(CF_ROOT)); + put("cfRootExit", EnumSet.of(CF_ROOT)); + put("cfBlockEnter", EnumSet.of(CF_BLOCK)); + put("cfBlockExit", EnumSet.of(CF_BLOCK)); put("_return", EnumSet.of(CF_BRANCH)); - put("awaitPre", EnumSet.of(CF_BRANCH)); - put("awaitPost", EnumSet.of(CF_BRANCH)); put("startExpression", EnumSet.of(EXPRESSION)); put("endExpression", EnumSet.of(EXPRESSION)); + } }); @@ -279,12 +283,6 @@ public void onReady() { new EvalFunctionFactory(this.jsAnalysis, callbacks.get("evalFunctionPre"), callbacks.get("evalFunctionPost"))); } - if (this.callbacks.containsKey("forObject")) { - this.instrument.onCallback( - ProfiledTagEnum.CF_ROOT, - new ForObjectFactory(this.jsAnalysis, callbacks.get("forObject"))); - } - /** * async function */ @@ -303,14 +301,18 @@ public void onReady() { } /** - * TODO - * - * Loop not tested + * Control flow roots (if, loops, etc.) and their related control flow blocks */ - if (this.callbacks.containsKey("loopEnter") || this.callbacks.containsKey("loopExit")) { + if (this.callbacks.containsKey("cfRootEnter") || this.callbacks.containsKey("cfRootExit")) { this.instrument.onCallback( ProfiledTagEnum.CF_ROOT, - new LoopFactory(this.jsAnalysis, callbacks.get("loopEnter"), callbacks.get("loopExit"))); + new CFRootFactory(this.jsAnalysis, callbacks.get("cfRootEnter"), callbacks.get("cfRootExit"))); + } + + if (this.callbacks.containsKey("cfBlockEnter") || this.callbacks.containsKey("cfBlockExit")) { + this.instrument.onCallback( + ProfiledTagEnum.CF_BLOCK, + new CFBlockFactory(this.jsAnalysis, callbacks.get("cfBlockEnter"), callbacks.get("cfBlockExit"))); } /** diff --git a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/ForObjectFactory.java b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/CFBlockFactory.java similarity index 63% rename from src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/ForObjectFactory.java rename to src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/CFBlockFactory.java index f7176049..7b24cea8 100644 --- a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/ForObjectFactory.java +++ b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/CFBlockFactory.java @@ -21,27 +21,37 @@ import com.oracle.truffle.api.object.DynamicObject; import ch.usi.inf.nodeprof.handlers.BaseEventHandlerNode; -import ch.usi.inf.nodeprof.handlers.LoopEventHandler; +import ch.usi.inf.nodeprof.handlers.CFBlockEventHandler; -public class ForObjectFactory extends AbstractFactory { - public ForObjectFactory(Object jalangiAnalysis, DynamicObject pre) { - super("forObject", jalangiAnalysis, pre, null, 2, -1); +public class CFBlockFactory extends AbstractFactory { + public CFBlockFactory(Object jalangiAnalysis, DynamicObject pre, DynamicObject post) { + super("cfblock", jalangiAnalysis, pre, post, 2, 2); } @Override public BaseEventHandlerNode create(EventContext context) { - return new LoopEventHandler(context) { + return new CFBlockEventHandler(context) { @Child DirectCallNode preCall = createPreCallNode(); + @Child DirectCallNode postCall = createPostCallNode(); @Override - public void executePre(VirtualFrame frame, - Object[] inputs) { - if (pre != null && (isForIn() || isForOf())) { + public void executePre(VirtualFrame frame, Object[] inputs) { + if (pre != null) { setPreArguments(0, getSourceIID()); - setPreArguments(1, isForIn()); + setPreArguments(1, getParentIID()); directCall(preCall, true, getSourceIID()); } } + + @Override + public void executePost(VirtualFrame frame, Object result, + Object[] inputs) { + if (post != null) { + setPostArguments(0, getSourceIID()); + setPostArguments(1, getParentIID()); + directCall(postCall, false, getSourceIID()); + } + } }; } diff --git a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/LoopFactory.java b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/CFRootFactory.java similarity index 82% rename from src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/LoopFactory.java rename to src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/CFRootFactory.java index ae175bad..016beed9 100644 --- a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/LoopFactory.java +++ b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/CFRootFactory.java @@ -21,16 +21,16 @@ import com.oracle.truffle.api.object.DynamicObject; import ch.usi.inf.nodeprof.handlers.BaseEventHandlerNode; -import ch.usi.inf.nodeprof.handlers.LoopEventHandler; +import ch.usi.inf.nodeprof.handlers.CFRootEventHandler; -public class LoopFactory extends AbstractFactory { - public LoopFactory(Object jalangiAnalysis, DynamicObject pre, DynamicObject post) { - super("loop", jalangiAnalysis, pre, post, 2, 2); +public class CFRootFactory extends AbstractFactory { + public CFRootFactory(Object jalangiAnalysis, DynamicObject pre, DynamicObject post) { + super("cfroot", jalangiAnalysis, pre, post, 2, 2); } @Override public BaseEventHandlerNode create(EventContext context) { - return new LoopEventHandler(context) { + return new CFRootEventHandler(context) { @Child DirectCallNode preCall = createPreCallNode(); @Child DirectCallNode postCall = createPostCallNode(); @@ -38,7 +38,7 @@ public BaseEventHandlerNode create(EventContext context) { public void executePre(VirtualFrame frame, Object[] inputs) { if (pre != null) { setPreArguments(0, getSourceIID()); - setPreArguments(1, getLoopType()); + setPreArguments(1, getCFRootType()); directCall(preCall, true, getSourceIID()); } } @@ -47,9 +47,8 @@ public void executePre(VirtualFrame frame, Object[] inputs) { public void executePost(VirtualFrame frame, Object result, Object[] inputs) { if (post != null) { - setPostArguments(0, getSourceIID()); - setPostArguments(1, getLoopType()); + setPostArguments(1, getCFRootType()); directCall(postCall, false, getSourceIID()); } } diff --git a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/utils/NodeProfUtil.java b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/utils/NodeProfUtil.java new file mode 100644 index 00000000..40ef380c --- /dev/null +++ b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/utils/NodeProfUtil.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * 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. + *******************************************************************************/ +package ch.usi.inf.nodeprof.utils; + +import com.oracle.truffle.api.instrumentation.InstrumentableNode; +import com.oracle.truffle.api.nodes.Node; +import com.oracle.truffle.js.nodes.access.GlobalScopeVarWrapperNode; +import com.oracle.truffle.js.nodes.control.GeneratorWrapperNode; +import com.oracle.truffle.js.nodes.instrumentation.JSInputGeneratingNodeWrapper; +import com.oracle.truffle.js.nodes.instrumentation.JSTaggedExecutionNode; + +public class NodeProfUtil { + public static Node getParentSkipWrappers(Node n) { + assert n != null; + Node parent = n.getParent(); + while (parent != null && (isWrapperNode(parent) || parent.getSourceSection() == null)) { + parent = parent.getParent(); + } + return parent; + } + + public static boolean isWrapperNode(Node n) { + return n instanceof InstrumentableNode.WrapperNode || n instanceof JSInputGeneratingNodeWrapper || + n instanceof GlobalScopeVarWrapperNode || n instanceof JSTaggedExecutionNode || + n instanceof GeneratorWrapperNode; + } +}