Various bug fixes and new tests.
Amusingly realized that many tests believed to be passing were in fact not
running at all. The test harness returned 0 if the test wasn't run, but some
of the tests used 0 as a success code. Will change the tests later.
Most were failing only because the function pointer table in Thread wasn't
fully initialized with the math helper functions.
Change-Id: If2e42f06139f219a423eef475b599258ccfc82d4
diff --git a/src/compiler/Frontend.cc b/src/compiler/Frontend.cc
index 1775375..272cb08 100644
--- a/src/compiler/Frontend.cc
+++ b/src/compiler/Frontend.cc
@@ -700,13 +700,7 @@
if (!method->IsStatic() ||
(method->GetName()->ToModifiedUtf8().find("foo") != std::string::npos) ||
(method->GetName()->ToModifiedUtf8().find("init>") != std::string::npos) ||
- (method->GetName()->ToModifiedUtf8().find("intOperTest") != std::string::npos) ||
- (method->GetName()->ToModifiedUtf8().find("intShiftTest") != std::string::npos) ||
- (method->GetName()->ToModifiedUtf8().find("lit16Test") != std::string::npos) ||
- (method->GetName()->ToModifiedUtf8().find("lit8Test") != std::string::npos) ||
(method->GetName()->ToModifiedUtf8().find("longOperTest") != std::string::npos) ||
- (method->GetName()->ToModifiedUtf8().find("longShiftTest") != std::string::npos) ||
- (method->GetName()->ToModifiedUtf8().find("shiftTest1") != std::string::npos) ||
(method->GetName()->ToModifiedUtf8().find("main") != std::string::npos)) {
LOG(INFO) << "not compiling " << PrettyMethod(method, true);
return false;
diff --git a/src/compiler/RuntimeUtilities.cc b/src/compiler/RuntimeUtilities.cc
index d40f097..b18e4da 100644
--- a/src/compiler/RuntimeUtilities.cc
+++ b/src/compiler/RuntimeUtilities.cc
@@ -23,7 +23,7 @@
* Float/double conversion requires clamping to min and max of integer form. If
* target doesn't support this normally, use these.
*/
-s8 artD2L(double d)
+int64_t artD2L(double d)
{
static const double kMaxLong = (double)(s8)0x7fffffffffffffffULL;
static const double kMinLong = (double)(s8)0x8000000000000000ULL;
@@ -37,7 +37,7 @@
return (s8)d;
}
-s8 artF2L(float f)
+int64_t artF2L(float f)
{
static const float kMaxLong = (float)(s8)0x7fffffffffffffffULL;
static const float kMinLong = (float)(s8)0x8000000000000000ULL;
diff --git a/src/compiler/codegen/arm/ArchFactory.cc b/src/compiler/codegen/arm/ArchFactory.cc
index bf87c1e..cf606a3 100644
--- a/src/compiler/codegen/arm/ArchFactory.cc
+++ b/src/compiler/codegen/arm/ArchFactory.cc
@@ -53,6 +53,8 @@
int dOffset, TGT_LIR* pcrLabel)
{
/* This particular Dalvik register has been null-checked */
+ UNIMPLEMENTED(WARNING) << "Need null check & throw support";
+ return pcrLabel;
if (oatIsBitSet(cUnit->regPool->nullCheckedRegs, sReg)) {
return pcrLabel;
}
diff --git a/src/compiler/codegen/arm/Assemble.cc b/src/compiler/codegen/arm/Assemble.cc
index 19b9445..d9dd8c4 100644
--- a/src/compiler/codegen/arm/Assemble.cc
+++ b/src/compiler/codegen/arm/Assemble.cc
@@ -1194,13 +1194,18 @@
} else if (lir->opcode == kThumbBCond ||
lir->opcode == kThumb2BCond) {
ArmLIR *targetLIR = (ArmLIR *) lir->generic.target;
- intptr_t pc = lir->generic.offset + 4;
- intptr_t target = targetLIR->generic.offset;
- int delta = target - pc;
- if ((lir->opcode == kThumbBCond) && (delta > 254 || delta < -256)) {
- lir->opcode = kThumb2BCond;
- oatSetupResourceMasks(lir);
- res = kRetryAll;
+ 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;
+ }
}
lir->operands[0] = delta >> 1;
} else if (lir->opcode == kThumb2BUncond) {
diff --git a/src/compiler/codegen/arm/MethodCodegenDriver.cc b/src/compiler/codegen/arm/MethodCodegenDriver.cc
index 6e2f285..f7194f1 100644
--- a/src/compiler/codegen/arm/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/arm/MethodCodegenDriver.cc
@@ -428,6 +428,66 @@
return state + 1;
}
+// Slow path sequence for virtual calls
+static int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir,
+ DecodedInstruction* dInsn, int state)
+{
+ RegLocation rlArg;
+ switch(state) {
+ case 0: // Get the current Method* [sets r0]
+ loadBaseDisp(cUnit, mir, rSP, 0, r0, kWord, INVALID_SREG);
+ break;
+ case 1: // Get the current Method->DeclaringClass() [uses/sets r0]
+ loadBaseDisp(cUnit, mir, r0,
+ OFFSETOF_MEMBER(art::Method, declaring_class_),
+ r0, kWord, INVALID_SREG);
+ break;
+ case 2: // Method->DeclaringClass()->GetDexCache() [uses/sets r0]
+ loadBaseDisp(cUnit, mir, r0,
+ OFFSETOF_MEMBER(art::Class, dex_cache_), r0, kWord,
+ INVALID_SREG);
+ break;
+ case 3: // ...()->GetDexCache()->methodsObjectArr [uses/sets r0]
+ loadBaseDisp(cUnit, mir, r0,
+ art::DexCache::MethodsOffset().Int32Value(), r0,
+ kWord, INVALID_SREG);
+ // Load "this" [set r1]
+ rlArg = oatGetSrc(cUnit, mir, 0);
+ loadValueDirectFixed(cUnit, rlArg, r1);
+ // Skip past the object header
+ opRegImm(cUnit, kOpAdd, r0, art::Array::DataOffset().Int32Value());
+ break;
+ case 4:
+ // Is "this" null? [use r1]
+ genNullCheck(cUnit, oatSSASrc(mir,0), r1, mir->offset, NULL);
+ // get this->clazz [use r1, set rLR]
+ loadBaseDisp(cUnit, mir, r1, OFFSETOF_MEMBER(Object, klass_), rLR,
+ kWord, INVALID_SREG);
+ // Get the base Method* [uses r0, sets r0]
+ loadBaseDisp(cUnit, mir, r0, dInsn->vB * 4, r0,
+ kWord, INVALID_SREG);
+ // get this->clazz->vtable [use rLR, set rLR]
+ loadBaseDisp(cUnit, mir, rLR,
+ OFFSETOF_MEMBER(Class, vtable_), rLR, kWord,
+ INVALID_SREG);
+ // Get the method index [use r0, set r12]
+ loadBaseDisp(cUnit, mir, r0, OFFSETOF_MEMBER(Method, method_index_),
+ r12, kUnsignedHalf, INVALID_SREG);
+ // Skip past the object header
+ opRegImm(cUnit, kOpAdd, rLR, art::Array::DataOffset().Int32Value());
+ // Get target Method*
+ loadBaseIndexed(cUnit, rLR, r12, r0, 2, kWord);
+ break;
+ case 5: // Get the target compiled code address [uses r0, sets rLR]
+ loadBaseDisp(cUnit, mir, r0, art::Method::GetCodeOffset(), rLR,
+ kWord, INVALID_SREG);
+ break;
+ default:
+ return -1;
+ }
+ return state + 1;
+}
+
/* Load up to 3 arguments in r1..r3 */
static int loadArgRegs(CompilationUnit* cUnit, MIR* mir,
DecodedInstruction* dInsn, int callState,
@@ -702,12 +762,6 @@
{
DecodedInstruction* dInsn = &mir->dalvikInsn;
int callState = 0;
- /*
- * TODO: check for/force resolution of target method
- * note to bdc: you can find the method index in
- * dInsn->vB. If you need it, the calling method's
- * Method* is cUnit->method.
- */
int fastPath = false; // TODO: set based on resolution results
NextCallInsn nextCallInsn = fastPath ? nextSDCallInsn : nextSDCallInsnSP;
@@ -731,15 +785,18 @@
DecodedInstruction* dInsn = &mir->dalvikInsn;
int callState = 0;
ArmLIR* nullCk;
+ int fastPath = false; // TODO: set based on resolution results
+
+ NextCallInsn nextCallInsn = fastPath ? nextSDCallInsn : nextSDCallInsnSP;
if (mir->dalvikInsn.opcode == OP_INVOKE_DIRECT)
callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
- false, nextSDCallInsn);
+ false, nextCallInsn);
else
callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
- nextSDCallInsn);
+ nextCallInsn);
// Finish up any of the call sequence not interleaved in arg loading
while (callState >= 0) {
- callState = nextSDCallInsn(cUnit, mir, dInsn, callState);
+ callState = nextCallInsn(cUnit, mir, dInsn, callState);
}
newLIR1(cUnit, kThumbBlxR, rLR);
}
@@ -788,16 +845,19 @@
DecodedInstruction* dInsn = &mir->dalvikInsn;
int callState = 0;
ArmLIR* nullCk;
-// FIXME - redundantly loading arg0/r1 ("this")
+ int fastPath = false; // TODO: set based on resolution results
+
+ NextCallInsn nextCallInsn = fastPath ? nextVCallInsn : nextVCallInsnSP;
+ // TODO - redundantly loading arg0/r1 ("this")
if (mir->dalvikInsn.opcode == OP_INVOKE_VIRTUAL)
callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, &nullCk,
- false, nextVCallInsn);
+ false, nextCallInsn);
else
callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, &nullCk,
- nextVCallInsn);
+ nextCallInsn);
// Finish up any of the call sequence not interleaved in arg loading
while (callState >= 0) {
- callState = nextVCallInsn(cUnit, mir, dInsn, callState);
+ callState = nextCallInsn(cUnit, mir, dInsn, callState);
}
newLIR1(cUnit, kThumbBlxR, rLR);
}
@@ -956,7 +1016,7 @@
rlResult = oatEvalLoc(cUnit, rlDest, kAnyReg, true);
loadConstantValueWide(cUnit, rlResult.lowReg, rlResult.highReg,
0, mir->dalvikInsn.vB << 16);
- storeValue(cUnit, rlDest, rlResult);
+ storeValueWide(cUnit, rlDest, rlResult);
break;
case OP_MONITOR_ENTER:
@@ -986,6 +1046,7 @@
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);
rlResult = oatEvalLoc(cUnit, rlDest, kCoreReg, true);
diff --git a/src/compiler/codegen/arm/Thumb2/Gen.cc b/src/compiler/codegen/arm/Thumb2/Gen.cc
index e06910d..2239bd9 100644
--- a/src/compiler/codegen/arm/Thumb2/Gen.cc
+++ b/src/compiler/codegen/arm/Thumb2/Gen.cc
@@ -1358,6 +1358,11 @@
oatFlushAllRegs(cUnit); /* Send everything to home location */
loadWordDisp(cUnit, rSELF, funcOffset, rLR);
loadValueDirectWideFixed(cUnit, rlSrc1, r0, r1);
+ if (rlShift.wide) {
+ LOG(WARNING) << "Invalid RegLocation size - dataflow problem";
+ LOG(WARNING) << " sReg[" << rlShift.sRegLow << "]";
+ rlShift.wide = false;
+ }
loadValueDirect(cUnit, rlShift, r2);
opReg(cUnit, kOpBlx, rLR);
oatClobberCallRegs(cUnit);
diff --git a/src/compiler_test.cc b/src/compiler_test.cc
index cab932f..186e4c4 100644
--- a/src/compiler_test.cc
+++ b/src/compiler_test.cc
@@ -120,10 +120,12 @@
38);
}
+#if 0 // Needs artFillArrayDataNoThrow() helper function
TEST_F(CompilerTest, ShiftTest1) {
CompileDex(kIntMathDex, "kIntMathDex");
AssertStaticIntMethod("IntMath", "shiftTest1", "()I", 0);
}
+#endif
TEST_F(CompilerTest, ShiftTest2) {
CompileDex(kIntMathDex, "kIntMathDex");
@@ -177,8 +179,8 @@
TEST_F(CompilerTest, LongShiftTest) {
CompileDex(kIntMathDex, "kIntMathDex");
- AssertStaticLongMethod("IntMath", "longShiftTest", "(JI)J", 0,
- 0xd5aa96deff00aa01LL, 8);
+ AssertStaticLongMethod("IntMath", "longShiftTest", "(JI)J",
+ 0x96deff00aa010000LL, 0xd5aa96deff00aa01LL, 16);
}
TEST_F(CompilerTest, SwitchTest1) {
@@ -199,7 +201,7 @@
-5LL, -4294967287LL, 4LL, 8LL);
}
-#if 0
+#if 0 // Weird NaN failure. Needs investigation
TEST_F(CompilerTest, FloatCompare) {
CompileDex(kIntMathDex, "kIntMathDex");
AssertStaticIntMethod("IntMath", "testFloatCompare", "(FFFF)I", 3333
@@ -221,4 +223,28 @@
10);
}
+#if 0 // Need to complete try/catch block handling
+TEST_F(CompilerTest, ThrowAndCatch) {
+ CompileDex(kIntMathDex, "kIntMathDex");
+ AssertStaticIntMethod("IntMath", "throwAndCatch", "()I", 4);
+}
+#endif
+
+TEST_F(CompilerTest, ManyArgs) {
+ CompileDex(kIntMathDex, "kIntMathDex");
+ AssertStaticIntMethod("IntMath", "manyArgs",
+ "(IJIJIJIIDFDSICIIBZIIJJIIIII)I", -1,
+ 0, 1LL, 2, 3LL, 4, 5LL, 6, 7, 8.0, 9.0f, 10.0,
+ (short)11, 12, (char)13, 14, 15, (int8_t)-16, true, 18,
+ 19, 20LL, 21LL, 22, 23, 24, 25, 26);
+}
+
+#if 0 // White-list needs some work, must allow some virtual methods through
+TEST_F(CompilerTest, VirtualCall) {
+ CompileDex(kIntMathDex, "kIntMathDex");
+ AssertStaticIntMethod("IntMath", "staticCall", "(I)I", 6,
+ 3);
+}
+#endif
+
} // namespace art
diff --git a/src/compiler_test.h b/src/compiler_test.h
index 57a08e1..d8eaf02 100644
--- a/src/compiler_test.h
+++ b/src/compiler_test.h
@@ -290,7 +290,7 @@
// }
//
// /*
-// * Shift some data. (value=0xd5aa96deff00aa01, dist=8)
+// * Shift some data. (value=0xd5aa96deff00aa01, dist=16)
// */
// static long longShiftTest(long value, int dist) {
// long results[] = new long[4];
@@ -298,10 +298,10 @@
// results[1] = value >> dist;
// results[2] = value >>> dist;
// results[3] = (((value << dist) >> dist) >>> dist) << dist;
-// if (results[0] != 0x96deff00aa010000L) { return 1; }
-// if (results[1] != 0xffffd5aa96deff00L) { return 2; }
-// if (results[2] != 0x0000d5aa96deff00L) { return 3; }
-// if (results[3] != 0xffff96deff000000L) { return 4; }
+// if (results[0] != 0x96deff00aa010000L) { return results[0]; }
+// if (results[1] != 0xffffd5aa96deff00L) { return results[1]; }
+// if (results[2] != 0x0000d5aa96deff00L) { return results[2]; }
+// if (results[3] != 0xffff96deff000000L) { return results[3]; }
// if (results.length != 4) { return 5; }
//
// return results[0]; // test return-long
@@ -531,6 +531,68 @@
// }
// }
//
+///*
+// static void throwNullPointerException() {
+// throw new NullPointerException("first throw");
+// }
+//
+// static int throwAndCatch() {
+// try {
+// throwNullPointerException();
+// return 1;
+// } catch (NullPointerException npe) {
+// return 0;
+// }
+// }
+//*/
+//
+// static int manyArgs(int a0, long a1, int a2, long a3, int a4, long a5,
+// int a6, int a7, double a8, float a9, double a10, short a11, int a12,
+// char a13, int a14, int a15, byte a16, boolean a17, int a18, int a19,
+// long a20, long a21, int a22, int a23, int a24, int a25, int a26)
+// {
+// if (a0 != 0) return 0;
+// if (a1 != 1L) return 1;
+// if (a2 != 2) return 2;
+// if (a3 != 3L) return 3;
+// if (a4 != 4) return 4;
+// if (a5 != 5L) return 5;
+// if (a6 != 6) return 6;
+// if (a7 != 7) return 7;
+// if (a8 != 8.0) return 8;
+// if (a9 != 9.0f) return 9;
+// if (a10 != 10.0) return 10;
+// if (a11 != (short)11) return 11;
+// if (a12 != 12) return 12;
+// if (a13 != (char)13) return 13;
+// if (a14 != 14) return 14;
+// if (a15 != 15) return 15;
+// if (a16 != (byte)-16) return 16;
+// if (a17 != true) return 17;
+// if (a18 != 18) return 18;
+// if (a19 != 19) return 19;
+// if (a20 != 20L) return 20;
+// if (a21 != 21L) return 21;
+// if (a22 != 22) return 22;
+// if (a23 != 23) return 23;
+// if (a24 != 24) return 24;
+// if (a25 != 25) return 25;
+// if (a26 != 26) return 26;
+// return -1;
+// }
+//
+// int virtualCall(int a)
+// {
+// return a * 2;
+// }
+//
+// static int staticCall(int a)
+// {
+// IntMath foo = new IntMath();
+// return foo.virtualCall(a);
+// }
+//
+//
// public static void main(String[] args) {
// int res = unopTest(38);
// if (res == 37) {
@@ -628,144 +690,214 @@
// } else {
// System.out.printf("fibonacci FAILED: %d\n", res);
// }
+//
+///*
+// res = throwAndCatch();
+// if (res == 0) {
+// System.out.printf("throwAndCatch PASSED\n");
+// } else {
+// System.out.printf("throwAndCatch FAILED: %d\n", res);
+// }
+//*/
+//
+// res = manyArgs(0, 1L, 2, 3L, 4, 5L, 6, 7, 8.0, 9.0f, 10.0,
+// (short)11, 12, (char)13, 14, 15, (byte)-16, true, 18,
+// 19, 20L, 21L, 22, 23, 24, 25, 26);
+// if (res == -1) {
+// System.out.printf("manyArgs PASSED\n");
+// } else {
+// System.out.printf("manyArgs FAILED: %d\n", res);
+// }
+//
+// res = staticCall(3);
+// if (res == 6) {
+// System.out.printf("virtualCall PASSED\n");
+// } else {
+// System.out.printf("virtualCall FAILED: %d\n", res);
+// }
+//
// }
//}
static const char kIntMathDex[] =
-"ZGV4CjAzNQDkd6TZ8pqDxU8AeTvdZuEG1XSONR7DLLU8HgAAcAAAAHhWNBIAAAAAAAAAAJwdAABR"
-"AAAAcAAAAA8AAAC0AQAADQAAAPABAAABAAAAjAIAABcAAACUAgAAAgAAAEwDAACwGgAAjAMAAPIV"
-"AAD6FQAA/RUAAAAWAAADFgAAChYAABEWAAAVFgAAGhYAACEWAAAmFgAALRYAADsWAAA+FgAAQxYA"
-"AEcWAABSFgAAVxYAAG4WAACDFgAAlxYAAKsWAAC/FgAAzBYAAM8WAADTFgAA1xYAANsWAADwFgAA"
-"BRcAABIXAAArFwAAQBcAAEoXAABgFwAAchcAAH0XAACUFwAApxcAALQXAADNFwAA4hcAAPAXAAD7"
-"FwAABRgAABMYAAAtGAAAQxgAAFIYAABtGAAAhBgAAIoYAACPGAAAlxgAAKMYAAC7GAAAzxgAANsY"
-"AADzGAAABxkAABMZAAArGQAAPxkAAFIZAABxGQAAjBkAAJ4ZAAC8GQAA1hkAAOYZAAACGgAAGhoA"
-"ACsaAABIGgAAYRoAAGsaAACBGgAAkxoAAKYaAADFGgAA4BoAAAEAAAACAAAAAwAAAAwAAAAPAAAA"
-"EQAAABIAAAATAAAAFAAAABUAAAAXAAAAGQAAABoAAAAbAAAAHAAAAAMAAAACAAAAAAAAAAQAAAAC"
-"AAAAlBUAAAUAAAACAAAAoBUAAAYAAAACAAAArBUAAAcAAAACAAAAtBUAAAgAAAACAAAAvBUAAAkA"
-"AAACAAAAyBUAAAoAAAACAAAA0BUAAA0AAAADAAAA3BUAABAAAAAFAAAA5BUAAA4AAAAGAAAArBUA"
-"ABcAAAAKAAAAAAAAABgAAAAKAAAA7BUAAAkABQAzAAAABAALAAAAAAAEAAAAHQAAAAQAAAAgAAAA"
-"BAADACMAAAAEAAQAJgAAAAQABAApAAAABAADACoAAAAEAAMAKwAAAAQABgAsAAAABAAIAC8AAAAE"
-"AAwAMgAAAAQAAAA1AAAABAAAADgAAAAEAAMAOwAAAAQAAQA+AAAABAACAEEAAAAEAAUARAAAAAQA"
-"BwBHAAAABAADAEoAAAAEAAAATQAAAAUACQA0AAAABgAKAFAAAAAHAAsAAAAAAAcAAAABAAAA////"
-"/wAAAAAWAAAAAAAAADkdAAAAAAAABAAAAAAAAAAHAAAAAAAAAAsAAAAAAAAAQx0AAAAAAAABAAEA"
-"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"
-"EwAIACjjEwAJACjgEwAKACjdEwALACjaEwAMACjXEwANACjULAJOAAAAErAsAFQAAAATABMAKMoT"
-"AA8AKMcTABAAKMQTABEAKMETABIAKL4BECi8AAEGAP////8EAAAABQAAAA0AAAAHAAAACQAAAAsA"
-"AAAAAQIAAwAAABAAAAASAAAAAAECAHhWNBIEAAAADwAAAAACBQD6////AwAAABYAAAA5AAAAeFY0"
-"EhEAAAAXAAAAFAAAAA4AAAAaAAAAAAICAPr///8DAAAACgAAAA0AAAAAAgMA+////wAAAAAMAAAA"
-"EgAAAA8AAAAMAAAACgAIAAAAAACLHAAASAAAABMAXBEvAQIEPQEEABIQDwAwAQQCOwEEABIgKPov"
+"ZGV4CjAzNQAeDs8/iIoiUVFtgM49kDyM3iE5XGier2cYKAAAcAAAAHhWNBIAAAAAAAAAAHgnAACf"
+"AAAAcAAAABMAAADsAgAADgAAADgDAAABAAAA4AMAABoAAADoAwAAAgAAALgEAAAgIwAA+AQAAL4b"
+"AADGGwAAyRsAAMwbAADPGwAA0hsAANUbAADcGwAA4xsAAOcbAADsGwAA8xsAABEcAAAWHAAAHRwA"
+"ACscAAAuHAAAMxwAADccAABCHAAARxwAAF4cAABzHAAAhxwAAJscAACvHAAAvBwAAL8cAADCHAAA"
+"xhwAAMkcAADNHAAA0RwAAOYcAAD7HAAA/hwAAAIdAAAGHQAACx0AABAdAAAVHQAAGh0AAB8dAAAk"
+"HQAAKR0AAC4dAAAzHQAAOB0AADwdAABBHQAARh0AAEsdAABQHQAAVR0AAFodAABfHQAAYx0AAGcd"
+"AABrHQAAbx0AAHMdAAB3HQAAex0AAIYdAACQHQAAlh0AAJkdAACcHQAAox0AAKodAAC3HQAA0B0A"
+"AOUdAADvHQAABR4AABceAAAaHgAAIB4AACMeAAAmHgAAMR4AAEgeAABbHgAAYB4AAGMeAABmHgAA"
+"aR4AAG0eAABxHgAAfh4AAJceAACsHgAAuh4AAL0eAADIHgAA0h4AAOAeAAD6HgAAEB8AAB8fAAA6"
+"HwAAUR8AAFcfAABfHwAAZR8AAG8fAACFHwAAlx8AAJ8fAACoHwAArx8AALIfAAC3HwAAvx8AAMQf"
+"AADKHwAA0R8AANofAADiHwAA5x8AAO8fAAD4HwAA+x8AAAcgAAAfIAAAMyAAAD8gAABXIAAAayAA"
+"AHcgAACDIAAAmyAAAK8gAADCIAAA4SAAAPwgAAAOIQAALCEAAEYhAABWIQAAciEAAIohAACbIQAA"
+"uCEAANEhAADXIQAA4SEAAPchAAAJIgAAHCIAADsiAABWIgAAXSIAAGYiAABzIgAAjCIAAKEiAACk"
+"IgAApyIAAAEAAAACAAAAAwAAAAQAAAAFAAAADwAAABIAAAAUAAAAFQAAABYAAAAXAAAAGAAAABoA"
+"AAAbAAAAHQAAAB4AAAAfAAAAIAAAACEAAAAFAAAABAAAAAAAAAAGAAAABAAAACQbAAAHAAAABAAA"
+"ADAbAAAIAAAABAAAADwbAAAJAAAABAAAAEQbAAAKAAAABAAAAEwbAAALAAAABAAAAFgbAAAMAAAA"
+"BAAAAJQbAAANAAAABAAAAJwbAAAQAAAABQAAAKgbAAATAAAABwAAALAbAAARAAAACAAAADwbAAAb"
+"AAAADQAAAAAAAAAcAAAADQAAALgbAAALAAcAcQAAAAYADAAAAAAABgAAAEUAAAAGAAAASAAAAAYA"
+"AwBPAAAABgAEAFgAAAAGAAQAWwAAAAYAAwBdAAAABgADAF4AAAAGAAcAXwAAAAYACQBiAAAABgAN"
+"AGcAAAAGAAYAaAAAAAYAAAB6AAAABgAAAH0AAAAGAAMAgAAAAAYAAwCBAAAABgABAIQAAAAGAAIA"
+"hwAAAAYABQCKAAAABgAIAI0AAAAGAAMAkQAAAAYAAACUAAAABgADAJkAAAAHAAoAdQAAAAgACwCY"
+"AAAACQAMAAAAAAAJAAAAAQAAAP////8AAAAAGQAAAAAAAAALJwAAAAAAAAYAAAAAAAAACQAAAAAA"
+"AAAOAAAAAAAAABUnAAAAAAAAAQABAAAAAACtIgAAAQAAAA4AAAABAAEAAQAAALIiAAAEAAAAcBAZ"
+"AAAADgAEAAAAAAAAALciAAAQAAAAEwDpABQB//8AAJECAAEUA+oA//8yMgQAEhMPAxIDKP4FAAAA"
+"AAAAAMwiAAAyAAAAEwDmHYEBFgPmHTEDAQM4AwQAEhMPAxMAGuKBARYDGuIxAwEDOAMEABIjKPUY"
+"AfUAflIBAAAAhBAUA/UAflIyMAQAEjMo6BgBC/+Brf7///+EEBQDC/+BrTIwBAASQyjbEgMo2QMA"
+"AQABAAAA6iIAABUAAAASEDkCBAASAA8AMgL//9gAAv9xEAMAAAAKANgBAv5xEAMAAQAKAbAQKPAA"
+"AA4AAgAAAAAA9SIAALAAAAASNxImEgkSWBIVEwoKACOkDwCQCgwNSwoECZEKDA1LCgQFkgoMDUsK"
+"BAaSCgwMSwoEBxJKkwsMDUsLBAp72pQKDApLCgQIEmqVCwwNSwsEChJ6lgsMDUsLBAoTCggAlwsM"
+"DUsLBAoTCgkAkAsMDbHbstuz27Tbtdu227fbsMtLCwQKFQAAgEQKBAh7oRISFQoAgLMakwMKATID"
+"AwAPBUQKBAkUC20RAQAyugQAAWUo90QKBAUUC3MRAQAyugQAAXUo7kQGBAYUCrDL/P8ypgQAEkUo"
+"5UQGBAcUBwARECQydgQAAYUo3BJGRAYEBhMH26QydgQAEmUo00QGBAgyVgQAEnUozRJlRAUEBRQG"
+"cBEBADJlBQATBQgAKMISdUQFBAUS1jJlBQATBQkAKLkTBQgARAUEBRQGje7+/zJlBQATBQoAKK0T"
+"BQkARAUEBRQGcBEBADJlBQATBQsAKKEBlSifCgACAAAAAAAxIwAAPwAAABJEEjMSIhIREgUjQA8A"
+"mAYICUsGAAWZBggJSwYAAZoGCAlLBgACmAYICbmWupa4lksGAANEBgAFFAcAAaoAMnYDAA8BRAEA"
+"ARQGqgD//zJhBAABISj3RAEAAhQCqgD/ADIhBAABMSjuRAEAAxQCAKoAADIhBAABQSjlAVEo4wAA"
+"CQABAAAAAABIIwAAdQAAABJEEjMSIhIREgUTBggAI2APANCG6ANLBgAF0YboA0sGAAHShugDSwYA"
+"AtOG6ANLBgAD1IboA0sGAAQSVtWH6ANLBwAGEmbWhxj8SwcABhJ214cY/EsHAAZEBgAFFAe5MwEA"
+"MnYDAA8BRAEAARQGF9T+/zJhBAABISj3RAEAAhQCaMiiBDIhBAABMSjuRAEAAxMCTQAyIQQAAUEo"
+"5kQBAAQTAgkDMiEEABJRKN4SUUQBAAETAsADMiEEABJhKNUSYUQBAAETAtn/MiEEABJxKMwScUQB"
+"AAEUAsnT/v8yIQUAEwEIACjBAVEovwAACwABAAAAAABoIwAAfAAAABJGEjUSJBITEgcTCAgAI4IP"
+"ANgICgpLCAIH2QgKCksIAgPaCAoKSwgCBNsICgpLCAIF3AgKCksIAgYSWN0JCgpLCQIIEmjeCQr2"
+"SwkCCBJ43wkK9ksJAggVAACA2wEA/zIBAwAPA0QIAgcUCQcn//8ymAQAAUMo90QDAgMUCA3ZAAAy"
+"gwQAAVMo7kQDAgQUBOKF9/8yQwQAAWMo5UQDAgUTBE3qMkMEABJTKN1EAwIGErQyQwQAEmMo1hJT"
+"RAMCAxMECAAyQwQAEnMozRJjRAMCAxL0MkMFABMDCAAoxBJzRAMCAxQEC9kAADJDBQATAwkAKLkB"
+"cyi3EQAEAAAAAACTIwAA7gAAABMJCgAjmBAAEgmbCg0PTAoICRIZnAoND0wKCAkSKZ0KDQ9MCggJ"
+"EjmdCg0NTAoICRJJngoND0wKCAkSWX36nwoNCkwKCAkSaaAKDQ9MCggJEnmhCg0PTAoICRMJCACi"
+"Cg0PTAoICRMJCQCbCg0PvPq9+r76v/rA+sH6wvq72kwKCAkZAACAEllFCQgJfZIWBAEAmwkABLxJ"
+"vimeBgkCMQkGADgJBAASGQ8JEglFCQgJGAv9O1NMEAAAADEJCQs4CQQAEiko8hIZRQkICRgLAzxT"
+"TBAAAAAxCQkLOAkEABI5KOQSKUUJCAkYCwBMBhvP////MQkJCzgJBAASSSjWEjlFCQgJGAsAABD2"
+"rwYpoTEJCQs4CQQAElkoyBJJRQkICRgLq5Y5kfr///8xCQkLOAkEABJpKLoSWUUJCAkWCwEAMQkJ"
+"CzgJBAASeSivEmlFCQgJGAsAPFNMEAAAADEJCQs4CQUAEwkIACigEnlFCQgJFgv9/zEJCQs4CQUA"
+"EwkJACiUEwkIAEUJCAkYC/3DrLPv////MQkJCzgJBQATCQoAKIQTCQkARQkICRgLADxTTBAAAAAx"
+"CQkLOAkGABMJCwApAHT/IYkTCgoAMqkGABMJDAApAGv/EgkpAGj/DQADAAAAAADTIwAAWwAAABJJ"
+"EjgSJxIWEgUjkBAAowEKDEwBAAWkAQoMTAEABqUBCgxMAQAHowEKDMTBxcHDwUwBAAhFAQAFGAMA"
+"AAGqAP/eljEBAQM4AQUARQEABRABRQEABhgDAP/elqrV//8xAQEDOAEFAEUBAAYo8kUBAAcYAwD/"
+"3paq1QAAMQEBAzgBBQBFAQAHKORFAQAIGAMAAAD/3pb//zEBAQM4AQUARQEACCjWIQEykQUAFgEF"
+"ACjQRQEABSjNAAAnAAEAIgAAAO0jAADlAgAAEwEmAHEQFAABAAolEwElAAIAJQAzEJgBYgEAABoC"
+"kwASAyMzEQBuMBcAIQNxAAwAAAAKJTklmwFiAQAAGgJ8ABIDIzMRAG4wFwAhA3EADQAAAAolOSWe"
+"AWIBAAAaAn8AEgMjMxEAbjAXACEDcQAVAAAACiU5JaEBYgEAABoClgASAyMzEQBuMBcAIQNxAAIA"
+"AAAKJTklpAFiAQAAGgJKABIDIzMRAG4wFwAhA3EAAQAAAAolOSWnAWIBAAAaAkcAEgMjMxEAbjAX"
+"ACEDFAFwEQEAEtJxIAQAIQAKJTklpgFiAQAAGgJaABIDIzMRAG4wFwAhAxgBADxTTBAAAAAWA/3/"
+"cUAIACFDCiU5JaIBYgEAABoCYQASAyMzEQBuMBcAIQMYAQGqAP/elqrVEwMQAHEwCQAhAwsjGAEA"
+"AAGqAP/eljEBIwE5AZcBYgEAABoCZAASAyMzEQBuMBcAIQMSEXEQDwABAAolEwHSBAIAJQAzEJUB"
+"YgEAABoCgwASAyMzEQBuMBcAIQMSsRJCEkMSBHFAEgAhQwolEwFXBAIAJQAzEJABYgEAABoCjAAS"
+"AyMzEQBuMBcAIQMWAfv/GAMJAAAA/////xYFBAAWBwgAdwgTAAEACiUTAa4IAgAlADMQhAFiAQAA"
+"GgKPABIDIzMRAG4wFwAhAxUBoMAVAoBAFQOAQBUEwH9xQBEAIUMKJRMBBQ0CACUAMxB7AWIBAAAa"
+"AokAEgMjMxEAbjAXACEDGQEUwBkDEEAZBRBAGQf4f3cIEAABAAolEwFcEQIAJQAzEHIBYgEAABoC"
+"hgASAyMzEQBuMBcAIQMTAQoAcRADAAEACiUTATcAAgAlADMQbwFiAQAAGgJRABIDIzMRAG4wFwAh"
+"AxIBFgIBABIkFgUDABJHFggFABJqEnsZDCBAFQ4QQRkPJEATEQsAExIMABMTDQATFA4AExUPABMW"
+"8P8TFwEAExgSABMZEwAWGhQAFhwVABMeFgATHxcAEyAYABMhGQATIhoAdyILAAEACiUS8QIAJQAz"
+"ED4BYgEAABoCagASAyMzEQBuMBcAIQMSMXEQDgABAAolEmECACUAMxA9AWIBAAAaApsAEgMjMxEA"
+"bjAXACEDDgBiAQAAGgKSABITIzMRABIEdwEYACUADAVNBQMEbjAXACEDKQBj/mIBAAAaAnsAEhMj"
+"MxEAEgR3ARgAJQAMBU0FAwRuMBcAIQMpAGD+YgEAABoCfgASEyMzEQASBHcBGAAlAAwFTQUDBG4w"
+"FwAhAykAXf5iAQAAGgKVABITIzMRABIEdwEYACUADAVNBQMEbjAXACEDKQBa/mIBAAAaAkkAEhMj"
+"MxEAEgR3ARgAJQAMBU0FAwRuMBcAIQMpAFf+YgEAABoCRgASEyMzEQASBHcBGAAlAAwFTQUDBG4w"
+"FwAhAykAVP5iAQAAGgJZABITIzMRABIEdwEYACUADAVNBQMEbjAXACEDKQBV/mIBAAAaAmAAEhMj"
+"MxEAEgR3ARgAJQAMBU0FAwRuMBcAIQMpAFn+YgEAABoCYwASEyMzEQASBHcBGAAlAAwFTQUDBG4w"
+"FwAhAykAZP5iAQAAGgKCABITIzMRABIEdwEYACUADAVNBQMEbjAXACEDKQBm/mIBAAAaAosAEhMj"
+"MxEAEgR3ARgAJQAMBU0FAwRuMBcAIQMpAGv+YgEAABoCjgASEyMzEQASBHcBGAAlAAwFTQUDBG4w"
+"FwAhAykAd/5iAQAAGgKIABITIzMRABIEdwEYACUADAVNBQMEbjAXACEDKQCA/mIBAAAaAoUAEhMj"
+"MxEAEgR3ARgAJQAMBU0FAwRuMBcAIQMpAIn+YgEAABoCUAASEyMzEQASBHcBGAAlAAwFTQUDBG4w"
+"FwAhAykAjP5iAQAAGgJpABITIzMRABIEdwEYACUADAVNBQMEbjAXACEDKQC9/mIBAAAaApoAEhMj"
+"MxEAEgR3ARgAJQAMBU0FAwRuMBcAIQMpAL7+AAAlACIAAAAAAG0kAADnAAAAOAMEABIBDwEWAQEA"
+"MQEEATgBBAASESj4EiEyFgQAEiEo8xYBAwAxAQcBOAEEABIxKOsSQTIZBAASQSjmFgEFADEBCgE4"
+"AQQAElEo3hJhMhwEABJhKNkScTIdBAAScSjUGQEgQC8BDgE4AQUAEwEIACjLFQEQQS0BEAE4AQUA"
+"EwEJACjCGQEkQC8BEQE4AQUAEwEKACi5EwELAAIAEwAyEAUAEwELACiwEwEMAAIAFAAyEAUAEwEM"
+"ACinEwENAAIAFQAyEAUAEwENACieEwEOAAIAFgAyEAUAEwEOACiVEwEPAAIAFwAyEAUAEwEPACiM"
+"EwHw/wIAGAAyEAUAEwEQACiDEhECABkAMhAGABMBEQApAHv/EwESAAIAGgAyEAYAEwESACkAcf8T"
+"ARMAAgAbADIQBgATARMAKQBn/xYBFAAxARwBOAEGABMBFAApAF3/FgEVADEBHgE4AQYAEwEVACkA"
+"U/8TARYAAgAgADIQBgATARYAKQBJ/xMBFwACACEAMhAGABMBFwApAD//EwEYAAIAIgAyEAYAEwEY"
+"ACkANf8TARkAAgAjADIQBgATARkAKQAr/xMBGgACACQAMhAGABMBGgApACH/EvEpAB7/AAAPAAAA"
+"AAAAAK4kAACsAAAAEkgSNxImEhUSCRMKCAAjpA8AJgSPAAAARAoECUQLBAXgCwsItrpECwQG4AsL"
+"ELa6RAsEB+ALCxiWAAoLRAoECBJbRAsEC+ALCwi2uhJrRAsEC+ALCxC2uhJ7RAsEC+ALCxiWAQoL"
+"gQqBHBMOIADD7KECCgwUChEiM0QyoAMADwUUCoiZqrsyoQQAAWUo+RgKESIzRIiZqrsxCgIKOAoE"
+"AAF1KO5ECgQJgapEBQQFgVwTBQgAw1zBykQFBAaBVRMMEADDxcGlRAcEB4F6EwcYAMN6waVEBwQI"
+"gXoTByAAw3rBpRJXRAcEB4F6EwcoAMN6waUSZ0QHBAeBehMHMADDesGlEndEBwQHgXoTBzgAw3qh"
+"AgUKGAURIjNEiJmquzEFAgU4BQQAAYUoqwGVKKkAAAADBAAIAAAAEQAAACIAAAAzAAAARAAAAIgA"
+"AACZAAAAqgAAALsAAAAWAAAAAAAAANokAABJAAAAFgARABYCIgAWBDMAFgZEABYIVQAWCmYAFgx3"
+"ABYOiAATEjgAoxIAEhMUMACjFAIUoRISFBMUKACjFAQUoRISFBMUIACjFAYUoRISFBMUGACjFAgU"
+"oRISFBMUEACjFAoUoRISFBMUCACjFAwUoRISFKEQEg4YEoh3ZlVEMyIRMRIQEjgSBQATEgEADxIT"
+"EgAAKP0AAAMAAQACAAAADyUAAAoAAAAiAAYAcBAAAAAAbiAWACAACgEPAQMAAQAAAAAAGyUAALAA"
+"AAATANIEKwJgAAAAEmABAQ8BEhABASj9EiABASj6EjABASj3EkABASj0ElABASjxKwJbAAAAFAJ4"
+"VjQSKwJdAAAAEhABASjlEnABASjiEwAIAAEBKN4TAAkAAQEo2iwCVAAAABMADgABASjTEwAKAAEB"
+"KM8TAAsAAQEoyxMADAABASjHEwANAAEBKMMsAlMAAAASsiwCWQAAABMAEwABASi4EwAPAAEBKLQT"
+"ABAAAQEosBMAEQABASisEwASAAEBKKgBASimAAEGAP////8GAAAACQAAABUAAAAMAAAADwAAABIA"
+"AAAAAQIAAwAAAAwAAAAPAAAAAAECAHhWNBIRAAAADQAAAAACBQD6////AwAAABYAAAA5AAAAeFY0"
+"EgsAAAATAAAADwAAAAcAAAAXAAAAAAICAPr///8DAAAACwAAAA8AAAAAAgMA+////wAAAAAMAAAA"
+"FwAAABMAAAAPAAAACgAIAAAAAAAoJgAASAAAABMAXBEvAQIEPQEEABIQDwAwAQQCOwEEABIgKPov"
"AQQCOQEEABIwKPQvAQQGOAEEABJAKO4wAQQIPAEEABJQKOgvAQQIOgEEABJgKOIwAQIIPAEEABJw"
"KNwvAQIIOgEFABMACAAo1S8BCAQ6AQUAEwAJACjOMAEIBDwBBQATAAoAKMcvAQgIOQHE/xMACwAo"
-"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"
+"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"
-"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"
-"AAADAAMAAwADAAIAAAADAAIAAgAAAAgADQABAAAADgAGPGluaXQ+AAFEAAFGAAFJAAVJRERERAAF"
-"SUZGRkYAAklJAANJSUkABUlJSUlJAANJSkoABUlKSkpKAAxJbnRNYXRoLmphdmEAAUoAA0pKSQAC"
-"TEkACUxJbnRNYXRoOwADTExMABVMamF2YS9pby9QcmludFN0cmVhbTsAE0xqYXZhL2xhbmcvSW50"
-"ZWdlcjsAEkxqYXZhL2xhbmcvT2JqZWN0OwASTGphdmEvbGFuZy9TdHJpbmc7ABJMamF2YS9sYW5n"
-"L1N5c3RlbTsAC09iamVjdC5qYXZhAAFWAAJWTAACW0kAAltKABNbTGphdmEvbGFuZy9PYmplY3Q7"
-"ABNbTGphdmEvbGFuZy9TdHJpbmc7AAtjaGFyU3ViVGVzdAAXY2hhclN1YlRlc3QgRkFJTEVEOiAl"
-"ZAoAE2NoYXJTdWJUZXN0IFBBU1NFRAoACGNvbnZUZXN0ABRjb252VGVzdCBGQUlMRUQ6ICVkCgAQ"
-"Y29udlRlc3QgUEFTU0VECgAJZmlib25hY2NpABVmaWJvbmFjY2kgRkFJTEVEOiAlZAoAEWZpYm9u"
-"YWNjaSBQQVNTRUQKAAtpbnRPcGVyVGVzdAAXaW50T3BlclRlc3QgRkFJTEVEOiAlZAoAE2ludE9w"
-"ZXJUZXN0IFBBU1NFRAoADGludFNoaWZ0VGVzdAAJbGl0MTZUZXN0AAhsaXQ4VGVzdAAMbG9uZ09w"
-"ZXJUZXN0ABhsb25nT3BlclRlc3QgRkFJTEVEOiAlZAoAFGxvbmdPcGVyVGVzdCBQQVNTRUQKAA1s"
-"b25nU2hpZnRUZXN0ABlsb25nU2hpZnRUZXN0IEZBSUxFRDogJWQKABVsb25nU2hpZnRUZXN0IFBB"
-"U1NFRAoABG1haW4AA291dAAGcHJpbnRmAApzaGlmdFRlc3QxABZzaGlmdFRlc3QxIEZBSUxFRDog"
-"JWQKABJzaGlmdFRlc3QxIFBBU1NFRAoACnNoaWZ0VGVzdDIAFnNoaWZ0VGVzdDIgRkFJTEVEOiAl"
-"ZAoAEnNoaWZ0VGVzdDIgUEFTU0VECgAKc3dpdGNoVGVzdAAWc3dpdGNoVGVzdCBGQUlMRUQ6ICVk"
-"CgASc3dpdGNoVGVzdCBQQVNTRUQKABF0ZXN0RG91YmxlQ29tcGFyZQAddGVzdERvdWJsZUNvbXBh"
-"cmUgRkFJTEVEOiAlZAoAGXRlc3REb3VibGVDb21wYXJlIFBBU1NFRAoAEHRlc3RGbG9hdENvbXBh"
-"cmUAHHRlc3RGbG9hdENvbXBhcmUgRkFJTEVEOiAlZAoAGHRlc3RGbG9hdENvbXBhcmUgUEFTU0VE"
-"CgAOdGVzdEludENvbXBhcmUAGnRlc3RJbnRDb21wYXJlIEZBSUxFRDogJWQKABZ0ZXN0SW50Q29t"
-"cGFyZSBQQVNTRUQKAA90ZXN0TG9uZ0NvbXBhcmUAG3Rlc3RMb25nQ29tcGFyZSBGQUlMRUQ6ICVk"
-"CgAXdGVzdExvbmdDb21wYXJlIFBBU1NFRAoACHVub3BUZXN0ABR1bm9wVGVzdCBGQUlMRUQ6ICVk"
-"CgAQdW5vcFRlc3QgUEFTU0VECgARdW5zaWduZWRTaGlmdFRlc3QAHXVuc2lnbmVkU2hpZnRUZXN0"
-"IEZBSUxFRDogJWQKABl1bnNpZ25lZFNoaWZ0VGVzdCBQQVNTRUQKAAd2YWx1ZU9mAAMABw4AAQAH"
-"DgBwAAcOAFQABw4tHgIOdwJ0HS0eiVoeeVoeeAD4AwEABx0tIRovAHgCAAAHWU1LS0tLWlpaWmvj"
-"LT1bAgwsAnUdlpaWlpZptJbD0wDcAQIAAAdZLUtLS3h7GpaWpQCiAQEAB1lNS0tLS0taWlt/Ankd"
-"lpaHh5aWwwC+AQEAB1lNS0tLS0taWl1/AnkdlpaHeJaWwwDtAQIAAAcOTVpaWlpaaVpaauItSy14"
-"AgxZAnUd4eHh4eG08MP/AREPlgCTAgIAAAdZLUtLS3jXAnsd4eHhagCCBAEAB3dpS5lLLZlLLZlL"
-"LZlLLZlLLZmHLZm0LZm0lppLS5paS5rwS5qHS5qlS5ppS5kCpH8dAREUAREUAREUAREUAREUAREU"
-"AREUAREUAREVAREVAREVAREVAREVAREVAA0AB1l9AREPARQPagIOWQJzHXi1ATcXwwJoHQAqAAcO"
-"LS0tLS0tLS4BIxGlAKICAQAHHS5CAigdAlMdLi0tL0E9T0ECbjstQz88PTw+QR4/AnY7PEE9UQJR"
-"HQEQF46LARYWqwDaAwQAAAAABw4uSwIXHQJqHUstSy1LLkstSy1LLUs8SzxLPUsAuQMEAAAAAAcO"
-"LkseSx5LHksfSx5LHkseSy1LLUsuSy4A2QIEAAAAAAcOLi0CJR0CXB0tLS0tLS0tLS0vMi03MS08"
-"LTwtPC08LT0vAIsDBAAAAAAHLC5LAiIdAl8dSy1LLmktaS9RSwJ7OzJLPEs+SzxLPEsABwEABw4e"
-"LQBAAAdoHh4gPxpLTAAAAAEAFoGABIwHAAAUAACAgASgBwEIuAcBCMwHAQjACAEI/AgBCOwLAQj8"
-"DAEI+A4BCPAQAQjgFAEJqBYBCIwfAQjsIQEI/CIBCMAlAQjgJgEI7CcBCIApAQi8KgEI1CoAAAAN"
-"AAAAAAAAAAEAAAAAAAAAAQAAAFEAAABwAAAAAgAAAA8AAAC0AQAAAwAAAA0AAADwAQAABAAAAAEA"
-"AACMAgAABQAAABcAAACUAgAABgAAAAIAAABMAwAAASAAABUAAACMAwAAARAAAAoAAACUFQAAAiAA"
-"AFEAAADyFQAAAyAAABUAAADpGgAAACAAAAIAAAA5HQAAABAAAAEAAACcHQAA";
-
+"AC4BBQM8AQQAEwAKAC0BBQU5AQQAEwALAA8ABgAEAAAAAAB6JgAAQwAAABMAVwQ3MgQAEhEPATQy"
+"BAASISj8NSMEABIxKPg2IwQAEkEo9DMjBAASUSjwMkMEABJhKOwyIwcAPQIHABMBCAAo5RJxKOM6"
+"AgUAEwEJACjeOwMFABMBCgAo2TwDBQATAQsAKNQ5AwUAEwEMACjPOAUFABMBDQAoyjkFBAABASjG"
+"EwEOACjDAAANAAgAAAAAAKsmAABYAAAAFgMBABMArggxAQUJPQEEABIhDwExAQkFOwEEABIxKPox"
+"AQkFOQEEABJBKPSbAQkDMQEJAToBBAASUSjsmwEFAzEBBQE6AQQAEmEo5DEBCQU4AQkAMQEJCz0B"
+"BwATAQgAKNkScSjXMQELCTsBBQATAQkAKNAxAQsJOQEFABMBCgAoyTEBBQc7AQUAEwELACjCMQEH"
+"BT0BBQATAQwAKLsxAQcFOQEFABMBDQAotAEBKLIBAAEAAAAAANkmAAAEAAAAewDfAAD/DwAHAAAA"
+"AAAAAOImAAAjAAAAEwb/DxL1FAT///8PEsASwxQB/P8AABLCjUCPQ45h4gICBDJQBAASFA8EMlME"
+"ABIkKPwyYQQAEjQo+DJCBAASRCj0EgQo8gAAAwACAAAAAAAEJwAAAwAAANoAAgIPAAAABAAAAAIA"
+"AgACAAIABAAAAAMAAwADAAMAAQAAAAQAAAACAAAABAAEAAQAAAAEAAQABAAEABsAAAAEAAUABAAF"
+"AAQABQAEAAQAAgADAAIADAAEAAEABAAEAAAADgAEAAQABQAFAAQABAAEAAQABAAAAAIAAAAFAAUA"
+"BAAAAAUABQAFAAUAAgAAAAUABAACAAAACgARAAEAAAASAAY8aW5pdD4AAUIAAUMAAUQAAUYAAUkA"
+"BUlEREREAAVJRkZGRgACSUkAA0lJSQAFSUlJSUkAHElJSklKSUpJSURGRFNJQ0lJQlpJSUpKSUlJ"
+"SUkAA0lKSgAFSUpKSkoADEludE1hdGguamF2YQABSgADSkpJAAJMSQAJTEludE1hdGg7AANMTEwA"
+"FUxqYXZhL2lvL1ByaW50U3RyZWFtOwATTGphdmEvbGFuZy9JbnRlZ2VyOwASTGphdmEvbGFuZy9P"
+"YmplY3Q7ABJMamF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVtOwALT2JqZWN0Lmph"
+"dmEAAVMAAVYAAlZMAAFaAAJbSQACW0oAE1tMamF2YS9sYW5nL09iamVjdDsAE1tMamF2YS9sYW5n"
+"L1N0cmluZzsAAWEAAmEwAAJhMQADYTEwAANhMTEAA2ExMgADYTEzAANhMTQAA2ExNQADYTE2AANh"
+"MTcAA2ExOAADYTE5AAJhMgADYTIwAANhMjEAA2EyMgADYTIzAANhMjQAA2EyNQADYTI2AAJhMwAC"
+"YTQAAmE1AAJhNgACYTcAAmE4AAJhOQAJYWxzb01pbnVzAAhhbHNvUGx1cwAEYXJncwABYgABYwAF"
+"Y2hhcjEABWNoYXIyAAtjaGFyU3ViVGVzdAAXY2hhclN1YlRlc3QgRkFJTEVEOiAlZAoAE2NoYXJT"
+"dWJUZXN0IFBBU1NFRAoACGNvbnZUZXN0ABRjb252VGVzdCBGQUlMRUQ6ICVkCgAQY29udlRlc3Qg"
+"UEFTU0VECgABZAAEZGlzdAABZQABZgAJZmlib25hY2NpABVmaWJvbmFjY2kgRkFJTEVEOiAlZAoA"
+"EWZpYm9uYWNjaSBQQVNTRUQKAANmb28AAWcAAWgAAWkAAmkxAAJpMgALaW50T3BlclRlc3QAF2lu"
+"dE9wZXJUZXN0IEZBSUxFRDogJWQKABNpbnRPcGVyVGVzdCBQQVNTRUQKAAxpbnRTaGlmdFRlc3QA"
+"AWwACWxpdDE2VGVzdAAIbGl0OFRlc3QADGxvbmdPcGVyVGVzdAAYbG9uZ09wZXJUZXN0IEZBSUxF"
+"RDogJWQKABRsb25nT3BlclRlc3QgUEFTU0VECgANbG9uZ1NoaWZ0VGVzdAAZbG9uZ1NoaWZ0VGVz"
+"dCBGQUlMRUQ6ICVkCgAVbG9uZ1NoaWZ0VGVzdCBQQVNTRUQKAARscmVzAAZtQnl0ZXMABG1haW4A"
+"CG1hbnlBcmdzABRtYW55QXJncyBGQUlMRUQ6ICVkCgAQbWFueUFyZ3MgUEFTU0VECgAGbWluSW50"
+"AAdtaW5Mb25nAAVtaW51cwABbgADbmFuAAZuZWdPbmUAA291dAAEcGx1cwAFcGx1czIAB3BsdXNP"
+"bmUABnByaW50ZgADcmVzAAZyZXN1bHQAB3Jlc3VsdHMAAXMACnNoaWZ0VGVzdDEAFnNoaWZ0VGVz"
+"dDEgRkFJTEVEOiAlZAoAEnNoaWZ0VGVzdDEgUEFTU0VECgAKc2hpZnRUZXN0MgAWc2hpZnRUZXN0"
+"MiBGQUlMRUQ6ICVkCgASc2hpZnRUZXN0MiBQQVNTRUQKAApzdGF0aWNDYWxsAApzd2l0Y2hUZXN0"
+"ABZzd2l0Y2hUZXN0IEZBSUxFRDogJWQKABJzd2l0Y2hUZXN0IFBBU1NFRAoAEXRlc3REb3VibGVD"
+"b21wYXJlAB10ZXN0RG91YmxlQ29tcGFyZSBGQUlMRUQ6ICVkCgAZdGVzdERvdWJsZUNvbXBhcmUg"
+"UEFTU0VECgAQdGVzdEZsb2F0Q29tcGFyZQAcdGVzdEZsb2F0Q29tcGFyZSBGQUlMRUQ6ICVkCgAY"
+"dGVzdEZsb2F0Q29tcGFyZSBQQVNTRUQKAA50ZXN0SW50Q29tcGFyZQAadGVzdEludENvbXBhcmUg"
+"RkFJTEVEOiAlZAoAFnRlc3RJbnRDb21wYXJlIFBBU1NFRAoAD3Rlc3RMb25nQ29tcGFyZQAbdGVz"
+"dExvbmdDb21wYXJlIEZBSUxFRDogJWQKABd0ZXN0TG9uZ0NvbXBhcmUgUEFTU0VECgAEdGhpcwAI"
+"dW5vcFRlc3QAFHVub3BUZXN0IEZBSUxFRDogJWQKABB1bm9wVGVzdCBQQVNTRUQKABF1bnNpZ25l"
+"ZFNoaWZ0VGVzdAAddW5zaWduZWRTaGlmdFRlc3QgRkFJTEVEOiAlZAoAGXVuc2lnbmVkU2hpZnRU"
+"ZXN0IFBBU1NFRAoABXZhbHVlAAd2YWx1ZU9mAAt2aXJ0dWFsQ2FsbAAXdmlydHVhbENhbGwgRkFJ"
+"TEVEOiAlZAoAE3ZpcnR1YWxDYWxsIFBBU1NFRAoAAXgAAXkABHplcm8AAwAHDgABAAcOAGkABw4t"
+"AwBEAj8DAUUCLQMCVgVpAFQABw4tAwBWBR4DAV0GAg53AnQdLR6JWh55Wh54APgDAW8HHS0hGi8A"
+"eAKdAZ4BB1lNAwR5EEtLS0taWlpaa+MtAwBsBTwDAXEFHgMCdQVbAwN4BQIMLAJ1HZaWlpaWabSW"
+"w9MA3AECmAFNB1ktAwB5EEtLS3h7GpaWpQCiAQGdAQdZTQMAeRBLS0tLS1paW38CeR2WloeHlpbD"
+"AL4BAZ0BB1lNAwJ5EEtLS0tLWlpaLQMAbAUtAwF4BTUCeB2WlpaHeJaWwwDtAQKdAZ4BBw5NAwh5"
+"EVpaWlpaaVpaauItAwBtBksDAnEGLQMEdQZpAwZ4BgIMWQJ1HeHh4eHhtPDD/wERD5YAkwICmAFN"
+"B1ktAwB5EUtLS3jXAnsd4eHhagDABAFBBw5pAyV3BWmoSy2oSy2oSy2oSy2oSy2ohy2otC2otAMj"
+"ZgaWqVppqYdpqfBpqcNpqcNpqWlpAg6kATURWqlaWqkCin8dBSMBExQBExQBExQBExQBExQBExQB"
+"ExQBExQGIwETFQETFQETFQETFQETFQETFQISARMOARMVAJUEGyQlMDg5Ojs8PT4mJygpKissLS4v"
+"MTIzNDU2NwcOAhs7AmYdh1qHWodaWpaWlpaWlpaWlpalpaWlpaWlpaUADQAHWX0DBGcQARIPAwBX"
+"BQEVDwMBWAV5AwJdBgIOWQJzHXi1ATgXwwJoHQAqAAcOLQMAIwYtAwJCBi0DBEMGLQMGTAYtAwhO"
+"Bi0DCk8GLQMMVAYuAw5VBgEqEQMQeAa0ALoEASMHDloDAFMHAKICASMHDi4DAHcFQgIoLAUAAwF3"
+"BQJSHQUBBgABAgUABgEeBQEGAAECBQAGAR8FAQYAAQIFAAYBHgUBBgABAgUABgEeBQEGAAECBQAG"
+"ASAFAQYAQT0+AQIFAAYBAnYdBQEGAAECBQAGAR4FAQYAAQMFAAYBJQUBBgABAwUABgEgBQEGAEEB"
+"AwUABgECex0FAQYAAQMFAAYBHgUBBgABAwUABgEfBQEGAAEDBQAGAR4FAQYAAQMFAAYBIAUBBgBB"
+"Hj8BAwUABgECdh0FAQYAAQMFAAYBHgUBBgABAwUABgEjBQEGAAEDBQAGAR8FAQYAAQMFAAYBAQEF"
+"AQYAJAUABgECUR0BEBeOiwEWFqsA2gMEbnN0cAcOLgMAdwVLAhcdBQACah0GAEstSy1LLkstSy1L"
+"LUs8SzxLPUsAuQMEbnN0cAcOLgMAdwVLHkseSx5LH0seSx5LHkstSy1LLksuANkCBG5zdJ8BBw4u"
+"AwB3BS0CJR0CXB0tLS0tLS0tLS0vMi03MS08LTwtPC08LT1AGwCLAwRuP3NABywuAwB3BUsCIh0C"
+"Xx1LLUsuaS1pL1FLAns7Mks8Sz5LPEs8S0wABwGdAQcOHi0AOwAHaB4DAEIBHgMDeg08AwFDAh8D"
+"AlYFHh4eLj8aS0tLALUEASMHDgAAAAEAGYGABPgJAAAWAQCAgASMCgEIpAoBCNQKAQjICwEIhAwB"
+"CPQOAQiEEAEIgBIBCIgUAQj0FwEJvBkBCJglAQj4KAEI4CsBCIQtAQioLQEImDABCLgxAQjEMgEI"
+"3DMBCJw1AQi0NRYAjDYADQAAAAAAAAABAAAAAAAAAAEAAACfAAAAcAAAAAIAAAATAAAA7AIAAAMA"
+"AAAOAAAAOAMAAAQAAAABAAAA4AMAAAUAAAAaAAAA6AMAAAYAAAACAAAAuAQAAAEgAAAYAAAA+AQA"
+"AAEQAAALAAAAJBsAAAIgAACfAAAAvhsAAAMgAAAYAAAArSIAAAAgAAACAAAACycAAAAQAAABAAAA"
+"eCcAAA==";
} // namespace art
diff --git a/src/runtime_support.h b/src/runtime_support.h
index 02b176b..e104035 100644
--- a/src/runtime_support.h
+++ b/src/runtime_support.h
@@ -4,9 +4,44 @@
#define ART_SRC_RUNTIME_SUPPORT_H_
#if defined(__arm__)
+ /* Compiler helpers */
extern "C" uint64_t art_shl_long(uint64_t, uint32_t);
extern "C" uint64_t art_shr_long(uint64_t, uint32_t);
extern "C" uint64_t art_ushr_long(uint64_t, uint32_t);
+ extern int64_t artD2L(double);
+ extern int64_t artF2L(float);
+
+ /* Conversions */
+ extern "C" float __aeabi_i2f(int op1); // OP_INT_TO_FLOAT
+ extern "C" int __aeabi_f2iz(float op1); // OP_FLOAT_TO_INT
+ extern "C" float __aeabi_d2f(double op1); // OP_DOUBLE_TO_FLOAT
+ extern "C" double __aeabi_f2d(float op1); // OP_FLOAT_TO_DOUBLE
+ extern "C" double __aeabi_i2d(int op1); // OP_INT_TO_DOUBLE
+ extern "C" int __aeabi_d2iz(double op1); // OP_DOUBLE_TO_INT
+ extern "C" float __aeabi_l2f(long op1); // OP_LONG_TO_FLOAT
+ extern "C" double __aeabi_l2d(long op1); // OP_LONG_TO_DOUBLE
+
+ /* Single-precision FP arithmetics */
+ extern "C" float __aeabi_fadd(float a, float b); // OP_ADD_FLOAT[_2ADDR]
+ extern "C" float __aeabi_fsub(float a, float b); // OP_SUB_FLOAT[_2ADDR]
+ extern "C" float __aeabi_fdiv(float a, float b); // OP_DIV_FLOAT[_2ADDR]
+ extern "C" float __aeabi_fmul(float a, float b); // OP_MUL_FLOAT[_2ADDR]
+ extern "C" float fmodf(float a, float b); // OP_REM_FLOAT[_2ADDR]
+
+ /* Double-precision FP arithmetics */
+ extern "C" double __aeabi_dadd(double a, double b); // OP_ADD_DOUBLE[_2ADDR]
+ extern "C" double __aeabi_dsub(double a, double b); // OP_SUB_DOUBLE[_2ADDR]
+ extern "C" double __aeabi_ddiv(double a, double b); // OP_DIV_DOUBLE[_2ADDR]
+ extern "C" double __aeabi_dmul(double a, double b); // OP_MUL_DOUBLE[_2ADDR]
+ extern "C" double fmod(double a, double b); // OP_REM_DOUBLE[_2ADDR]
+
+ /* Integer arithmetics */
+ extern "C" int __aeabi_idivmod(int op1, int op2); // OP_REM_INT[_2ADDR|_LIT8|_LIT16]
+ extern "C" int __aeabi_idiv(int op1, int op2); // OP_DIV_INT[_2ADDR|_LIT8|_LIT16]
+
+/* Long long arithmetics - OP_REM_LONG[_2ADDR] & OP_DIV_LONG[_2ADDR] */
+extern "C" long long __aeabi_ldivmod(long long op1, long long op2);
+
#endif
#endif // ART_SRC_RUNTIME_SUPPORT_H_
diff --git a/src/thread.cc b/src/thread.cc
index 047c89d..4d9386f 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -37,34 +37,32 @@
pShlLong = art_shl_long;
pShrLong = art_shr_long;
pUshrLong = art_ushr_long;
+ pIdiv = __aeabi_idiv;
+ pIdivmod = __aeabi_idivmod;
+ pI2f = __aeabi_i2f;
+ pF2iz = __aeabi_f2iz;
+ pD2f = __aeabi_d2f;
+ pF2d = __aeabi_f2d;
+ pD2iz = __aeabi_d2iz;
+ pL2f = __aeabi_l2f;
+ pL2d = __aeabi_l2d;
+ pFadd = __aeabi_fadd;
+ pFsub = __aeabi_fsub;
+ pFdiv = __aeabi_fdiv;
+ pFmul = __aeabi_fmul;
+ pFmodf = fmodf;
+ pDadd = __aeabi_dadd;
+ pDsub = __aeabi_dsub;
+ pDdiv = __aeabi_ddiv;
+ pDmul = __aeabi_dmul;
+ pFmod = fmod;
+ pArtF2l = artF2L;
+ pArtD2l = artD2L;
+ pLdivmod = __aeabi_ldivmod;
#endif
pArtAllocArrayByClass = Array::Alloc;
pMemcpy = memcpy;
#if 0
-//void* (Thread::*pMemcpy)(void*, const void*, size_t) /* = memcpy*/ ;
-float (Thread::*pI2f)(int);
-int (Thread::*pF2iz)(float);
-float (Thread::*pD2f)(double);
-double (Thread::*pF2d)(float);
-double (Thread::*pI2d)(int);
-int (Thread::*pD2iz)(double);
-float (Thread::*pL2f)(long);
-double (Thread::*pL2d)(long);
-long long (Thread::*pArtF2l)(float);
-long long (Thread::*pArtD2l)(double);
-float (Thread::*pFadd)(float, float);
-float (Thread::*pFsub)(float, float);
-float (Thread::*pFdiv)(float, float);
-float (Thread::*pFmul)(float, float);
-float (Thread::*pFmodf)(float, float);
-double (Thread::*pDadd)(double, double);
-double (Thread::*pDsub)(double, double);
-double (Thread::*pDdiv)(double, double);
-double (Thread::*pDmul)(double, double);
-double (Thread::*pFmod)(double, double);
-int (Thread::*pIdivmod)(int, int);
-int (Thread::*pIdiv)(int, int);
-long long (Thread::*pLdivmod)(long long, long long);
bool (Thread::*pArtUnlockObject)(struct Thread*, struct Object*);
bool (Thread::*pArtCanPutArrayElementNoThrow)(const struct ClassObject*,
const struct ClassObject*);