├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── de
│ └── matthiasmann
│ └── continuations
│ ├── CoIterator.java
│ ├── Coroutine.java
│ ├── CoroutineProto.java
│ ├── Stack.java
│ ├── SuspendExecution.java
│ ├── Util.java
│ ├── instrument
│ ├── AlreadyInstrumented.java
│ ├── CheckInstrumentationVisitor.java
│ ├── DBClassWriter.java
│ ├── ExtractSuperClass.java
│ ├── InstrumentClass.java
│ ├── InstrumentMethod.java
│ ├── InstrumentationTask.java
│ ├── JavaAgent.java
│ ├── Log.java
│ ├── LogLevel.java
│ ├── MethodDatabase.java
│ ├── NewValue.java
│ ├── OmittedInstruction.java
│ ├── TypeAnalyzer.java
│ ├── TypeInterpreter.java
│ ├── UnableToInstrumentException.java
│ └── package-info.java
│ └── package-info.java
└── test
└── java
└── de
└── matthiasmann
└── continuations
├── ArrayIT.java
├── BlockingIT.java
├── CatchIT.java
├── CoIteratorIT.java
├── DoubleIT.java
├── FinallyIT.java
├── InheritIT.java
├── InitialSizeIT.java
├── InterfaceIT.java
├── Merge2IT.java
├── Merge3IT.java
├── MergeIT.java
├── NullIT.java
├── SerializeIT.java
├── SomeInterface.java
├── SuspendConstructorArgumentIT.java
├── SuspendIT.java
├── ThrowIT.java
└── UninitializedIT.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .settings/
2 | .classpath
3 | .project
4 | target/
5 | nbproject/
6 | build.xml
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2008-2013, Matthias Mann
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice,
8 | this list of conditions and the following disclaimer.
9 | * Redistributions in binary form must reproduce the above copyright
10 | notice, this list of conditions and the following disclaimer in the
11 | documentation and/or other materials provided with the distribution.
12 | * Neither the name of Matthias Mann nor the names of its
13 | contributors may be used to endorse or promote products derived from
14 | this software without specific prior written permission.
15 |
16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 | POSSIBILITY OF SUCH DAMAGE.
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Continuations library by Matthias Mann from . Original documentation follows.
2 |
3 | # Continuations Library by Matthias Mann
4 |
5 | This small library allows you to write your game AI or animation code in a simple sequential way, blocking on commands like `walkTo()` and all this without blocking your AI thread or the need for additional threads.
6 |
7 | Some of you might be familiar with the features of scripting languages like [Lua](http://www.lua.org/) or [AngelScript](http://www.angelcode.com/angelscript/). One of these features are Coroutines. These allow a control transfer that is beyond a simple `if`/`else` or `goto`. Somewhere you define the entry point - the coroutine - and while executing inside the coroutine you can suspend your code and return to the coroutine call. This is comparable to stack unwinding of exceptions. But coroutines offer you the unique feature to return to the state where you suspended execution. This allows you to write code in a simple sequential way that would otherwise require either its own thread or a hand written state machine.
8 |
9 | But I'm writing this for the Java rubric - and this feature is not part of your standard Java runtime today. This library offers you a very easy and still power full way to use these features in Java without affecting your code by intrusive requirements.
10 |
11 | Lets start with what you get:
12 |
13 | * Write simple sequential code - you no longer need to create state machines by hand
14 | * No `Thread`s are created or needed - no multi thread synchronization issues
15 | * No garbage creation from code execution
16 | * Very small runtime overhead
17 | * Only suspendable method calls are changed - all calls into your standard library (like `java.util.*` etc) are not affected at all.
18 | * Full serialization support
19 | * You can store the execution state of coroutines as part of your game state in your save game without any additional code. This of course requires that your classes and data types which you use in your coroutines are serializable.
20 | * Full support for exception handling and finally blocks
21 | * Offline preprocessing does not slow down you application load time
22 | * Of course runtime instrumentation is also possible.
23 | * Very small runtime library - less then 10 KByte (uncompressed JAR)
24 | * BSD License
25 |
26 | With all these great features - you may be asking for the drawbacks. Well there are of course a few drawbacks:
27 |
28 | * Constructors and static initializers can't be suspended
29 | * Suspendable methods can't be synchronized or have synchronized blocks
30 | * You need to download [ASM3 library](https://asm.ow2.io/) to run the instrumentation task
31 |
32 | You can't call suspendable method with reflection
33 |
34 | The synchronization issue can be worked around by putting code which requires the use of synchronization into its own method.
35 |
36 | Lets look at an example - an iterator. Writing iterators can be quite complex - especially if the implementation is more then just a table walk. This library comes with a utility class that allows you to write iterators in a simple sequential way - also known as producers. It is based on a JUnit test which is also distributed with the source code of this library.
37 |
38 | ```java
39 | public class TestIterator extends CoIterator implements Serializable {
40 | @Override
41 | protected void run() throws SuspendExecution {
42 | produce("A");
43 | produce("B");
44 | for(int i = 0; i < 4; i++) {
45 | produce("C" + i);
46 | }
47 | produce("D");
48 | produce("E");
49 | }
50 | }
51 | ```
52 |
53 | This class extends the class `CoIterator` which provides the `produce` method and implements all methods of the `Iterator` interface.
54 | The `run` method is an abstract method from `CoIterator` which is the body of our iterator. This method is declared to throw the special exception `SuspendExecution`. This exception must never be caught by any user code - it must be always propagated. But don't fear - you can still use the infamous `catch(Throwable)` if you like. This exception is the marker for suspendable methods - it tells the preprocessor that this method calls others methods which might suspend execution. In our example each call to `produce` will suspend execution until the consumer (the caller of `next`) has consumed the produced value. Let's take a look at code that uses our `Iterator`:
55 |
56 | ```java
57 | Iterator iter1 = new TestIterator();
58 | while(iter.hasNext()) {
59 | System.out.println(iter.next());
60 | }
61 | ```
62 |
63 | Which will produce the following output:
64 |
65 | ```
66 | A
67 | B
68 | C0
69 | C1
70 | C2
71 | C3
72 | D
73 | E
74 | ```
75 |
76 | This looks very familiar - it's your everyday iterator usage. Of course it also works with an enhanced `for` loop if the `Iterator` is returned from a class which implements `Iterable`.
77 |
78 | But you can also write this with standard Java code without support from this library:
79 |
80 | ```java
81 | public class TestIterator implements Iterator, Serializable {
82 | private int state;
83 | private int i;
84 | public String next() {
85 | switch(state) {
86 | case 0: state=1; return "A";
87 | case 1: state=2; i=0; return "B";
88 | case 2:
89 | if(i == 3) state = 3;
90 | return "C" + (i++);
91 | case 3: state=4; return "D";
92 | case 4: state=5; return "E";
93 | default: throw new NoSuchElementException();
94 | }
95 | }
96 | public boolean hasNext() {
97 | return state < 5;
98 | }
99 | public void remove() {
100 | throw new UnsupportedOperationException("Not supported");
101 | }
102 | }
103 | ```
104 |
105 | That is much more complex - and if your code gets more complicated it will be very hard to create a state machine for it. But with the help of this library you can spend your time to write your application.
106 |
107 | An important point is that the underlying `Coroutine` is only executed when `hasNext()` or `next()` of the `Iterator` is executed. `hasNext()` will return `false` if the `run()` method finishes its execution. It also means that if you don't consume all values that the `Iterator` returns that the `run()` method of your `CoIterator` subclass never get the chance to finish its execution - which includes any not yet executed finally blocks.
108 |
109 | If you look closely at our `TestIterator` class you will see that it also implements `Serializable` which means that you can store the iterator in a file. See the JUnit test for the complete example.
110 |
111 | To use the Ant task you need the full JAR and the full ASM3 JAR. It also works with ASM 3.1. All dependencies of your application needs to be in the class path of the instrumentation Ant task - otherwise it can't analyze the method calls. You can safely run this task over already instrumented class files - it will detect already transformed classes and skip them. This example Ant snippet assumes the Netbeans build properties:
112 |
113 | ```xml
114 |
117 |
118 |
119 |
120 |
121 |
122 |
123 | ```
124 |
125 | The embedded fileset is used to specify the list of classes that should be instrumented. The task also has a few parameters that can be used to alter its behavior:
126 |
127 | |Attribute|Description|Required|Default|
128 | |---------|-----------|--------|-------|
129 | |`verbose`|Outputs informations about each processing step|No|`false`|
130 | |`check`|Includes the ASM verifier in the transformation chain. Mostly a debugging option.|No|`false`|
131 | |`debug`|Outputs internal and detailed information about the processing of the class files.|No|`false`|
132 |
133 | Enough with the talk for now - here is the link to the library:
134 |
135 | * Javadoc (multiple HTML pages)
136 | * Binaries, Source code and zipped Javadoc
137 | * ASM3 (for the 2010 version), ASM4 (for the 2012 and newer version) library
138 |
139 | So have fun and let me know if you find it useful
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
3 | 4.0.0
4 |
5 | de.matthiasmann.continuations
6 | continuations
7 | 1.0-SNAPSHOT
8 | jar
9 | continuations
10 | http://www.matthiasmann.de/content/view/24/26/
11 |
12 |
13 | UTF-8
14 | UTF-8
15 |
16 |
17 |
18 |
19 |
20 | org.apache.maven.plugins
21 | maven-compiler-plugin
22 | 3.6.0
23 |
24 | 1.8
25 | 1.8
26 |
27 |
28 |
29 | org.apache.maven.plugins
30 | maven-jar-plugin
31 | 3.0.1
32 |
33 |
34 |
35 | de.matthiasmann.continuations.instrument.JavaAgent
36 |
37 |
38 |
39 |
40 |
41 | org.apache.maven.plugins
42 | maven-failsafe-plugin
43 | 2.19.1
44 |
45 | -javaagent:${project.build.directory}/${project.build.finalName}.jar -ea
46 |
47 |
48 |
49 |
50 | integration-test
51 | verify
52 |
53 |
54 |
55 |
56 |
57 | org.apache.maven.plugins
58 | maven-antrun-plugin
59 | 1.8
60 |
61 |
62 | instrument-classes
63 | compile
64 |
65 |
66 |
68 |
71 |
72 |
75 |
76 |
77 |
78 |
79 | run
80 |
81 |
82 |
83 |
84 | instrument-test-classes
85 | test-compile
86 |
87 |
88 |
90 |
93 |
94 |
97 |
98 |
99 |
100 |
101 | run
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 | junit
112 | junit
113 | 4.13.1
114 | test
115 |
116 |
117 | org.ow2.asm
118 | asm-all
119 | 5.1
120 |
121 |
122 | org.apache.ant
123 | ant
124 | 1.10.11
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/CoIterator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import java.io.Serializable;
32 | import java.util.Iterator;
33 | import java.util.NoSuchElementException;
34 |
35 | /**
36 | * A Coroutine based iterator
37 | *
38 | * @param the element class that the Iterator returns
39 | * @author Matthias Mann
40 | */
41 | public abstract class CoIterator implements Iterator, Serializable {
42 |
43 | private static final long serialVersionUID = 351278561539L;
44 |
45 | private final Coroutine co;
46 |
47 | private E element;
48 | private boolean hasElement;
49 |
50 | protected CoIterator() {
51 | co = new Coroutine(new DelegateExecute());
52 | }
53 |
54 | @Override
55 | public boolean hasNext() {
56 | while(!hasElement && co.getState() != Coroutine.State.FINISHED) {
57 | co.run();
58 | }
59 | return hasElement;
60 | }
61 |
62 | @Override
63 | public E next() {
64 | if(!hasNext()) {
65 | throw new NoSuchElementException();
66 | }
67 | E result = element;
68 | hasElement = false;
69 | element = null;
70 | return result;
71 | }
72 |
73 | /**
74 | * Always throws UnsupportedOperationException.
75 | * @throws java.lang.UnsupportedOperationException always
76 | */
77 | @Override
78 | public void remove() throws UnsupportedOperationException {
79 | throw new UnsupportedOperationException("Not supported");
80 | }
81 |
82 | /**
83 | * Produces the next value to be returned by the {@link #next} method.
84 | *
85 | * @param element The value that should be returned by {@link #next}
86 | * @throws de.matthiasmann.continuations.SuspendExecution This method will suspend the execution
87 | */
88 | protected void produce(E element) throws SuspendExecution {
89 | if(hasElement) {
90 | throw new IllegalStateException("hasElement = true");
91 | }
92 | this.element = element;
93 | hasElement = true;
94 | Coroutine.yield();
95 | }
96 |
97 | /**
98 | *
This is the body of the Iterator. This method is executed as a
99 | * {@link Coroutine} to {@link #produce} the values of the Iterator.
100 | *
101 | *
Note that this method is suspended each time it calls produce. And if
102 | * the consumer does not consume all values of the Iterator then this
103 | * method does not get the chance to finish it's execution. This also
104 | * includes the finally blocks.
105 | *
106 | *
This method must only suspend by calling produce. Any other reason
107 | * for suspension will cause a busy loop in the Iterator.
108 | *
109 | * @throws de.matthiasmann.continuations.SuspendExecution
110 | */
111 | protected abstract void run() throws SuspendExecution;
112 |
113 | private class DelegateExecute implements CoroutineProto, Serializable {
114 | private static final long serialVersionUID = 12784529515412L;
115 |
116 | @Override
117 | public void coExecute() throws SuspendExecution {
118 | CoIterator.this.run();
119 | }
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/Coroutine.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import java.io.IOException;
32 | import java.io.Serializable;
33 | import java.lang.annotation.Annotation;
34 |
35 | /**
36 | *
A Coroutine is used to run a CoroutineProto.
37 | *
It also provides a function to suspend a running Coroutine.
38 | *
39 | *
A Coroutine can be serialized if it's not running and all involved
40 | * classes and data types are also {@link Serializable}.
41 | *
42 | * @author Matthias Mann
43 | */
44 | public class Coroutine implements Runnable, Serializable {
45 |
46 | /**
47 | * Default stack size for the data stack.
48 | * @see #Coroutine(de.matthiasmann.continuations.CoroutineProto, int)
49 | */
50 | public static final int DEFAULT_STACK_SIZE = 16;
51 |
52 | private static final long serialVersionUID = 2783452871536981L;
53 |
54 | public enum State {
55 | /** The Coroutine has not yet been executed */
56 | NEW,
57 | /** The Coroutine is currently executing */
58 | RUNNING,
59 | /** The Coroutine has suspended it's execution */
60 | SUSPENDED,
61 | /** The Coroutine has finished it's run method
62 | * @see CoroutineProto#coExecute()
63 | */
64 | FINISHED
65 | };
66 |
67 | private final CoroutineProto proto;
68 | private final Stack stack;
69 | private State state;
70 |
71 | /**
72 | * Suspend the currently running Coroutine on the calling thread.
73 | *
74 | * @throws de.matthiasmann.continuations.SuspendExecution This exception is used for control transfer - don't catch it !
75 | * @throws java.lang.IllegalStateException If not called from a Coroutine
76 | */
77 | public static void yield() throws SuspendExecution, IllegalStateException {
78 | throw new Error("Calling function not instrumented");
79 | }
80 |
81 | /**
82 | * Creates a new Coroutine from the given CoroutineProto. A CoroutineProto
83 | * can be used in several Coroutines at the same time - but then the normal
84 | * multi threading rules apply to the member state.
85 | *
86 | * @param proto the CoroutineProto for the Coroutine.
87 | */
88 | public Coroutine(CoroutineProto proto) {
89 | this(proto, DEFAULT_STACK_SIZE);
90 | }
91 |
92 | /**
93 | * Creates a new Coroutine from the given CoroutineProto. A CoroutineProto
94 | * can be used in several Coroutines at the same time - but then the normal
95 | * multi threading rules apply to the member state.
96 | *
97 | * @param proto the CoroutineProto for the Coroutine.
98 | * @param stackSize the initial stack size for the data stack
99 | * @throws NullPointerException when proto is null
100 | * @throws IllegalArgumentException when stackSize is <= 0
101 | */
102 | public Coroutine(CoroutineProto proto, int stackSize) {
103 | this.proto = proto;
104 | this.stack = new Stack(this, stackSize);
105 | this.state = State.NEW;
106 |
107 | if(proto == null) {
108 | throw new NullPointerException("proto");
109 | }
110 | assert isInstrumented(proto) : "Not instrumented";
111 | }
112 |
113 | /**
114 | * Returns the active Coroutine on this thread or NULL if no coroutine is running.
115 | * @return the active Coroutine on this thread or NULL if no coroutine is running.
116 | */
117 | public static Coroutine getActiveCoroutine() {
118 | Stack s = Stack.getStack();
119 | if(s != null) {
120 | return s.co;
121 | }
122 | return null;
123 | }
124 |
125 | /**
126 | * Returns the CoroutineProto that is used for this Coroutine
127 | * @return The CoroutineProto that is used for this Coroutine
128 | */
129 | public CoroutineProto getProto() {
130 | return proto;
131 | }
132 |
133 | /**
134 | *
Returns the current state of this Coroutine. May be called by the Coroutine
135 | * itself but should not be called by another thread.
136 | *
137 | *
The Coroutine starts in the state NEW then changes to RUNNING. From
138 | * RUNNING it may change to FINISHED or SUSPENDED. SUSPENDED can only change
139 | * to RUNNING by calling run() again.
140 | *
141 | * @return The current state of this Coroutine
142 | * @see #run()
143 | */
144 | public State getState() {
145 | return state;
146 | }
147 |
148 | /**
149 | * Runs the Coroutine until it is finished or suspended. This method must only
150 | * be called when the Coroutine is in the states NEW or SUSPENDED. It is not
151 | * multi threading safe.
152 | *
153 | * @throws java.lang.IllegalStateException if the Coroutine is currently running or already finished.
154 | */
155 | @Override
156 | public void run() throws IllegalStateException {
157 | if(state != State.NEW && state != State.SUSPENDED) {
158 | throw new IllegalStateException("Not new or suspended");
159 | }
160 | State result = State.FINISHED;
161 | Stack oldStack = Stack.getStack();
162 | try {
163 | state = State.RUNNING;
164 | Stack.setStack(stack);
165 | try {
166 | proto.coExecute();
167 | } catch (SuspendExecution ex) {
168 | assert ex == SuspendExecution.instance;
169 | result = State.SUSPENDED;
170 | //stack.dump();
171 | stack.resumeStack();
172 | }
173 | } finally {
174 | Stack.setStack(oldStack);
175 | state = result;
176 | }
177 | }
178 |
179 | private void writeObject(java.io.ObjectOutputStream out) throws IOException {
180 | if(state == State.RUNNING) {
181 | throw new IllegalStateException("trying to serialize a running coroutine");
182 | }
183 | out.defaultWriteObject();
184 | }
185 |
186 | @SuppressWarnings("unchecked")
187 | private boolean isInstrumented(CoroutineProto proto) {
188 | try {
189 | Class> clz = Class.forName("de.matthiasmann.continuations.instrument.AlreadyInstrumented");
190 | return proto.getClass().isAnnotationPresent((Class extends Annotation>) clz);
191 | } catch (ClassNotFoundException ex) {
192 | return true; // can't check
193 | } catch (Throwable ex) {
194 | return true; // it's just a check - make sure we don't fail if something goes wrong
195 | }
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/CoroutineProto.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | /**
32 | * A class that implements this interface can be run as a Coroutine.
33 | *
34 | * @see Coroutine
35 | * @author Matthias Mann
36 | */
37 | public interface CoroutineProto {
38 |
39 | /**
40 | * Entry point for Coroutine execution.
41 | *
42 | * This method should never be called directly.
43 | *
44 | * @see Coroutine#Coroutine(de.matthiasmann.continuations.CoroutineProto)
45 | * @see Coroutine#run()
46 | * @see SuspendExecution
47 | * @throws de.matthiasmann.continuations.SuspendExecution This exception should never be cought
48 | */
49 | public void coExecute() throws SuspendExecution;
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/Stack.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import java.io.Serializable;
32 |
33 | /**
34 | * Internal Class - DO NOT USE !
35 | *
36 | * Needs to be public so that instrumented code can access it.
37 | * ANY CHANGE IN THIS CLASS NEEDS TO BE SYNCHRONIZED WITH {@link de.matthiasmann.continuations.instrument.InstrumentMethod}
38 | *
39 | * @author Matthias Mann
40 | */
41 | public final class Stack implements Serializable {
42 |
43 | private static final long serialVersionUID = 12786283751253L;
44 |
45 | private static final ThreadLocal tls = new ThreadLocal<>();
46 |
47 | /** sadly this need to be here */
48 | public static SuspendExecution exception_instance_not_for_user_code = SuspendExecution.instance;
49 |
50 | final Coroutine co;
51 |
52 | private int methodTOS = -1;
53 | private int[] method;
54 |
55 | private long[] dataLong;
56 | private Object[] dataObject;
57 |
58 | transient int curMethodSP;
59 |
60 | Stack(Coroutine co, int stackSize) {
61 | if(stackSize <= 0) {
62 | throw new IllegalArgumentException("stackSize");
63 | }
64 | this.co = co;
65 | this.method = new int[8];
66 | this.dataLong = new long[stackSize];
67 | this.dataObject = new Object[stackSize];
68 | }
69 |
70 | public static Stack getStack() {
71 | return tls.get();
72 | }
73 |
74 | static void setStack(Stack s) {
75 | tls.set(s);
76 | }
77 |
78 | /**
79 | * Called before a method is called.
80 | * @param entry the entry point in the method for resume
81 | * @param numSlots the number of required stack slots for storing the state
82 | */
83 | public final void pushMethodAndReserveSpace(int entry, int numSlots) {
84 | final int methodIdx = methodTOS;
85 |
86 | if(method.length - methodIdx < 2) {
87 | growMethodStack();
88 | }
89 |
90 | curMethodSP = method[methodIdx-1];
91 | int dataTOS = curMethodSP + numSlots;
92 |
93 | method[methodIdx] = entry;
94 | method[methodIdx+1] = dataTOS;
95 |
96 | //System.out.println("entry="+entry+" size="+size+" sp="+curMethodSP+" tos="+dataTOS+" nr="+methodIdx);
97 |
98 | if(dataTOS > dataObject.length) {
99 | growDataStack(dataTOS);
100 | }
101 | }
102 |
103 | /**
104 | * Called at the end of a method.
105 | * Undoes the effects of nextMethodEntry() and clears the dataObject[] array
106 | * to allow the values to be GCed.
107 | */
108 | public final void popMethod() {
109 | int idx = methodTOS;
110 | method[idx] = 0;
111 | int oldSP = curMethodSP;
112 | int newSP = method[idx-1];
113 | curMethodSP = newSP;
114 | methodTOS = idx-2;
115 | for(int i=newSP ; iAn exception used to initiate the control transfer.
33 | *
It does not support stack traces.
34 | *
35 | *
Methods which are declared to throw this exception are "suspendable". This
36 | * exception must always be propagated and never be caught.
The instrumentation ANT task will enhance the bytecode of these methods to
42 | * support suspension and continuation of their execution.
43 | *
44 | * @author Matthias Mann
45 | */
46 | public final class SuspendExecution extends Exception {
47 |
48 | static final SuspendExecution instance = new SuspendExecution();
49 |
50 | private SuspendExecution() {
51 | }
52 |
53 | @Override
54 | public Throwable fillInStackTrace() {
55 | return this;
56 | }
57 |
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/Util.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | /**
32 | *
33 | * @author Matthias Mann
34 | */
35 | public class Util {
36 |
37 | public static int[] copyOf(int[] src, int size) {
38 | int[] dst = new int[size];
39 | System.arraycopy(src, 0, dst, 0, Math.min(src.length, size));
40 | return dst;
41 | }
42 |
43 | public static long[] copyOf(long[] src, int size) {
44 | long[] dst = new long[size];
45 | System.arraycopy(src, 0, dst, 0, Math.min(src.length, size));
46 | return dst;
47 | }
48 |
49 | public static Object[] copyOf(Object[] src, int size) {
50 | Object[] dst = new Object[size];
51 | System.arraycopy(src, 0, dst, 0, Math.min(src.length, size));
52 | return dst;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/instrument/AlreadyInstrumented.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations.instrument;
30 |
31 | import java.lang.annotation.ElementType;
32 | import java.lang.annotation.Retention;
33 | import java.lang.annotation.RetentionPolicy;
34 | import java.lang.annotation.Target;
35 |
36 | /**
37 | * An annotation used to mark a class as instrumented.
38 | * It must never be used in Java source code.
39 | *
40 | * @author Matthias Mann
41 | */
42 | @Target(ElementType.TYPE)
43 | @Retention(RetentionPolicy.RUNTIME)
44 | public @interface AlreadyInstrumented {
45 | }
46 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/instrument/CheckInstrumentationVisitor.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations.instrument;
30 |
31 | import de.matthiasmann.continuations.SuspendExecution;
32 | import de.matthiasmann.continuations.instrument.MethodDatabase.ClassEntry;
33 | import org.objectweb.asm.AnnotationVisitor;
34 | import org.objectweb.asm.ClassVisitor;
35 | import org.objectweb.asm.MethodVisitor;
36 | import org.objectweb.asm.Opcodes;
37 | import org.objectweb.asm.Type;
38 |
39 | /**
40 | * Check if a class contains suspendable methods.
41 | * Basicly this class checks if a method is declared to throw {@link SuspendExecution}.
42 | *
43 | * @author Matthias Mann
44 | */
45 | public class CheckInstrumentationVisitor extends ClassVisitor {
46 |
47 | static final String EXCEPTION_NAME = Type.getInternalName(SuspendExecution.class);
48 | static final String EXCEPTION_DESC = Type.getDescriptor(SuspendExecution.class);
49 |
50 | private String className;
51 | private ClassEntry classEntry;
52 | private boolean hasSuspendable;
53 | private boolean alreadyInstrumented;
54 |
55 | public CheckInstrumentationVisitor() {
56 | super(Opcodes.ASM5);
57 | }
58 |
59 | public boolean needsInstrumentation() {
60 | return hasSuspendable;
61 | }
62 |
63 | ClassEntry getClassEntry() {
64 | return classEntry;
65 | }
66 |
67 | public String getName() {
68 | return className;
69 | }
70 |
71 | public boolean isAlreadyInstrumented() {
72 | return alreadyInstrumented;
73 | }
74 |
75 | @Override
76 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
77 | this.className = name;
78 | this.classEntry = new ClassEntry(superName);
79 | }
80 |
81 | @Override
82 | public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
83 | if(desc.equals(InstrumentClass.ALREADY_INSTRUMENTED_NAME)) {
84 | alreadyInstrumented = true;
85 | }
86 | return null;
87 | }
88 |
89 | @Override
90 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
91 | boolean suspendable = checkExceptions(exceptions);
92 | if(suspendable) {
93 | hasSuspendable = true;
94 | // synchronized methods can't be made suspendable
95 | if((access & Opcodes.ACC_SYNCHRONIZED) == Opcodes.ACC_SYNCHRONIZED) {
96 | throw new UnableToInstrumentException("synchronized method", className, name, desc);
97 | }
98 | }
99 | classEntry.set(name, desc, suspendable);
100 | return null;
101 | }
102 |
103 | public static boolean checkExceptions(String[] exceptions) {
104 | if(exceptions != null) {
105 | for(String ex : exceptions) {
106 | if(ex.equals(EXCEPTION_NAME)) {
107 | return true;
108 | }
109 | }
110 | }
111 | return false;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/instrument/DBClassWriter.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | *
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * * Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * * Neither the name of Matthias Mann nor the names of its contributors may
15 | * be used to endorse or promote products derived from this software
16 | * without specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 | */
30 | package de.matthiasmann.continuations.instrument;
31 |
32 | import org.objectweb.asm.ClassReader;
33 | import org.objectweb.asm.ClassWriter;
34 |
35 | /**
36 | *
37 | * @author Matthias Mann
38 | */
39 | public class DBClassWriter extends ClassWriter {
40 |
41 | private final MethodDatabase db;
42 |
43 | public DBClassWriter(MethodDatabase db, ClassReader classReader) {
44 | super(classReader, COMPUTE_FRAMES | COMPUTE_MAXS);
45 | this.db = db;
46 | }
47 |
48 | @Override
49 | protected String getCommonSuperClass(String type1, String type2) {
50 | return db.getCommonSuperClass(type1, type2);
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/instrument/ExtractSuperClass.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2012, Matthias Mann
3 | *
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * * Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * * Neither the name of Matthias Mann nor the names of its contributors may
15 | * be used to endorse or promote products derived from this software
16 | * without specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 | */
30 | package de.matthiasmann.continuations.instrument;
31 |
32 | import org.objectweb.asm.ClassVisitor;
33 | import org.objectweb.asm.Opcodes;
34 |
35 | /**
36 | *
37 | * @author Matthias Mann
38 | */
39 | public class ExtractSuperClass extends ClassVisitor {
40 |
41 | String superClass;
42 |
43 | public ExtractSuperClass() {
44 | super(Opcodes.ASM5);
45 | }
46 |
47 | @Override
48 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
49 | this.superClass = superName;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/instrument/InstrumentClass.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations.instrument;
30 |
31 | import java.util.ArrayList;
32 | import java.util.List;
33 |
34 | import org.objectweb.asm.AnnotationVisitor;
35 | import org.objectweb.asm.ClassVisitor;
36 | import org.objectweb.asm.MethodVisitor;
37 | import org.objectweb.asm.Opcodes;
38 | import org.objectweb.asm.Type;
39 | import org.objectweb.asm.tree.MethodNode;
40 | import org.objectweb.asm.tree.analysis.AnalyzerException;
41 |
42 | import de.matthiasmann.continuations.Coroutine;
43 | import de.matthiasmann.continuations.instrument.MethodDatabase.ClassEntry;
44 |
45 | /**
46 | * Instrument a class by instrumenting all suspendable methods and copying the others.
47 | *
48 | * @author Matthias Mann
49 | */
50 | public class InstrumentClass extends ClassVisitor {
51 |
52 | static final String COROUTINE_NAME = Type.getInternalName(Coroutine.class);
53 | static final String ALREADY_INSTRUMENTED_NAME = Type.getDescriptor(AlreadyInstrumented.class);
54 |
55 | private final MethodDatabase db;
56 | private final boolean forceInstrumentation;
57 | private String className;
58 | private ClassEntry classEntry;
59 | private boolean alreadyInstrumented;
60 | private ArrayList methods;
61 |
62 | public InstrumentClass(ClassVisitor cv, MethodDatabase db, boolean forceInstrumentation) {
63 | super(Opcodes.ASM5, cv);
64 |
65 | this.db = db;
66 | this.forceInstrumentation = forceInstrumentation;
67 | }
68 |
69 | @Override
70 | public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
71 | this.className = name;
72 | this.classEntry = new ClassEntry(superName);
73 |
74 | // need atleast 1.5 for annotations to work
75 | if(version < Opcodes.V1_5) {
76 | version = Opcodes.V1_5;
77 | }
78 |
79 | super.visit(version, access, name, signature, superName, interfaces);
80 | }
81 |
82 | @Override
83 | public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
84 | if(desc.equals(InstrumentClass.ALREADY_INSTRUMENTED_NAME)) {
85 | alreadyInstrumented = true;
86 | }
87 | return super.visitAnnotation(desc, visible);
88 | }
89 |
90 | @Override
91 | public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
92 | boolean suspendable = CheckInstrumentationVisitor.checkExceptions(exceptions);
93 | classEntry.set(name, desc, suspendable);
94 |
95 | if(suspendable && checkAccess(access) && !(className.equals(COROUTINE_NAME) && name.equals("yield"))) {
96 | if(db.isDebug()) {
97 | db.log(LogLevel.INFO, "Instrumenting method %s#%s", className, name);
98 | }
99 |
100 | if(methods == null) {
101 | methods = new ArrayList<>();
102 | }
103 |
104 | MethodNode mn = new MethodNode(access, name, desc, signature, exceptions);
105 | methods.add(mn);
106 | return mn;
107 | }
108 | return super.visitMethod(access, name, desc, signature, exceptions);
109 | }
110 |
111 | @Override
112 | @SuppressWarnings("CallToThreadDumpStack")
113 | public void visitEnd() {
114 | db.recordSuspendableMethods(className, classEntry);
115 |
116 | if(methods != null) {
117 | if(alreadyInstrumented && !forceInstrumentation) {
118 | for(MethodNode mn : methods) {
119 | mn.accept(makeOutMV(mn));
120 | }
121 | } else {
122 | if(!alreadyInstrumented) {
123 | super.visitAnnotation(ALREADY_INSTRUMENTED_NAME, true);
124 | }
125 |
126 | for(MethodNode mn : methods) {
127 | MethodVisitor outMV = makeOutMV(mn);
128 | try {
129 | InstrumentMethod im = new InstrumentMethod(db, className, mn);
130 | if(im.collectCodeBlocks()) {
131 | if(mn.name.charAt(0) == '<') {
132 | throw new UnableToInstrumentException("special method", className, mn.name, mn.desc);
133 | }
134 | im.accept(outMV);
135 | } else {
136 | mn.accept(outMV);
137 | }
138 | } catch(AnalyzerException ex) {
139 | ex.printStackTrace();
140 | throw new InternalError(ex.getMessage());
141 | }
142 | }
143 | }
144 | }
145 | super.visitEnd();
146 | }
147 |
148 | private MethodVisitor makeOutMV(MethodNode mn) {
149 | return super.visitMethod(mn.access, mn.name, mn.desc, mn.signature, toStringArray(mn.exceptions));
150 | }
151 |
152 | private static boolean checkAccess(int access) {
153 | return (access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE)) == 0;
154 | }
155 |
156 | private static String[] toStringArray(List> l) {
157 | if(l.isEmpty()) {
158 | return null;
159 | }
160 | return l.toArray(new String[l.size()]);
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/instrument/InstrumentMethod.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations.instrument;
30 |
31 | import java.util.List;
32 |
33 | import org.objectweb.asm.Label;
34 | import org.objectweb.asm.MethodVisitor;
35 | import org.objectweb.asm.Opcodes;
36 | import org.objectweb.asm.Type;
37 | import org.objectweb.asm.tree.AbstractInsnNode;
38 | import org.objectweb.asm.tree.AnnotationNode;
39 | import org.objectweb.asm.tree.InsnList;
40 | import org.objectweb.asm.tree.LabelNode;
41 | import org.objectweb.asm.tree.LocalVariableNode;
42 | import org.objectweb.asm.tree.MethodInsnNode;
43 | import org.objectweb.asm.tree.MethodNode;
44 | import org.objectweb.asm.tree.TryCatchBlockNode;
45 | import org.objectweb.asm.tree.analysis.Analyzer;
46 | import org.objectweb.asm.tree.analysis.AnalyzerException;
47 | import org.objectweb.asm.tree.analysis.BasicValue;
48 | import org.objectweb.asm.tree.analysis.Frame;
49 | import org.objectweb.asm.tree.analysis.Value;
50 |
51 | import de.matthiasmann.continuations.Stack;
52 | import de.matthiasmann.continuations.SuspendExecution;
53 |
54 | /**
55 | * Instrument a method to allow suspension
56 | *
57 | * @author Matthias Mann
58 | */
59 | public class InstrumentMethod {
60 |
61 | private static final String STACK_NAME = Type.getInternalName(Stack.class);
62 |
63 | private final MethodDatabase db;
64 | private final String className;
65 | private final MethodNode mn;
66 | private final Frame[] frames;
67 | private final int lvarStack;
68 | private final int firstLocal;
69 |
70 | private FrameInfo[] codeBlocks = new FrameInfo[32];
71 | private int numCodeBlocks;
72 | private int additionalLocals;
73 |
74 | private boolean warnedAboutMonitors;
75 | private int warnedAboutBlocking;
76 |
77 | private static final BlockingMethod BLOCKING_METHODS[] = {
78 | new BlockingMethod("java/lang/Thread", "sleep", "(J)V", "(JI)V"),
79 | new BlockingMethod("java/lang/Thread", "join", "()V", "(J)V", "(JI)V"),
80 | new BlockingMethod("java/lang/Object", "wait", "()V", "(J)V", "(JI)V"),
81 | new BlockingMethod("java/util/concurrent/locks/Lock", "lock", "()V"),
82 | new BlockingMethod("java/util/concurrent/locks/Lock", "lockInterruptibly", "()V"),
83 | };
84 |
85 | public InstrumentMethod(MethodDatabase db, String className, MethodNode mn) throws AnalyzerException {
86 | this.db = db;
87 | this.className = className;
88 | this.mn = mn;
89 |
90 | try {
91 | Analyzer a = new TypeAnalyzer(db);
92 | this.frames = a.analyze(className, mn);
93 | this.lvarStack = mn.maxLocals;
94 | this.firstLocal = ((mn.access & Opcodes.ACC_STATIC) == Opcodes.ACC_STATIC) ? 0 : 1;
95 | } catch (UnsupportedOperationException ex) {
96 | throw new AnalyzerException(null, ex.getMessage(), ex);
97 | }
98 | }
99 |
100 | public boolean collectCodeBlocks() {
101 | int numIns = mn.instructions.size();
102 |
103 | codeBlocks[0] = FrameInfo.FIRST;
104 | for(int i=0 ; i= 0) {
119 | int mask = 1 << blockingId;
120 | if(!db.isAllowBlocking()) {
121 | throw new UnableToInstrumentException("blocking call to " +
122 | min.owner + "#" + min.name + min.desc, className, mn.name, mn.desc);
123 | } else if((warnedAboutBlocking & mask) == 0) {
124 | warnedAboutBlocking |= mask;
125 | db.log(LogLevel.WARNING, "Method %s#%s%s contains potentially blocking call to " +
126 | min.owner + "#" + min.name + min.desc, className, mn.name, mn.desc);
127 | }
128 | }
129 | }
130 | }
131 | }
132 | }
133 | addCodeBlock(null, numIns);
134 |
135 | return numCodeBlocks > 1;
136 | }
137 |
138 | private static int isBlockingCall(MethodInsnNode ins) {
139 | for(int i=0,n=BLOCKING_METHODS.length ; i= fi.endInstruction) {
282 | //System.out.println("i="+i+" start="+start+" end="+end+" split="+splitIdx+
283 | // " start="+mn.instructions.get(start)+" end="+mn.instructions.get(end));
284 |
285 | // need to split try/catch around the suspendable call
286 | if(start == fi.endInstruction) {
287 | tcb.start = fi.createAfterLabel();
288 | } else {
289 | if(end > fi.endInstruction) {
290 | TryCatchBlockNode tcb2 = new TryCatchBlockNode(
291 | fi.createAfterLabel(),
292 | tcb.end, tcb.handler, tcb.type);
293 | mn.tryCatchBlocks.add(i+1, tcb2);
294 | }
295 |
296 | tcb.end = fi.createBeforeLabel();
297 | }
298 | }
299 | }
300 | }
301 |
302 | private void dumpCodeBlock(MethodVisitor mv, int idx, int skip) {
303 | int start = codeBlocks[idx].endInstruction;
304 | int end = codeBlocks[idx+1].endInstruction;
305 |
306 | for(int i=start+skip ; i".equals(min.name)) {
331 | int argSize = TypeAnalyzer.getNumArguments(min.desc);
332 | Frame frame = frames[i];
333 | int stackIndex = frame.getStackSize() - argSize - 1;
334 | Value thisValue = frame.getStack(stackIndex);
335 | if(stackIndex >= 1 &&
336 | isNewValue(thisValue, true) &&
337 | isNewValue(frame.getStack(stackIndex-1), false)) {
338 | NewValue newValue = (NewValue)thisValue;
339 | if(newValue.omitted) {
340 | emitNewAndDup(mv, frame, stackIndex, min);
341 | }
342 | } else {
343 | db.log(LogLevel.WARNING, "Expected to find a NewValue on stack index %d: %s", stackIndex, frame);
344 | }
345 | }
346 | break;
347 | }
348 | ins.accept(mv);
349 | }
350 | }
351 |
352 | private static void dumpParameterAnnotations(MethodVisitor mv, List[] parameterAnnotations, boolean visible) {
353 | for(int i=0 ; i= -1 && value <= 5) {
364 | mv.visitInsn(Opcodes.ICONST_0 + value);
365 | } else if((byte)value == value) {
366 | mv.visitIntInsn(Opcodes.BIPUSH, value);
367 | } else if((short)value == value) {
368 | mv.visitIntInsn(Opcodes.SIPUSH, value);
369 | } else {
370 | mv.visitLdcInsn(value);
371 | }
372 | }
373 |
374 | private void emitNewAndDup(MethodVisitor mv, Frame frame, int stackIndex, MethodInsnNode min) {
375 | int arguments = frame.getStackSize() - stackIndex - 1;
376 | int neededLocals = 0;
377 | for(int i=arguments ; i>=1 ; i--) {
378 | BasicValue v = (BasicValue)frame.getStack(stackIndex+i);
379 | mv.visitVarInsn(v.getType().getOpcode(Opcodes.ISTORE), lvarStack+1+neededLocals);
380 | neededLocals += v.getSize();
381 | }
382 | db.log(LogLevel.DEBUG, "Inserting NEW & DUP for constructor call %s%s with %d arguments (%d locals)", min.owner, min.desc, arguments, neededLocals);
383 | if(additionalLocals < neededLocals) {
384 | additionalLocals = neededLocals;
385 | }
386 | ((NewValue)frame.getStack(stackIndex-1)).insn.accept(mv);
387 | ((NewValue)frame.getStack(stackIndex )).insn.accept(mv);
388 | for(int i=1 ; i<=arguments ; i++) {
389 | BasicValue v = (BasicValue)frame.getStack(stackIndex+i);
390 | neededLocals -= v.getSize();
391 | mv.visitVarInsn(v.getType().getOpcode(Opcodes.ILOAD), lvarStack+1+neededLocals);
392 | }
393 | }
394 |
395 | private void emitPopMethod(MethodVisitor mv) {
396 | mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
397 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "popMethod", "()V");
398 | }
399 |
400 | private void emitStoreState(MethodVisitor mv, int idx, FrameInfo fi) {
401 | Frame f = frames[fi.endInstruction];
402 |
403 | if(fi.lBefore != null) {
404 | fi.lBefore.accept(mv);
405 | }
406 |
407 | mv.visitVarInsn(Opcodes.ALOAD,lvarStack);
408 | emitConst(mv, idx);
409 | emitConst(mv, fi.numSlots);
410 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "pushMethodAndReserveSpace", "(II)V");
411 |
412 | for(int i=f.getStackSize() ; i-->0 ;) {
413 | BasicValue v = (BasicValue) f.getStack(i);
414 | if(!isOmitted(v)) {
415 | if(!isNullType(v)) {
416 | int slotIdx = fi.stackSlotIndices[i];
417 | assert slotIdx >= 0 && slotIdx < fi.numSlots;
418 | emitStoreValue(mv, v, lvarStack, slotIdx);
419 | } else {
420 | db.log(LogLevel.DEBUG, "NULL stack entry: type=%s size=%d", v.getType(), v.getSize());
421 | mv.visitInsn(Opcodes.POP);
422 | }
423 | }
424 | }
425 |
426 | for(int i=firstLocal ; i= 0 && slotIdx < fi.numSlots;
432 | emitStoreValue(mv, v, lvarStack, slotIdx);
433 | }
434 | }
435 | }
436 |
437 | private void emitRestoreState(MethodVisitor mv, int idx, FrameInfo fi) {
438 | Frame f = frames[fi.endInstruction];
439 |
440 | for(int i=firstLocal ; i= 0 && slotIdx < fi.numSlots;
445 | emitRestoreValue(mv, v, lvarStack, slotIdx);
446 | mv.visitVarInsn(v.getType().getOpcode(Opcodes.ISTORE), i);
447 | } else if(v != BasicValue.UNINITIALIZED_VALUE) {
448 | mv.visitInsn(Opcodes.ACONST_NULL);
449 | mv.visitVarInsn(Opcodes.ASTORE, i);
450 | }
451 | }
452 |
453 | for(int i=0 ; i= 0 && slotIdx < fi.numSlots;
459 | emitRestoreValue(mv, v, lvarStack, slotIdx);
460 | } else {
461 | mv.visitInsn(Opcodes.ACONST_NULL);
462 | }
463 | }
464 | }
465 |
466 | if(fi.lAfter != null) {
467 | fi.lAfter.accept(mv);
468 | }
469 | }
470 |
471 | private void emitStoreValue(MethodVisitor mv, BasicValue v, int lvarStack, int idx) throws InternalError, IndexOutOfBoundsException {
472 | String desc;
473 |
474 | switch(v.getType().getSort()) {
475 | case Type.OBJECT:
476 | case Type.ARRAY:
477 | desc = "(Ljava/lang/Object;L"+STACK_NAME+";I)V";
478 | break;
479 | case Type.BOOLEAN:
480 | case Type.BYTE:
481 | case Type.SHORT:
482 | case Type.CHAR:
483 | case Type.INT:
484 | desc = "(IL"+STACK_NAME+";I)V";
485 | break;
486 | case Type.FLOAT:
487 | desc = "(FL"+STACK_NAME+";I)V";
488 | break;
489 | case Type.LONG:
490 | desc = "(JL"+STACK_NAME+";I)V";
491 | break;
492 | case Type.DOUBLE:
493 | desc = "(DL"+STACK_NAME+";I)V";
494 | break;
495 | default:
496 | throw new InternalError("Unexpected type: " + v.getType());
497 | }
498 |
499 | mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
500 | emitConst(mv, idx);
501 | mv.visitMethodInsn(Opcodes.INVOKESTATIC, STACK_NAME, "push", desc);
502 | }
503 |
504 | private void emitRestoreValue(MethodVisitor mv, BasicValue v, int lvarStack, int idx) {
505 | mv.visitVarInsn(Opcodes.ALOAD, lvarStack);
506 | emitConst(mv, idx);
507 |
508 | switch(v.getType().getSort()) {
509 | case Type.OBJECT:
510 | String internalName = v.getType().getInternalName();
511 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "getObject", "(I)Ljava/lang/Object;");
512 | if(!internalName.equals("java/lang/Object")) { // don't cast to Object ;)
513 | mv.visitTypeInsn(Opcodes.CHECKCAST, internalName);
514 | }
515 | break;
516 | case Type.ARRAY:
517 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "getObject", "(I)Ljava/lang/Object;");
518 | mv.visitTypeInsn(Opcodes.CHECKCAST, v.getType().getDescriptor());
519 | break;
520 | case Type.BYTE:
521 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "getInt", "(I)I");
522 | mv.visitInsn(Opcodes.I2B);
523 | break;
524 | case Type.SHORT:
525 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "getInt", "(I)I");
526 | mv.visitInsn(Opcodes.I2S);
527 | break;
528 | case Type.CHAR:
529 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "getInt", "(I)I");
530 | mv.visitInsn(Opcodes.I2C);
531 | break;
532 | case Type.BOOLEAN:
533 | case Type.INT:
534 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "getInt", "(I)I");
535 | break;
536 | case Type.FLOAT:
537 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "getFloat", "(I)F");
538 | break;
539 | case Type.LONG:
540 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "getLong", "(I)J");
541 | break;
542 | case Type.DOUBLE:
543 | mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, STACK_NAME, "getDouble", "(I)D");
544 | break;
545 | default:
546 | throw new InternalError("Unexpected type: " + v.getType());
547 | }
548 | }
549 |
550 | static boolean isNullType(BasicValue v) {
551 | return (v == BasicValue.UNINITIALIZED_VALUE) ||
552 | (v.isReference() && v.getType().getInternalName().equals("null"));
553 | }
554 |
555 | static boolean isOmitted(BasicValue v) {
556 | if(v instanceof NewValue) {
557 | return ((NewValue)v).omitted;
558 | }
559 | return false;
560 | }
561 |
562 | static boolean isNewValue(Value v, boolean dupped) {
563 | if(v instanceof NewValue) {
564 | return ((NewValue)v).isDupped == dupped;
565 | }
566 | return false;
567 | }
568 |
569 | static class BlockLabelNode extends LabelNode {
570 | final int idx;
571 |
572 | BlockLabelNode(int idx) {
573 | this.idx = idx;
574 | }
575 | }
576 |
577 | static class FrameInfo {
578 | static final FrameInfo FIRST = new FrameInfo(null, 0, 0, null, null);
579 |
580 | final int endInstruction;
581 | final int numSlots;
582 | final int numObjSlots;
583 | final int[] localSlotIndices;
584 | final int[] stackSlotIndices;
585 |
586 | BlockLabelNode lBefore;
587 | BlockLabelNode lAfter;
588 |
589 | FrameInfo(Frame f, int firstLocal, int endInstruction, InsnList insnList, MethodDatabase db) {
590 | this.endInstruction = endInstruction;
591 |
592 | int idxObj = 0;
593 | int idxPrim = 0;
594 |
595 | if(f != null) {
596 | stackSlotIndices = new int[f.getStackSize()];
597 | for(int i=0 ; iInstrumentation ANT task
51 | *
52 | *
It requires one or more FileSet elements pointing to class files that should
53 | * be instrumented.
54 | *
Classes that are referenced from the instrumented classes are searched in
55 | * the classpath of the task. If a referenced class is not found a warning is
56 | * generated and the instrumentation will result in less efficent code.
57 | *
58 | *
The following options can be set:
59 | *
check - default: false The resulting code is run through a verifier.
60 | *
verbose - default: false The name of each processed class and all suspendable method calles is displayed.
61 | *
debug - default: false Prints internal debugging information.
62 | *
allowmonitors - default: false Allows the use of synchronized statements - this is DANGEROUS !
63 | *
allowblocking - default: false Allows the use known blocking calls like Thread.sleep, Object.wait etc.
64 | *
65 | *
66 | * @see ANT FileSet
67 | * @see SuspendExecution
68 | * @author Matthias Mann
69 | */
70 | public class InstrumentationTask extends Task {
71 |
72 | private ArrayList filesets = new ArrayList<>();
73 | private boolean check;
74 | private boolean verbose;
75 | private boolean allowMonitors;
76 | private boolean allowBlocking;
77 | private boolean debug;
78 | private boolean writeClasses = true;
79 |
80 | public void addFileSet(FileSet fs) {
81 | filesets.add(fs);
82 | }
83 |
84 | public void setCheck(boolean check) {
85 | this.check = check;
86 | }
87 |
88 | public void setVerbose(boolean verbose) {
89 | this.verbose = verbose;
90 | }
91 |
92 | public void setAllowMonitors(boolean allowMonitors) {
93 | this.allowMonitors = allowMonitors;
94 | }
95 |
96 | public void setAllowBlocking(boolean allowBlocking) {
97 | this.allowBlocking = allowBlocking;
98 | }
99 |
100 | public void setDebug(boolean debug) {
101 | this.debug = debug;
102 | }
103 |
104 | public void setWriteClasses(boolean writeClasses) {
105 | this.writeClasses = writeClasses;
106 | }
107 |
108 | @Override
109 | public void execute() throws BuildException {
110 | MethodDatabase db = new MethodDatabase(getClass().getClassLoader());
111 |
112 | db.setVerbose(verbose);
113 | db.setDebug(debug);
114 | db.setAllowMonitors(allowMonitors);
115 | db.setAllowBlocking(allowBlocking);
116 | db.setLog(new Log() {
117 | @Override
118 | public void log(LogLevel level, String msg, Object... args) {
119 | int msgLevel;
120 | switch(level) {
121 | case DEBUG: msgLevel = Project.MSG_INFO; break;
122 | case INFO: msgLevel = Project.MSG_INFO; break;
123 | case WARNING: msgLevel = Project.MSG_WARN; break;
124 | default: throw new AssertionError("Unhandled log level: " + level);
125 | }
126 | InstrumentationTask.this.log(level+": "+String.format(msg, args), msgLevel);
127 | }
128 | @Override
129 | public void error(String msg, Exception ex) {
130 | InstrumentationTask.this.log("ERROR: "+msg, ex, Project.MSG_ERR);
131 | }
132 | });
133 |
134 | try {
135 | for(FileSet fs : filesets) {
136 | DirectoryScanner ds = fs.getDirectoryScanner(getProject());
137 | String[] includedFiles = ds.getIncludedFiles();
138 |
139 | for(String filename : includedFiles) {
140 | if(filename.endsWith(".class")) {
141 | File file = new File(fs.getDir(), filename);
142 | if(file.isFile()) {
143 | db.checkClass(file);
144 | } else {
145 | log("File not found: " + filename);
146 | }
147 | }
148 | }
149 | }
150 |
151 | db.log(LogLevel.INFO, "Instrumenting " + db.getWorkList().size() + " classes");
152 |
153 | for(File f : db.getWorkList()) {
154 | instrumentClass(db, f);
155 | }
156 | } catch (UnableToInstrumentException ex) {
157 | log(ex.getMessage());
158 | throw new BuildException(ex.getMessage(), ex);
159 | }
160 | }
161 |
162 | private void instrumentClass(MethodDatabase db, File f) {
163 | db.log(LogLevel.INFO, "Instrumenting class %s", f);
164 |
165 | try {
166 | ClassReader r;
167 |
168 | FileInputStream fis = new FileInputStream(f);
169 | try {
170 | r = new ClassReader(fis);
171 | } finally {
172 | fis.close();
173 | }
174 |
175 | ClassWriter cw = new DBClassWriter(db, r);
176 | ClassVisitor cv = check ? new CheckClassAdapter(cw) : cw;
177 | InstrumentClass ic = new InstrumentClass(cv, db, false);
178 | r.accept(ic, ClassReader.SKIP_FRAMES);
179 |
180 | byte[] newClass = cw.toByteArray();
181 |
182 | if(writeClasses) {
183 | FileOutputStream fos = new FileOutputStream(f);
184 | try {
185 | fos.write(newClass);
186 | } finally {
187 | fos.close();
188 | }
189 | }
190 | } catch (IOException ex) {
191 | throw new BuildException("Instrumenting file " + f, ex);
192 | }
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/instrument/JavaAgent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | *
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * * Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * * Neither the name of Matthias Mann nor the names of its contributors may
15 | * be used to endorse or promote products derived from this software
16 | * without specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 | */
30 |
31 | /*
32 | * Copyright (c) 2012, Enhanced Four
33 | * All rights reserved.
34 | *
35 | * Redistribution and use in source and binary forms, with or without
36 | * modification, are permitted provided that the following conditions are
37 | * met:
38 | *
39 | * * Redistributions of source code must retain the above copyright
40 | * notice, this list of conditions and the following disclaimer.
41 | *
42 | * * Redistributions in binary form must reproduce the above copyright
43 | * notice, this list of conditions and the following disclaimer in the
44 | * documentation and/or other materials provided with the distribution.
45 | *
46 | * * Neither the name of 'Enhanced Four' nor the names of its contributors
47 | * may be used to endorse or promote products derived from this software
48 | * without specific prior written permission.
49 | *
50 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
52 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
53 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
54 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
55 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
56 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
57 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
58 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
59 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
60 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 | */
62 | package de.matthiasmann.continuations.instrument;
63 |
64 | import java.lang.instrument.ClassFileTransformer;
65 | import java.lang.instrument.IllegalClassFormatException;
66 | import java.lang.instrument.Instrumentation;
67 | import java.security.ProtectionDomain;
68 |
69 | import org.objectweb.asm.ClassReader;
70 | import org.objectweb.asm.ClassVisitor;
71 | import org.objectweb.asm.ClassWriter;
72 | import org.objectweb.asm.util.CheckClassAdapter;
73 |
74 | /*
75 | * Created on Nov 21, 2010
76 | *
77 | * @author Riven
78 | * @author Matthias Mann
79 | */
80 | public class JavaAgent {
81 | public static void premain(String agentArguments, Instrumentation instrumentation) {
82 | MethodDatabase db = new MethodDatabase(Thread.currentThread().getContextClassLoader());
83 | boolean checkArg = false;
84 |
85 | if(agentArguments != null) {
86 | for(char c : agentArguments.toCharArray()) {
87 | switch(c) {
88 | case 'v':
89 | db.setVerbose(true);
90 | break;
91 |
92 | case 'd':
93 | db.setDebug(true);
94 | break;
95 |
96 | case 'm':
97 | db.setAllowMonitors(true);
98 | break;
99 |
100 | case 'c':
101 | checkArg = true;
102 | break;
103 |
104 | case 'b':
105 | db.setAllowBlocking(true);
106 | break;
107 |
108 | default:
109 | throw new IllegalStateException("Usage: vdmc (verbose, debug, allow monitors, check class)");
110 | }
111 | }
112 | }
113 |
114 | db.setLog(new Log() {
115 | public void log(LogLevel level, String msg, Object... args) {
116 | System.out.println("[Continuations] " + level + ": " + String.format(msg, args));
117 | }
118 |
119 | public void error(String msg, Exception exc) {
120 | System.out.println("[Continuations] ERROR: " + msg);
121 |
122 | exc.printStackTrace(System.out);
123 | }
124 | });
125 |
126 | instrumentation.addTransformer(new Transformer(db, checkArg));
127 | }
128 |
129 | static byte[] instrumentClass(MethodDatabase db, byte[] data, boolean check) {
130 | ClassReader r = new ClassReader(data);
131 | ClassWriter cw = new DBClassWriter(db, r);
132 | ClassVisitor cv = check ? new CheckClassAdapter(cw) : cw;
133 | InstrumentClass ic = new InstrumentClass(cv, db, false);
134 | r.accept(ic, ClassReader.SKIP_FRAMES);
135 | return cw.toByteArray();
136 | }
137 |
138 | private static class Transformer implements ClassFileTransformer {
139 | private final MethodDatabase db;
140 | private final boolean check;
141 |
142 | public Transformer(MethodDatabase db, boolean check) {
143 | this.db = db;
144 | this.check = check;
145 | }
146 |
147 | @Override
148 | public byte[] transform(ClassLoader loader, String className, Class> classBeingRedefined,
149 | ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
150 | if(MethodDatabase.isJavaCore(className)) {
151 | return null;
152 | }
153 | if(className.startsWith("org/objectweb/asm/")) {
154 | return null;
155 | }
156 |
157 | db.log(LogLevel.INFO, "TRANSFORM: %s", className);
158 |
159 | try {
160 | return instrumentClass(db, classfileBuffer, check);
161 | } catch(Exception ex) {
162 | db.error("Unable to instrument", ex);
163 | return null;
164 | }
165 | }
166 | }
167 | }
168 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/instrument/Log.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations.instrument;
30 |
31 | /**
32 | * Allow access to the ANT logging routines
33 | *
34 | * @author Matthias Mann
35 | */
36 | public interface Log {
37 |
38 | public void log(LogLevel level, String msg, Object ... args);
39 |
40 | public void error(String msg, Exception ex);
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/instrument/LogLevel.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | *
4 | * All rights reserved.
5 | *
6 | * Redistribution and use in source and binary forms, with or without
7 | * modification, are permitted provided that the following conditions are met:
8 | *
9 | * * Redistributions of source code must retain the above copyright notice,
10 | * this list of conditions and the following disclaimer.
11 | * * Redistributions in binary form must reproduce the above copyright
12 | * notice, this list of conditions and the following disclaimer in the
13 | * documentation and/or other materials provided with the distribution.
14 | * * Neither the name of Matthias Mann nor the names of its contributors may
15 | * be used to endorse or promote products derived from this software
16 | * without specific prior written permission.
17 | *
18 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
22 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 | */
30 | package de.matthiasmann.continuations.instrument;
31 |
32 | /**
33 | *
34 | * @author Matthias Mann
35 | */
36 | public enum LogLevel {
37 | DEBUG,
38 | INFO,
39 | WARNING
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/de/matthiasmann/continuations/instrument/MethodDatabase.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations.instrument;
30 |
31 | import java.io.File;
32 | import java.io.FileInputStream;
33 | import java.io.IOException;
34 | import java.io.InputStream;
35 | import java.util.ArrayList;
36 | import java.util.HashMap;
37 |
38 | import org.objectweb.asm.ClassReader;
39 |
40 | /**
41 | *
Collects information about classes and their suspendable methods.
42 | *
Provides access to configuration parameters and to logging
4 | * Copyright (c) 2008, Matthias Mann
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions are met:
9 | *
10 | * * Redistributions of source code must retain the above copyright notice,
11 | * this list of conditions and the following disclaimer.
12 | * * Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * * Neither the name of Matthias Mann nor the names of its
16 | * contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | *
Continuations Library for Coroutine support in Java.
3 | *
4 | * Copyright (c) 2008, Matthias Mann
5 | * All rights reserved.
6 | *
7 | * Redistribution and use in source and binary forms, with or without
8 | * modification, are permitted provided that the following conditions are met:
9 | *
10 | * * Redistributions of source code must retain the above copyright notice,
11 | * this list of conditions and the following disclaimer.
12 | * * Redistributions in binary form must reproduce the above copyright
13 | * notice, this list of conditions and the following disclaimer in the
14 | * documentation and/or other materials provided with the distribution.
15 | * * Neither the name of Matthias Mann nor the names of its
16 | * contributors may be used to endorse or promote products derived from
17 | * this software without specific prior written permission.
18 | *
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 | * POSSIBILITY OF SUCH DAMAGE.
30 | *
31 | *
32 | *
This package contains the runtime of the Continuations library.
33 | *
34 | * @see de.matthiasmann.continuations.Coroutine
35 | * @author Matthias Mann
36 | */
37 | package de.matthiasmann.continuations;
38 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/ArrayIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertEquals;
32 |
33 | /**
34 | *
35 | * @author Matthias Mann
36 | */
37 | public class ArrayIT implements CoroutineProto {
38 |
39 | private static final PatchLevel l1 = new PatchLevel();
40 | private static final PatchLevel[] l2 = new PatchLevel[] { l1 };
41 | private static final PatchLevel[][] l3 = new PatchLevel[][] { l2 };
42 |
43 | public void testArray() {
44 | Coroutine co = new Coroutine(this);
45 | co.run();
46 | assertEquals(42, l1.i);
47 | }
48 |
49 | @Override
50 | public void coExecute() throws SuspendExecution {
51 | PatchLevel[][] local_patch_levels = l3;
52 | PatchLevel patch_level = local_patch_levels[0][0];
53 | patch_level.setLevel(42);
54 | }
55 |
56 | public static class PatchLevel {
57 | int i;
58 |
59 | public void setLevel(int value) throws SuspendExecution {
60 | i = value;
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/BlockingIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertTrue;
32 |
33 | import java.io.IOException;
34 | import java.io.InputStream;
35 | import java.util.HashSet;
36 | import java.util.Locale;
37 | import java.util.concurrent.locks.Lock;
38 |
39 | import org.junit.Test;
40 | import org.objectweb.asm.ClassReader;
41 | import org.objectweb.asm.ClassWriter;
42 |
43 | import de.matthiasmann.continuations.instrument.AlreadyInstrumented;
44 | import de.matthiasmann.continuations.instrument.InstrumentClass;
45 | import de.matthiasmann.continuations.instrument.Log;
46 | import de.matthiasmann.continuations.instrument.LogLevel;
47 | import de.matthiasmann.continuations.instrument.MethodDatabase;
48 |
49 | /**
50 | * Test to checking blocking call detection
51 | *
52 | * @author Matthias Mann
53 | */
54 | @AlreadyInstrumented
55 | public class BlockingIT {
56 |
57 | @Test
58 | public void testSuspend() throws IOException {
59 | final String className = BlockingIT.class.getName().replace('.', '/');
60 | final HashSet msgs = new HashSet<>();
61 | msgs.add("Method "+className+"#t_wait()V contains potentially blocking call to java/lang/Object#wait()V");
62 | msgs.add("Method "+className+"#t_sleep1()V contains potentially blocking call to java/lang/Thread#sleep(J)V");
63 | msgs.add("Method "+className+"#t_sleep2()V contains potentially blocking call to java/lang/Thread#sleep(JI)V");
64 | msgs.add("Method "+className+"#t_join1(Ljava/lang/Thread;)V contains potentially blocking call to java/lang/Thread#join()V");
65 | msgs.add("Method "+className+"#t_join2(Ljava/lang/Thread;)V contains potentially blocking call to java/lang/Thread#join(J)V");
66 | msgs.add("Method "+className+"#t_join3(Ljava/lang/Thread;)V contains potentially blocking call to java/lang/Thread#join(JI)V");
67 | msgs.add("Method "+className+"#t_lock1(Ljava/util/concurrent/locks/Lock;)V contains potentially blocking call to java/util/concurrent/locks/Lock#lock()V");
68 | msgs.add("Method "+className+"#t_lock2(Ljava/util/concurrent/locks/Lock;)V contains potentially blocking call to java/util/concurrent/locks/Lock#lockInterruptibly()V");
69 |
70 | MethodDatabase db = new MethodDatabase(BlockingIT.class.getClassLoader());
71 | db.setAllowBlocking(true);
72 | db.setLog(new Log() {
73 | public void log(LogLevel level, String msg, Object... args) {
74 | if(level == LogLevel.WARNING) {
75 | msg = String.format(Locale.ENGLISH, msg, args);
76 | assertTrue("Unexpected message: " + msg, msgs.remove(msg));
77 | }
78 | }
79 | public void error(String msg, Exception ex) {
80 | throw new AssertionError(msg, ex);
81 | }
82 | });
83 |
84 | InputStream in = BlockingIT.class.getResourceAsStream("BlockingIT.class");
85 | try {
86 | ClassReader r = new ClassReader(in);
87 | ClassWriter cw = new ClassWriter(0);
88 | InstrumentClass ic = new InstrumentClass(cw, db, true);
89 | r.accept(ic, ClassReader.SKIP_FRAMES);
90 | } finally {
91 | in.close();
92 | }
93 |
94 | assertTrue("Expected messages not generated: "+msgs.toString(), msgs.isEmpty());
95 | }
96 |
97 | public void t_wait() throws SuspendExecution, InterruptedException {
98 | synchronized (this) {
99 | wait();
100 | }
101 | }
102 |
103 | public void t_notify() throws SuspendExecution {
104 | synchronized (this) {
105 | notify();
106 | }
107 | }
108 |
109 | public void t_sleep1() throws SuspendExecution, InterruptedException {
110 | Thread.sleep(1000);
111 | }
112 |
113 | public void t_sleep2() throws SuspendExecution, InterruptedException {
114 | Thread.sleep(1000, 100);
115 | }
116 |
117 | public void t_join1(Thread t) throws SuspendExecution, InterruptedException {
118 | t.join();
119 | }
120 |
121 | public void t_join2(Thread t) throws SuspendExecution, InterruptedException {
122 | t.join(1000);
123 | }
124 |
125 | public void t_join3(Thread t) throws SuspendExecution, InterruptedException {
126 | t.join(1, 100);
127 | }
128 |
129 | public void t_lock1(Lock lock) throws SuspendExecution {
130 | lock.lock();
131 | }
132 |
133 | public void t_lock2(Lock lock) throws SuspendExecution, InterruptedException {
134 | lock.lockInterruptibly();
135 | }
136 |
137 | public void t_lock3() throws SuspendExecution {
138 | lock();
139 | }
140 |
141 | public void lock() {
142 | System.out.println("Just a method which have similar signature");
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/CatchIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertEquals;
32 |
33 | import java.util.ArrayList;
34 | import java.util.Iterator;
35 |
36 | import org.junit.Test;
37 |
38 | /**
39 | * Check that a generic catch all does not affect the suspendtion of a method
40 | *
41 | * @author Matthias Mann
42 | */
43 | public class CatchIT implements CoroutineProto {
44 |
45 | private ArrayList results = new ArrayList<>();
46 |
47 | int cnt = 0;
48 | private void throwOnSecondCall() throws SuspendExecution {
49 | results.add("cnt=" + cnt);
50 | Coroutine.yield();
51 | if(++cnt >= 2) {
52 | throw new IllegalStateException("called second time");
53 | }
54 | results.add("not thrown");
55 | }
56 |
57 | @Override
58 | public void coExecute() throws SuspendExecution {
59 | results.add("A");
60 | Coroutine.yield();
61 | try {
62 | results.add("C");
63 | Coroutine.yield();
64 | throwOnSecondCall();
65 | Coroutine.yield();
66 | throwOnSecondCall();
67 | results.add("never reached");
68 | } catch(Throwable ex) {
69 | results.add(ex.getMessage());
70 | }
71 | results.add("H");
72 | }
73 |
74 | @Test
75 | public void testCatch() {
76 | results.clear();
77 |
78 | try {
79 | Coroutine co = new Coroutine(this);
80 | co.run();
81 | results.add("B");
82 | co.run();
83 | results.add("D");
84 | co.run();
85 | results.add("E");
86 | co.run();
87 | results.add("F");
88 | co.run();
89 | results.add("G");
90 | co.run();
91 | results.add("I");
92 | } finally {
93 | System.out.println(results);
94 | }
95 |
96 | assertEquals(13, results.size());
97 | Iterator iter = results.iterator();
98 | assertEquals("A", iter.next());
99 | assertEquals("B", iter.next());
100 | assertEquals("C", iter.next());
101 | assertEquals("D", iter.next());
102 | assertEquals("cnt=0", iter.next());
103 | assertEquals("E", iter.next());
104 | assertEquals("not thrown", iter.next());
105 | assertEquals("F", iter.next());
106 | assertEquals("cnt=1", iter.next());
107 | assertEquals("G", iter.next());
108 | assertEquals("called second time", iter.next());
109 | assertEquals("H", iter.next());
110 | assertEquals("I", iter.next());
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/CoIteratorIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertEquals;
32 | import static org.junit.Assert.assertFalse;
33 |
34 | import java.util.Iterator;
35 |
36 | import org.junit.Test;
37 |
38 | /**
39 | *
40 | * Test the {@link CoIterato} class
41 | *
42 | * @author Matthias Mann
43 | */
44 | public class CoIteratorIT {
45 |
46 | @Test
47 | public void testCoIterator() {
48 | Iterator iter = new CoIterator() {
49 | @Override
50 | public void run() throws SuspendExecution {
51 | for(int j=0 ; j<3 ; j++) {
52 | produce("Hugo " + j);
53 | produce("Test");
54 | for(int i=1 ; i<10 ; i++) {
55 | produce("Number " + i);
56 | }
57 | produce("Nix");
58 | }
59 | }
60 | };
61 |
62 | for(int j=0 ; j<3 ; j++) {
63 | assertEquals("Hugo " + j, iter.next());
64 | assertEquals("Test", iter.next());
65 | for(int i=1 ; i<10 ; i++) {
66 | assertEquals("Number " + i, iter.next());
67 | }
68 | assertEquals("Nix", iter.next());
69 | }
70 |
71 | assertFalse(iter.hasNext());
72 | }
73 |
74 | }
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/DoubleIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertEquals;
32 |
33 | import org.junit.Test;
34 |
35 | /**
36 | *
37 | * @author Matthias Mann
38 | */
39 | public class DoubleIT implements CoroutineProto {
40 |
41 | double result;
42 |
43 | @Test
44 | public void testDouble() {
45 | Coroutine co = new Coroutine(this);
46 | co.run();
47 | assertEquals(0, result, 1e-8);
48 | co.run();
49 | assertEquals(1, result, 1e-8);
50 | assertEquals(Coroutine.State.FINISHED, co.getState());
51 | }
52 |
53 | @Override
54 | public void coExecute() throws SuspendExecution {
55 | double temp = Math.cos(0);
56 | Coroutine.yield();
57 | this.result = temp;
58 | }
59 |
60 | }
61 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/FinallyIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertEquals;
32 |
33 | import java.util.ArrayList;
34 |
35 | import org.junit.Test;
36 |
37 | /**
38 | * Test correct execution of a finally statement
39 | *
40 | * @author Matthias Mann
41 | */
42 | public class FinallyIT implements CoroutineProto {
43 |
44 | private ArrayList results = new ArrayList<>();
45 |
46 | public void coExecute() throws SuspendExecution {
47 | results.add("A");
48 | Coroutine.yield();
49 | try {
50 | results.add("C");
51 | Coroutine.yield();
52 | results.add("E");
53 | } finally {
54 | results.add("F");
55 | }
56 | results.add("G");
57 | Coroutine.yield();
58 | results.add("I");
59 | }
60 |
61 | @Test
62 | public void testFinally() {
63 | results.clear();
64 |
65 | try {
66 | Coroutine co = new Coroutine(this);
67 | co.run();
68 | results.add("B");
69 | co.run();
70 | results.add("D");
71 | co.run();
72 | results.add("H");
73 | co.run();
74 | } finally {
75 | System.out.println(results);
76 | }
77 |
78 | assertEquals(9, results.size());
79 | assertEquals("A", results.get(0));
80 | assertEquals("B", results.get(1));
81 | assertEquals("C", results.get(2));
82 | assertEquals("D", results.get(3));
83 | assertEquals("E", results.get(4));
84 | assertEquals("F", results.get(5));
85 | assertEquals("G", results.get(6));
86 | assertEquals("H", results.get(7));
87 | assertEquals("I", results.get(8));
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/InheritIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertEquals;
32 |
33 | import java.util.ArrayList;
34 |
35 | import org.junit.Test;
36 |
37 | /**
38 | *
39 | * @author mam
40 | */
41 | public class InheritIT {
42 |
43 | @Test
44 | public void testInherit() {
45 | final C dut = new C();
46 | Coroutine c = new Coroutine(new CoroutineProto() {
47 | public void coExecute() throws SuspendExecution {
48 | dut.myMethod();
49 | }
50 | });
51 | for(int i=0 ; i<3 ; i++) {
52 | c.run();
53 | }
54 |
55 | assertEquals(5, dut.result.size());
56 | assertEquals("a", dut.result.get(0));
57 | assertEquals("o1", dut.result.get(1));
58 | assertEquals("o2", dut.result.get(2));
59 | assertEquals("b", dut.result.get(3));
60 | assertEquals("b", dut.result.get(4));
61 | }
62 |
63 | public static class A {
64 | public static void yield() throws SuspendExecution {
65 | Coroutine.yield();
66 | }
67 | }
68 |
69 | public static class B extends A {
70 | final ArrayList result = new ArrayList<>();
71 | }
72 |
73 | public static class C extends B {
74 |
75 | public void otherMethod() throws SuspendExecution {
76 | result.add("o1");
77 | Coroutine.yield();
78 | result.add("o2");
79 | }
80 |
81 | public void myMethod() throws SuspendExecution {
82 | result.add("a");
83 | otherMethod();
84 |
85 | for(;;) {
86 | result.add("b");
87 | if(result.size() > 10) {
88 | otherMethod();
89 | result.add("Ohh!");
90 | }
91 | yield();
92 | }
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/InitialSizeIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertEquals;
32 | import static org.junit.Assert.assertTrue;
33 |
34 | import java.lang.reflect.Field;
35 |
36 | import org.junit.Test;
37 |
38 | /**
39 | *
40 | * @author Matthias Mann
41 | */
42 | public class InitialSizeIT implements CoroutineProto {
43 |
44 | @Test
45 | public void test1() {
46 | testWithSize(1);
47 | }
48 |
49 | @Test
50 | public void test2() {
51 | testWithSize(2);
52 | }
53 |
54 | @Test
55 | public void test3() {
56 | testWithSize(3);
57 | }
58 |
59 | private void testWithSize(int stackSize) {
60 | Coroutine c = new Coroutine(this, stackSize);
61 | assertEquals(getStackSize(c), stackSize);
62 | c.run();
63 | assertEquals(Coroutine.State.SUSPENDED, c.getState());
64 | c.run();
65 | assertEquals(Coroutine.State.FINISHED, c.getState());
66 | assertTrue(getStackSize(c) > 10);
67 | }
68 |
69 | @Override
70 | public void coExecute() throws SuspendExecution {
71 | assertEquals(3628800, factorial(10));
72 | }
73 |
74 | private int factorial(Integer a) throws SuspendExecution {
75 | if(a == 0) {
76 | Coroutine.yield();
77 | return 1;
78 | }
79 | return a * factorial(a - 1);
80 | }
81 |
82 | private int getStackSize(Coroutine c) {
83 | try {
84 | Field stackField = Coroutine.class.getDeclaredField("stack");
85 | stackField.setAccessible(true);
86 | Object stack = stackField.get(c);
87 | Field dataObjectField = Stack.class.getDeclaredField("dataObject");
88 | dataObjectField.setAccessible(true);
89 | Object[] dataObject = (Object[])dataObjectField.get(stack);
90 | return dataObject.length;
91 | } catch(Throwable ex) {
92 | throw new AssertionError(ex);
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/InterfaceIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import org.junit.Test;
32 |
33 | /**
34 | *
35 | * @author Elias Naur
36 | */
37 | public class InterfaceIT {
38 |
39 | public class C2 implements SomeInterface {
40 | public void doStuff() throws SuspendExecution {
41 | }
42 | }
43 |
44 | public class C implements SomeInterface {
45 | public void doStuff() throws SuspendExecution {
46 | /* float time = 0f;
47 | float seconds = .8f;
48 | do {
49 | float t = .06667f;
50 | System.out.println("time = " + time + " " + (time + t));
51 | // time = StrictMath.min(time + t, seconds);
52 | time = time + t;
53 | System.out.println("seconds = " + seconds + " | time = " + time + " | t = " + t);
54 | System.out.println("this = " + this);
55 |
56 | System.out.println("time just not after = " + time);
57 | Coroutine.yield();
58 | System.out.println("time after = " + time);
59 | } while (time < seconds);
60 | System.out.println("1 = " + 1);*/
61 | }
62 | }
63 |
64 | @Test
65 | public void testSuspend() {
66 | // final I i = new C();
67 | Coroutine co = new Coroutine(new CoroutineProto() {
68 | public final void coExecute() throws SuspendExecution {
69 | // next line causes an error because of incomplete merge in TypeInterpreter
70 | //SomeInterface i = System.currentTimeMillis() > 0 ? new C() : new C2();
71 | SomeInterface i = new C();
72 | System.out.println("i = " + i);
73 | i.doStuff();
74 | }
75 | });
76 | while(co.getState() != Coroutine.State.FINISHED) {
77 | System.out.println("State="+co.getState());
78 | co.run();
79 | }
80 | System.out.println("State="+co.getState());
81 | }
82 |
83 | }
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/Merge2IT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertTrue;
32 |
33 | import org.junit.Test;
34 |
35 | /**
36 | *
37 | * @author mam
38 | */
39 | public class Merge2IT implements CoroutineProto {
40 |
41 | public interface Interface {
42 | public void method();
43 | }
44 |
45 | public static Interface getInterface() {
46 | return null;
47 | }
48 |
49 | public static void suspendable() throws SuspendExecution {
50 | }
51 |
52 | public void coExecute() throws SuspendExecution {
53 | try {
54 | Interface iface = getInterface();
55 | iface.method();
56 | } catch(IllegalStateException ise) {
57 | suspendable();
58 | }
59 | }
60 |
61 | @Test
62 | public void testMerge2() {
63 | try {
64 | Coroutine c = new Coroutine(new Merge2IT());
65 | c.run();
66 | assertTrue("Should not reach here", false);
67 | } catch (NullPointerException ex) {
68 | // NPE expected
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/Merge3IT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import org.junit.Test;
32 |
33 |
34 | /**
35 | *
36 | * @author Matthias Mann
37 | */
38 | public class Merge3IT implements CoroutineProto {
39 |
40 | public boolean a;
41 | public boolean b;
42 |
43 | public void coExecute() throws SuspendExecution {
44 | if(a) {
45 | Object[] arr = new Object[2];
46 | System.out.println(arr);
47 | } else {
48 | float[] arr = new float[3];
49 | System.out.println(arr);
50 | }
51 | blub();
52 | System.out.println();
53 | }
54 |
55 | private void blub() throws SuspendExecution {
56 | }
57 |
58 | @Test
59 | public void testMerge3() {
60 | Coroutine c = new Coroutine(new Merge3IT());
61 | c.run();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/MergeIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import java.io.FileNotFoundException;
32 | import java.io.IOException;
33 |
34 | import org.junit.Test;
35 |
36 | /**
37 | *
38 | * @author mam
39 | */
40 | public class MergeIT implements CoroutineProto {
41 |
42 | public static void throwsIO() throws IOException {
43 | }
44 |
45 | public void coExecute() throws SuspendExecution {
46 | try {
47 | throwsIO();
48 | } catch(FileNotFoundException e) {
49 | e.printStackTrace();
50 | } catch(IOException e) {
51 | e.printStackTrace();
52 | }
53 | }
54 |
55 | @Test
56 | public void testMerge() {
57 | Coroutine c = new Coroutine(new MergeIT());
58 | c.run();
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/NullIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertEquals;
32 |
33 | import org.junit.Test;
34 |
35 | /**
36 | *
37 | * @author Matthias Mann
38 | */
39 | public class NullIT implements CoroutineProto {
40 |
41 | Object result = "b";
42 |
43 | @Test
44 | public void testNull() {
45 | int count = 0;
46 | Coroutine co = new Coroutine(this);
47 | while(co.getState() != Coroutine.State.FINISHED) {
48 | ++count;
49 | co.run();
50 | }
51 | assertEquals(2, count);
52 | assertEquals("a", result);
53 | }
54 |
55 | @Override
56 | public void coExecute() throws SuspendExecution {
57 | result = getProperty();
58 | }
59 |
60 | private Object getProperty() throws SuspendExecution {
61 | Object x = null;
62 |
63 | Object y = getProperty("a");
64 | if(y != null) {
65 | x = y;
66 | }
67 |
68 | return x;
69 | }
70 |
71 | private Object getProperty(String string) throws SuspendExecution {
72 | Coroutine.yield();
73 | return string;
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/SerializeIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertEquals;
32 | import static org.junit.Assert.assertFalse;
33 | import static org.junit.Assert.assertNotSame;
34 |
35 | import java.io.ByteArrayInputStream;
36 | import java.io.ByteArrayOutputStream;
37 | import java.io.IOException;
38 | import java.io.ObjectInputStream;
39 | import java.io.ObjectOutputStream;
40 | import java.util.Iterator;
41 |
42 | import org.junit.Test;
43 |
44 | /**
45 | *
46 | * @author Matthias Mann
47 | */
48 | public class SerializeIT {
49 |
50 | @Test
51 | public void testSerialize() throws IOException, ClassNotFoundException, SuspendExecution {
52 | Iterator iter1 = new TestIterator();
53 |
54 | assertEquals("A", iter1.next());
55 | assertEquals("B", iter1.next());
56 | assertEquals("C0", iter1.next());
57 | assertEquals("C1", iter1.next());
58 |
59 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
60 | ObjectOutputStream oos = new ObjectOutputStream(baos);
61 | oos.writeObject(iter1);
62 | oos.close();
63 |
64 | byte[] bytes = baos.toByteArray();
65 |
66 | ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
67 | ObjectInputStream ois = new ObjectInputStream(bais);
68 | @SuppressWarnings("unchecked")
69 | Iterator iter2 = (Iterator)ois.readObject();
70 |
71 | assertNotSame(iter1, iter2);
72 |
73 | assertEquals("C2", iter2.next());
74 | assertEquals("C3", iter2.next());
75 | assertEquals("D", iter2.next());
76 | assertEquals("E", iter2.next());
77 | assertFalse(iter2.hasNext());
78 |
79 | assertEquals("C2", iter1.next());
80 | assertEquals("C3", iter1.next());
81 | assertEquals("D", iter1.next());
82 | assertEquals("E", iter1.next());
83 | assertFalse(iter1.hasNext());
84 | }
85 |
86 | private static class TestIterator extends CoIterator {
87 | @Override
88 | protected void run() throws SuspendExecution {
89 | produce("A");
90 | produce("B");
91 | for(int i = 0; i < 4; i++) {
92 | produce("C" + i);
93 | }
94 | produce("D");
95 | produce("E");
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/SomeInterface.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | /**
32 | * A dummy interface used for the InterfaceIT
33 | *
34 | * @author Elias Naur
35 | */
36 | public interface SomeInterface {
37 |
38 | void doStuff() throws SuspendExecution;
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/SuspendConstructorArgumentIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertEquals;
32 | import static org.junit.Assert.assertFalse;
33 |
34 | import java.io.IOException;
35 | import java.util.Iterator;
36 |
37 | import org.junit.Test;
38 |
39 | /**
40 | * Test to checking suspendable method calls as constructor parameters
41 | *
42 | * @author Matthias Mann
43 | */
44 | public class SuspendConstructorArgumentIT {
45 |
46 | @Test
47 | public void testCalls() throws IOException, SuspendExecution {
48 | Iterator iter = new CoIterator() {
49 | @Override
50 | public void run() throws SuspendExecution {
51 | m1();
52 | m2();
53 | m3();
54 | m4();
55 | }
56 |
57 | private void m1() throws SuspendExecution {
58 | // this is the pattern generated by Eclipse's compiler for: str() + " Bla"
59 | produce(new StringBuilder(str()).append(" Bla").toString());
60 | }
61 |
62 | private void m2() throws SuspendExecution {
63 | produce(new String(buf(), offset(), len()));
64 | }
65 |
66 | private void m3() throws SuspendExecution {
67 | produce(new Long(l()).toString());
68 | }
69 |
70 | private void m4() throws SuspendExecution {
71 | produce(new StringBuilder(new String(buf(), offset(), len())).append(str()).toString());
72 | }
73 |
74 | private String str() throws SuspendExecution {
75 | produce("str()");
76 | return "Test";
77 | }
78 |
79 | private char[] buf() throws SuspendExecution {
80 | produce("buf()");
81 | return "Hugo".toCharArray();
82 | }
83 |
84 | private int offset() throws SuspendExecution {
85 | produce("offset()");
86 | return 1;
87 | }
88 |
89 | private int len() throws SuspendExecution {
90 | produce("len()");
91 | return 3;
92 | }
93 |
94 | private long l() throws SuspendExecution {
95 | produce("l()");
96 | return 4711L << 32;
97 | }
98 | };
99 |
100 | assertEquals("str()", iter.next());
101 | assertEquals("Test Bla", iter.next());
102 | assertEquals("buf()", iter.next());
103 | assertEquals("offset()", iter.next());
104 | assertEquals("len()", iter.next());
105 | assertEquals("ugo", iter.next());
106 | assertEquals("l()", iter.next());
107 | assertEquals(Long.toString(4711L << 32), iter.next());
108 | assertEquals("buf()", iter.next());
109 | assertEquals("offset()", iter.next());
110 | assertEquals("len()", iter.next());
111 | assertEquals("str()", iter.next());
112 | assertEquals("ugoTest", iter.next());
113 | assertFalse(iter.hasNext());
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/SuspendIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import org.junit.Test;
32 |
33 | /**
34 | * Basic test
35 | *
36 | * @author Matthias Mann
37 | */
38 | public class SuspendIT implements CoroutineProto {
39 |
40 | @Test
41 | public void testSuspend() {
42 | SuspendIT test = new SuspendIT();
43 | Coroutine co = new Coroutine(test);
44 |
45 | while(co.getState() != Coroutine.State.FINISHED) {
46 | System.out.println("State="+co.getState());
47 | co.run();
48 | }
49 | System.out.println("State="+co.getState());
50 | }
51 |
52 | public void coExecute() throws SuspendExecution {
53 | int i0=0, i1=1;
54 | for(int j=0 ; j<10 ; j++) {
55 | i1 = i1 + i0;
56 | i0 = i1 - i0;
57 | print("bla %d %d\n", i0, i1);
58 | }
59 | }
60 |
61 | private static void print(String fmt, Object ... args) throws SuspendExecution {
62 | System.out.printf(fmt, args);
63 | Coroutine.yield();
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/ThrowIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertEquals;
32 | import static org.junit.Assert.assertTrue;
33 |
34 | import java.util.ArrayList;
35 |
36 | import org.junit.Test;
37 |
38 | /**
39 | * Test the propagation of unhandled exceptions throw a suspendable call
40 | *
41 | * @author Matthias Mann
42 | */
43 | public class ThrowIT implements CoroutineProto {
44 |
45 | private ArrayList results = new ArrayList<>();
46 |
47 | public void coExecute() throws SuspendExecution {
48 | results.add("A");
49 | Coroutine.yield();
50 | try {
51 | results.add("C");
52 | Coroutine.yield();
53 | if("".length() == 0) {
54 | throw new IllegalStateException("bla");
55 | }
56 | results.add("E");
57 | } finally {
58 | results.add("F");
59 | }
60 | results.add("G");
61 | }
62 |
63 | @Test
64 | public void testThrow() {
65 | results.clear();
66 |
67 | Coroutine co = new Coroutine(this);
68 | try {
69 | co.run();
70 | results.add("B");
71 | co.run();
72 | results.add("D");
73 | co.run();
74 | assertTrue(false);
75 | } catch (IllegalStateException es) {
76 | assertEquals("bla", es.getMessage());
77 | assertEquals(Coroutine.State.FINISHED, co.getState());
78 | } finally {
79 | System.out.println(results);
80 | }
81 |
82 | assertEquals(5, results.size());
83 | assertEquals("A", results.get(0));
84 | assertEquals("B", results.get(1));
85 | assertEquals("C", results.get(2));
86 | assertEquals("D", results.get(3));
87 | assertEquals("F", results.get(4));
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/test/java/de/matthiasmann/continuations/UninitializedIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2008-2013, Matthias Mann
3 | * All rights reserved.
4 | *
5 | * Redistribution and use in source and binary forms, with or without
6 | * modification, are permitted provided that the following conditions are met:
7 | *
8 | * * Redistributions of source code must retain the above copyright notice,
9 | * this list of conditions and the following disclaimer.
10 | * * Redistributions in binary form must reproduce the above copyright
11 | * notice, this list of conditions and the following disclaimer in the
12 | * documentation and/or other materials provided with the distribution.
13 | * * Neither the name of Matthias Mann nor the names of its
14 | * contributors may be used to endorse or promote products derived from
15 | * this software without specific prior written permission.
16 | *
17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 | * POSSIBILITY OF SUCH DAMAGE.
28 | */
29 | package de.matthiasmann.continuations;
30 |
31 | import static org.junit.Assert.assertEquals;
32 |
33 | import org.junit.Test;
34 |
35 | /**
36 | *
37 | * @author Matthias Mann
38 | */
39 | public class UninitializedIT implements CoroutineProto {
40 |
41 | Object result = "b";
42 |
43 | @Test
44 | public void testUninitialized() {
45 | int count = 0;
46 | Coroutine co = new Coroutine(this);
47 | while(co.getState() != Coroutine.State.FINISHED) {
48 | ++count;
49 | co.run();
50 | }
51 | assertEquals(2, count);
52 | assertEquals("a", result);
53 | }
54 |
55 | public void coExecute() throws SuspendExecution {
56 | result = getProperty();
57 | }
58 |
59 | private Object getProperty() throws SuspendExecution {
60 | Object x;
61 |
62 | Object y = getProperty("a");
63 | if(y != null) {
64 | x = y;
65 | } else {
66 | x = getProperty("c");
67 | }
68 |
69 | return x;
70 | }
71 |
72 | private Object getProperty(String string) throws SuspendExecution {
73 | Coroutine.yield();
74 | return string;
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------