mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
C backend: bugfixes
This commit is contained in:
parent
cbc8d3f638
commit
f828d049c4
|
@ -1,7 +0,0 @@
|
||||||
<component name="InspectionProjectProfileManager">
|
|
||||||
<settings>
|
|
||||||
<option name="PROJECT_PROFILE" value="Project Default" />
|
|
||||||
<option name="USE_PROJECT_PROFILE" value="true" />
|
|
||||||
<version value="1.0" />
|
|
||||||
</settings>
|
|
||||||
</component>
|
|
|
@ -36,6 +36,7 @@ import java.util.stream.Collectors;
|
||||||
import org.teavm.ast.InvocationExpr;
|
import org.teavm.ast.InvocationExpr;
|
||||||
import org.teavm.ast.decompilation.Decompiler;
|
import org.teavm.ast.decompilation.Decompiler;
|
||||||
import org.teavm.backend.c.analyze.CDependencyListener;
|
import org.teavm.backend.c.analyze.CDependencyListener;
|
||||||
|
import org.teavm.backend.c.analyze.InteropDependencyListener;
|
||||||
import org.teavm.backend.c.generate.BufferedCodeWriter;
|
import org.teavm.backend.c.generate.BufferedCodeWriter;
|
||||||
import org.teavm.backend.c.generate.ClassGenerator;
|
import org.teavm.backend.c.generate.ClassGenerator;
|
||||||
import org.teavm.backend.c.generate.CodeGenerationVisitor;
|
import org.teavm.backend.c.generate.CodeGenerationVisitor;
|
||||||
|
@ -148,7 +149,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<DependencyListener> getDependencyListeners() {
|
public List<DependencyListener> getDependencyListeners() {
|
||||||
return Arrays.asList(new CDependencyListener(), exportDependencyListener);
|
return Arrays.asList(new CDependencyListener(), exportDependencyListener, new InteropDependencyListener());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2019 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.c.analyze;
|
||||||
|
|
||||||
|
import org.teavm.dependency.AbstractDependencyListener;
|
||||||
|
import org.teavm.dependency.DependencyAgent;
|
||||||
|
import org.teavm.dependency.MethodDependency;
|
||||||
|
import org.teavm.interop.Import;
|
||||||
|
import org.teavm.interop.Structure;
|
||||||
|
import org.teavm.model.AnnotationReader;
|
||||||
|
import org.teavm.model.ClassReader;
|
||||||
|
import org.teavm.model.ElementModifier;
|
||||||
|
import org.teavm.model.FieldReader;
|
||||||
|
|
||||||
|
public class InteropDependencyListener extends AbstractDependencyListener {
|
||||||
|
@Override
|
||||||
|
public void classReached(DependencyAgent agent, String className) {
|
||||||
|
if (agent.getClassHierarchy().isSuperType(Structure.class.getName(), className, false)) {
|
||||||
|
ClassReader cls = agent.getClassSource().get(className);
|
||||||
|
if (cls != null) {
|
||||||
|
for (FieldReader field : cls.getFields()) {
|
||||||
|
if (!field.hasModifier(ElementModifier.STATIC)) {
|
||||||
|
agent.linkField(field.getReference());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void methodReached(DependencyAgent agent, MethodDependency method) {
|
||||||
|
if (method.isMissing() || !method.getMethod().hasModifier(ElementModifier.NATIVE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AnnotationReader importAnnot = method.getMethod().getAnnotations().get(Import.class.getName());
|
||||||
|
if (importAnnot == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (method.getReference().getReturnType().isObject("java.lang.String")) {
|
||||||
|
method.getResult().propagate(agent.getType("java.lang.String"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -37,7 +37,6 @@ import org.teavm.model.MethodReader;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.Program;
|
import org.teavm.model.Program;
|
||||||
import org.teavm.model.TextLocation;
|
import org.teavm.model.TextLocation;
|
||||||
import org.teavm.model.TryCatchBlock;
|
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.model.Variable;
|
import org.teavm.model.Variable;
|
||||||
import org.teavm.model.instructions.BranchingCondition;
|
import org.teavm.model.instructions.BranchingCondition;
|
||||||
|
@ -61,13 +60,15 @@ import org.teavm.model.util.DefinitionExtractor;
|
||||||
import org.teavm.model.util.LivenessAnalyzer;
|
import org.teavm.model.util.LivenessAnalyzer;
|
||||||
import org.teavm.model.util.PhiUpdater;
|
import org.teavm.model.util.PhiUpdater;
|
||||||
import org.teavm.model.util.ProgramUtils;
|
import org.teavm.model.util.ProgramUtils;
|
||||||
import org.teavm.model.util.TransitionExtractor;
|
|
||||||
import org.teavm.model.util.TypeInferer;
|
import org.teavm.model.util.TypeInferer;
|
||||||
import org.teavm.model.util.UsageExtractor;
|
import org.teavm.model.util.UsageExtractor;
|
||||||
import org.teavm.model.util.VariableType;
|
import org.teavm.model.util.VariableType;
|
||||||
import org.teavm.runtime.Fiber;
|
import org.teavm.runtime.Fiber;
|
||||||
|
|
||||||
public class CoroutineTransformation {
|
public class CoroutineTransformation {
|
||||||
|
private static final MethodReference FIBER_SUSPEND = new MethodReference(Fiber.class, "suspend",
|
||||||
|
Fiber.AsyncCall.class, Object.class);
|
||||||
|
private static final String ASYNC_CALL = Fiber.class.getName() + "$AsyncCall";
|
||||||
private ClassReaderSource classSource;
|
private ClassReaderSource classSource;
|
||||||
private LivenessAnalyzer livenessAnalysis = new LivenessAnalyzer();
|
private LivenessAnalyzer livenessAnalysis = new LivenessAnalyzer();
|
||||||
private TypeInferer variableTypes = new TypeInferer();
|
private TypeInferer variableTypes = new TypeInferer();
|
||||||
|
@ -89,6 +90,11 @@ public class CoroutineTransformation {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ClassReader cls = classSource.get(methodReference.getClassName());
|
||||||
|
if (cls != null && cls.getInterfaces().contains(ASYNC_CALL)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
boolean hasJob = false;
|
boolean hasJob = false;
|
||||||
for (BasicBlock block : program.getBasicBlocks()) {
|
for (BasicBlock block : program.getBasicBlocks()) {
|
||||||
if (hasSplitInstructions(block)) {
|
if (hasSplitInstructions(block)) {
|
||||||
|
@ -176,15 +182,7 @@ public class CoroutineTransformation {
|
||||||
return Collections.emptyMap();
|
return Collections.emptyMap();
|
||||||
}
|
}
|
||||||
|
|
||||||
BitSet live = new BitSet();
|
BitSet live = livenessAnalysis.liveOut(block.getIndex());
|
||||||
TransitionExtractor transitionExtractor = new TransitionExtractor();
|
|
||||||
block.getLastInstruction().acceptVisitor(transitionExtractor);
|
|
||||||
for (BasicBlock successor : transitionExtractor.getTargets()) {
|
|
||||||
live.or(livenessAnalysis.liveIn(successor.getIndex()));
|
|
||||||
}
|
|
||||||
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
|
||||||
live.or(livenessAnalysis.liveIn(tryCatch.getHandler().getIndex()));
|
|
||||||
}
|
|
||||||
|
|
||||||
Map<Instruction, BitSet> result = new LinkedHashMap<>();
|
Map<Instruction, BitSet> result = new LinkedHashMap<>();
|
||||||
UsageExtractor use = new UsageExtractor();
|
UsageExtractor use = new UsageExtractor();
|
||||||
|
@ -224,6 +222,9 @@ public class CoroutineTransformation {
|
||||||
if (instruction instanceof InvokeInstruction) {
|
if (instruction instanceof InvokeInstruction) {
|
||||||
InvokeInstruction invoke = (InvokeInstruction) instruction;
|
InvokeInstruction invoke = (InvokeInstruction) instruction;
|
||||||
MethodReference method = findRealMethod(invoke.getMethod());
|
MethodReference method = findRealMethod(invoke.getMethod());
|
||||||
|
if (method.equals(FIBER_SUSPEND)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if (method.getClassName().equals(Fiber.class.getName())) {
|
if (method.getClassName().equals(Fiber.class.getName())) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,6 @@ import org.teavm.model.Instruction;
|
||||||
import org.teavm.model.MethodReference;
|
import org.teavm.model.MethodReference;
|
||||||
import org.teavm.model.Phi;
|
import org.teavm.model.Phi;
|
||||||
import org.teavm.model.Program;
|
import org.teavm.model.Program;
|
||||||
import org.teavm.model.TryCatchBlock;
|
|
||||||
import org.teavm.model.ValueType;
|
import org.teavm.model.ValueType;
|
||||||
import org.teavm.model.Variable;
|
import org.teavm.model.Variable;
|
||||||
import org.teavm.model.instructions.AbstractInstructionVisitor;
|
import org.teavm.model.instructions.AbstractInstructionVisitor;
|
||||||
|
@ -65,7 +64,6 @@ import org.teavm.model.instructions.StringConstantInstruction;
|
||||||
import org.teavm.model.instructions.UnwrapArrayInstruction;
|
import org.teavm.model.instructions.UnwrapArrayInstruction;
|
||||||
import org.teavm.model.util.DefinitionExtractor;
|
import org.teavm.model.util.DefinitionExtractor;
|
||||||
import org.teavm.model.util.LivenessAnalyzer;
|
import org.teavm.model.util.LivenessAnalyzer;
|
||||||
import org.teavm.model.util.TransitionExtractor;
|
|
||||||
import org.teavm.model.util.UsageExtractor;
|
import org.teavm.model.util.UsageExtractor;
|
||||||
|
|
||||||
public class EscapeAnalysis {
|
public class EscapeAnalysis {
|
||||||
|
@ -189,17 +187,7 @@ public class EscapeAnalysis {
|
||||||
}
|
}
|
||||||
|
|
||||||
private BitSet getUsedVarsInBlock(LivenessAnalyzer liveness, BasicBlock block) {
|
private BitSet getUsedVarsInBlock(LivenessAnalyzer liveness, BasicBlock block) {
|
||||||
BitSet usedVars = new BitSet();
|
return liveness.liveOut(block.getIndex());
|
||||||
TransitionExtractor transitionExtractor = new TransitionExtractor();
|
|
||||||
block.getLastInstruction().acceptVisitor(transitionExtractor);
|
|
||||||
for (BasicBlock successor : transitionExtractor.getTargets()) {
|
|
||||||
usedVars.or(liveness.liveIn(successor.getIndex()));
|
|
||||||
}
|
|
||||||
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
|
||||||
usedVars.or(liveness.liveIn(tryCatch.getHandler().getIndex()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return usedVars;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void propagateFields(Program program, List<Set<FieldReference>> fields) {
|
private void propagateFields(Program program, List<Set<FieldReference>> fields) {
|
||||||
|
|
|
@ -72,8 +72,8 @@ public class GCShadowStackContributor {
|
||||||
public int contribute(Program program, MethodReader method) {
|
public int contribute(Program program, MethodReader method) {
|
||||||
List<Map<Instruction, BitSet>> liveInInformation = findCallSiteLiveIns(program, method);
|
List<Map<Instruction, BitSet>> liveInInformation = findCallSiteLiveIns(program, method);
|
||||||
|
|
||||||
Graph interferenceGraph = buildInterferenceGraph(liveInInformation, program);
|
|
||||||
boolean[] spilled = getAffectedVariables(liveInInformation, program);
|
boolean[] spilled = getAffectedVariables(liveInInformation, program);
|
||||||
|
Graph interferenceGraph = buildInterferenceGraph(liveInInformation, program, spilled);
|
||||||
int[] colors = new int[interferenceGraph.size()];
|
int[] colors = new int[interferenceGraph.size()];
|
||||||
Arrays.fill(colors, -1);
|
Arrays.fill(colors, -1);
|
||||||
new GraphColorer().colorize(interferenceGraph, colors);
|
new GraphColorer().colorize(interferenceGraph, colors);
|
||||||
|
@ -81,8 +81,10 @@ public class GCShadowStackContributor {
|
||||||
int usedColors = 0;
|
int usedColors = 0;
|
||||||
for (int var = 0; var < colors.length; ++var) {
|
for (int var = 0; var < colors.length; ++var) {
|
||||||
if (spilled[var]) {
|
if (spilled[var]) {
|
||||||
usedColors = Math.max(usedColors, colors[var] + 1);
|
usedColors = Math.max(usedColors, colors[var]);
|
||||||
colors[var]--;
|
colors[var]--;
|
||||||
|
} else {
|
||||||
|
colors[var] = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (usedColors == 0) {
|
if (usedColors == 0) {
|
||||||
|
@ -182,7 +184,8 @@ public class GCShadowStackContributor {
|
||||||
return liveInInformation;
|
return liveInInformation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Graph buildInterferenceGraph(List<Map<Instruction, BitSet>> liveInInformation, Program program) {
|
private Graph buildInterferenceGraph(List<Map<Instruction, BitSet>> liveInInformation, Program program,
|
||||||
|
boolean[] spilled) {
|
||||||
GraphBuilder builder = new GraphBuilder(program.variableCount());
|
GraphBuilder builder = new GraphBuilder(program.variableCount());
|
||||||
for (Map<Instruction, BitSet> blockLiveIn : liveInInformation) {
|
for (Map<Instruction, BitSet> blockLiveIn : liveInInformation) {
|
||||||
for (BitSet liveVarsSet : blockLiveIn.values()) {
|
for (BitSet liveVarsSet : blockLiveIn.values()) {
|
||||||
|
@ -193,8 +196,12 @@ public class GCShadowStackContributor {
|
||||||
int[] liveVarArray = liveVars.toArray();
|
int[] liveVarArray = liveVars.toArray();
|
||||||
for (int i = 0; i < liveVarArray.length - 1; ++i) {
|
for (int i = 0; i < liveVarArray.length - 1; ++i) {
|
||||||
for (int j = i + 1; j < liveVarArray.length; ++j) {
|
for (int j = i + 1; j < liveVarArray.length; ++j) {
|
||||||
builder.addEdge(liveVarArray[i], liveVarArray[j]);
|
int a = liveVarArray[i];
|
||||||
builder.addEdge(liveVarArray[j], liveVarArray[i]);
|
int b = liveVarArray[j];
|
||||||
|
if (spilled[a] && spilled[b]) {
|
||||||
|
builder.addEdge(a, b);
|
||||||
|
builder.addEdge(b, a);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -270,7 +277,7 @@ public class GCShadowStackContributor {
|
||||||
Step[] stack = new Step[program.basicBlockCount() * 2];
|
Step[] stack = new Step[program.basicBlockCount() * 2];
|
||||||
int head = 0;
|
int head = 0;
|
||||||
Step start = new Step(0);
|
Step start = new Step(0);
|
||||||
Arrays.fill(start.slotStates, usedColors);
|
Arrays.fill(start.slotStates, program.variableCount());
|
||||||
stack[head++] = start;
|
stack[head++] = start;
|
||||||
|
|
||||||
while (head > 0) {
|
while (head > 0) {
|
||||||
|
|
|
@ -34,13 +34,7 @@ class InterferenceGraphBuilder {
|
||||||
BasicBlock block = program.basicBlockAt(i);
|
BasicBlock block = program.basicBlockAt(i);
|
||||||
block.getLastInstruction().acceptVisitor(succExtractor);
|
block.getLastInstruction().acceptVisitor(succExtractor);
|
||||||
|
|
||||||
BitSet liveOut = new BitSet(program.variableCount());
|
BitSet liveOut = liveness.liveOut(i);
|
||||||
for (BasicBlock succ : succExtractor.getTargets()) {
|
|
||||||
liveOut.or(liveness.liveIn(succ.getIndex()));
|
|
||||||
}
|
|
||||||
for (TryCatchBlock tryCatch : block.getTryCatchBlocks()) {
|
|
||||||
liveOut.or(liveness.liveIn(tryCatch.getHandler().getIndex()));
|
|
||||||
}
|
|
||||||
live.clear();
|
live.clear();
|
||||||
for (int j = 0; j < liveOut.length(); ++j) {
|
for (int j = 0; j < liveOut.length(); ++j) {
|
||||||
if (liveOut.get(j)) {
|
if (liveOut.get(j)) {
|
||||||
|
|
|
@ -30,6 +30,7 @@ import org.teavm.model.Variable;
|
||||||
|
|
||||||
public class LivenessAnalyzer {
|
public class LivenessAnalyzer {
|
||||||
private BitSet[] liveVars;
|
private BitSet[] liveVars;
|
||||||
|
private BitSet[] liveOutVars;
|
||||||
|
|
||||||
public boolean liveIn(int block, int var) {
|
public boolean liveIn(int block, int var) {
|
||||||
return liveVars[block].get(var);
|
return liveVars[block].get(var);
|
||||||
|
@ -39,11 +40,17 @@ public class LivenessAnalyzer {
|
||||||
return (BitSet) liveVars[block].clone();
|
return (BitSet) liveVars[block].clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BitSet liveOut(int block) {
|
||||||
|
return (BitSet) liveOutVars[block].clone();
|
||||||
|
}
|
||||||
|
|
||||||
public void analyze(Program program) {
|
public void analyze(Program program) {
|
||||||
Graph cfg = ProgramUtils.buildControlFlowGraph(program);
|
Graph cfg = ProgramUtils.buildControlFlowGraph(program);
|
||||||
liveVars = new BitSet[cfg.size()];
|
liveVars = new BitSet[cfg.size()];
|
||||||
|
liveOutVars = new BitSet[cfg.size()];
|
||||||
for (int i = 0; i < liveVars.length; ++i) {
|
for (int i = 0; i < liveVars.length; ++i) {
|
||||||
liveVars[i] = new BitSet(program.basicBlockCount());
|
liveVars[i] = new BitSet(program.basicBlockCount());
|
||||||
|
liveOutVars[i] = new BitSet(program.basicBlockCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
UsageExtractor usageExtractor = new UsageExtractor();
|
UsageExtractor usageExtractor = new UsageExtractor();
|
||||||
|
@ -99,6 +106,18 @@ public class LivenessAnalyzer {
|
||||||
stack.push(nextTask);
|
stack.push(nextTask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < liveVars.length; ++i) {
|
||||||
|
for (int j : cfg.incomingEdges(i)) {
|
||||||
|
liveOutVars[j].or(liveVars[i]);
|
||||||
|
}
|
||||||
|
BasicBlock block = program.basicBlockAt(i);
|
||||||
|
for (Phi phi : block.getPhis()) {
|
||||||
|
for (Incoming incoming : phi.getIncomings()) {
|
||||||
|
liveOutVars[incoming.getSource().getIndex()].set(incoming.getValue().getIndex());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class Task {
|
private static class Task {
|
||||||
|
|
|
@ -44,6 +44,7 @@ public class Fiber {
|
||||||
private boolean daemon;
|
private boolean daemon;
|
||||||
|
|
||||||
private static Fiber current;
|
private static Fiber current;
|
||||||
|
private static PendingCall lastPendingCall;
|
||||||
|
|
||||||
private Fiber(FiberRunner runner, boolean daemon) {
|
private Fiber(FiberRunner runner, boolean daemon) {
|
||||||
this.runner = runner;
|
this.runner = runner;
|
||||||
|
@ -187,26 +188,65 @@ public class Fiber {
|
||||||
}
|
}
|
||||||
return fiber.result;
|
return fiber.result;
|
||||||
}
|
}
|
||||||
|
PendingCall pendingCall = new PendingCall(call, lastPendingCall);
|
||||||
|
if (lastPendingCall != null) {
|
||||||
|
lastPendingCall.next = pendingCall;
|
||||||
|
}
|
||||||
|
lastPendingCall = pendingCall;
|
||||||
|
|
||||||
fiber.state = STATE_SUSPENDING;
|
fiber.state = STATE_SUSPENDING;
|
||||||
call.run(new AsyncCallback<Object>() {
|
pendingCall.callback = new AsyncCallbackImpl(pendingCall, javaThread, fiber);
|
||||||
@Override
|
call.run(pendingCall.callback);
|
||||||
public void complete(Object result) {
|
|
||||||
setCurrentThread(javaThread);
|
|
||||||
fiber.result = result;
|
|
||||||
fiber.resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void error(Throwable e) {
|
|
||||||
setCurrentThread(javaThread);
|
|
||||||
fiber.exception = e;
|
|
||||||
fiber.resume();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class AsyncCallbackImpl implements AsyncCallback<Object> {
|
||||||
|
PendingCall pendingCall;
|
||||||
|
Thread javaThread;
|
||||||
|
Fiber fiber;
|
||||||
|
|
||||||
|
AsyncCallbackImpl(PendingCall pendingCall, Thread javaThread, Fiber fiber) {
|
||||||
|
this.pendingCall = pendingCall;
|
||||||
|
this.javaThread = javaThread;
|
||||||
|
this.fiber = fiber;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void complete(Object result) {
|
||||||
|
setCurrentThread(javaThread);
|
||||||
|
javaThread = null;
|
||||||
|
Fiber fiber = this.fiber;
|
||||||
|
this.fiber = null;
|
||||||
|
fiber.result = result;
|
||||||
|
removePendingCall();
|
||||||
|
fiber.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void error(Throwable e) {
|
||||||
|
setCurrentThread(javaThread);
|
||||||
|
javaThread = null;
|
||||||
|
Fiber fiber = this.fiber;
|
||||||
|
this.fiber = null;
|
||||||
|
fiber.exception = e;
|
||||||
|
removePendingCall();
|
||||||
|
fiber.resume();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removePendingCall() {
|
||||||
|
if (pendingCall.previous != null) {
|
||||||
|
pendingCall.previous.next = pendingCall.next;
|
||||||
|
}
|
||||||
|
if (pendingCall.next != null) {
|
||||||
|
pendingCall.next.previous = pendingCall.previous;
|
||||||
|
}
|
||||||
|
if (pendingCall == lastPendingCall) {
|
||||||
|
lastPendingCall = pendingCall.previous;
|
||||||
|
}
|
||||||
|
pendingCall = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static native void setCurrentThread(Thread thread);
|
static native void setCurrentThread(Thread thread);
|
||||||
|
|
||||||
public static void start(FiberRunner runner, boolean daemon) {
|
public static void start(FiberRunner runner, boolean daemon) {
|
||||||
|
@ -241,4 +281,17 @@ public class Fiber {
|
||||||
public interface AsyncCall {
|
public interface AsyncCall {
|
||||||
void run(AsyncCallback<?> callback);
|
void run(AsyncCallback<?> callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class PendingCall {
|
||||||
|
AsyncCall value;
|
||||||
|
PendingCall next;
|
||||||
|
PendingCall previous;
|
||||||
|
AsyncCallbackImpl callback;
|
||||||
|
|
||||||
|
PendingCall(AsyncCall value, PendingCall previous) {
|
||||||
|
this.value = value;
|
||||||
|
this.next = null;
|
||||||
|
this.previous = previous;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user