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) {
|
||||
writer.append("function ").appendClass(cls.getName()).append("_$callClinit()").ws()
|
||||
.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();
|
||||
renderCallClinit(clinit, cls, clinitMethods);
|
||||
}
|
||||
if (!cls.getModifiers().contains(ElementModifier.INTERFACE)) {
|
||||
for (MethodNode method : cls.getMethods()) {
|
||||
|
@ -396,6 +387,71 @@ public class Renderer implements RenderingManager {
|
|||
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) {
|
||||
try {
|
||||
writer.append("$rt_metadata([");
|
||||
|
@ -598,6 +654,18 @@ public class Renderer implements RenderingManager {
|
|||
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 boolean async;
|
||||
private StatementRenderer statementRenderer;
|
||||
|
@ -726,10 +794,8 @@ public class Renderer implements RenderingManager {
|
|||
if (methodNode.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
||||
writer.append("try").ws().append('{').indent().softNewLine();
|
||||
}
|
||||
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();
|
||||
|
||||
renderAsyncPrologue();
|
||||
for (int i = 0; i < methodNode.getBody().size(); ++i) {
|
||||
writer.append("case ").append(i).append(":").indent().softNewLine();
|
||||
if (i == 0 && methodNode.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
||||
|
@ -746,8 +812,7 @@ public class Renderer implements RenderingManager {
|
|||
part.getStatement().acceptVisitor(statementRenderer);
|
||||
writer.outdent();
|
||||
}
|
||||
writer.append("default:").ws().appendFunction("$rt_invalidPointer").append("();").softNewLine();
|
||||
writer.append("}}").softNewLine();
|
||||
renderAsyncEpilogue();
|
||||
|
||||
if (methodNode.getModifiers().contains(ElementModifier.SYNCHRONIZED)) {
|
||||
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) {
|
||||
window[names[j]] = (function(cls, name) {
|
||||
return function() {
|
||||
var clinit = cls.$clinit;
|
||||
cls.$clinit = function() {};
|
||||
var ptr = 0;
|
||||
if ($rt_resuming()) {
|
||||
ptr = $rt_nativeThread().pop();
|
||||
}
|
||||
main: while (true) {
|
||||
switch (ptr) {
|
||||
case 0:
|
||||
clinit = cls.$clinit;
|
||||
clinit();
|
||||
return window[name].apply(window, arguments);
|
||||
ptr = 1;
|
||||
case 1:
|
||||
var result = window[name].apply(window, arguments);
|
||||
if ($rt_suspend()) {
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
$rt_nativeThread().push(ptr);
|
||||
}
|
||||
})(cls, names[j]);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@ import org.teavm.backend.javascript.spi.GeneratedBy;
|
|||
import org.teavm.dependency.PluggableDependency;
|
||||
import org.teavm.diagnostics.Diagnostics;
|
||||
import org.teavm.interop.Async;
|
||||
import org.teavm.interop.Sync;
|
||||
import org.teavm.model.AnnotationHolder;
|
||||
import org.teavm.model.AnnotationValue;
|
||||
import org.teavm.model.CallLocation;
|
||||
|
@ -32,10 +31,6 @@ import org.teavm.model.MethodHolder;
|
|||
import org.teavm.model.ValueType;
|
||||
import org.teavm.platform.async.AsyncCallback;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Alexey Andreev
|
||||
*/
|
||||
public class AsyncMethodProcessor implements ClassHolderTransformer {
|
||||
@Override
|
||||
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)));
|
||||
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));
|
||||
}
|
||||
|
||||
@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() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user