From 94a96f571be080c66a9e8ae6e3522fc89abe5f1c Mon Sep 17 00:00:00 2001 From: Alexey Andreev Date: Fri, 4 Oct 2019 19:15:22 +0300 Subject: [PATCH] C: support array bound checking --- .../java/org/teavm/backend/c/CTarget.java | 17 +- .../c/generate/CodeGenerationVisitor.java | 30 +++ .../CheckInstructionTransformation.java | 221 ++++++++++++++++++ ...ceptionHandlingShadowStackContributor.java | 3 +- .../lowlevel/NullCheckTransformation.java | 142 ----------- .../org/teavm/runtime/ExceptionHandling.java | 6 + .../main/resources/org/teavm/backend/c/core.h | 5 +- .../org/teavm/backend/c/exceptions.h | 49 ++-- .../resources/org/teavm/backend/c/heaptrace.h | 1 + .../resources/org/teavm/backend/c/stack.h | 4 + 10 files changed, 313 insertions(+), 165 deletions(-) create mode 100644 core/src/main/java/org/teavm/model/lowlevel/CheckInstructionTransformation.java delete mode 100644 core/src/main/java/org/teavm/model/lowlevel/NullCheckTransformation.java diff --git a/core/src/main/java/org/teavm/backend/c/CTarget.java b/core/src/main/java/org/teavm/backend/c/CTarget.java index bb521b67d..882d3fb43 100644 --- a/core/src/main/java/org/teavm/backend/c/CTarget.java +++ b/core/src/main/java/org/teavm/backend/c/CTarget.java @@ -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, "", 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"); diff --git a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java index 77f6e73b6..ac77c3d20 100644 --- a/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java +++ b/core/src/main/java/org/teavm/backend/c/generate/CodeGenerationVisitor.java @@ -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() { diff --git a/core/src/main/java/org/teavm/model/lowlevel/CheckInstructionTransformation.java b/core/src/main/java/org/teavm/model/lowlevel/CheckInstructionTransformation.java new file mode 100644 index 000000000..9839f8c46 --- /dev/null +++ b/core/src/main/java/org/teavm/model/lowlevel/CheckInstructionTransformation.java @@ -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); + } +} diff --git a/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java b/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java index c1bbe2c47..0fdc0a1af 100644 --- a/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java +++ b/core/src/main/java/org/teavm/model/lowlevel/ExceptionHandlingShadowStackContributor.java @@ -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()); diff --git a/core/src/main/java/org/teavm/model/lowlevel/NullCheckTransformation.java b/core/src/main/java/org/teavm/model/lowlevel/NullCheckTransformation.java deleted file mode 100644 index 19083cca0..000000000 --- a/core/src/main/java/org/teavm/model/lowlevel/NullCheckTransformation.java +++ /dev/null @@ -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); - } -} diff --git a/core/src/main/java/org/teavm/runtime/ExceptionHandling.java b/core/src/main/java/org/teavm/runtime/ExceptionHandling.java index da9c1405c..ce419abe5 100644 --- a/core/src/main/java/org/teavm/runtime/ExceptionHandling.java +++ b/core/src/main/java/org/teavm/runtime/ExceptionHandling.java @@ -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(); diff --git a/core/src/main/resources/org/teavm/backend/c/core.h b/core/src/main/resources/org/teavm/backend/c/core.h index 72e10ff7f..a815c3844 100644 --- a/core/src/main/resources/org/teavm/backend/c/core.h +++ b/core/src/main/resources/org/teavm/backend/c/core.h @@ -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)) diff --git a/core/src/main/resources/org/teavm/backend/c/exceptions.h b/core/src/main/resources/org/teavm/backend/c/exceptions.h index 6e54a365f..1e9b64fd7 100644 --- a/core/src/main/resources/org/teavm/backend/c/exceptions.h +++ b/core/src/main/resources/org/teavm/backend/c/exceptions.h @@ -1,5 +1,6 @@ #pragma once #include "definitions.h" +#include "core.h" #include #include @@ -7,9 +8,6 @@ #include #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) diff --git a/core/src/main/resources/org/teavm/backend/c/heaptrace.h b/core/src/main/resources/org/teavm/backend/c/heaptrace.h index 4dd8be4e0..429ebd6c0 100644 --- a/core/src/main/resources/org/teavm/backend/c/heaptrace.h +++ b/core/src/main/resources/org/teavm/backend/c/heaptrace.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include "definitions.h" #if TEAVM_MEMORY_TRACE diff --git a/core/src/main/resources/org/teavm/backend/c/stack.h b/core/src/main/resources/org/teavm/backend/c/stack.h index e918332ef..3b9752ca5 100644 --- a/core/src/main/resources/org/teavm/backend/c/stack.h +++ b/core/src/main/resources/org/teavm/backend/c/stack.h @@ -4,6 +4,10 @@ #include "string.h" #include "definitions.h" +#if TEAVM_USE_SETJMP +#include +#endif + typedef struct { TeaVM_String* value; } TeaVM_StringPtr;