├── .gitignore
├── CONTRIBUTING.md
├── LICENSE.md
├── README.md
├── ci.jsonnet
├── example.js
├── pom.xml
├── runJsWithCoverage.sh
├── simpletool
└── src
├── main
└── java
│ ├── com
│ └── oracle
│ │ └── truffle
│ │ └── st
│ │ ├── Coverage.java
│ │ ├── CoverageEventFactory.java
│ │ ├── CoverageNode.java
│ │ ├── GatherSourceSectionsListener.java
│ │ └── SimpleCoverageInstrument.java
│ └── module-info.java
└── test
└── java
├── com
└── oracle
│ └── truffle
│ └── st
│ └── test
│ └── SimpleCoverageInstrumentTest.java
└── module-info.java
/.gitignore:
--------------------------------------------------------------------------------
1 | /target/
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | This repository contains a snapshot of SimpleTool that is updated only after major changes. The development version is part of the Truffle repository: https://github.com/graalvm/truffle
2 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
2 |
3 | The Universal Permissive License (UPL), Version 1.0
4 |
5 | Subject to the condition set forth below, permission is hereby granted to any
6 | person obtaining a copy of this software, associated documentation and/or data
7 | (collectively the "Software"), free of charge and under any and all copyright
8 | rights in the Software, and any and all patent rights owned or freely
9 | licensable by each licensor hereunder covering either (i) the unmodified
10 | Software as contributed to or provided by such licensor, or (ii) the Larger
11 | Works (as defined below), to deal in both
12 |
13 | (a) the Software, and
14 |
15 | (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
16 | one is included with the Software each a "Larger Work" to which the Software
17 | is contributed by such licensors),
18 |
19 | without restriction, including without limitation the rights to copy, create
20 | derivative works of, display, perform, and distribute the Software and make,
21 | use, sell, offer for sale, import, export, have made, and have sold the
22 | Software and the Larger Work(s), and to sublicense the foregoing rights on
23 | either these or other terms.
24 |
25 | This license is subject to the following condition:
26 |
27 | The above copyright notice and either this complete permission notice or at a
28 | minimum a reference to the UPL must be included in all copies or substantial
29 | portions of the Software.
30 |
31 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
32 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
34 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
36 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37 | SOFTWARE.
38 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Simple Tool
2 |
3 | A simple demonstration code coverage tool built using Truffle for GraalVM.
4 |
5 | The source code is documented to explain the how and why of writing a Truffle
6 | tool. A good way to find out more is to read the source with comments. We also
7 | like to encourage people to clone the repository and start hacking.
8 |
9 | This repository is licensed under the permissive UPL licence. Fork it to begin
10 | your own Truffle tool.
11 |
12 | For instructions on how to get started please refer to [our website](https://www.graalvm.org/docs/graalvm-as-a-platform/implement-instrument/)
13 |
--------------------------------------------------------------------------------
/ci.jsonnet:
--------------------------------------------------------------------------------
1 | {
2 | local basicBuild = {
3 | targets: ['gate'],
4 | timelimit: '00:59:59',
5 | run: [
6 | ['mvn', 'clean'],
7 | ['mvn', 'package'],
8 | ['./simpletool', 'example.js'],
9 | ],
10 | },
11 |
12 | local graalvm = {
13 | downloads+: {
14 | JAVA_HOME: { name: 'graalvm-community-java21', version: '23.1.0', platformspecific: true },
15 | },
16 | },
17 |
18 | local linux = {
19 | capabilities+: ['linux', 'amd64'],
20 | packages+: {
21 | maven: '==3.3.9',
22 | },
23 | docker: {
24 | image: "buildslave_ol7",
25 | mount_modules: true,
26 | },
27 | },
28 |
29 | local darwin = {
30 | capabilities+: ['darwin_sierra', 'amd64'],
31 | environment+: {
32 | MACOSX_DEPLOYMENT_TARGET: '10.11',
33 | JAVA_HOME: '$JAVA_HOME/Contents/Home'
34 | },
35 | },
36 |
37 | builds: [
38 | basicBuild + linux + graalvm + { name: 'linux' },
39 |
40 | basicBuild + darwin + graalvm + { name: 'darwin' },
41 | ],
42 | }
43 |
--------------------------------------------------------------------------------
/example.js:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * The Universal Permissive License (UPL), Version 1.0
6 | *
7 | * Subject to the condition set forth below, permission is hereby granted to any
8 | * person obtaining a copy of this software, associated documentation and/or
9 | * data (collectively the "Software"), free of charge and under any and all
10 | * copyright rights in the Software, and any and all patent rights owned or
11 | * freely licensable by each licensor hereunder covering either (i) the
12 | * unmodified Software as contributed to or provided by such licensor, or (ii)
13 | * the Larger Works (as defined below), to deal in both
14 | *
15 | * (a) the Software, and
16 | *
17 | * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18 | * one is included with the Software each a "Larger Work" to which the Software
19 | * is contributed by such licensors),
20 | *
21 | * without restriction, including without limitation the rights to copy, create
22 | * derivative works of, display, perform, and distribute the Software and make,
23 | * use, sell, offer for sale, import, export, have made, and have sold the
24 | * Software and the Larger Work(s), and to sublicense the foregoing rights on
25 | * either these or other terms.
26 | *
27 | * This license is subject to the following condition:
28 | *
29 | * The above copyright notice and either this complete permission notice or at a
30 | * minimum a reference to the UPL must be included in all copies or substantial
31 | * portions of the Software.
32 | *
33 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 | * SOFTWARE.
40 | */
41 | var N = 2000;
42 | var EXPECTED = 17393;
43 |
44 | function Natural() {
45 | x = 2;
46 | return {
47 | 'next' : function() { return x++; }
48 | };
49 | }
50 |
51 | function Filter(number, filter) {
52 | var self = this;
53 | this.number = number;
54 | this.filter = filter;
55 | this.accept = function(n) {
56 | var filter = self;
57 | for (;;) {
58 | if (n % filter.number === 0) {
59 | return false;
60 | }
61 | filter = filter.filter;
62 | if (filter === null) {
63 | break;
64 | }
65 | }
66 | return true;
67 | };
68 | return this;
69 | }
70 |
71 | function Primes(natural) {
72 | var self = this;
73 | this.natural = natural;
74 | this.filter = null;
75 | this.next = function() {
76 | for (;;) {
77 | var n = self.natural.next();
78 | if (self.filter === null || self.filter.accept(n)) {
79 | self.filter = new Filter(n, self.filter);
80 | return n;
81 | }
82 | }
83 | };
84 | }
85 |
86 | var holdsAFunctionThatIsNeverCalled = function(natural) {
87 | var self = this;
88 | this.natural = natural;
89 | this.filter = null;
90 | this.next = function() {
91 | for (;;) {
92 | var n = self.natural.next();
93 | if (self.filter === null || self.filter.accept(n)) {
94 | self.filter = new Filter(n, self.filter);
95 | return n;
96 | }
97 | }
98 | };
99 | }
100 |
101 | var holdsAFunctionThatIsNeverCalledOneLine = function() {return null;}
102 |
103 | function primesMain() {
104 | var primes = new Primes(Natural());
105 | var primArray = [];
106 | for (var i=0;i<=N;i++) { primArray.push(primes.next()); }
107 | if (primArray[N] != EXPECTED) { throw new Error('wrong prime found: ' + primArray[N]); }
108 | }
109 | primesMain();
110 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
42 |
45 | 4.0.0
46 | com.oracle
47 | simpletool
48 | ${graalvm.version}
49 | simpletool
50 |
51 | 23.1.0
52 | UTF-8
53 | 17
54 | 17
55 | jdt_apt
56 |
57 |
58 |
59 | junit
60 | junit
61 | 4.13.2
62 | test
63 |
64 |
65 | org.graalvm.polyglot
66 | polyglot
67 | ${graalvm.version}
68 |
69 |
70 | org.graalvm.truffle
71 | truffle-api
72 | ${graalvm.version}
73 |
74 |
75 | org.graalvm.truffle
76 | truffle-runtime
77 | ${graalvm.version}
78 | runtime
79 |
80 |
81 | org.graalvm.sdk
82 | jniutils
83 | ${graalvm.version}
84 | runtime
85 |
86 |
87 |
88 | org.graalvm.js
89 | js-language
90 | ${graalvm.version}
91 | runtime
92 |
93 |
94 | org.graalvm.js
95 | js-launcher
96 | ${graalvm.version}
97 |
98 |
99 |
100 |
101 |
102 | org.apache.maven.plugins
103 | maven-dependency-plugin
104 | 3.2.0
105 |
106 |
107 | copy-dependencies
108 | package
109 |
110 | copy-dependencies
111 |
112 |
113 | ${project.build.directory}/modules
114 | true
115 |
116 |
117 |
118 |
119 |
120 | maven-compiler-plugin
121 | 3.11.0
122 |
123 | 17
124 | 17
125 |
126 |
127 | org.graalvm.truffle
128 | truffle-dsl-processor
129 | ${graalvm.version}
130 |
131 |
132 |
133 |
134 |
135 | org.apache.maven.plugins
136 | maven-surefire-plugin
137 | 3.1.2
138 |
139 | true
140 |
141 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/runJsWithCoverage.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
4 | # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 | #
6 | # The Universal Permissive License (UPL), Version 1.0
7 | #
8 | # Subject to the condition set forth below, permission is hereby granted to any
9 | # person obtaining a copy of this software, associated documentation and/or
10 | # data (collectively the "Software"), free of charge and under any and all
11 | # copyright rights in the Software, and any and all patent rights owned or
12 | # freely licensable by each licensor hereunder covering either (i) the
13 | # unmodified Software as contributed to or provided by such licensor, or (ii)
14 | # the Larger Works (as defined below), to deal in both
15 | #
16 | # (a) the Software, and
17 | #
18 | # (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
19 | # one is included with the Software each a "Larger Work" to which the Software
20 | # is contributed by such licensors),
21 | #
22 | # without restriction, including without limitation the rights to copy, create
23 | # derivative works of, display, perform, and distribute the Software and make,
24 | # use, sell, offer for sale, import, export, have made, and have sold the
25 | # Software and the Larger Work(s), and to sublicense the foregoing rights on
26 | # either these or other terms.
27 | #
28 | # This license is subject to the following condition:
29 | #
30 | # The above copyright notice and either this complete permission notice or at a
31 | # minimum a reference to the UPL must be included in all copies or substantial
32 | # portions of the Software.
33 | #
34 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40 | # SOFTWARE.
41 | #
42 |
43 | ./simpletool example.js
44 |
--------------------------------------------------------------------------------
/simpletool:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | #
3 | # Copyright (c) 2018, 2019, Oracle and/or its affiliates. All rights reserved.
4 | # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 | #
6 | # The Universal Permissive License (UPL), Version 1.0
7 | #
8 | # Subject to the condition set forth below, permission is hereby granted to any
9 | # person obtaining a copy of this software, associated documentation and/or
10 | # data (collectively the "Software"), free of charge and under any and all
11 | # copyright rights in the Software, and any and all patent rights owned or
12 | # freely licensable by each licensor hereunder covering either (i) the
13 | # unmodified Software as contributed to or provided by such licensor, or (ii)
14 | # the Larger Works (as defined below), to deal in both
15 | #
16 | # (a) the Software, and
17 | #
18 | # (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
19 | # one is included with the Software each a "Larger Work" to which the Software
20 | # is contributed by such licensors),
21 | #
22 | # without restriction, including without limitation the rights to copy, create
23 | # derivative works of, display, perform, and distribute the Software and make,
24 | # use, sell, offer for sale, import, export, have made, and have sold the
25 | # Software and the Larger Work(s), and to sublicense the foregoing rights on
26 | # either these or other terms.
27 | #
28 | # This license is subject to the following condition:
29 | #
30 | # The above copyright notice and either this complete permission notice or at a
31 | # minimum a reference to the UPL must be included in all copies or substantial
32 | # portions of the Software.
33 | #
34 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
40 | # SOFTWARE.
41 | #
42 |
43 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
44 |
45 | "$JAVA_HOME/bin/java" -p "${DIR}/target/modules:${DIR}/target/classes" -m org.graalvm.js.launcher/com.oracle.truffle.js.shell.JSLauncher --simple-code-coverage "$@"
--------------------------------------------------------------------------------
/src/main/java/com/oracle/truffle/st/Coverage.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * The Universal Permissive License (UPL), Version 1.0
6 | *
7 | * Subject to the condition set forth below, permission is hereby granted to any
8 | * person obtaining a copy of this software, associated documentation and/or
9 | * data (collectively the "Software"), free of charge and under any and all
10 | * copyright rights in the Software, and any and all patent rights owned or
11 | * freely licensable by each licensor hereunder covering either (i) the
12 | * unmodified Software as contributed to or provided by such licensor, or (ii)
13 | * the Larger Works (as defined below), to deal in both
14 | *
15 | * (a) the Software, and
16 | *
17 | * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18 | * one is included with the Software each a "Larger Work" to which the Software
19 | * is contributed by such licensors),
20 | *
21 | * without restriction, including without limitation the rights to copy, create
22 | * derivative works of, display, perform, and distribute the Software and make,
23 | * use, sell, offer for sale, import, export, have made, and have sold the
24 | * Software and the Larger Work(s), and to sublicense the foregoing rights on
25 | * either these or other terms.
26 | *
27 | * This license is subject to the following condition:
28 | *
29 | * The above copyright notice and either this complete permission notice or at a
30 | * minimum a reference to the UPL must be included in all copies or substantial
31 | * portions of the Software.
32 | *
33 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 | * SOFTWARE.
40 | */
41 | package com.oracle.truffle.st;
42 |
43 | import java.util.HashSet;
44 | import java.util.Set;
45 |
46 | import com.oracle.truffle.api.source.SourceSection;
47 |
48 | /**
49 | * Contains per {@link com.oracle.truffle.api.source.Source} coverage by keeping track of loaded and
50 | * covered {@link com.oracle.truffle.api.source.SourceSection}s.
51 | */
52 | public final class Coverage {
53 | private final Set loaded = new HashSet<>();
54 | private final Set covered = new HashSet<>();
55 |
56 | void addCovered(SourceSection sourceSection) {
57 | covered.add(sourceSection);
58 | }
59 |
60 | void addLoaded(SourceSection sourceSection) {
61 | loaded.add(sourceSection);
62 | }
63 |
64 | private Set nonCoveredSections() {
65 | final HashSet nonCovered = new HashSet<>();
66 | nonCovered.addAll(loaded);
67 | nonCovered.removeAll(covered);
68 | return nonCovered;
69 | }
70 |
71 | Set nonCoveredLineNumbers() {
72 | Set linesNotCovered = new HashSet<>();
73 | for (SourceSection ss : nonCoveredSections()) {
74 | for (int i = ss.getStartLine(); i <= ss.getEndLine(); i++) {
75 | linesNotCovered.add(i);
76 | }
77 | }
78 | return linesNotCovered;
79 | }
80 |
81 | Set loadedLineNumbers() {
82 | Set loadedLines = new HashSet<>();
83 | for (SourceSection ss : loaded) {
84 | for (int i = ss.getStartLine(); i <= ss.getEndLine(); i++) {
85 | loadedLines.add(i);
86 | }
87 | }
88 | return loadedLines;
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/src/main/java/com/oracle/truffle/st/CoverageEventFactory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * The Universal Permissive License (UPL), Version 1.0
6 | *
7 | * Subject to the condition set forth below, permission is hereby granted to any
8 | * person obtaining a copy of this software, associated documentation and/or
9 | * data (collectively the "Software"), free of charge and under any and all
10 | * copyright rights in the Software, and any and all patent rights owned or
11 | * freely licensable by each licensor hereunder covering either (i) the
12 | * unmodified Software as contributed to or provided by such licensor, or (ii)
13 | * the Larger Works (as defined below), to deal in both
14 | *
15 | * (a) the Software, and
16 | *
17 | * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18 | * one is included with the Software each a "Larger Work" to which the Software
19 | * is contributed by such licensors),
20 | *
21 | * without restriction, including without limitation the rights to copy, create
22 | * derivative works of, display, perform, and distribute the Software and make,
23 | * use, sell, offer for sale, import, export, have made, and have sold the
24 | * Software and the Larger Work(s), and to sublicense the foregoing rights on
25 | * either these or other terms.
26 | *
27 | * This license is subject to the following condition:
28 | *
29 | * The above copyright notice and either this complete permission notice or at a
30 | * minimum a reference to the UPL must be included in all copies or substantial
31 | * portions of the Software.
32 | *
33 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 | * SOFTWARE.
40 | */
41 | package com.oracle.truffle.st;
42 |
43 | import com.oracle.truffle.api.instrumentation.EventContext;
44 | import com.oracle.truffle.api.instrumentation.ExecutionEventNode;
45 | import com.oracle.truffle.api.instrumentation.ExecutionEventNodeFactory;
46 | import com.oracle.truffle.api.source.SourceSection;
47 |
48 | /**
49 | * A factory for nodes that track coverage
50 | *
51 | * Because we
52 | * {@link SimpleCoverageInstrument#enable(com.oracle.truffle.api.instrumentation.TruffleInstrument.Env)
53 | * attached} an instance of this factory, each time a AST node of interest is created, it is
54 | * instrumented with a node created by this factory.
55 | */
56 | final class CoverageEventFactory implements ExecutionEventNodeFactory {
57 |
58 | private SimpleCoverageInstrument simpleCoverageInstrument;
59 |
60 | CoverageEventFactory(SimpleCoverageInstrument simpleCoverageInstrument) {
61 | this.simpleCoverageInstrument = simpleCoverageInstrument;
62 | }
63 |
64 | /**
65 | * @param ec context of the event, used in our case to lookup the {@link SourceSection} that our
66 | * node is instrumenting.
67 | * @return An {@link ExecutionEventNode}
68 | */
69 | public ExecutionEventNode create(final EventContext ec) {
70 | return new CoverageNode(simpleCoverageInstrument, ec.getInstrumentedSourceSection());
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/main/java/com/oracle/truffle/st/CoverageNode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * The Universal Permissive License (UPL), Version 1.0
6 | *
7 | * Subject to the condition set forth below, permission is hereby granted to any
8 | * person obtaining a copy of this software, associated documentation and/or
9 | * data (collectively the "Software"), free of charge and under any and all
10 | * copyright rights in the Software, and any and all patent rights owned or
11 | * freely licensable by each licensor hereunder covering either (i) the
12 | * unmodified Software as contributed to or provided by such licensor, or (ii)
13 | * the Larger Works (as defined below), to deal in both
14 | *
15 | * (a) the Software, and
16 | *
17 | * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18 | * one is included with the Software each a "Larger Work" to which the Software
19 | * is contributed by such licensors),
20 | *
21 | * without restriction, including without limitation the rights to copy, create
22 | * derivative works of, display, perform, and distribute the Software and make,
23 | * use, sell, offer for sale, import, export, have made, and have sold the
24 | * Software and the Larger Work(s), and to sublicense the foregoing rights on
25 | * either these or other terms.
26 | *
27 | * This license is subject to the following condition:
28 | *
29 | * The above copyright notice and either this complete permission notice or at a
30 | * minimum a reference to the UPL must be included in all copies or substantial
31 | * portions of the Software.
32 | *
33 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 | * SOFTWARE.
40 | */
41 | package com.oracle.truffle.st;
42 |
43 | import com.oracle.truffle.api.CompilerDirectives;
44 | import com.oracle.truffle.api.frame.VirtualFrame;
45 | import com.oracle.truffle.api.instrumentation.ExecutionEventNode;
46 | import com.oracle.truffle.api.instrumentation.Instrumenter;
47 | import com.oracle.truffle.api.source.SourceSection;
48 |
49 | /**
50 | * Node that "wraps" AST nodes of interest (Nodes that correspond to expressions in our case as
51 | * defined by the filter given to the {@link Instrumenter} in
52 | * {@link SimpleCoverageInstrument#onCreate(com.oracle.truffle.api.instrumentation.TruffleInstrument.Env) }
53 | * ), and informs the {@link SimpleCoverageInstrument} that we
54 | * {@link SimpleCoverageInstrument#addCovered(SourceSection) covered} it's
55 | * {@link #instrumentedSourceSection source section}.
56 | */
57 | final class CoverageNode extends ExecutionEventNode {
58 |
59 | private final SimpleCoverageInstrument instrument;
60 | @CompilerDirectives.CompilationFinal private boolean covered;
61 |
62 | /**
63 | * Each node knows which {@link SourceSection} it instruments.
64 | */
65 | private final SourceSection instrumentedSourceSection;
66 |
67 | CoverageNode(SimpleCoverageInstrument instrument, SourceSection instrumentedSourceSection) {
68 | this.instrument = instrument;
69 | this.instrumentedSourceSection = instrumentedSourceSection;
70 | }
71 |
72 | /**
73 | * The {@link ExecutionEventNode} class let's us define several events that we can intercept.
74 | * The one of interest to us is
75 | * {@link ExecutionEventNode#onReturnValue(com.oracle.truffle.api.frame.VirtualFrame, Object) }
76 | * as we wish to track this nodes {@link #instrumentedSourceSection} in the
77 | * {@link SimpleCoverageInstrument#coverageMap} only once the node is successfully executed (as
78 | * oppose to, for example,
79 | * {@link ExecutionEventNode#onReturnExceptional(com.oracle.truffle.api.frame.VirtualFrame, Throwable) }
80 | * ).
81 | *
82 | * Each node keeps a {@link #covered} flag so that the removal only happens once. The fact that
83 | * the flag is annotated with {@link CompilerDirectives.CompilationFinal} means that this flag
84 | * will be treated as {@code final} during compilation of instrumented source code (i.e. the
85 | * {@code false} branch of the if statement can be optimized away).
86 | *
87 | * The way it's used in this method is a pattern when writing Truffle nodes:
88 | *
89 | *
If we are compiling a covered node, the if condition will evaluate to false and the
90 | * if-guarded code will be optimized away. This means that once this {@link SourceSection} is
91 | * confirmed to be covered, there is no further instrumentation overhead on performance.
92 | *
If we are compiling a not-yet-covered node, the if condition will evaluate to true, and
93 | * the if-guarded code will be included for compilation. The first statement in this block is a
94 | * {@link CompilerDirectives#transferToInterpreterAndInvalidate() directive to the compiler} to
95 | * make sure that if this point in the execution is reached, the execution should return to the
96 | * interpreter and the existing compiled code is no longer valid (since once the covered flag is
97 | * set to true, the check is unnecessary). The code following the directive is thus always
98 | * executed in the interpreter: We set the {@link #covered} flag to true, ensuring that the next
99 | * compilation will have no instrumentation overhead on performance.
100 | *
101 | *
102 | * @param vFrame unused
103 | * @param result unused
104 | */
105 | @Override
106 | public void onReturnValue(VirtualFrame vFrame, Object result) {
107 | if (!covered) {
108 | CompilerDirectives.transferToInterpreterAndInvalidate();
109 | covered = true;
110 | instrument.addCovered(instrumentedSourceSection);
111 | }
112 | }
113 |
114 | }
115 |
--------------------------------------------------------------------------------
/src/main/java/com/oracle/truffle/st/GatherSourceSectionsListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * The Universal Permissive License (UPL), Version 1.0
6 | *
7 | * Subject to the condition set forth below, permission is hereby granted to any
8 | * person obtaining a copy of this software, associated documentation and/or
9 | * data (collectively the "Software"), free of charge and under any and all
10 | * copyright rights in the Software, and any and all patent rights owned or
11 | * freely licensable by each licensor hereunder covering either (i) the
12 | * unmodified Software as contributed to or provided by such licensor, or (ii)
13 | * the Larger Works (as defined below), to deal in both
14 | *
15 | * (a) the Software, and
16 | *
17 | * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18 | * one is included with the Software each a "Larger Work" to which the Software
19 | * is contributed by such licensors),
20 | *
21 | * without restriction, including without limitation the rights to copy, create
22 | * derivative works of, display, perform, and distribute the Software and make,
23 | * use, sell, offer for sale, import, export, have made, and have sold the
24 | * Software and the Larger Work(s), and to sublicense the foregoing rights on
25 | * either these or other terms.
26 | *
27 | * This license is subject to the following condition:
28 | *
29 | * The above copyright notice and either this complete permission notice or at a
30 | * minimum a reference to the UPL must be included in all copies or substantial
31 | * portions of the Software.
32 | *
33 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 | * SOFTWARE.
40 | */
41 | package com.oracle.truffle.st;
42 |
43 | import com.oracle.truffle.api.instrumentation.LoadSourceSectionEvent;
44 | import com.oracle.truffle.api.instrumentation.LoadSourceSectionListener;
45 | import com.oracle.truffle.api.source.SourceSection;
46 |
47 | /**
48 | * A listener for new {@link SourceSection}s being loaded.
49 | *
50 | * Because we
51 | * {@link SimpleCoverageInstrument#enable(com.oracle.truffle.api.instrumentation.TruffleInstrument.Env)
52 | * attached} an instance of this listener, each time a new {@link SourceSection} of interest is
53 | * loaded, we are notified in the
54 | * {@link #onLoad(com.oracle.truffle.api.instrumentation.LoadSourceSectionEvent) } method.
55 | */
56 | final class GatherSourceSectionsListener implements LoadSourceSectionListener {
57 |
58 | private final SimpleCoverageInstrument instrument;
59 |
60 | GatherSourceSectionsListener(SimpleCoverageInstrument instrument) {
61 | this.instrument = instrument;
62 | }
63 |
64 | /**
65 | * Notification that a new {@link LoadSourceSectionEvent} has occurred.
66 | *
67 | * @param event information about the event. We use this information to keep our
68 | * {@link SimpleCoverageInstrument#coverageMap} up to date.
69 | */
70 | @Override
71 | public void onLoad(LoadSourceSectionEvent event) {
72 | final SourceSection sourceSection = event.getSourceSection();
73 | instrument.addLoaded(sourceSection);
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/com/oracle/truffle/st/SimpleCoverageInstrument.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * The Universal Permissive License (UPL), Version 1.0
6 | *
7 | * Subject to the condition set forth below, permission is hereby granted to any
8 | * person obtaining a copy of this software, associated documentation and/or
9 | * data (collectively the "Software"), free of charge and under any and all
10 | * copyright rights in the Software, and any and all patent rights owned or
11 | * freely licensable by each licensor hereunder covering either (i) the
12 | * unmodified Software as contributed to or provided by such licensor, or (ii)
13 | * the Larger Works (as defined below), to deal in both
14 | *
15 | * (a) the Software, and
16 | *
17 | * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18 | * one is included with the Software each a "Larger Work" to which the Software
19 | * is contributed by such licensors),
20 | *
21 | * without restriction, including without limitation the rights to copy, create
22 | * derivative works of, display, perform, and distribute the Software and make,
23 | * use, sell, offer for sale, import, export, have made, and have sold the
24 | * Software and the Larger Work(s), and to sublicense the foregoing rights on
25 | * either these or other terms.
26 | *
27 | * This license is subject to the following condition:
28 | *
29 | * The above copyright notice and either this complete permission notice or at a
30 | * minimum a reference to the UPL must be included in all copies or substantial
31 | * portions of the Software.
32 | *
33 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 | * SOFTWARE.
40 | */
41 | package com.oracle.truffle.st;
42 |
43 | import java.io.PrintStream;
44 | import java.util.Collections;
45 | import java.util.HashMap;
46 | import java.util.Map;
47 | import java.util.Set;
48 | import java.util.function.Function;
49 |
50 | import org.graalvm.options.OptionCategory;
51 | import org.graalvm.options.OptionDescriptors;
52 | import org.graalvm.options.OptionKey;
53 | import org.graalvm.options.OptionStability;
54 | import org.graalvm.options.OptionValues;
55 |
56 | import com.oracle.truffle.api.Option;
57 | import com.oracle.truffle.api.instrumentation.Instrumenter;
58 | import com.oracle.truffle.api.instrumentation.SourceSectionFilter;
59 | import com.oracle.truffle.api.instrumentation.StandardTags.ExpressionTag;
60 | import com.oracle.truffle.api.instrumentation.TruffleInstrument;
61 | import com.oracle.truffle.api.instrumentation.TruffleInstrument.Registration;
62 | import com.oracle.truffle.api.nodes.Node;
63 | import com.oracle.truffle.api.source.Source;
64 | import com.oracle.truffle.api.source.SourceSection;
65 |
66 | /**
67 | * Example for simple version of an expression coverage instrument.
68 | *
69 | * The instrument {@link #coverageMap keeps track} of all loaded {@link SourceSection}s and all
70 | * coverd (i.e. executed) {@link SourceSection}s for each {@link Source}. At the end of the
71 | * execution this information can be used to calculate coverage.
72 | *
73 | * The instrument is registered with the Truffle framework using the {@link Registration}
74 | * annotation. The annotation specifies a unique {@link Registration#id}, a human readable
75 | * {@link Registration#name} and {@link Registration#version} for the instrument. It also specifies
76 | * all service classes that the instrument exports to other instruments and, exceptionally, tests.
77 | * In this case the instrument itself is exported as a service and used in the
78 | * SimpleCoverageInstrumentTest.
79 | *
80 | * NOTE: Fot the registration annotation to work the truffle dsl processor must be used (i.e. Must
81 | * be a dependency. This is so in this maven project, as can be seen in the pom file.
82 | */
83 | @Registration(id = SimpleCoverageInstrument.ID, name = "Simple Code Coverage", version = "0.1", services = SimpleCoverageInstrument.class)
84 | public final class SimpleCoverageInstrument extends TruffleInstrument {
85 |
86 | // @formatter:off
87 | /**
88 | * Look at {@link #onCreate(Env)} and {@link #getOptionDescriptors()} for more info.
89 | */
90 | @Option(name = "", help = "Enable Simple Coverage (default: false).", category = OptionCategory.USER, stability = OptionStability.STABLE)
91 | static final OptionKey ENABLED = new OptionKey<>(false);
92 |
93 | /**
94 | * Look at {@link #onCreate(Env)} and {@link #getOptionDescriptors()} for more info.
95 | */
96 | @Option(name = "PrintCoverage", help = "Print coverage to stdout on process exit (default: true).", category = OptionCategory.USER, stability = OptionStability.STABLE)
97 | static final OptionKey PRINT_COVERAGE = new OptionKey<>(true);
98 | // @formatter:on
99 |
100 | public static final String ID = "simple-code-coverage";
101 |
102 | /**
103 | * The instrument keeps a mapping between a {@link Source} and {@link Coverage coverage} data
104 | * for that source. Coverage tracks loaded and covered {@link SourceSection} during execution.
105 | */
106 | final Map coverageMap = new HashMap<>();
107 |
108 | public synchronized Map getCoverageMap() {
109 | return Collections.unmodifiableMap(coverageMap);
110 | }
111 |
112 | /**
113 | * Each instrument must override the
114 | * {@link TruffleInstrument#onCreate(com.oracle.truffle.api.instrumentation.TruffleInstrument.Env)}
115 | * method.
116 | *
117 | * This method is used to properly initialize the instrument. A common practice is to use the
118 | * {@link Option} system to enable and configure the instrument, as is done in this method.
119 | * Defining {@link Option}s as is shown in {@link #ENABLED} and {@link #PRINT_COVERAGE}, and
120 | * their usage can be seen in the SimpleCoverageInstrumentTest when the context is being
121 | * created. Using them from the command line is shown in the simpletool.sh script.
122 | *
123 | * @param env the environment for the instrument. Allows us to read the {@link Option}s, input
124 | * and output streams to be used for reading and writing, as well as
125 | * {@link Env#registerService(java.lang.Object) registering} and
126 | * {@link Env#lookup(com.oracle.truffle.api.InstrumentInfo, java.lang.Class) looking
127 | * up} services.
128 | */
129 | @Override
130 | protected void onCreate(final Env env) {
131 | final OptionValues options = env.getOptions();
132 | if (ENABLED.getValue(options)) {
133 | enable(env);
134 | env.registerService(this);
135 | }
136 | }
137 |
138 | /**
139 | * Enable the instrument.
140 | *
141 | * In this method we enable and configure the instrument. We do this by first creating a
142 | * {@link SourceSectionFilter} instance in order to specify exactly which parts of the source
143 | * code we are interested in. In this particular case, we are interested in expressions. Since
144 | * Truffle Instruments are language agnostic, they rely on language implementers to tag AST
145 | * nodes with adequate tags. This, we tell our {@link SourceSectionFilter.Builder} that we are
146 | * care about AST nodes {@link SourceSectionFilter.Builder#tagIs(java.lang.Class...) tagged}
147 | * with {@link ExpressionTag}. We also tell it we don't care about AST nodes
148 | * {@link SourceSectionFilter.Builder#includeInternal(boolean) internal} to languages.
149 | *
150 | * After than, we use the {@link Env enviroment} to obtain the {@link Instrumenter}, which
151 | * allows us to specify in which way we wish to instrument the AST.
152 | *
153 | * Firstly, we
154 | * {@link Instrumenter#attachLoadSourceListener(com.oracle.truffle.api.instrumentation.SourceFilter, com.oracle.truffle.api.instrumentation.LoadSourceListener, boolean)
155 | * attach attach} our own {@link GatherSourceSectionsListener listener} to loading source
156 | * section events. Each the a {@link SourceSection} is loaded, our listener is notified, so our
157 | * instrument is always aware of all loaded code. Note that we have specified the filter defined
158 | * earlier as a constraint, so we are not notified if internal code is loaded.
159 | *
160 | * Secondly, we
161 | * {@link Instrumenter#attachExecutionEventFactory(com.oracle.truffle.api.instrumentation.SourceSectionFilter, com.oracle.truffle.api.instrumentation.ExecutionEventNodeFactory)
162 | * attach} our {@link CoverageEventFactory node factory} using the same filter. This factory
163 | * produces {@link Node Truffle Nodes} that will be inserted into the AST at positions specified
164 | * by the filter. Each of the inserted nodes will, once executed, remove the corresponding
165 | * source section from the {@link #coverageMap set of unexecuted source sections}.
166 | *
167 | * @param env The environment, used to get the {@link Instrumenter}
168 | */
169 | private void enable(final Env env) {
170 | SourceSectionFilter filter = SourceSectionFilter.newBuilder().tagIs(ExpressionTag.class).includeInternal(false).build();
171 | Instrumenter instrumenter = env.getInstrumenter();
172 | instrumenter.attachLoadSourceSectionListener(filter, new GatherSourceSectionsListener(this), true);
173 | instrumenter.attachExecutionEventFactory(filter, new CoverageEventFactory(this));
174 | }
175 |
176 | /**
177 | * Ensures that the coverage info gathered by the instrument is printed at the end of execution.
178 | *
179 | * @param env
180 | */
181 | @Override
182 | protected void onFinalize(Env env) {
183 | if (PRINT_COVERAGE.getValue(env.getOptions())) {
184 | printResults(env);
185 | }
186 | }
187 |
188 | /**
189 | * Print the coverage results for each source.
190 | *
191 | * The printing is one the the {@link Env#out output stream} specified by the {@link Env
192 | * enviroment}.
193 | *
194 | * @param env
195 | */
196 | private synchronized void printResults(final Env env) {
197 | final PrintStream printStream = new PrintStream(env.out());
198 | for (Source source : coverageMap.keySet()) {
199 | printResult(printStream, source);
200 | }
201 | }
202 |
203 | private void printResult(PrintStream printStream, Source source) {
204 | String path = source.getPath();
205 | int lineCount = source.getLineCount();
206 | Set nonCoveredLineNumbers = nonCoveredLineNumbers(source);
207 | Set loadedLineNumbers = coverageMap.get(source).loadedLineNumbers();
208 | double coveredPercentage = 100 * ((double) loadedLineNumbers.size() - nonCoveredLineNumbers.size()) / lineCount;
209 | printStream.println("==");
210 | printStream.println("Coverage of " + path + " is " + String.format("%.2f%%", coveredPercentage));
211 | for (int i = 1; i <= source.getLineCount(); i++) {
212 | char covered = getCoverageCharacter(nonCoveredLineNumbers, loadedLineNumbers, i);
213 | printStream.println(String.format("%s %s", covered, source.getCharacters(i)));
214 | }
215 | }
216 |
217 | private static char getCoverageCharacter(Set nonCoveredLineNumbers, Set loadedLineNumbers, int i) {
218 | if (loadedLineNumbers.contains(i)) {
219 | return nonCoveredLineNumbers.contains(i) ? '-' : '+';
220 | } else {
221 | return ' ';
222 | }
223 | }
224 |
225 | /**
226 | * @param source
227 | * @return A sorted list of line numbers for not-yet-covered lines of source code in the given
228 | * {@link Source}
229 | */
230 | public synchronized Set nonCoveredLineNumbers(final Source source) {
231 | return coverageMap.get(source).nonCoveredLineNumbers();
232 | }
233 |
234 | /**
235 | * Which {@link OptionDescriptors} are used for this instrument.
236 | *
237 | * If the {@link TruffleInstrument} uses {@link Option}s, it is nesesery to specify which
238 | * {@link Option}s. The {@link OptionDescriptors} is automatically generated from this class due
239 | * to the {@link Option} annotation. In our case, this is the
240 | * {@code SimpleCodeCoverageInstrumentOptionDescriptors} class.
241 | *
242 | * @return The class generated by the {@link Option.Group} annotation
243 | */
244 | @Override
245 | protected OptionDescriptors getOptionDescriptors() {
246 | return new SimpleCoverageInstrumentOptionDescriptors();
247 | }
248 |
249 | /**
250 | * Called when a new {@link SourceSection} is loaded. We can update our {@link #coverageMap}.
251 | *
252 | * @param sourceSection the newly loaded {@link SourceSection}
253 | */
254 | synchronized void addLoaded(SourceSection sourceSection) {
255 | final Coverage coverage = coverageMap.computeIfAbsent(sourceSection.getSource(), new Function() {
256 | @Override
257 | public Coverage apply(Source s) {
258 | return new Coverage();
259 | }
260 | });
261 | coverage.addLoaded(sourceSection);
262 | }
263 |
264 | /**
265 | * Called after a {@link SourceSection} is executed, and thus covered. We can update our
266 | * {@link #coverageMap}.
267 | *
268 | * @param sourceSection the executed {@link SourceSection}
269 | */
270 | synchronized void addCovered(SourceSection sourceSection) {
271 | final Coverage coverage = coverageMap.get(sourceSection.getSource());
272 | coverage.addCovered(sourceSection);
273 | }
274 |
275 | }
276 |
--------------------------------------------------------------------------------
/src/main/java/module-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * The Universal Permissive License (UPL), Version 1.0
6 | *
7 | * Subject to the condition set forth below, permission is hereby granted to any
8 | * person obtaining a copy of this software, associated documentation and/or
9 | * data (collectively the "Software"), free of charge and under any and all
10 | * copyright rights in the Software, and any and all patent rights owned or
11 | * freely licensable by each licensor hereunder covering either (i) the
12 | * unmodified Software as contributed to or provided by such licensor, or (ii)
13 | * the Larger Works (as defined below), to deal in both
14 | *
15 | * (a) the Software, and
16 | *
17 | * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18 | * one is included with the Software each a "Larger Work" to which the Software
19 | * is contributed by such licensors),
20 | *
21 | * without restriction, including without limitation the rights to copy, create
22 | * derivative works of, display, perform, and distribute the Software and make,
23 | * use, sell, offer for sale, import, export, have made, and have sold the
24 | * Software and the Larger Work(s), and to sublicense the foregoing rights on
25 | * either these or other terms.
26 | *
27 | * This license is subject to the following condition:
28 | *
29 | * The above copyright notice and either this complete permission notice or at a
30 | * minimum a reference to the UPL must be included in all copies or substantial
31 | * portions of the Software.
32 | *
33 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 | * SOFTWARE.
40 | */
41 | module org.graalvm.st {
42 | requires java.base;
43 | requires java.logging;
44 | requires jdk.unsupported;
45 | requires org.graalvm.polyglot;
46 | requires org.graalvm.truffle;
47 | exports com.oracle.truffle.st to org.graalvm.st.test;
48 | provides com.oracle.truffle.api.instrumentation.provider.TruffleInstrumentProvider with
49 | com.oracle.truffle.st.SimpleCoverageInstrumentProvider;
50 | }
51 |
--------------------------------------------------------------------------------
/src/test/java/com/oracle/truffle/st/test/SimpleCoverageInstrumentTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * The Universal Permissive License (UPL), Version 1.0
6 | *
7 | * Subject to the condition set forth below, permission is hereby granted to any
8 | * person obtaining a copy of this software, associated documentation and/or
9 | * data (collectively the "Software"), free of charge and under any and all
10 | * copyright rights in the Software, and any and all patent rights owned or
11 | * freely licensable by each licensor hereunder covering either (i) the
12 | * unmodified Software as contributed to or provided by such licensor, or (ii)
13 | * the Larger Works (as defined below), to deal in both
14 | *
15 | * (a) the Software, and
16 | *
17 | * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18 | * one is included with the Software each a "Larger Work" to which the Software
19 | * is contributed by such licensors),
20 | *
21 | * without restriction, including without limitation the rights to copy, create
22 | * derivative works of, display, perform, and distribute the Software and make,
23 | * use, sell, offer for sale, import, export, have made, and have sold the
24 | * Software and the Larger Work(s), and to sublicense the foregoing rights on
25 | * either these or other terms.
26 | *
27 | * This license is subject to the following condition:
28 | *
29 | * The above copyright notice and either this complete permission notice or at a
30 | * minimum a reference to the UPL must be included in all copies or substantial
31 | * portions of the Software.
32 | *
33 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 | * SOFTWARE.
40 | */
41 | package com.oracle.truffle.st.test;
42 |
43 | import java.io.IOException;
44 | import java.util.Map;
45 | import java.util.Set;
46 |
47 | import org.graalvm.polyglot.Context;
48 | import org.graalvm.polyglot.Engine;
49 | import org.graalvm.polyglot.Source;
50 | import org.junit.Assert;
51 | import org.junit.Assume;
52 | import org.junit.Test;
53 |
54 | import com.oracle.truffle.st.Coverage;
55 | import com.oracle.truffle.st.SimpleCoverageInstrument;
56 |
57 | public class SimpleCoverageInstrumentTest {
58 |
59 | private static final String JS_SOURCE = "var N = 2000;\n" +
60 | "var EXPECTED = 17393;\n" +
61 | "\n" +
62 | "function Natural() {\n" +
63 | " x = 2;\n" +
64 | " return {\n" +
65 | " 'next' : function() { return x++; }\n" +
66 | " };\n" +
67 | "}\n" +
68 | "\n" +
69 | "function Filter(number, filter) {\n" +
70 | " var self = this;\n" +
71 | " this.number = number;\n" +
72 | " this.filter = filter;\n" +
73 | " this.accept = function(n) {\n" +
74 | " var filter = self;\n" +
75 | " for (;;) {\n" +
76 | " if (n % filter.number === 0) {\n" +
77 | " return false;\n" +
78 | " }\n" +
79 | " filter = filter.filter;\n" +
80 | " if (filter === null) {\n" +
81 | " break;\n" +
82 | " }\n" +
83 | " }\n" +
84 | " return true;\n" +
85 | " };\n" +
86 | " return this;\n" +
87 | "}\n" +
88 | "\n" +
89 | "function Primes(natural) {\n" +
90 | " var self = this;\n" +
91 | " this.natural = natural;\n" +
92 | " this.filter = null;\n" +
93 | " this.next = function() {\n" +
94 | " for (;;) {\n" +
95 | " var n = self.natural.next();\n" +
96 | " if (self.filter === null || self.filter.accept(n)) {\n" +
97 | " self.filter = new Filter(n, self.filter);\n" +
98 | " return n;\n" +
99 | " }\n" +
100 | " }\n" +
101 | " };\n" +
102 | "}\n" +
103 | "\n" +
104 | "var holdsAFunctionThatIsNeverCalled = function(natural) {\n" +
105 | " var self = this;\n" +
106 | " this.natural = natural;\n" +
107 | " this.filter = null;\n" +
108 | " this.next = function() {\n" +
109 | " for (;;) {\n" +
110 | " var n = self.natural.next();\n" +
111 | " if (self.filter === null || self.filter.accept(n)) {\n" +
112 | " self.filter = new Filter(n, self.filter);\n" +
113 | " return n;\n" +
114 | " }\n" +
115 | " }\n" +
116 | " };\n" +
117 | "}\n" +
118 | "\n" +
119 | "var holdsAFunctionThatIsNeverCalledOneLine = function() {return null;}\n" +
120 | "\n" +
121 | "function primesMain() {\n" +
122 | " var primes = new Primes(Natural());\n" +
123 | " var primArray = [];\n" +
124 | " for (var i=0;i<=N;i++) { primArray.push(primes.next()); }\n" +
125 | " if (primArray[N] != EXPECTED) { throw new Error('wrong prime found: ' + primArray[N]); }\n" +
126 | "}\n" +
127 | "primesMain();\n";
128 |
129 | @Test
130 | public void exampleJSTest() throws IOException {
131 | // This test only makes sense if JS is available.
132 | Assume.assumeTrue(Engine.create().getLanguages().containsKey("js"));
133 | // This is how we can create a context with our tool enabled if we are embeddined in java
134 | try (Context context = Context.newBuilder("js").option(SimpleCoverageInstrument.ID, "true").option(SimpleCoverageInstrument.ID + ".PrintCoverage", "false").build()) {
135 | Source source = Source.newBuilder("js", JS_SOURCE, "main").build();
136 | context.eval(source);
137 | assertJSCorrect(context);
138 | }
139 | }
140 |
141 | // NOTE: This lookup mechanism used in this method does not work in normal deployments
142 | // due to Truffles class path issolation. Services can be looked up by other
143 | // instruments, but not by the embedder. We can do this in the tests because the
144 | // class path issolation is disabled in the pom.xml file by adding -XX:-UseJVMCIClassLoader to
145 | // the command line.
146 | // This command line flag should never be used in production.
147 | private static void assertJSCorrect(final Context context) {
148 | // We can lookup services exported by the instrument, in our case this is
149 | // the instrument itself but it does not have to be.
150 | SimpleCoverageInstrument coverageInstrument = context.getEngine().getInstruments().get(SimpleCoverageInstrument.ID).lookup(SimpleCoverageInstrument.class);
151 | // We then use the looked up service to assert that it behaves as expected, just like in any
152 | // other test.
153 | Map coverageMap = coverageInstrument.getCoverageMap();
154 | Assert.assertEquals(1, coverageMap.size());
155 | coverageMap.forEach((com.oracle.truffle.api.source.Source s, Coverage v) -> {
156 | Set notYetCoveredLineNumbers = coverageInstrument.nonCoveredLineNumbers(s);
157 | Object[] expected = new Integer[]{47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 61, 67};
158 | Assert.assertArrayEquals(expected, notYetCoveredLineNumbers.stream().sorted().toArray());
159 | });
160 | }
161 |
162 | private static final String SL_SOURCE = "\n" +
163 | "function neverCalled() {\n" +
164 | " x = 5;\n" +
165 | " y = 9;\n" +
166 | " return x + 5;\n" +
167 | "}\n" +
168 | "function isCalled() {\n" +
169 | " return 5 + 5;\n" +
170 | "}\n" +
171 | "function main() { \n" +
172 | " 10 + isCalled(); \n" +
173 | "}\n";
174 |
175 | // Similar test using simple language
176 | @Test
177 | public void exampleSLTest() throws IOException {
178 | // This test only makes sense if SL is available.
179 | Assume.assumeTrue(Engine.create().getLanguages().containsKey("sl"));
180 | // This is how we can create a context with our tool enabled if we are embeddined in java
181 | try (Context context = Context.newBuilder("sl").option(SimpleCoverageInstrument.ID, "true").option(SimpleCoverageInstrument.ID + ".PrintCoverage", "false").build()) {
182 | Source source = Source.newBuilder("sl", SL_SOURCE, "main").build();
183 | context.eval(source);
184 | // We can lookup services exported by the instrument, in our case this is
185 | // the instrument itself but it does not have to be.
186 | SimpleCoverageInstrument coverageInstrument = context.getEngine().getInstruments().get(SimpleCoverageInstrument.ID).lookup(SimpleCoverageInstrument.class);
187 | // We then use the looked up service to assert that it behaves as expected, just like in
188 | // any other test.
189 | Map coverageMap = coverageInstrument.getCoverageMap();
190 | Assert.assertEquals(1, coverageMap.size());
191 | coverageMap.forEach((com.oracle.truffle.api.source.Source s, Coverage v) -> {
192 | Set notYetCoveredLineNumbers = coverageInstrument.nonCoveredLineNumbers(s);
193 | Object[] expected = new Integer[]{3, 4, 5};
194 | Assert.assertArrayEquals(expected, notYetCoveredLineNumbers.stream().sorted().toArray());
195 | });
196 | }
197 | }
198 | }
199 |
--------------------------------------------------------------------------------
/src/test/java/module-info.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * The Universal Permissive License (UPL), Version 1.0
6 | *
7 | * Subject to the condition set forth below, permission is hereby granted to any
8 | * person obtaining a copy of this software, associated documentation and/or
9 | * data (collectively the "Software"), free of charge and under any and all
10 | * copyright rights in the Software, and any and all patent rights owned or
11 | * freely licensable by each licensor hereunder covering either (i) the
12 | * unmodified Software as contributed to or provided by such licensor, or (ii)
13 | * the Larger Works (as defined below), to deal in both
14 | *
15 | * (a) the Software, and
16 | *
17 | * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
18 | * one is included with the Software each a "Larger Work" to which the Software
19 | * is contributed by such licensors),
20 | *
21 | * without restriction, including without limitation the rights to copy, create
22 | * derivative works of, display, perform, and distribute the Software and make,
23 | * use, sell, offer for sale, import, export, have made, and have sold the
24 | * Software and the Larger Work(s), and to sublicense the foregoing rights on
25 | * either these or other terms.
26 | *
27 | * This license is subject to the following condition:
28 | *
29 | * The above copyright notice and either this complete permission notice or at a
30 | * minimum a reference to the UPL must be included in all copies or substantial
31 | * portions of the Software.
32 | *
33 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
34 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
35 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
36 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
37 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
38 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 | * SOFTWARE.
40 | */
41 | open module org.graalvm.st.test {
42 | requires java.logging;
43 | requires jdk.unsupported;
44 | requires org.graalvm.polyglot;
45 | requires junit;
46 | requires org.graalvm.truffle;
47 | requires org.graalvm.st;
48 | exports com.oracle.truffle.st.test;
49 |
50 | }
51 |
--------------------------------------------------------------------------------