diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d183cf32..f496ed69 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -55,3 +55,11 @@ jobs: run: mx --dy /compiler build - name: test NPM (with compiler) run: mx --dy /compiler --jdk jvmci test-npm + + - name: build with native image + run: | + cd ../graal/vm + mx --dy nodeprof,/substratevm --force-bash-launchers=true --disable-polyglot --skip-libraries=native-image-agent,jvmcicompiler,native-image-diagnostics-agent,polyglot build + cd - + - name: test with native image + run: mx test-specific --svm --all diff --git a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/BaseEventHandlerNode.java b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/BaseEventHandlerNode.java index a20ae35e..34f350cd 100644 --- a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/BaseEventHandlerNode.java +++ b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/BaseEventHandlerNode.java @@ -1,6 +1,6 @@ /******************************************************************************* * Copyright 2018 Dynamic Analysis Group, Università della Svizzera Italiana (USI) - * Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, 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. @@ -30,6 +30,7 @@ import com.oracle.truffle.api.object.DynamicObject; import com.oracle.truffle.api.source.SourceSection; import com.oracle.truffle.js.runtime.builtins.JSFunction; +import com.oracle.truffle.js.runtime.objects.JSLazyString; import com.oracle.truffle.js.runtime.objects.Undefined; import ch.usi.inf.nodeprof.utils.GlobalConfiguration; @@ -136,6 +137,7 @@ public void executeExceptionalCtrlFlow(VirtualFrame frame, Throwable exception, * @param key of the current InstrumentableNode * @return the value of this key */ + @TruffleBoundary public Object getAttribute(String key) { Object result = null; try { @@ -181,34 +183,45 @@ private void reportAttributeMissingError(String key, Exception e) { * * @param index * @param inputs - * @param inputName + * @param inputHint * @return the value of inputs[index] */ - protected Object assertGetInput(int index, Object[] inputs, String inputName) { + protected Object assertGetInput(int index, Object[] inputs, String inputHint) { if (inputs == null) { - reportInputsError(index, inputs, "InputsArrayNull"); + reportInputsError(index, null, "InputsArrayNull", inputHint); return Undefined.instance; } if (index < inputs.length) { Object result = inputs[index]; if (result == null) { result = Undefined.instance; - reportInputsError(index, inputs, "InputElementNull " + index); + reportInputsError(index, inputs, "InputElementNull", inputHint); } return result; } else { /** * if the inputs are not there, report the detail and stop the engine. */ - reportInputsError(index, inputs, "MissingInput"); + reportInputsError(index, inputs, "MissingInput", inputHint); } return Undefined.instance; } + protected String assertGetStringInput(int index, Object[] inputs, String inputHint) { + Object input = assertGetInput(index, inputs, inputHint); + if (input instanceof String) { + return (String) input; + } else if (input instanceof JSLazyString) { + return ((JSLazyString) input).toString(); + } + reportInputsError(1, inputs, "ExpectedStringLike", inputHint); + return null; + } + @TruffleBoundary - private void reportInputsError(int index, Object[] inputs, String info) { + private void reportInputsError(int index, Object[] inputs, String info, String inputHint) { Logger.error(context.getInstrumentedSourceSection(), - "Error[" + info + "] getting inputs at index '" + index + "' from " + + "Error[" + info + "] getting input (" + inputHint + ") at index '" + index + "' from " + context.getInstrumentedNode().getClass().getSimpleName() + " (has " + (inputs == null ? 0 : inputs.length) + " input(s))"); if (!GlobalConfiguration.IGNORE_JALANGI_EXCEPTION) { @@ -278,6 +291,7 @@ private static boolean isModuleInvocation(Object[] args) { return false; } + @TruffleBoundary protected static void checkForSymbolicLocation(Node node, Object[] args) { if (GlobalConfiguration.SYMBOLIC_LOCATIONS) { RootNode root = node.getRootNode(); diff --git a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/EvalEventHandler.java b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/EvalEventHandler.java index a951ba8b..5b73492e 100644 --- a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/EvalEventHandler.java +++ b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/EvalEventHandler.java @@ -1,6 +1,6 @@ /* ***************************************************************************** * Copyright 2018 Dynamic Analysis Group, Università della Svizzera Italiana (USI) - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, 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. @@ -29,7 +29,7 @@ public EvalEventHandler(EventContext context) { } protected String getCode(Object[] inputs) { - return assertGetInput(1, inputs, "code").toString(); + return assertGetStringInput(1, inputs, "code"); } } diff --git a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/FunctionRootEventHandler.java b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/FunctionRootEventHandler.java index e49e004e..a79774e0 100644 --- a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/FunctionRootEventHandler.java +++ b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/handlers/FunctionRootEventHandler.java @@ -1,6 +1,6 @@ /* ***************************************************************************** * Copyright 2018 Dynamic Analysis Group, Università della Svizzera Italiana (USI) - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, 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. @@ -144,6 +144,7 @@ public String getFunctionName() { * @return the source of the instrumented node (or its closest parent), or null if no source is * available */ + @TruffleBoundary public Source getSource() { if (isRegularExpression() || this.isBuiltin) { return null; diff --git a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/JalangiAdapter.java b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/JalangiAdapter.java index 2990e038..cc558501 100644 --- a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/JalangiAdapter.java +++ b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/JalangiAdapter.java @@ -1,6 +1,6 @@ /* ***************************************************************************** * Copyright 2018 Dynamic Analysis Group, Università della Svizzera Italiana (USI) - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, 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. @@ -150,6 +150,7 @@ private Object getConfig() { } @ExportMessage + @TruffleBoundary final Object invokeMember(String identifier, Object[] arguments) throws ArityException, UnsupportedTypeException { ApiMember api; try { diff --git a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/AbstractFactory.java b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/AbstractFactory.java index fce641f7..20949fdf 100644 --- a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/AbstractFactory.java +++ b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/AbstractFactory.java @@ -1,6 +1,6 @@ /* ***************************************************************************** * Copyright 2018 Dynamic Analysis Group, Università della Svizzera Italiana (USI) - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, 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. @@ -177,13 +177,18 @@ private static void afterCall() { public class CallbackNode extends Node { @Node.Child DirectCallNode preCall = pre == null ? null : Truffle.getRuntime().createDirectCallNode(JSFunction.getCallTarget(pre)); @Node.Child DirectCallNode postCall = post == null ? null : Truffle.getRuntime().createDirectCallNode(JSFunction.getCallTarget(post)); + @Child private InteropLibrary interopLibrary = InteropLibrary.getFactory().createDispatched(3); private void checkDeactivate(Object ret, BaseEventHandlerNode handler) { if (ret != null && ret != Undefined.instance && JSObject.isJSObject(ret)) { - Object prop = JSObject.get((DynamicObject) ret, "deactivate"); - if (prop.equals(true)) { - CompilerDirectives.transferToInterpreterAndInvalidate(); - handler.deactivate(); + try { + Object prop = interopLibrary.readMember(ret, "deactivate"); + if (interopLibrary.asBoolean(prop)) { + CompilerDirectives.transferToInterpreterAndInvalidate(); + handler.deactivate(); + } + } catch (UnsupportedMessageException | UnknownIdentifierException ignored) { + // ignore, don't deactivate } } } diff --git a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/InitialRootFactory.java b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/InitialRootFactory.java index 0668fd58..ee57c933 100644 --- a/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/InitialRootFactory.java +++ b/src/ch.usi.inf.nodeprof/src/ch/usi/inf/nodeprof/jalangi/factory/InitialRootFactory.java @@ -1,6 +1,6 @@ /* ***************************************************************************** * Copyright 2018 Dynamic Analysis Group, Università della Svizzera Italiana (USI) - * Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2018, 2021, 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. @@ -38,12 +38,22 @@ public InitialRootFactory(Object jalangiAnalysis, DynamicObject post) { private final Set seenSources = new HashSet<>(); + /** + * Returns the code for source as a string if source has not been seen yet. + * + * @param source source object + * @return source as String or null + */ @TruffleBoundary - private boolean isNewSource(Source source) { + private String sourceStringIfNew(Source source) { if (source == null) { - return false; + return null; } - return seenSources.add(source); + if (seenSources.add(source)) { + // getCharacters() needs to be behind boundary + return source.getCharacters().toString(); + } + return null; } @Override @@ -75,13 +85,15 @@ public void executePre(VirtualFrame frame, Object[] inputs) throws InteropExcept return; } - if (isNewSource(source)) { + String sourceAsString = sourceStringIfNew(source); + + if (sourceAsString != null) { cbNode.postCall(this, jalangiAnalysis, post, SourceMapping.getJSObjectForSource(source), // arg 1: source // object - source.getCharacters().toString()); // arg 2: source code + sourceAsString); // arg 2: source code } } };