Complete compiler portion of exception handling
Will still need much testing once the runtime portions are in place.
Change-Id: I90fc7c1fd89bfae89dfd19a6e422024b6b5454ec
diff --git a/src/compiler/CompilerIR.h b/src/compiler/CompilerIR.h
index 9c9bcb0..e9933ff 100644
--- a/src/compiler/CompilerIR.h
+++ b/src/compiler/CompilerIR.h
@@ -235,6 +235,7 @@
BasicBlock* nextCodegenBlock; // for extended trace codegen
GrowableList dfsOrder;
GrowableList domPostOrderTraversal;
+ GrowableList throwLaunchpads;
ArenaBitVector* tryBlockAddr;
ArenaBitVector** defBlockMatrix; // numDalvikRegister x numBlocks
ArenaBitVector* tempBlockV;
@@ -245,12 +246,10 @@
bool quitLoopMode; // cold path/complex bytecode
int preservedRegsUsed; // How many callee save regs used
/*
- * Frame layout details. TODO: Reorganize, remove reduncancy
- * and move elsewhere. Some of this is already in struct Method,
- * at least frameSize should eventually move there. Delay regorg
- * until we get a feel for how this will be used by the low-level
- * codegen utilities. "num" fields are in 4-byte words, "Size" and
- * "Offset" in bytes.
+ * Frame layout details.
+ * NOTE: for debug support it will be necessary to add a structure
+ * to map the Dalvik virtual registers to the promoted registers.
+ * NOTE: "num" fields are in 4-byte words, "Size" and "Offset" in bytes.
*/
int numIns;
int numOuts;
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 2f86c48..2e94516 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -719,6 +719,9 @@
/* Intialize the fillArrayData list */
oatInitGrowableList(&cUnit.fillArrayData, 4);
+ /* Intialize the throwLaunchpads list */
+ oatInitGrowableList(&cUnit.throwLaunchpads, 4);
+
/* Allocate the bit-vector to track the beginning of basic blocks */
ArenaBitVector *tryBlockAddr = oatAllocBitVector(cUnit.insnsSize,
true /* expandable */);
diff --git a/src/compiler/RuntimeUtilities.cc b/src/compiler/RuntimeUtilities.cc
deleted file mode 100644
index 8c94d62..0000000
--- a/src/compiler/RuntimeUtilities.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * 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.
- */
-
-#include "Dalvik.h"
-#include "CompilerInternals.h"
-
-namespace art {
-/* FIXME - codegen helper functions, move to art runtime proper */
-
-/*
- * Float/double conversion requires clamping to min and max of integer form. If
- * target doesn't support this normally, use these.
- */
-int64_t D2L(double d)
-{
- static const double kMaxLong = (double)(s8)0x7fffffffffffffffULL;
- static const double kMinLong = (double)(s8)0x8000000000000000ULL;
- if (d >= kMaxLong)
- return (s8)0x7fffffffffffffffULL;
- else if (d <= kMinLong)
- return (s8)0x8000000000000000ULL;
- else if (d != d) // NaN case
- return 0;
- else
- return (s8)d;
-}
-
-int64_t F2L(float f)
-{
- static const float kMaxLong = (float)(s8)0x7fffffffffffffffULL;
- static const float kMinLong = (float)(s8)0x8000000000000000ULL;
- if (f >= kMaxLong)
- return (s8)0x7fffffffffffffffULL;
- else if (f <= kMinLong)
- return (s8)0x8000000000000000ULL;
- else if (f != f) // NaN case
- return 0;
- else
- return (s8)f;
-}
-
-/*
- * Temporary placeholder. Should include run-time checks for size
- * of fill data <= size of array. If not, throw arrayOutOfBoundsException.
- * As with other new "FromCode" routines, this should return to the caller
- * only if no exception has been thrown.
- *
- * NOTE: When dealing with a raw dex file, the data to be copied uses
- * little-endian ordering. Require that oat2dex do any required swapping
- * so this routine can get by with a memcpy().
- *
- * Format of the data:
- * ushort ident = 0x0300 magic value
- * ushort width width of each element in the table
- * uint size number of elements in the table
- * ubyte data[size*width] table of data values (may contain a single-byte
- * padding at the end)
- */
-void HandleFillArrayDataFromCode(Array* array, const uint16_t* table)
-{
- uint32_t size = (uint32_t)table[2] | (((uint32_t)table[3]) << 16);
- uint32_t size_in_bytes = size * table[1];
- if (static_cast<int32_t>(size) > array->GetLength()) {
- UNIMPLEMENTED(FATAL) << "need to throw AIOOBE and unwind";
- }
- memcpy((char*)array + art::Array::DataOffset().Int32Value(),
- (char*)&table[4], size_in_bytes);
-}
-
-} // namespace art
diff --git a/src/compiler/codegen/Ralloc.h b/src/compiler/codegen/Ralloc.h
index 67ed6ee..82ce23e 100644
--- a/src/compiler/codegen/Ralloc.h
+++ b/src/compiler/codegen/Ralloc.h
@@ -165,7 +165,6 @@
extern void oatKillNullCheckedLoc(CompilationUnit* cUnit,
RegLocation loc);
-//FIXME - this needs to also check the preserved pool.
extern RegisterInfo *oatIsLive(CompilationUnit* cUnit, int reg);
/* To be used when explicitly managing register use */
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc
index 574bb57..66eaf54 100644
--- a/src/compiler/codegen/arm/ArchFactory.cc
+++ b/src/compiler/codegen/arm/ArchFactory.cc
@@ -22,6 +22,10 @@
*
*/
+static ArmLIR* genUnconditionalBranch(CompilationUnit*, ArmLIR*);
+static ArmLIR* genConditionalBranch(CompilationUnit*, ArmConditionCode,
+ ArmLIR*);
+
/*
* Utiltiy to load the current Method*. Broken out
* to allow easy change between placing the current Method* in a
@@ -47,26 +51,23 @@
#endif
}
-/*
- * Perform a "reg cmp imm" operation and jump to the PCR region if condition
- * satisfies.
- */
-static TGT_LIR* genRegImmCheck(CompilationUnit* cUnit,
- ArmConditionCode cond, int reg,
- int checkValue, int dOffset,
- TGT_LIR* pcrLabel)
+static ArmLIR* genImmedCheck(CompilationUnit* cUnit, ArmConditionCode cCode,
+ int reg, int immVal, MIR* mir, ArmThrowKind kind)
{
- TGT_LIR* branch = genCmpImmBranch(cUnit, cond, reg, checkValue);
- BasicBlock* bb = cUnit->curBlock;
- if (bb->taken) {
- ArmLIR *exceptionLabel = (ArmLIR* ) cUnit->blockLabelList;
- exceptionLabel += bb->taken->id;
- branch->generic.target = (LIR* ) exceptionLabel;
- return exceptionLabel;
+ ArmLIR* tgt = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
+ tgt->opcode = kArmPseudoThrowTarget;
+ tgt->operands[0] = kind;
+ tgt->operands[1] = mir->offset;
+ ArmLIR* branch;
+ if (cCode == kArmCondAl) {
+ branch = genUnconditionalBranch(cUnit, tgt);
} else {
- LOG(FATAL) << "Catch blocks not handled yet";
- return NULL; // quiet gcc
+ branch = genCmpImmBranch(cUnit, kArmCondEq, reg, 0);
+ branch->generic.target = (LIR*)tgt;
}
+ // Remember branch target - will process later
+ oatInsertGrowableList(&cUnit->throwLaunchpads, (intptr_t)tgt);
+ return branch;
}
/*
@@ -74,42 +75,30 @@
* and mReg is the machine register holding the actual value. If internal state
* indicates that sReg has been checked before the check request is ignored.
*/
-static TGT_LIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg,
- int dOffset, TGT_LIR* pcrLabel)
+static ArmLIR* genNullCheck(CompilationUnit* cUnit, int sReg, int mReg,
+ MIR* mir)
{
- /* This particular Dalvik register has been null-checked */
-#if 0
- // Yes, I know. Please be quiet.
- UNIMPLEMENTED(WARNING) << "Need null check & throw support";
-#endif
- return pcrLabel;
if (oatIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
- return pcrLabel;
+ /* This particular Dalvik register has been null-checked */
+ return NULL;
}
oatSetBit(cUnit->regPool->nullCheckedRegs, sReg);
- return genRegImmCheck(cUnit, kArmCondEq, mReg, 0, dOffset, pcrLabel);
-}
-
-/*
- * Perform a "reg cmp reg" operation and jump to the PCR region if condition
- * satisfies.
- */
-static TGT_LIR* genRegRegCheck(CompilationUnit* cUnit,
- ArmConditionCode cond,
- int reg1, int reg2, int dOffset,
- TGT_LIR* pcrLabel)
-{
- TGT_LIR* res;
- res = opRegReg(cUnit, kOpCmp, reg1, reg2);
- TGT_LIR* branch = opCondBranch(cUnit, cond);
- genCheckCommon(cUnit, dOffset, branch, pcrLabel);
- return res;
+ return genImmedCheck(cUnit, kArmCondEq, mReg, 0, mir, kArmThrowNullPointer);
}
/* Perform bound check on two registers */
static TGT_LIR* genBoundsCheck(CompilationUnit* cUnit, int rIndex,
- int rBound, int dOffset, TGT_LIR* pcrLabel)
+ int rBound, MIR* mir, ArmThrowKind kind)
{
- return genRegRegCheck(cUnit, kArmCondCs, rIndex, rBound, dOffset,
- pcrLabel);
+ ArmLIR* tgt = (ArmLIR*)oatNew(sizeof(ArmLIR), true);
+ tgt->opcode = kArmPseudoThrowTarget;
+ tgt->operands[0] = kind;
+ tgt->operands[1] = mir->offset;
+ tgt->operands[2] = rIndex;
+ tgt->operands[3] = rBound;
+ opRegReg(cUnit, kOpCmp, rIndex, rBound);
+ ArmLIR* branch = genConditionalBranch(cUnit, kArmCondCs, tgt);
+ // Remember branch target - will process later
+ oatInsertGrowableList(&cUnit->throwLaunchpads, (intptr_t)tgt);
+ return branch;
}
diff --git a/src/compiler/codegen/arm/ArchUtility.cc b/src/compiler/codegen/arm/ArchUtility.cc
index e51774e..6f435e7 100644
--- a/src/compiler/codegen/arm/ArchUtility.cc
+++ b/src/compiler/codegen/arm/ArchUtility.cc
@@ -351,6 +351,9 @@
case kArmPseudoNormalBlockLabel:
LOG(INFO) << "L" << (intptr_t)lir << ":";
break;
+ case kArmPseudoThrowTarget:
+ LOG(INFO) << "LT" << (intptr_t)lir << ":";
+ break;
case kArmPseudoCaseLabel:
LOG(INFO) << "LC" << (intptr_t)lir << ": Case target 0x" <<
std::hex << lir->operands[0] << "|" << std::dec <<
diff --git a/src/compiler/codegen/arm/ArmLIR.h b/src/compiler/codegen/arm/ArmLIR.h
index 9d22c4f..b35f39f 100644
--- a/src/compiler/codegen/arm/ArmLIR.h
+++ b/src/compiler/codegen/arm/ArmLIR.h
@@ -347,6 +347,17 @@
kArmCondNv = 0xf, /* 1111 */
} ArmConditionCode;
+typedef enum ArmThrowKind {
+ kArmThrowNullPointer,
+ kArmThrowDivZero,
+ kArmThrowArrayBounds,
+ kArmThrowVerificationError,
+ kArmThrowNegArraySize,
+ kArmThrowInternalError,
+ kArmThrowRuntimeException,
+ kArmThrowNoSuchMethod,
+} ArmThrowKind;
+
#define isPseudoOpcode(opcode) ((int)(opcode) < 0)
/*
@@ -355,6 +366,7 @@
* Assemble.c.
*/
typedef enum ArmOpcode {
+ kArmPseudoThrowTarget = -14,
kArmPseudoCaseLabel = -13,
kArmPseudoMethodEntry = -12,
kArmPseudoMethodExit = -11,
diff --git a/src/compiler/codegen/arm/ArmRallocUtil.cc b/src/compiler/codegen/arm/ArmRallocUtil.cc
index bea85ea..030131f 100644
--- a/src/compiler/codegen/arm/ArmRallocUtil.cc
+++ b/src/compiler/codegen/arm/ArmRallocUtil.cc
@@ -178,7 +178,6 @@
qsort(coreRegs, numRegs, sizeof(RefCounts), sortCounts);
qsort(fpRegs, numRegs, sizeof(RefCounts), sortCounts);
- // TODO: temp for debugging, too verbose. Remove when unneeded
if (cUnit->printMeVerbose) {
dumpCounts(coreRegs, numRegs, "coreRegs");
dumpCounts(fpRegs, numRegs, "fpRegs");
diff --git a/src/compiler/codegen/arm/Assemble.cc b/src/compiler/codegen/arm/Assemble.cc
index 2004d46..475f096 100644
--- a/src/compiler/codegen/arm/Assemble.cc
+++ b/src/compiler/codegen/arm/Assemble.cc
@@ -1195,17 +1195,14 @@
lir->opcode == kThumb2BCond) {
ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
int delta = 0;
- if (targetLIR == NULL) {
- UNIMPLEMENTED(WARNING) << "Throw targets unimplemented";
- } else {
- intptr_t pc = lir->generic.offset + 4;
- intptr_t target = targetLIR->generic.offset;
- delta = target - pc;
- if ((lir->opcode == kThumbBCond) && (delta > 254 || delta < -256)) {
- lir->opcode = kThumb2BCond;
- oatSetupResourceMasks(lir);
- res = kRetryAll;
- }
+ assert(targetLIR);
+ intptr_t pc = lir->generic.offset + 4;
+ intptr_t target = targetLIR->generic.offset;
+ delta = target - pc;
+ if ((lir->opcode == kThumbBCond) && (delta > 254 || delta < -256)) {
+ lir->opcode = kThumb2BCond;
+ oatSetupResourceMasks(lir);
+ res = kRetryAll;
}
lir->operands[0] = delta >> 1;
} else if (lir->opcode == kThumb2BUncond) {
diff --git a/src/compiler/codegen/arm/CodegenCommon.cc b/src/compiler/codegen/arm/CodegenCommon.cc
index 1aba82c..208eecf 100644
--- a/src/compiler/codegen/arm/CodegenCommon.cc
+++ b/src/compiler/codegen/arm/CodegenCommon.cc
@@ -226,37 +226,6 @@
}
/*
- * Set up the accurate resource mask for branch instructions
- */
-static void relaxBranchMasks(ArmLIR* lir)
-{
- int flags = EncodingMap[lir->opcode].flags;
-
- /* Make sure only branch instructions are passed here */
- assert(flags & IS_BRANCH);
-
- lir->useMask = lir->defMask = ENCODE_REG_PC;
-
- if (flags & REG_DEF_LR) {
- lir->defMask |= ENCODE_REG_LR;
- }
-
- if (flags & (REG_USE0 | REG_USE1 | REG_USE2 | REG_USE3)) {
- int i;
-
- for (i = 0; i < 4; i++) {
- if (flags & (1 << (kRegUse0 + i))) {
- setupRegMask(&lir->useMask, lir->operands[i]);
- }
- }
- }
-
- if (flags & USES_CCODES) {
- lir->useMask |= ENCODE_CCODE;
- }
-}
-
-/*
* The following are building blocks to construct low-level IRs with 0 - 4
* operands.
*/
@@ -383,36 +352,3 @@
/* Mark all resources as being clobbered */
barrier->defMask = -1;
}
-
-/* Create the PC reconstruction slot if not already done */
-static ArmLIR* genCheckCommon(CompilationUnit* cUnit, int dOffset,
- ArmLIR* branch,
- ArmLIR* pcrLabel)
-{
- //FIXME - won't be rolling back, need to throw now.
- UNIMPLEMENTED(WARNING);
-#if 0
-
- /* Forget all def info (because we might rollback here. Bug #2367397 */
- oatResetDefTracking(cUnit);
-
- /* Set up the place holder to reconstruct this Dalvik PC */
- if (pcrLabel == NULL) {
- int dPC = (int) (cUnit->insns + dOffset);
- pcrLabel = (ArmLIR* ) oatNew(sizeof(ArmLIR), true);
- pcrLabel->opcode = kArmPseudoPCReconstructionCell;
- pcrLabel->operands[0] = dPC;
- pcrLabel->operands[1] = dOffset;
- /* Insert the place holder to the growable list */
- oatInsertGrowableList(&cUnit->pcReconstructionList,
- (intptr_t) pcrLabel);
- }
-#endif
- /* Branch to the PC reconstruction code */
- branch->generic.target = (LIR*) pcrLabel;
-
- /* Clear the conservative flags for branches that punt to the interpreter */
- relaxBranchMasks(branch);
-
- return pcrLabel;
-}
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index c7c15cf..a9d77ec 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -438,7 +438,7 @@
loadValueDirectFixed(cUnit, rlArg, r1);
break;
case 1: // Is "this" null? [use r1]
- genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
+ genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
// get this->klass_ [use r1, set rLR]
loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
break;
@@ -507,7 +507,7 @@
break;
case 4:
// Is "this" null? [use r1]
- genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
+ genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
// get this->clazz [use r1, set rLR]
loadWordDisp(cUnit, r1, Object::ClassOffset().Int32Value(), rLR);
break;
@@ -601,8 +601,7 @@
loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
rLR);
// Is "this" null? [use r1]
- genNullCheck(cUnit, oatSSASrc(mir,0), r1,
- mir->offset, NULL);
+ genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
break;
case 1: // Get method->declaring_class_->super_class [usr rLR, set rLR]
loadWordDisp(cUnit, rLR, Class::SuperClassOffset().Int32Value(),
@@ -676,7 +675,7 @@
loadWordDisp(cUnit, r0, Method::DeclaringClassOffset().Int32Value(),
r0);
// Null this?
- genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
+ genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
// Get method->declaring_class_->super_class [usr r0, set r0]
loadWordDisp(cUnit, r0, Class::SuperClassOffset().Int32Value(), r0);
break;
@@ -687,7 +686,7 @@
tReg = oatAllocTemp(cUnit);
loadWordDisp(cUnit, r0, art::Array::LengthOffset().Int32Value(),
tReg);
- genBoundsCheck(cUnit, tReg, rLR, mir->offset, NULL);
+ genBoundsCheck(cUnit, tReg, rLR, mir, kArmThrowNoSuchMethod);
oatFreeTemp(cUnit, tReg);
}
// Adjust vtable_ base past object header
@@ -761,8 +760,7 @@
//TODO: better to move this into CallInsn lists
// Load direct & need a "this" null check?
if (pcrLabel) {
- *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1,
- mir->offset, NULL);
+ *pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir);
}
return callState;
}
@@ -1215,12 +1213,19 @@
genThrow(cUnit, mir, rlSrc[0]);
break;
+ case OP_THROW_VERIFICATION_ERROR:
+ loadWordDisp(cUnit, rSELF,
+ OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode), rLR);
+ loadConstant(cUnit, r0, mir->dalvikInsn.vA);
+ loadConstant(cUnit, r1, mir->dalvikInsn.vB);
+ opReg(cUnit, kOpBlx, rLR);
+ break;
+
case OP_ARRAY_LENGTH:
int lenOffset;
lenOffset = Array::LengthOffset().Int32Value();
rlSrc[0] = loadValue(cUnit, rlSrc[0], kCoreReg);
- genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg,
- mir->offset, NULL);
+ genNullCheck(cUnit, rlSrc[0].sRegLow, rlSrc[0].lowReg, mir);
rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
loadWordDisp(cUnit, rlSrc[0].lowReg, lenOffset,
rlResult.lowReg);
@@ -1986,6 +1991,77 @@
}
}
+static void handleThrowLaunchpads(CompilationUnit *cUnit)
+{
+ ArmLIR** throwLabel =
+ (ArmLIR **) cUnit->throwLaunchpads.elemList;
+ int numElems = cUnit->throwLaunchpads.numUsed;
+ int i;
+
+ for (i = 0; i < numElems; i++) {
+ ArmLIR* lab = throwLabel[i];
+ cUnit->currentDalvikOffset = lab->operands[1];
+ oatAppendLIR(cUnit, (LIR *)lab);
+ int funcOffset = 0;
+ int v1 = lab->operands[2];
+ int v2 = lab->operands[3];
+ switch(lab->operands[0]) {
+ case kArmThrowNullPointer:
+ funcOffset = OFFSETOF_MEMBER(Thread, pThrowNullPointerFromCode);
+ break;
+ case kArmThrowArrayBounds:
+ if (v2 != r0) {
+ genRegCopy(cUnit, r0, v1);
+ genRegCopy(cUnit, r1, v2);
+ } else {
+ if (v1 == r1) {
+ genRegCopy(cUnit, r12, v1);
+ genRegCopy(cUnit, r1, v2);
+ genRegCopy(cUnit, r0, r12);
+ } else {
+ genRegCopy(cUnit, r1, v2);
+ genRegCopy(cUnit, r0, v1);
+ }
+ }
+ funcOffset = OFFSETOF_MEMBER(Thread, pThrowArrayBoundsFromCode);
+ break;
+ case kArmThrowDivZero:
+ funcOffset = OFFSETOF_MEMBER(Thread, pThrowDivZeroFromCode);
+ break;
+ case kArmThrowVerificationError:
+ loadConstant(cUnit, r0, v1);
+ loadConstant(cUnit, r1, v2);
+ funcOffset =
+ OFFSETOF_MEMBER(Thread, pThrowVerificationErrorFromCode);
+ break;
+ case kArmThrowNegArraySize:
+ genRegCopy(cUnit, r0, v1);
+ funcOffset =
+ OFFSETOF_MEMBER(Thread, pThrowNegArraySizeFromCode);
+ break;
+ case kArmThrowInternalError:
+ genRegCopy(cUnit, r0, v1);
+ funcOffset =
+ OFFSETOF_MEMBER(Thread, pThrowInternalErrorFromCode);
+ break;
+ case kArmThrowRuntimeException:
+ genRegCopy(cUnit, r0, v1);
+ funcOffset =
+ OFFSETOF_MEMBER(Thread, pThrowRuntimeExceptionFromCode);
+ break;
+ case kArmThrowNoSuchMethod:
+ genRegCopy(cUnit, r0, v1);
+ funcOffset =
+ OFFSETOF_MEMBER(Thread, pThrowNoSuchMethodFromCode);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
+ }
+ loadWordDisp(cUnit, rSELF, funcOffset, rLR);
+ opReg(cUnit, kOpBlx, rLR);
+ }
+}
+
void oatMethodMIR2LIR(CompilationUnit* cUnit)
{
/* Used to hold the labels of each block */
@@ -1995,6 +2071,8 @@
oatDataFlowAnalysisDispatcher(cUnit, methodBlockCodeGen,
kPreOrderDFSTraversal, false /* Iterative */);
removeRedundantBranches(cUnit);
+
+ handleThrowLaunchpads(cUnit);
}
/* Common initialization routine for an architecture family */
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index 89911fe..0db63f9 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -445,8 +445,7 @@
// Field offset in r0
rlObj = loadValue(cUnit, rlObj, kCoreReg);
rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
- NULL);/* null object? */
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
loadBaseIndexed(cUnit, rlObj.lowReg, r0, rlResult.lowReg, 0, size);
oatGenMemBarrier(cUnit, kSY);
storeValue(cUnit, rlDest, rlResult);
@@ -459,8 +458,7 @@
int fieldOffset = fieldPtr->GetOffset().Int32Value();
rlObj = loadValue(cUnit, rlObj, kCoreReg);
rlResult = oatEvalLoc(cUnit, rlDest, regClass, true);
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
- NULL);/* null object? */
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
loadBaseDisp(cUnit, mir, rlObj.lowReg, fieldOffset, rlResult.lowReg,
size, rlObj.sRegLow);
if (isVolatile) {
@@ -481,8 +479,7 @@
// Field offset in r0
rlObj = loadValue(cUnit, rlObj, kCoreReg);
rlSrc = loadValue(cUnit, rlSrc, regClass);
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
- NULL);/* null object? */
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null object? */
oatGenMemBarrier(cUnit, kSY);
storeBaseIndexed(cUnit, rlObj.lowReg, r0, rlSrc.lowReg, 0, size);
} else {
@@ -494,8 +491,7 @@
int fieldOffset = fieldPtr->GetOffset().Int32Value();
rlObj = loadValue(cUnit, rlObj, kCoreReg);
rlSrc = loadValue(cUnit, rlSrc, regClass);
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
- NULL);/* null object? */
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
if (isVolatile) {
oatGenMemBarrier(cUnit, kSY);
@@ -519,8 +515,7 @@
// Field offset in r0
rlObj = loadValue(cUnit, rlObj, kCoreReg);
rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
- NULL);/* null object? */
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
loadPair(cUnit, r0, rlResult.lowReg, rlResult.highReg);
oatGenMemBarrier(cUnit, kSY);
@@ -537,8 +532,7 @@
assert(rlDest.wide);
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
- NULL);/* null object? */
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
@@ -563,8 +557,7 @@
// Field offset in r0
rlObj = loadValue(cUnit, rlObj, kCoreReg);
rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
- NULL);/* null object? */
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
opRegReg(cUnit, kOpAdd, r0, rlObj.lowReg);
oatGenMemBarrier(cUnit, kSY);
storePair(cUnit, r0, rlSrc.lowReg, rlSrc.highReg);
@@ -579,8 +572,7 @@
rlObj = loadValue(cUnit, rlObj, kCoreReg);
int regPtr;
rlSrc = loadValueWide(cUnit, rlSrc, kAnyReg);
- genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir->offset,
- NULL);/* null object? */
+ genNullCheck(cUnit, rlObj.sRegLow, rlObj.lowReg, mir);/* null obj? */
regPtr = oatAllocTemp(cUnit);
opRegRegImm(cUnit, kOpAdd, regPtr, rlObj.lowReg, fieldOffset);
@@ -919,7 +911,7 @@
assert(art::Monitor::kLwShapeThin == 0);
loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj
oatLockCallTemps(cUnit); // Prepare for explicit register usage
- genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
+ genNullCheck(cUnit, rlSrc.sRegLow, r1, mir);
loadWordDisp(cUnit, rSELF, Thread::IdOffset().Int32Value(), r3);
newLIR3(cUnit, kThumb2Ldrex, r2, r1,
Object::MonitorOffset().Int32Value() >> 2); // Get object->lock
@@ -970,7 +962,7 @@
oatFlushAllRegs(cUnit);
loadValueDirectFixed(cUnit, rlSrc, r1); // Get obj
oatLockCallTemps(cUnit); // Prepare for explicit register usage
- genNullCheck(cUnit, rlSrc.sRegLow, r1, mir->offset, NULL);
+ genNullCheck(cUnit, rlSrc.sRegLow, r1, mir);
loadWordDisp(cUnit, r1, Object::MonitorOffset().Int32Value(), r2); // Get lock
loadWordDisp(cUnit, rSELF, Thread::IdOffset().Int32Value(), r3);
// Is lock unheld on lock or held by us (==threadId) on unlock?
@@ -1241,14 +1233,6 @@
return branch;
}
-/* Generate a unconditional branch to go to the interpreter */
-static inline ArmLIR* genTrap(CompilationUnit* cUnit, int dOffset,
- ArmLIR* pcrLabel)
-{
- ArmLIR* branch = opNone(cUnit, kOpUncondBr);
- return genCheckCommon(cUnit, dOffset, branch, pcrLabel);
-}
-
/*
* Generate array store
*
@@ -1269,8 +1253,7 @@
ArmLIR* pcrLabel = NULL;
if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
- pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, r1,
- mir->offset, NULL);
+ pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, r1, mir);
}
loadWordDisp(cUnit, rSELF,
OFFSETOF_MEMBER(Thread, pCanPutArrayElementFromCode), rLR);
@@ -1302,8 +1285,8 @@
loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
/* regPtr -> array data */
opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
- genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
- pcrLabel);
+ genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir,
+ kArmThrowArrayBounds);
oatFreeTemp(cUnit, regLen);
} else {
/* regPtr -> array data */
@@ -1334,8 +1317,7 @@
ArmLIR* pcrLabel = NULL;
if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
- pcrLabel = genNullCheck(cUnit, rlArray.sRegLow,
- rlArray.lowReg, mir->offset, NULL);
+ pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
}
regPtr = oatAllocTemp(cUnit);
@@ -1346,8 +1328,8 @@
loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
/* regPtr -> array data */
opRegRegImm(cUnit, kOpAdd, regPtr, rlArray.lowReg, dataOffset);
- genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
- pcrLabel);
+ genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir,
+ kArmThrowArrayBounds);
oatFreeTemp(cUnit, regLen);
} else {
/* regPtr -> array data */
@@ -1409,8 +1391,7 @@
ArmLIR* pcrLabel = NULL;
if (!(mir->OptimizationFlags & MIR_IGNORE_NULL_CHECK)) {
- pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg,
- mir->offset, NULL);
+ pcrLabel = genNullCheck(cUnit, rlArray.sRegLow, rlArray.lowReg, mir);
}
if (!(mir->OptimizationFlags & MIR_IGNORE_RANGE_CHECK)) {
@@ -1420,8 +1401,8 @@
loadWordDisp(cUnit, rlArray.lowReg, lenOffset, regLen);
/* regPtr -> array data */
opRegImm(cUnit, kOpAdd, regPtr, dataOffset);
- genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir->offset,
- pcrLabel);
+ genBoundsCheck(cUnit, rlIndex.lowReg, regLen, mir,
+ kArmThrowArrayBounds);
oatFreeTemp(cUnit, regLen);
} else {
/* regPtr -> array data */
@@ -1429,7 +1410,7 @@
}
/* at this point, regPtr points to array, 2 live temps */
if ((size == kLong) || (size == kDouble)) {
- //TODO: need specific wide routine that can handle fp regs
+ //TUNING: specific wide routine that can handle fp regs
if (scale) {
int rNewIndex = oatAllocTemp(cUnit);
opRegRegImm(cUnit, kOpLsl, rNewIndex, rlIndex.lowReg, scale);
@@ -1693,7 +1674,7 @@
loadWordDisp(cUnit, rSELF, funcOffset, rLR);
loadValueDirectFixed(cUnit, rlSrc1, r0);
if (checkZero) {
- genNullCheck(cUnit, rlSrc2.sRegLow, r1, mir->offset, NULL);
+ genImmedCheck(cUnit, kArmCondEq, r1, 0, mir, kArmThrowDivZero);
}
opReg(cUnit, kOpBlx, rLR);
oatClobberCallRegs(cUnit);
@@ -1844,7 +1825,7 @@
} else {
// Reverse subtract: (src << (shift + 1)) - src.
assert(powerOfTwoMinusOne);
- // TODO: rsb dst, src, src lsl#lowestSetBit(lit + 1)
+ // TUNING: rsb dst, src, src lsl#lowestSetBit(lit + 1)
int tReg = oatAllocTemp(cUnit);
opRegRegImm(cUnit, kOpLsl, tReg, rlSrc.lowReg, lowestSetBit(lit + 1));
opRegRegReg(cUnit, kOpSub, rlResult.lowReg, tReg, rlSrc.lowReg);
@@ -1925,8 +1906,7 @@
case OP_REM_INT_LIT8:
case OP_REM_INT_LIT16:
if (lit == 0) {
- UNIMPLEMENTED(FATAL);
- // FIXME: generate an explicit throw here
+ genImmedCheck(cUnit, kArmCondAl, 0, 0, mir, kArmThrowDivZero);
return false;
}
if (handleEasyDivide(cUnit, dalvikOpcode, rlSrc, rlDest, lit)) {
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 23126d7..04c464f 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -44,10 +44,4 @@
#endif
-namespace art {
- int64_t D2L(double);
- int64_t F2L(float);
- void HandleFillArrayDataFromCode(art::Array*, const uint16_t*);
-}
-
#endif // ART_SRC_RUNTIME_SUPPORT_H_
diff --git a/src/thread.cc b/src/thread.cc
index 45ff6dd..d5174ab 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -142,6 +142,110 @@
UNIMPLEMENTED(FATAL) << "Stack overflow: " << PrettyMethod(method);
}
+// TODO: placeholder
+static void ThrowNullPointerFromCode() {
+ //NOTE: to save code space, this handler must look up caller's Method*
+ UNIMPLEMENTED(FATAL) << "Null pointer exception";
+}
+
+// TODO: placeholder
+static void ThrowDivZeroFromCode() {
+ UNIMPLEMENTED(FATAL) << "Divide by zero";
+}
+
+// TODO: placeholder
+static void ThrowArrayBoundsFromCode(int32_t index, int32_t limit) {
+ UNIMPLEMENTED(FATAL) << "Bound check exception, idx: " << index <<
+ ", limit: " << limit;
+}
+
+// TODO: placeholder
+static void ThrowVerificationErrorFromCode(int32_t src1, int32_t ref) {
+ UNIMPLEMENTED(FATAL) << "Verification error, src1: " << src1 <<
+ " ref: " << ref;
+}
+
+// TODO: placeholder
+static void ThrowNegArraySizeFromCode(int32_t index) {
+ UNIMPLEMENTED(FATAL) << "Negative array size: " << index;
+}
+
+// TODO: placeholder
+static void ThrowInternalErrorFromCode(int32_t errnum) {
+ UNIMPLEMENTED(FATAL) << "Internal error: " << errnum;
+}
+
+// TODO: placeholder
+static void ThrowRuntimeExceptionFromCode(int32_t errnum) {
+ UNIMPLEMENTED(FATAL) << "Internal error: " << errnum;
+}
+
+// TODO: placeholder
+static void ThrowNoSuchMethodFromCode(int32_t method_idx) {
+ UNIMPLEMENTED(FATAL) << "No such method, idx: " << method_idx;
+}
+
+/*
+ * Temporary placeholder. Should include run-time checks for size
+ * of fill data <= size of array. If not, throw arrayOutOfBoundsException.
+ * As with other new "FromCode" routines, this should return to the caller
+ * only if no exception has been thrown.
+ *
+ * NOTE: When dealing with a raw dex file, the data to be copied uses
+ * little-endian ordering. Require that oat2dex do any required swapping
+ * so this routine can get by with a memcpy().
+ *
+ * Format of the data:
+ * ushort ident = 0x0300 magic value
+ * ushort width width of each element in the table
+ * uint size number of elements in the table
+ * ubyte data[size*width] table of data values (may contain a single-byte
+ * padding at the end)
+ */
+static void HandleFillArrayDataFromCode(Array* array, const uint16_t* table)
+{
+ uint32_t size = (uint32_t)table[2] | (((uint32_t)table[3]) << 16);
+ uint32_t size_in_bytes = size * table[1];
+ if (static_cast<int32_t>(size) > array->GetLength()) {
+ ThrowArrayBoundsFromCode(array->GetLength(), size);
+ }
+ memcpy((char*)array + art::Array::DataOffset().Int32Value(),
+ (char*)&table[4], size_in_bytes);
+}
+
+// TODO: move to more appropriate location
+/*
+ * Float/double conversion requires clamping to min and max of integer form. If
+ * target doesn't support this normally, use these.
+ */
+static int64_t D2L(double d)
+{
+ static const double kMaxLong = (double)(int64_t)0x7fffffffffffffffULL;
+ static const double kMinLong = (double)(int64_t)0x8000000000000000ULL;
+ if (d >= kMaxLong)
+ return (int64_t)0x7fffffffffffffffULL;
+ else if (d <= kMinLong)
+ return (int64_t)0x8000000000000000ULL;
+ else if (d != d) // NaN case
+ return 0;
+ else
+ return (int64_t)d;
+}
+
+static int64_t F2L(float f)
+{
+ static const float kMaxLong = (float)(int64_t)0x7fffffffffffffffULL;
+ static const float kMinLong = (float)(int64_t)0x8000000000000000ULL;
+ if (f >= kMaxLong)
+ return (int64_t)0x7fffffffffffffffULL;
+ else if (f <= kMinLong)
+ return (int64_t)0x8000000000000000ULL;
+ else if (f != f) // NaN case
+ return 0;
+ else
+ return (int64_t)f;
+}
+
void Thread::InitFunctionPointers() {
#if defined(__arm__)
pShlLong = art_shl_long;
@@ -195,6 +299,14 @@
pFindFieldFromCode = Field::FindFieldFromCode;
pCheckSuspendFromCode = CheckSuspendFromCode;
pStackOverflowFromCode = StackOverflowFromCode;
+ pThrowNullPointerFromCode = ThrowNullPointerFromCode;
+ pThrowArrayBoundsFromCode = ThrowArrayBoundsFromCode;
+ pThrowDivZeroFromCode = ThrowDivZeroFromCode;
+ pThrowVerificationErrorFromCode = ThrowVerificationErrorFromCode;
+ pThrowNegArraySizeFromCode = ThrowNegArraySizeFromCode;
+ pThrowRuntimeExceptionFromCode = ThrowRuntimeExceptionFromCode;
+ pThrowInternalErrorFromCode = ThrowInternalErrorFromCode;
+ pThrowNoSuchMethodFromCode = ThrowNoSuchMethodFromCode;
pDebugMe = DebugMe;
}
diff --git a/src/thread.h b/src/thread.h
index 9573458..4d27151 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -224,6 +224,14 @@
Field* (*pFindFieldFromCode)(uint32_t, const Method*);
void (*pCheckSuspendFromCode)(Thread*);
void (*pStackOverflowFromCode)(Method*);
+ void (*pThrowNullPointerFromCode)();
+ void (*pThrowArrayBoundsFromCode)(int32_t, int32_t);
+ void (*pThrowDivZeroFromCode)();
+ void (*pThrowVerificationErrorFromCode)(int32_t, int32_t);
+ void (*pThrowNegArraySizeFromCode)(int32_t);
+ void (*pThrowRuntimeExceptionFromCode)(int32_t);
+ void (*pThrowInternalErrorFromCode)(int32_t);
+ void (*pThrowNoSuchMethodFromCode)(int32_t);
class StackVisitor {
public: