mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Working on support of async <clinit> methods
This commit is contained in:
parent
8e2814f984
commit
764c9bbb1e
|
@ -363,16 +363,7 @@ public class Renderer implements RenderingManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsClinit) {
|
if (needsClinit) {
|
||||||
writer.append("function ").appendClass(cls.getName()).append("_$callClinit()").ws()
|
renderCallClinit(clinit, cls, clinitMethods);
|
||||||
.append("{").softNewLine().indent();
|
|
||||||
writer.appendClass(cls.getName()).append("_$callClinit").ws().append("=").ws()
|
|
||||||
.append("function(){};").newLine();
|
|
||||||
for (MethodNode method : clinitMethods) {
|
|
||||||
renderBody(method, true);
|
|
||||||
}
|
|
||||||
writer.appendMethodBody(new MethodReference(cls.getName(), clinit.getDescriptor()))
|
|
||||||
.append("();").softNewLine();
|
|
||||||
writer.outdent().append("}").newLine();
|
|
||||||
}
|
}
|
||||||
if (!cls.getModifiers().contains(ElementModifier.INTERFACE)) {
|
if (!cls.getModifiers().contains(ElementModifier.INTERFACE)) {
|
||||||
for (MethodNode method : cls.getMethods()) {
|
for (MethodNode method : cls.getMethods()) {
|
||||||
|
@ -396,6 +387,71 @@ public class Renderer implements RenderingManager {
|
||||||
debugEmitter.emitClass(null);
|
debugEmitter.emitClass(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void renderCallClinit(MethodReader clinit, ClassNode cls, List<MethodNode> clinitMethods)
|
||||||
|
throws IOException {
|
||||||
|
boolean isAsync = asyncMethods.contains(clinit.getReference());
|
||||||
|
|
||||||
|
if (isAsync) {
|
||||||
|
writer.append("var ").appendClass(cls.getName()).append("_$clinitCalled").ws().append("=").ws()
|
||||||
|
.append("false;").softNewLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.append("function ").appendClass(cls.getName()).append("_$callClinit()").ws()
|
||||||
|
.append("{").softNewLine().indent();
|
||||||
|
|
||||||
|
if (isAsync) {
|
||||||
|
writer.append("var ").append(context.pointerName()).ws().append("=").ws()
|
||||||
|
.append("0").append(";").softNewLine();
|
||||||
|
writer.append("if").ws().append("(").appendFunction("$rt_resuming").append("())").ws().append("{")
|
||||||
|
.indent().softNewLine();
|
||||||
|
writer.append(context.pointerName()).ws().append("=").ws().appendFunction("$rt_nativeThread")
|
||||||
|
.append("().pop();").softNewLine();
|
||||||
|
writer.outdent().append("}").ws();
|
||||||
|
writer.append("else if").ws().append("(").appendClass(cls.getName()).append("_$clinitCalled)").ws()
|
||||||
|
.append("{").indent().softNewLine();
|
||||||
|
writer.append("return;").softNewLine();
|
||||||
|
writer.outdent().append("}").softNewLine();
|
||||||
|
|
||||||
|
renderAsyncPrologue();
|
||||||
|
|
||||||
|
writer.append("case 0:").indent().softNewLine();
|
||||||
|
writer.appendClass(cls.getName()).append("_$clinitCalled").ws().append('=').ws().append("true;")
|
||||||
|
.softNewLine();
|
||||||
|
} else {
|
||||||
|
renderEraseClinit(cls);
|
||||||
|
for (MethodNode method : clinitMethods) {
|
||||||
|
renderBody(method, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAsync) {
|
||||||
|
writer.append(context.pointerName()).ws().append("=").ws().append("1;").softNewLine();
|
||||||
|
writer.outdent().append("case 1:").indent().softNewLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.appendMethodBody(new MethodReference(cls.getName(), clinit.getDescriptor()))
|
||||||
|
.append("();").softNewLine();
|
||||||
|
|
||||||
|
if (isAsync) {
|
||||||
|
writer.append("if").ws().append("(").appendFunction("$rt_suspending").append("())").ws().append("{")
|
||||||
|
.indent().softNewLine();
|
||||||
|
writer.append("break " + context.mainLoopName() + ";").softNewLine();
|
||||||
|
writer.outdent().append("}").softNewLine();
|
||||||
|
renderEraseClinit(cls);
|
||||||
|
writer.append("return;").softNewLine().outdent();
|
||||||
|
|
||||||
|
renderAsyncEpilogue();
|
||||||
|
writer.appendFunction("$rt_nativeThread").append("().push(" + context.pointerName() + ");").softNewLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.outdent().append("}").newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderEraseClinit(ClassNode cls) throws IOException {
|
||||||
|
writer.appendClass(cls.getName()).append("_$callClinit").ws().append("=").ws()
|
||||||
|
.append("function(){};").newLine();
|
||||||
|
}
|
||||||
|
|
||||||
private void renderClassMetadata(List<ClassNode> classes) {
|
private void renderClassMetadata(List<ClassNode> classes) {
|
||||||
try {
|
try {
|
||||||
writer.append("$rt_metadata([");
|
writer.append("$rt_metadata([");
|
||||||
|
@ -598,6 +654,18 @@ public class Renderer implements RenderingManager {
|
||||||
debugEmitter.emitMethod(null);
|
debugEmitter.emitMethod(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void renderAsyncPrologue() throws IOException {
|
||||||
|
writer.append(context.mainLoopName()).append(":").ws().append("while").ws().append("(true)")
|
||||||
|
.ws().append("{").ws();
|
||||||
|
writer.append("switch").ws().append("(").append(context.pointerName()).append(")").ws()
|
||||||
|
.append('{').softNewLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void renderAsyncEpilogue() throws IOException {
|
||||||
|
writer.append("default:").ws().appendFunction("$rt_invalidPointer").append("();").softNewLine();
|
||||||
|
writer.append("}}").softNewLine();
|
||||||
|
}
|
||||||
|
|
||||||
private class MethodBodyRenderer implements MethodNodeVisitor, GeneratorContext {
|
private class MethodBodyRenderer implements MethodNodeVisitor, GeneratorContext {
|
||||||
private boolean async;
|
private boolean async;
|
||||||
private StatementRenderer statementRenderer;
|
private StatementRenderer statementRenderer;
|
||||||
|
@ -726,10 +794,8 @@ public class Renderer implements RenderingManager {
|
||||||
if (methodNode.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
if (methodNode.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
||||||
writer.append("try").ws().append('{').indent().softNewLine();
|
writer.append("try").ws().append('{').indent().softNewLine();
|
||||||
}
|
}
|
||||||
writer.append(context.mainLoopName()).append(":").ws().append("while").ws().append("(true)")
|
|
||||||
.ws().append("{").ws();
|
renderAsyncPrologue();
|
||||||
writer.append("switch").ws().append("(").append(context.pointerName()).append(")").ws()
|
|
||||||
.append('{').softNewLine();
|
|
||||||
for (int i = 0; i < methodNode.getBody().size(); ++i) {
|
for (int i = 0; i < methodNode.getBody().size(); ++i) {
|
||||||
writer.append("case ").append(i).append(":").indent().softNewLine();
|
writer.append("case ").append(i).append(":").indent().softNewLine();
|
||||||
if (i == 0 && methodNode.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
if (i == 0 && methodNode.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
||||||
|
@ -746,8 +812,7 @@ public class Renderer implements RenderingManager {
|
||||||
part.getStatement().acceptVisitor(statementRenderer);
|
part.getStatement().acceptVisitor(statementRenderer);
|
||||||
writer.outdent();
|
writer.outdent();
|
||||||
}
|
}
|
||||||
writer.append("default:").ws().appendFunction("$rt_invalidPointer").append("();").softNewLine();
|
renderAsyncEpilogue();
|
||||||
writer.append("}}").softNewLine();
|
|
||||||
|
|
||||||
if (methodNode.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
if (methodNode.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
||||||
writer.outdent().append("}").ws().append("finally").ws().append('{').indent().softNewLine();
|
writer.outdent().append("}").ws().append("finally").ws().append('{').indent().softNewLine();
|
||||||
|
|
|
@ -406,10 +406,25 @@ function $rt_metadata(data) {
|
||||||
for (var j = 0; j < names.length; j = (j + 1) | 0) {
|
for (var j = 0; j < names.length; j = (j + 1) | 0) {
|
||||||
window[names[j]] = (function(cls, name) {
|
window[names[j]] = (function(cls, name) {
|
||||||
return function() {
|
return function() {
|
||||||
var clinit = cls.$clinit;
|
var ptr = 0;
|
||||||
cls.$clinit = function() {};
|
if ($rt_resuming()) {
|
||||||
clinit();
|
ptr = $rt_nativeThread().pop();
|
||||||
return window[name].apply(window, arguments);
|
}
|
||||||
|
main: while (true) {
|
||||||
|
switch (ptr) {
|
||||||
|
case 0:
|
||||||
|
clinit = cls.$clinit;
|
||||||
|
clinit();
|
||||||
|
ptr = 1;
|
||||||
|
case 1:
|
||||||
|
var result = window[name].apply(window, arguments);
|
||||||
|
if ($rt_suspend()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$rt_nativeThread().push(ptr);
|
||||||
}
|
}
|
||||||
})(cls, names[j]);
|
})(cls, names[j]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,6 @@ import org.teavm.backend.javascript.spi.GeneratedBy;
|
||||||
import org.teavm.dependency.PluggableDependency;
|
import org.teavm.dependency.PluggableDependency;
|
||||||
import org.teavm.diagnostics.Diagnostics;
|
import org.teavm.diagnostics.Diagnostics;
|
||||||
import org.teavm.interop.Async;
|
import org.teavm.interop.Async;
|
||||||
import org.teavm.interop.Sync;
|
|
||||||
import org.teavm.model.AnnotationHolder;
|
import org.teavm.model.AnnotationHolder;
|
||||||
import org.teavm.model.AnnotationValue;
|
import org.teavm.model.AnnotationValue;
|
||||||
import org.teavm.model.CallLocation;
|
import org.teavm.model.CallLocation;
|
||||||
|
@ -32,10 +31,6 @@ import org.teavm.model.MethodHolder;
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.platform.async.AsyncCallback;
|
import org.teavm.platform.async.AsyncCallback;
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @author Alexey Andreev
|
|
||||||
*/
|
|
||||||
public class AsyncMethodProcessor implements ClassHolderTransformer {
|
public class AsyncMethodProcessor implements ClassHolderTransformer {
|
||||||
@Override
|
@Override
|
||||||
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
|
public void transformClass(ClassHolder cls, ClassReaderSource innerSource, Diagnostics diagnostics) {
|
||||||
|
@ -65,11 +60,6 @@ public class AsyncMethodProcessor implements ClassHolderTransformer {
|
||||||
annot.getValues().put("value", new AnnotationValue(ValueType.parse(AsyncMethodGenerator.class)));
|
annot.getValues().put("value", new AnnotationValue(ValueType.parse(AsyncMethodGenerator.class)));
|
||||||
method.getAnnotations().add(annot);
|
method.getAnnotations().add(annot);
|
||||||
}
|
}
|
||||||
} else if (method.getName().equals("<clinit>")) {
|
|
||||||
if (method.getAnnotations().get(Sync.class.getName()) == null) {
|
|
||||||
AnnotationHolder annot = new AnnotationHolder(Sync.class.getName());
|
|
||||||
method.getAnnotations().add(annot);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,6 +116,41 @@ public class VMTest {
|
||||||
assertEquals(x, id(23));
|
assertEquals(x, id(23));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void asyncClinit() {
|
||||||
|
assertEquals(0, initCount);
|
||||||
|
assertEquals("foo", AsyncClinitClass.foo());
|
||||||
|
assertEquals(1, initCount);
|
||||||
|
assertEquals(AsyncClinitClass.state, "ok");
|
||||||
|
assertEquals("bar", AsyncClinitClass.bar());
|
||||||
|
assertEquals(1, initCount);
|
||||||
|
assertEquals(AsyncClinitClass.state, "ok");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int initCount = 0;
|
||||||
|
|
||||||
|
private static class AsyncClinitClass {
|
||||||
|
static String state = "";
|
||||||
|
|
||||||
|
static {
|
||||||
|
initCount++;
|
||||||
|
try {
|
||||||
|
Thread.sleep(1);
|
||||||
|
state += "ok";
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
state += "error";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String foo() {
|
||||||
|
return "foo";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String bar() {
|
||||||
|
return "bar";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void throwException() {
|
private void throwException() {
|
||||||
throw new RuntimeException();
|
throw new RuntimeException();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user