mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 16:14:10 -08:00
C: support array bound checking
This commit is contained in:
parent
6f50eefaf9
commit
94a96f571b
|
@ -106,12 +106,13 @@ import org.teavm.model.instructions.InvocationType;
|
|||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.lowlevel.CallSiteDescriptor;
|
||||
import org.teavm.model.lowlevel.Characteristics;
|
||||
import org.teavm.model.lowlevel.CheckInstructionTransformation;
|
||||
import org.teavm.model.lowlevel.ClassInitializerEliminator;
|
||||
import org.teavm.model.lowlevel.ClassInitializerTransformer;
|
||||
import org.teavm.model.lowlevel.ExportDependencyListener;
|
||||
import org.teavm.model.lowlevel.LowLevelNullCheckFilter;
|
||||
import org.teavm.model.lowlevel.NullCheckTransformation;
|
||||
import org.teavm.model.lowlevel.ShadowStackTransformer;
|
||||
import org.teavm.model.transformation.BoundCheckInsertion;
|
||||
import org.teavm.model.transformation.ClassPatch;
|
||||
import org.teavm.model.transformation.NullCheckInsertion;
|
||||
import org.teavm.model.util.AsyncMethodFinder;
|
||||
|
@ -150,7 +151,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
private ClassInitializerTransformer classInitializerTransformer;
|
||||
private ShadowStackTransformer shadowStackTransformer;
|
||||
private NullCheckInsertion nullCheckInsertion;
|
||||
private NullCheckTransformation nullCheckTransformation;
|
||||
private BoundCheckInsertion boundCheckInsertion = new BoundCheckInsertion();
|
||||
private CheckInstructionTransformation checkTransformation;
|
||||
private ExportDependencyListener exportDependencyListener = new ExportDependencyListener();
|
||||
private int minHeapSize = 4 * 1024 * 1024;
|
||||
private int maxHeapSize = 128 * 1024 * 1024;
|
||||
|
@ -222,7 +224,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
classInitializerTransformer = new ClassInitializerTransformer();
|
||||
shadowStackTransformer = new ShadowStackTransformer(characteristics, !longjmpUsed);
|
||||
nullCheckInsertion = new NullCheckInsertion(new LowLevelNullCheckFilter(characteristics));
|
||||
nullCheckTransformation = new NullCheckTransformation();
|
||||
checkTransformation = new CheckInstructionTransformation();
|
||||
|
||||
controller.addVirtualMethods(VIRTUAL_METHODS::contains);
|
||||
}
|
||||
|
@ -267,6 +269,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
void.class)).use();
|
||||
dependencyAnalyzer.linkMethod(new MethodReference(ExceptionHandling.class, "throwNullPointerException",
|
||||
void.class)).use();
|
||||
dependencyAnalyzer.linkMethod(new MethodReference(ExceptionHandling.class,
|
||||
"throwArrayIndexOutOfBoundsException", void.class)).use();
|
||||
dependencyAnalyzer.linkMethod(new MethodReference(NullPointerException.class, "<init>", void.class))
|
||||
.propagate(0, NullPointerException.class.getName())
|
||||
.use();
|
||||
|
@ -324,6 +328,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
@Override
|
||||
public void beforeOptimizations(Program program, MethodReader method) {
|
||||
nullCheckInsertion.transformProgram(program, method.getReference());
|
||||
boundCheckInsertion.transformProgram(program, method.getReference());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -331,7 +336,7 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
classInitializerEliminator.apply(program);
|
||||
classInitializerTransformer.transform(program);
|
||||
if (!longjmpUsed) {
|
||||
nullCheckTransformation.apply(program, method.getResultType());
|
||||
checkTransformation.apply(program, method.getResultType());
|
||||
}
|
||||
new CoroutineTransformation(controller.getUnprocessedClassSource(), asyncMethods, hasThreads)
|
||||
.apply(program, method.getReference());
|
||||
|
@ -394,8 +399,8 @@ public class CTarget implements TeaVMTarget, TeaVMCHost {
|
|||
if (incremental) {
|
||||
configHeaderWriter.println("#define TEAVM_INCREMENTAL 1");
|
||||
}
|
||||
if (longjmpUsed) {
|
||||
configHeaderWriter.println("#define TEAVM_USE_SETJMP 1");
|
||||
if (!longjmpUsed) {
|
||||
configHeaderWriter.println("#define TEAVM_USE_SETJMP 0");
|
||||
}
|
||||
if (vmAssertions) {
|
||||
configHeaderWriter.println("#define TEAVM_MEMORY_TRACE 1");
|
||||
|
|
|
@ -1423,7 +1423,37 @@ public class CodeGenerationVisitor implements ExprVisitor, StatementVisitor {
|
|||
|
||||
@Override
|
||||
public void visit(BoundCheckExpr expr) {
|
||||
if (expr.getArray() == null && !expr.isLower()) {
|
||||
expr.getIndex().acceptVisitor(this);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean needParenthesis = false;
|
||||
if (needsCallSiteId()) {
|
||||
needParenthesis = true;
|
||||
withCallSite();
|
||||
}
|
||||
|
||||
String functionName;
|
||||
if (expr.getArray() == null) {
|
||||
functionName = "teavm_checkLowerBound";
|
||||
} else if (!expr.isLower()) {
|
||||
functionName = "teavm_checkUpperBound";
|
||||
} else {
|
||||
functionName = "teavm_checkBounds";
|
||||
}
|
||||
|
||||
writer.print(functionName);
|
||||
writer.print("(");
|
||||
expr.getIndex().acceptVisitor(this);
|
||||
if (expr.getArray() != null) {
|
||||
writer.print(", ");
|
||||
visitReference(expr.getArray());
|
||||
}
|
||||
writer.print(")");
|
||||
if (needParenthesis) {
|
||||
writer.print(")");
|
||||
}
|
||||
}
|
||||
|
||||
private IntrinsicContext intrinsicContext = new IntrinsicContext() {
|
||||
|
|
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* Copyright 2018 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.model.lowlevel;
|
||||
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.Variable;
|
||||
import org.teavm.model.instructions.ArrayLengthInstruction;
|
||||
import org.teavm.model.instructions.AssignInstruction;
|
||||
import org.teavm.model.instructions.BinaryInstruction;
|
||||
import org.teavm.model.instructions.BinaryOperation;
|
||||
import org.teavm.model.instructions.BoundCheckInstruction;
|
||||
import org.teavm.model.instructions.BranchingCondition;
|
||||
import org.teavm.model.instructions.BranchingInstruction;
|
||||
import org.teavm.model.instructions.DoubleConstantInstruction;
|
||||
import org.teavm.model.instructions.ExitInstruction;
|
||||
import org.teavm.model.instructions.FloatConstantInstruction;
|
||||
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.instructions.JumpInstruction;
|
||||
import org.teavm.model.instructions.LongConstantInstruction;
|
||||
import org.teavm.model.instructions.NullCheckInstruction;
|
||||
import org.teavm.model.instructions.NullConstantInstruction;
|
||||
import org.teavm.model.instructions.NumericOperandType;
|
||||
import org.teavm.model.util.BasicBlockSplitter;
|
||||
import org.teavm.runtime.ExceptionHandling;
|
||||
|
||||
public class CheckInstructionTransformation {
|
||||
private BasicBlock returnBlock;
|
||||
private BasicBlock next;
|
||||
|
||||
public void apply(Program program, ValueType returnType) {
|
||||
BasicBlockSplitter splitter = new BasicBlockSplitter(program);
|
||||
|
||||
returnBlock = null;
|
||||
int count = program.basicBlockCount();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
next = program.basicBlockAt(i);
|
||||
BasicBlock block;
|
||||
while (next != null) {
|
||||
block = next;
|
||||
next = null;
|
||||
for (Instruction instruction : block) {
|
||||
if (instruction instanceof NullCheckInstruction) {
|
||||
replaceNullCheck(splitter, program, (NullCheckInstruction) instruction);
|
||||
} else if (instruction instanceof BoundCheckInstruction) {
|
||||
replaceBoundCheck(splitter, program, (BoundCheckInstruction) instruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (returnBlock != null) {
|
||||
ExitInstruction fakeExit = new ExitInstruction();
|
||||
if (returnType != ValueType.VOID) {
|
||||
Variable fakeReturnVar = program.createVariable();
|
||||
createFakeReturnValue(returnBlock, fakeReturnVar, returnType);
|
||||
fakeExit.setValueToReturn(fakeReturnVar);
|
||||
}
|
||||
returnBlock.add(fakeExit);
|
||||
}
|
||||
|
||||
splitter.fixProgram();
|
||||
}
|
||||
|
||||
private void replaceNullCheck(BasicBlockSplitter splitter, Program program, NullCheckInstruction nullCheck) {
|
||||
BasicBlock block = nullCheck.getBasicBlock();
|
||||
BasicBlock continueBlock = splitter.split(block, nullCheck);
|
||||
BasicBlock throwBlock = program.createBasicBlock();
|
||||
|
||||
InvokeInstruction throwNPE = new InvokeInstruction();
|
||||
throwNPE.setType(InvocationType.SPECIAL);
|
||||
throwNPE.setMethod(new MethodReference(ExceptionHandling.class, "throwNullPointerException",
|
||||
void.class));
|
||||
throwNPE.setLocation(nullCheck.getLocation());
|
||||
throwBlock.add(throwNPE);
|
||||
|
||||
jumpToReturn(program, nullCheck, throwBlock);
|
||||
|
||||
BranchingInstruction jumpIfNull = new BranchingInstruction(BranchingCondition.NULL);
|
||||
jumpIfNull.setOperand(nullCheck.getValue());
|
||||
jumpIfNull.setConsequent(throwBlock);
|
||||
jumpIfNull.setAlternative(continueBlock);
|
||||
jumpIfNull.setLocation(nullCheck.getLocation());
|
||||
nullCheck.replace(jumpIfNull);
|
||||
|
||||
AssignInstruction assign = new AssignInstruction();
|
||||
assign.setAssignee(nullCheck.getValue());
|
||||
assign.setReceiver(nullCheck.getReceiver());
|
||||
assign.setLocation(nullCheck.getLocation());
|
||||
continueBlock.addFirst(assign);
|
||||
|
||||
next = continueBlock;
|
||||
}
|
||||
|
||||
private void replaceBoundCheck(BasicBlockSplitter splitter, Program program, BoundCheckInstruction boundCheck) {
|
||||
BasicBlock block = boundCheck.getBasicBlock();
|
||||
BasicBlock continueBlock = splitter.split(block, boundCheck);
|
||||
BasicBlock throwBlock = program.createBasicBlock();
|
||||
|
||||
BasicBlock ifPositiveBlock = continueBlock;
|
||||
if (boundCheck.isLower() && boundCheck.getArray() != null) {
|
||||
ifPositiveBlock = program.createBasicBlock();
|
||||
}
|
||||
|
||||
InvokeInstruction throwAIOOBE = new InvokeInstruction();
|
||||
throwAIOOBE.setType(InvocationType.SPECIAL);
|
||||
throwAIOOBE.setMethod(new MethodReference(ExceptionHandling.class, "throwArrayIndexOutOfBoundsException",
|
||||
void.class));
|
||||
throwAIOOBE.setLocation(boundCheck.getLocation());
|
||||
throwBlock.add(throwAIOOBE);
|
||||
|
||||
jumpToReturn(program, boundCheck, throwBlock);
|
||||
|
||||
if (boundCheck.isLower()) {
|
||||
BranchingInstruction jumpIfLess = new BranchingInstruction(BranchingCondition.LESS);
|
||||
jumpIfLess.setOperand(boundCheck.getIndex());
|
||||
jumpIfLess.setConsequent(throwBlock);
|
||||
jumpIfLess.setAlternative(ifPositiveBlock);
|
||||
jumpIfLess.setLocation(boundCheck.getLocation());
|
||||
boundCheck.replace(jumpIfLess);
|
||||
}
|
||||
|
||||
if (boundCheck.getArray() != null) {
|
||||
ArrayLengthInstruction arrayLength = new ArrayLengthInstruction();
|
||||
arrayLength.setArray(boundCheck.getArray());
|
||||
arrayLength.setReceiver(program.createVariable());
|
||||
arrayLength.setLocation(boundCheck.getLocation());
|
||||
|
||||
BinaryInstruction compare = new BinaryInstruction(BinaryOperation.COMPARE, NumericOperandType.INT);
|
||||
compare.setFirstOperand(boundCheck.getIndex());
|
||||
compare.setSecondOperand(arrayLength.getReceiver());
|
||||
compare.setReceiver(program.createVariable());
|
||||
compare.setLocation(boundCheck.getLocation());
|
||||
|
||||
BranchingInstruction jumpIfGreater = new BranchingInstruction(BranchingCondition.GREATER_OR_EQUAL);
|
||||
jumpIfGreater.setOperand(compare.getReceiver());
|
||||
jumpIfGreater.setConsequent(throwBlock);
|
||||
jumpIfGreater.setAlternative(continueBlock);
|
||||
jumpIfGreater.setLocation(boundCheck.getLocation());
|
||||
|
||||
if (boundCheck.isLower()) {
|
||||
ifPositiveBlock.add(jumpIfGreater);
|
||||
} else {
|
||||
boundCheck.replace(jumpIfGreater);
|
||||
}
|
||||
|
||||
jumpIfGreater.insertPrevious(arrayLength);
|
||||
jumpIfGreater.insertPrevious(compare);
|
||||
}
|
||||
|
||||
AssignInstruction assign = new AssignInstruction();
|
||||
assign.setAssignee(boundCheck.getIndex());
|
||||
assign.setReceiver(boundCheck.getReceiver());
|
||||
assign.setLocation(boundCheck.getLocation());
|
||||
continueBlock.addFirst(assign);
|
||||
}
|
||||
|
||||
private void jumpToReturn(Program program, Instruction instruction, BasicBlock throwBlock) {
|
||||
if (returnBlock == null) {
|
||||
returnBlock = program.createBasicBlock();
|
||||
}
|
||||
|
||||
JumpInstruction jumpToFakeReturn = new JumpInstruction();
|
||||
jumpToFakeReturn.setTarget(returnBlock);
|
||||
jumpToFakeReturn.setLocation(instruction.getLocation());
|
||||
throwBlock.add(jumpToFakeReturn);
|
||||
}
|
||||
|
||||
private void createFakeReturnValue(BasicBlock block, Variable variable, ValueType type) {
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
case BOOLEAN:
|
||||
case BYTE:
|
||||
case SHORT:
|
||||
case INTEGER:
|
||||
case CHARACTER:
|
||||
IntegerConstantInstruction intZero = new IntegerConstantInstruction();
|
||||
intZero.setReceiver(variable);
|
||||
block.add(intZero);
|
||||
return;
|
||||
case LONG:
|
||||
LongConstantInstruction longZero = new LongConstantInstruction();
|
||||
longZero.setReceiver(variable);
|
||||
block.add(longZero);
|
||||
return;
|
||||
case FLOAT:
|
||||
FloatConstantInstruction floatZero = new FloatConstantInstruction();
|
||||
floatZero.setReceiver(variable);
|
||||
block.add(floatZero);
|
||||
return;
|
||||
case DOUBLE:
|
||||
DoubleConstantInstruction doubleZero = new DoubleConstantInstruction();
|
||||
doubleZero.setReceiver(variable);
|
||||
block.add(doubleZero);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NullConstantInstruction nullConstant = new NullConstantInstruction();
|
||||
nullConstant.setReceiver(variable);
|
||||
block.add(nullConstant);
|
||||
}
|
||||
}
|
|
@ -40,6 +40,7 @@ import org.teavm.model.ValueType;
|
|||
import org.teavm.model.Variable;
|
||||
import org.teavm.model.instructions.BinaryBranchingCondition;
|
||||
import org.teavm.model.instructions.BinaryBranchingInstruction;
|
||||
import org.teavm.model.instructions.BoundCheckInstruction;
|
||||
import org.teavm.model.instructions.CloneArrayInstruction;
|
||||
import org.teavm.model.instructions.ConstructArrayInstruction;
|
||||
import org.teavm.model.instructions.ConstructInstruction;
|
||||
|
@ -283,7 +284,7 @@ public class ExceptionHandlingShadowStackContributor {
|
|||
|| insn instanceof ConstructArrayInstruction || insn instanceof ConstructMultiArrayInstruction
|
||||
|| insn instanceof CloneArrayInstruction || insn instanceof RaiseInstruction
|
||||
|| insn instanceof MonitorEnterInstruction || insn instanceof MonitorExitInstruction
|
||||
|| insn instanceof NullCheckInstruction) {
|
||||
|| insn instanceof NullCheckInstruction || insn instanceof BoundCheckInstruction) {
|
||||
return true;
|
||||
} else if (insn instanceof InvokeInstruction) {
|
||||
return isManagedMethodCall(characteristics, ((InvokeInstruction) insn).getMethod());
|
||||
|
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* Copyright 2018 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.model.lowlevel;
|
||||
|
||||
import org.teavm.model.BasicBlock;
|
||||
import org.teavm.model.Instruction;
|
||||
import org.teavm.model.MethodReference;
|
||||
import org.teavm.model.Program;
|
||||
import org.teavm.model.ValueType;
|
||||
import org.teavm.model.Variable;
|
||||
import org.teavm.model.instructions.AssignInstruction;
|
||||
import org.teavm.model.instructions.BranchingCondition;
|
||||
import org.teavm.model.instructions.BranchingInstruction;
|
||||
import org.teavm.model.instructions.DoubleConstantInstruction;
|
||||
import org.teavm.model.instructions.ExitInstruction;
|
||||
import org.teavm.model.instructions.FloatConstantInstruction;
|
||||
import org.teavm.model.instructions.IntegerConstantInstruction;
|
||||
import org.teavm.model.instructions.InvocationType;
|
||||
import org.teavm.model.instructions.InvokeInstruction;
|
||||
import org.teavm.model.instructions.JumpInstruction;
|
||||
import org.teavm.model.instructions.LongConstantInstruction;
|
||||
import org.teavm.model.instructions.NullCheckInstruction;
|
||||
import org.teavm.model.instructions.NullConstantInstruction;
|
||||
import org.teavm.model.util.BasicBlockSplitter;
|
||||
import org.teavm.runtime.ExceptionHandling;
|
||||
|
||||
public class NullCheckTransformation {
|
||||
public void apply(Program program, ValueType returnType) {
|
||||
BasicBlockSplitter splitter = new BasicBlockSplitter(program);
|
||||
|
||||
BasicBlock returnBlock = null;
|
||||
int count = program.basicBlockCount();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
BasicBlock next = program.basicBlockAt(i);
|
||||
BasicBlock block;
|
||||
while (next != null) {
|
||||
block = next;
|
||||
next = null;
|
||||
for (Instruction instruction : block) {
|
||||
if (!(instruction instanceof NullCheckInstruction)) {
|
||||
continue;
|
||||
}
|
||||
NullCheckInstruction nullCheck = (NullCheckInstruction) instruction;
|
||||
BasicBlock continueBlock = splitter.split(block, nullCheck);
|
||||
BasicBlock throwBlock = program.createBasicBlock();
|
||||
|
||||
InvokeInstruction throwNPE = new InvokeInstruction();
|
||||
throwNPE.setType(InvocationType.SPECIAL);
|
||||
throwNPE.setMethod(new MethodReference(ExceptionHandling.class, "throwNullPointerException",
|
||||
void.class));
|
||||
throwNPE.setLocation(nullCheck.getLocation());
|
||||
throwBlock.add(throwNPE);
|
||||
|
||||
if (returnBlock == null) {
|
||||
returnBlock = program.createBasicBlock();
|
||||
}
|
||||
|
||||
JumpInstruction jumpToFakeReturn = new JumpInstruction();
|
||||
jumpToFakeReturn.setTarget(returnBlock);
|
||||
jumpToFakeReturn.setLocation(nullCheck.getLocation());
|
||||
throwBlock.add(jumpToFakeReturn);
|
||||
|
||||
BranchingInstruction jumpIfNull = new BranchingInstruction(BranchingCondition.NULL);
|
||||
jumpIfNull.setOperand(nullCheck.getValue());
|
||||
jumpIfNull.setConsequent(throwBlock);
|
||||
jumpIfNull.setAlternative(continueBlock);
|
||||
jumpIfNull.setLocation(nullCheck.getLocation());
|
||||
nullCheck.replace(jumpIfNull);
|
||||
|
||||
AssignInstruction assign = new AssignInstruction();
|
||||
assign.setAssignee(nullCheck.getValue());
|
||||
assign.setReceiver(nullCheck.getReceiver());
|
||||
assign.setLocation(nullCheck.getLocation());
|
||||
continueBlock.addFirst(assign);
|
||||
|
||||
next = continueBlock;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (returnBlock != null) {
|
||||
ExitInstruction fakeExit = new ExitInstruction();
|
||||
if (returnType != ValueType.VOID) {
|
||||
Variable fakeReturnVar = program.createVariable();
|
||||
createFakeReturnValue(returnBlock, fakeReturnVar, returnType);
|
||||
fakeExit.setValueToReturn(fakeReturnVar);
|
||||
}
|
||||
returnBlock.add(fakeExit);
|
||||
}
|
||||
|
||||
splitter.fixProgram();
|
||||
}
|
||||
|
||||
private void createFakeReturnValue(BasicBlock block, Variable variable, ValueType type) {
|
||||
if (type instanceof ValueType.Primitive) {
|
||||
switch (((ValueType.Primitive) type).getKind()) {
|
||||
case BOOLEAN:
|
||||
case BYTE:
|
||||
case SHORT:
|
||||
case INTEGER:
|
||||
case CHARACTER:
|
||||
IntegerConstantInstruction intZero = new IntegerConstantInstruction();
|
||||
intZero.setReceiver(variable);
|
||||
block.add(intZero);
|
||||
return;
|
||||
case LONG:
|
||||
LongConstantInstruction longZero = new LongConstantInstruction();
|
||||
longZero.setReceiver(variable);
|
||||
block.add(longZero);
|
||||
return;
|
||||
case FLOAT:
|
||||
FloatConstantInstruction floatZero = new FloatConstantInstruction();
|
||||
floatZero.setReceiver(variable);
|
||||
block.add(floatZero);
|
||||
return;
|
||||
case DOUBLE:
|
||||
DoubleConstantInstruction doubleZero = new DoubleConstantInstruction();
|
||||
doubleZero.setReceiver(variable);
|
||||
block.add(doubleZero);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NullConstantInstruction nullConstant = new NullConstantInstruction();
|
||||
nullConstant.setReceiver(variable);
|
||||
block.add(nullConstant);
|
||||
}
|
||||
}
|
|
@ -126,6 +126,12 @@ public final class ExceptionHandling {
|
|||
throw new NullPointerException();
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
@Export(name = "teavm_throwArrayIndexOutOfBoundsException")
|
||||
public static void throwArrayIndexOutOfBoundsException() {
|
||||
throw new ArrayIndexOutOfBoundsException();
|
||||
}
|
||||
|
||||
@Unmanaged
|
||||
public static int callStackSize() {
|
||||
Address stackFrame = ShadowStack.getStackTop();
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
#include "definitions.h"
|
||||
#include "heapdump.h"
|
||||
#include "memory.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
#if TEAVM_MEMORY_TRACE
|
||||
#include "heaptrace.h"
|
||||
|
@ -53,6 +52,10 @@ typedef struct TeaVM_String {
|
|||
|
||||
extern char* teavm_beforeClasses;
|
||||
|
||||
extern void* teavm_throwClassCastException();
|
||||
extern void teavm_throwNullPointerException();
|
||||
extern void teavm_throwArrayIndexOutOfBoundsException();
|
||||
|
||||
#define TEAVM_PACK_CLASS(cls) ((int32_t) ((uintptr_t) ((char*) (cls) - teavm_beforeClasses) >> 3))
|
||||
#define TEAVM_UNPACK_CLASS(cls) ((TeaVM_Class*) (teavm_beforeClasses + ((cls) << 3)))
|
||||
#define TEAVM_CLASS_OF(obj) (TEAVM_UNPACK_CLASS(((TeaVM_Object*) (obj))->header))
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "definitions.h"
|
||||
#include "core.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
@ -7,9 +8,6 @@
|
|||
#include <setjmp.h>
|
||||
#endif
|
||||
|
||||
extern void* teavm_throwClassCastException();
|
||||
extern void teavm_throwNullPointerException();
|
||||
|
||||
#if TEAVM_USE_SETJMP
|
||||
#define TEAVM_JUMP_SUPPORTED 1
|
||||
#define TEAVM_TRY \
|
||||
|
@ -35,18 +33,7 @@ extern void teavm_throwNullPointerException();
|
|||
#define TEAVM_JUMP_TO_FRAME(frame, id) \
|
||||
teavm_stackTop = (TeaVM_StackFrame*) (frame); \
|
||||
longjmp(*teavm_stackTop->jmpTarget, id)
|
||||
inline static void* teavm_nullCheck(void* o) {
|
||||
if (o == NULL) {
|
||||
teavm_throwNullPointerException();
|
||||
#if TEAVM_UNIX
|
||||
__builtin_unreachable();
|
||||
#endif
|
||||
#if TEAVM_WINDOWS
|
||||
__assume(0);
|
||||
#endif
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
#if TEAVM_UNIX
|
||||
#define TEAVM_UNREACHABLE __builtin_unreachable();
|
||||
|
@ -58,6 +45,38 @@ extern void teavm_throwNullPointerException();
|
|||
#define TEAVM_UNREACHABLE return;
|
||||
#endif
|
||||
|
||||
inline static void* teavm_nullCheck(void* o) {
|
||||
if (o == NULL) {
|
||||
teavm_throwNullPointerException();
|
||||
TEAVM_UNREACHABLE
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
inline static int32_t teavm_checkBounds(int32_t index, void* array) {
|
||||
if (index < 0 || index >= TEAVM_ARRAY_LENGTH(array)) {
|
||||
teavm_throwArrayIndexOutOfBoundsException();
|
||||
TEAVM_UNREACHABLE
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
inline static int32_t teavm_checkLowerBound(int32_t index) {
|
||||
if (index < 0) {
|
||||
teavm_throwArrayIndexOutOfBoundsException();
|
||||
TEAVM_UNREACHABLE
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
inline static int32_t teavm_checkUpperBound(int32_t index, void* array) {
|
||||
if (index >= TEAVM_ARRAY_LENGTH(array)) {
|
||||
teavm_throwArrayIndexOutOfBoundsException();
|
||||
TEAVM_UNREACHABLE
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
#else
|
||||
#define TEAVM_JUMP_SUPPORTED 0
|
||||
#define TEAVM_JUMP_TO_FRAME(frame, id)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stddef.h>
|
||||
#include "definitions.h"
|
||||
|
||||
#if TEAVM_MEMORY_TRACE
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
#include "string.h"
|
||||
#include "definitions.h"
|
||||
|
||||
#if TEAVM_USE_SETJMP
|
||||
#include <setjmp.h>
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
TeaVM_String* value;
|
||||
} TeaVM_StringPtr;
|
||||
|
|
Loading…
Reference in New Issue
Block a user