oat file patching
Change-Id: Idbbdf19f3a77498d79d043fd33ca12ce39cafbb7
diff --git a/src/class_linker.cc b/src/class_linker.cc
index f15d46f..c65cf7d 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -1339,9 +1339,6 @@
const OatFile::OatClass* ClassLinker::GetOatClass(const DexFile& dex_file, const char* descriptor) {
DCHECK(descriptor != NULL);
- if (!Runtime::Current()->IsStarted() || Runtime::Current()->UseCompileTimeClassPath()) {
- return NULL;
- }
const OatFile* oat_file = FindOpenedOatFileForDexFile(dex_file);
CHECK(oat_file != NULL) << dex_file.GetLocation() << " " << descriptor;
const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_file.GetLocation());
@@ -1354,9 +1351,9 @@
return oat_class;
}
+// Special case to get oat code without overwriting a trampoline.
const void* ClassLinker::GetOatCodeFor(const Method* method) {
- // Special case to get oat code without overwriting a trampoline.
- CHECK(method->GetDeclaringClass()->IsInitializing());
+ CHECK(Runtime::Current()->IsCompiler() || method->GetDeclaringClass()->IsInitializing());
// Although we overwrite the trampoline of non-static methods, we may get here via the resolution
// method for direct methods (or virtual methods made direct).
Class* declaring_class = method->GetDeclaringClass();
@@ -1381,6 +1378,7 @@
}
ClassHelper kh(declaring_class);
UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(kh.GetDexFile(), kh.GetDescriptor()));
+ CHECK(oat_class.get() != NULL);
return oat_class->GetOatMethod(oat_method_index).GetCode();
}
@@ -1393,11 +1391,12 @@
if (class_data == NULL) {
return; // no fields or methods - for example a marker interface
}
- UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(dex_file, kh.GetDescriptor()));
- if (oat_class.get() == NULL) {
+ if (!Runtime::Current()->IsStarted() || Runtime::Current()->UseCompileTimeClassPath()) {
// OAT file unavailable
return;
}
+ UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(dex_file, kh.GetDescriptor()));
+ CHECK(oat_class.get() != NULL);
ClassDataItemIterator it(dex_file, class_data);
// Skip fields
while (it.HasNextStaticField()) {
@@ -1499,7 +1498,10 @@
LoadField(dex_file, it, klass, ifield);
}
- UniquePtr<const OatFile::OatClass> oat_class(GetOatClass(dex_file, descriptor));
+ UniquePtr<const OatFile::OatClass> oat_class;
+ if (Runtime::Current()->IsStarted() && !Runtime::Current()->UseCompileTimeClassPath()) {
+ oat_class.reset(GetOatClass(dex_file, descriptor));
+ }
// Load methods.
if (it.NumDirectMethods() != 0) {
diff --git a/src/compiler.cc b/src/compiler.cc
index 6a65b69..f066b0a 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -355,6 +355,14 @@
MutexLock mu(compiled_invoke_stubs_lock_);
STLDeleteValues(&compiled_invoke_stubs_);
}
+ {
+ MutexLock mu(compiled_methods_lock_);
+ STLDeleteElements(&code_to_patch_);
+ }
+ {
+ MutexLock mu(compiled_methods_lock_);
+ STLDeleteElements(&methods_to_patch_);
+ }
#if defined(ART_USE_LLVM_COMPILER)
CompilerCallbackFn f = FindFunction<CompilerCallbackFn>(MakeCompilerSoName(instruction_set_),
compiler_library_,
@@ -793,19 +801,37 @@
return false; // Incomplete knowledge needs slow path.
}
-void Compiler::AddCodePatch(DexCache* dex_cache, const DexFile* dex_file,
- uint32_t referrer_method_idx, uint32_t target_method_idx,
+void Compiler::AddCodePatch(DexCache* dex_cache,
+ const DexFile* dex_file,
+ uint32_t referrer_method_idx,
+ uint32_t referrer_access_flags,
+ uint32_t target_method_idx,
+ bool target_is_direct,
size_t literal_offset) {
MutexLock mu(compiled_methods_lock_);
- code_to_patch_.push_back(new PatchInformation(dex_cache, dex_file, referrer_method_idx,
- target_method_idx, literal_offset));
+ code_to_patch_.push_back(new PatchInformation(dex_cache,
+ dex_file,
+ referrer_method_idx,
+ referrer_access_flags,
+ target_method_idx,
+ target_is_direct,
+ literal_offset));
}
-void Compiler::AddMethodPatch(DexCache* dex_cache, const DexFile* dex_file,
- uint32_t referrer_method_idx, uint32_t target_method_idx,
+void Compiler::AddMethodPatch(DexCache* dex_cache,
+ const DexFile* dex_file,
+ uint32_t referrer_method_idx,
+ uint32_t referrer_access_flags,
+ uint32_t target_method_idx,
+ bool target_is_direct,
size_t literal_offset) {
MutexLock mu(compiled_methods_lock_);
- methods_to_patch_.push_back(new PatchInformation(dex_cache, dex_file, referrer_method_idx,
- target_method_idx, literal_offset));
+ methods_to_patch_.push_back(new PatchInformation(dex_cache,
+ dex_file,
+ referrer_method_idx,
+ referrer_access_flags,
+ target_method_idx,
+ target_is_direct,
+ literal_offset));
}
// Return true if the class should be skipped during compilation. We
diff --git a/src/compiler.h b/src/compiler.h
index b7a04bb..cd2b2c8 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -118,11 +118,19 @@
int& vtable_idx, uintptr_t& direct_code, uintptr_t& direct_method);
// Record patch information for later fix up
- void AddCodePatch(DexCache* dex_cache, const DexFile* dex_file,
- uint32_t referrer_method_idx, uint32_t target_method_idx,
+ void AddCodePatch(DexCache* dex_cache,
+ const DexFile* dex_file,
+ uint32_t referrer_method_idx,
+ uint32_t referrer_access_flags,
+ uint32_t target_method_idx,
+ bool target_is_direct,
size_t literal_offset);
- void AddMethodPatch(DexCache* dex_cache, const DexFile* dex_file,
- uint32_t referrer_method_idx, uint32_t target_method_idx,
+ void AddMethodPatch(DexCache* dex_cache,
+ const DexFile* dex_file,
+ uint32_t referrer_method_idx,
+ uint32_t referrer_access_flags,
+ uint32_t target_method_idx,
+ bool target_is_direct,
size_t literal_offset);
#if defined(ART_USE_LLVM_COMPILER)
@@ -140,6 +148,66 @@
return compiler_context_;
}
+ class PatchInformation {
+ public:
+ DexCache* GetDexCache() const {
+ return dex_cache_;
+ }
+ const DexFile& GetDexFile() const {
+ return *dex_file_;
+ }
+ uint32_t GetReferrerMethodIdx() const {
+ return referrer_method_idx_;
+ }
+ bool GetReferrerIsDirect() const {
+ return referrer_is_direct_;
+ }
+ uint32_t GetTargetMethodIdx() const {
+ return target_method_idx_;
+ }
+ bool GetTargetIsDirect() const {
+ return target_is_direct_;
+ }
+ size_t GetLiteralOffset() const {;
+ return literal_offset_;
+ }
+
+ private:
+ PatchInformation(DexCache* dex_cache,
+ const DexFile* dex_file,
+ uint32_t referrer_method_idx,
+ uint32_t referrer_access_flags,
+ uint32_t target_method_idx,
+ uint32_t target_is_direct,
+ size_t literal_offset)
+ : dex_cache_(dex_cache),
+ dex_file_(dex_file),
+ referrer_method_idx_(referrer_method_idx),
+ referrer_is_direct_(Method::IsDirect(referrer_access_flags)),
+ target_method_idx_(target_method_idx),
+ target_is_direct_(target_is_direct),
+ literal_offset_(literal_offset) {
+ CHECK(dex_file_ != NULL);
+ }
+
+ DexCache* dex_cache_;
+ const DexFile* dex_file_;
+ uint32_t referrer_method_idx_;
+ bool referrer_is_direct_;
+ uint32_t target_method_idx_;
+ bool target_is_direct_;
+ size_t literal_offset_;
+
+ friend class Compiler;
+ };
+
+ const std::vector<const PatchInformation*>& GetCodeToPatch() const {
+ return code_to_patch_;
+ }
+ const std::vector<const PatchInformation*>& GetMethodsToPatch() const {
+ return methods_to_patch_;
+ }
+
private:
// Compute constant code and method pointers when possible
@@ -181,24 +249,8 @@
void InsertInvokeStub(bool is_static, const char* shorty,
const CompiledInvokeStub* compiled_invoke_stub);
- class PatchInformation {
- public:
- PatchInformation(DexCache* dex_cache, const DexFile* dex_file,
- uint32_t referrer_method_idx, uint32_t target_method_idx,
- size_t literal_offset) :
- dex_cache_(dex_cache), dex_file_(dex_file),
- referrer_method_idx_(referrer_method_idx),
- target_method_idx_(target_method_idx),
- literal_offset_(literal_offset) {}
- private:
- DexCache* dex_cache_;
- const DexFile* dex_file_;
- uint32_t referrer_method_idx_;
- uint32_t target_method_idx_;
- size_t literal_offset_;
- };
- std::vector<PatchInformation*> code_to_patch_;
- std::vector<PatchInformation*> methods_to_patch_;
+ std::vector<const PatchInformation*> code_to_patch_;
+ std::vector<const PatchInformation*> methods_to_patch_;
InstructionSet instruction_set_;
diff --git a/src/compiler/codegen/CodegenUtil.cc b/src/compiler/codegen/CodegenUtil.cc
index 0226fac..c9c9c5e 100644
--- a/src/compiler/codegen/CodegenUtil.cc
+++ b/src/compiler/codegen/CodegenUtil.cc
@@ -590,6 +590,11 @@
}
}
+bool IsDirect(int invokeType) {
+ InvokeType type = static_cast<InvokeType>(invokeType);
+ return type == kStatic || type == kDirect;
+}
+
/* Write the literal pool to the output stream */
void installLiteralPools(CompilationUnit* cUnit)
{
@@ -603,20 +608,32 @@
dataLIR = cUnit->codeLiteralList;
if (dataLIR != NULL) {
while (dataLIR != NULL) {
+ uint32_t target = dataLIR->operands[0];
cUnit->compiler->AddCodePatch(cUnit->dex_cache, cUnit->dex_file,
cUnit->method_idx,
- dataLIR->operands[0],
+ cUnit->access_flags,
+ target,
+ IsDirect(dataLIR->operands[1]),
cUnit->codeBuffer.size());
- pushWord(cUnit->codeBuffer, 0xEBAD9A7C); // value to be patched
+ const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
+ // unique based on target to ensure code deduplication works
+ uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id);
+ pushWord(cUnit->codeBuffer, unique_patch_value);
dataLIR = NEXT_LIR(dataLIR);
}
dataLIR = cUnit->methodLiteralList;
while (dataLIR != NULL) {
+ uint32_t target = dataLIR->operands[0];
cUnit->compiler->AddMethodPatch(cUnit->dex_cache, cUnit->dex_file,
cUnit->method_idx,
- dataLIR->operands[0],
+ cUnit->access_flags,
+ target,
+ IsDirect(dataLIR->operands[1]),
cUnit->codeBuffer.size());
- pushWord(cUnit->codeBuffer, 0xEBAD9A7D); // value to be patched
+ const DexFile::MethodId& id = cUnit->dex_file->GetMethodId(target);
+ // unique based on target to ensure code deduplication works
+ uint32_t unique_patch_value = reinterpret_cast<uint32_t>(&id);
+ pushWord(cUnit->codeBuffer, unique_patch_value);
dataLIR = NEXT_LIR(dataLIR);
}
}
diff --git a/src/compiler/codegen/GenInvoke.cc b/src/compiler/codegen/GenInvoke.cc
index 2810936..4847ef8 100644
--- a/src/compiler/codegen/GenInvoke.cc
+++ b/src/compiler/codegen/GenInvoke.cc
@@ -22,10 +22,9 @@
* and "op" calls may be used here.
*/
-
typedef int (*NextCallInsn)(CompilationUnit*, MIR*, int, uint32_t dexIdx,
uint32_t methodIdx, uintptr_t directCode,
- uintptr_t directMethod);
+ uintptr_t directMethod, InvokeType type);
/*
* If there are any ins passed in registers that have not been promoted
* to a callee-save register, flush them to the frame. Perform intial
@@ -137,8 +136,13 @@
*/
int nextSDCallInsn(CompilationUnit* cUnit, MIR* mir,
int state, uint32_t dexIdx, uint32_t unused,
- uintptr_t directCode, uintptr_t directMethod)
+ uintptr_t directCode, uintptr_t directMethod,
+ InvokeType type)
{
+#if !defined(TARGET_ARM)
+ directCode = 0;
+ directMethod = 0;
+#endif
if (directCode != 0 && directMethod != 0) {
switch(state) {
case 0: // Get the current Method* [sets rARG0]
@@ -148,6 +152,7 @@
LIR* dataTarget = scanLiteralPool(cUnit->codeLiteralList, dexIdx, 0);
if (dataTarget == NULL) {
dataTarget = addWordData(cUnit, &cUnit->codeLiteralList, dexIdx);
+ dataTarget->operands[1] = type;
}
#if defined(TARGET_ARM)
LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset,
@@ -163,6 +168,7 @@
LIR* dataTarget = scanLiteralPool(cUnit->methodLiteralList, dexIdx, 0);
if (dataTarget == NULL) {
dataTarget = addWordData(cUnit, &cUnit->methodLiteralList, dexIdx);
+ dataTarget->operands[1] = type;
}
#if defined(TARGET_ARM)
LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset,
@@ -194,6 +200,7 @@
LIR* dataTarget = scanLiteralPool(cUnit->codeLiteralList, dexIdx, 0);
if (dataTarget == NULL) {
dataTarget = addWordData(cUnit, &cUnit->codeLiteralList, dexIdx);
+ dataTarget->operands[1] = type;
}
#if defined(TARGET_ARM)
LIR* loadPcRel = rawLIR(cUnit, cUnit->currentDalvikOffset,
@@ -234,7 +241,7 @@
*/
int nextVCallInsn(CompilationUnit* cUnit, MIR* mir,
int state, uint32_t dexIdx, uint32_t methodIdx,
- uintptr_t unused, uintptr_t unused2)
+ uintptr_t unused, uintptr_t unused2, InvokeType unused3)
{
RegLocation rlArg;
/*
@@ -294,7 +301,8 @@
int nextStaticCallInsnSP(CompilationUnit* cUnit, MIR* mir,
int state, uint32_t dexIdx, uint32_t methodIdx,
- uintptr_t unused, uintptr_t unused2)
+ uintptr_t unused, uintptr_t unused2,
+ InvokeType unused3)
{
int trampoline = OFFSETOF_MEMBER(Thread, pInvokeStaticTrampolineWithAccessCheck);
return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
@@ -302,7 +310,7 @@
int nextDirectCallInsnSP(CompilationUnit* cUnit, MIR* mir, int state,
uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused,
- uintptr_t unused2)
+ uintptr_t unused2, InvokeType unused3)
{
int trampoline = OFFSETOF_MEMBER(Thread, pInvokeDirectTrampolineWithAccessCheck);
return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
@@ -310,7 +318,7 @@
int nextSuperCallInsnSP(CompilationUnit* cUnit, MIR* mir, int state,
uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused,
- uintptr_t unused2)
+ uintptr_t unused2, InvokeType unused3)
{
int trampoline = OFFSETOF_MEMBER(Thread, pInvokeSuperTrampolineWithAccessCheck);
return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
@@ -318,7 +326,7 @@
int nextVCallInsnSP(CompilationUnit* cUnit, MIR* mir, int state,
uint32_t dexIdx, uint32_t methodIdx, uintptr_t unused,
- uintptr_t unused2)
+ uintptr_t unused2, InvokeType unused3)
{
int trampoline = OFFSETOF_MEMBER(Thread, pInvokeVirtualTrampolineWithAccessCheck);
return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
@@ -330,7 +338,7 @@
*/
int nextInterfaceCallInsn(CompilationUnit* cUnit, MIR* mir, int state,
uint32_t dexIdx, uint32_t unused, uintptr_t unused2,
- uintptr_t unused3)
+ uintptr_t unused3, InvokeType unused4)
{
int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampoline);
return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
@@ -339,7 +347,7 @@
int nextInterfaceCallInsnWithAccessCheck(CompilationUnit* cUnit, MIR* mir,
int state, uint32_t dexIdx,
uint32_t unused, uintptr_t unused2,
- uintptr_t unused3)
+ uintptr_t unused3, InvokeType unused4)
{
int trampoline = OFFSETOF_MEMBER(Thread, pInvokeInterfaceTrampolineWithAccessCheck);
return nextInvokeInsnSP(cUnit, mir, trampoline, state, dexIdx, 0);
@@ -348,7 +356,7 @@
int loadArgRegs(CompilationUnit* cUnit, MIR* mir, DecodedInstruction* dInsn,
int callState, NextCallInsn nextCallInsn, uint32_t dexIdx,
uint32_t methodIdx, uintptr_t directCode,
- uintptr_t directMethod, bool skipThis)
+ uintptr_t directMethod, InvokeType type, bool skipThis)
{
#if !defined(TARGET_X86)
int lastArgReg = rARG3;
@@ -373,7 +381,7 @@
loadValueDirectFixed(cUnit, rlArg, nextReg);
}
callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
- directCode, directMethod);
+ directCode, directMethod, type);
}
return callState;
}
@@ -390,7 +398,7 @@
LIR** pcrLabel, NextCallInsn nextCallInsn,
uint32_t dexIdx, uint32_t methodIdx,
uintptr_t directCode, uintptr_t directMethod,
- bool skipThis)
+ InvokeType type, bool skipThis)
{
RegLocation rlArg;
@@ -399,7 +407,7 @@
return callState;
callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
- directCode, directMethod);
+ directCode, directMethod, type);
DCHECK_LE(dInsn->vA, 5U);
if (dInsn->vA > 3) {
@@ -425,12 +433,13 @@
loadWordDisp(cUnit, rSP,
oatSRegOffset(cUnit, rlArg.sRegLow) + 4, reg);
callState = nextCallInsn(cUnit, mir, callState, dexIdx,
- methodIdx, directCode, directMethod);
+ methodIdx, directCode, directMethod,
+ type);
}
storeBaseDisp(cUnit, rSP, (nextUse + 1) * 4, reg, kWord);
storeBaseDisp(cUnit, rSP, 16 /* (3+1)*4 */, reg, kWord);
callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
- directCode, directMethod);
+ directCode, directMethod, type);
nextUse++;
}
// Loop through the rest
@@ -455,7 +464,8 @@
loadValueDirectFixed(cUnit, rlArg, lowReg);
}
callState = nextCallInsn(cUnit, mir, callState, dexIdx,
- methodIdx, directCode, directMethod);
+ methodIdx, directCode, directMethod,
+ type);
}
int outsOffset = (nextUse + 1) * 4;
if (rlArg.wide) {
@@ -466,13 +476,13 @@
nextUse++;
}
callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
- directCode, directMethod);
+ directCode, directMethod, type);
}
}
callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
dexIdx, methodIdx, directCode, directMethod,
- skipThis);
+ type, skipThis);
if (pcrLabel) {
*pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), rARG1, mir);
@@ -500,7 +510,7 @@
LIR** pcrLabel, NextCallInsn nextCallInsn,
uint32_t dexIdx, uint32_t methodIdx,
uintptr_t directCode, uintptr_t directMethod,
- bool skipThis)
+ InvokeType type, bool skipThis)
{
int firstArg = dInsn->vC;
int numArgs = dInsn->vA;
@@ -509,7 +519,7 @@
if (numArgs <= 5)
return genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pcrLabel,
nextCallInsn, dexIdx, methodIdx,
- directCode, directMethod, skipThis);
+ directCode, directMethod, type, skipThis);
/*
* Make sure range list doesn't span the break between in normal
* Dalvik vRegs and the ins.
@@ -567,32 +577,32 @@
// Use vldm/vstm pair using rARG3 as a temp
int regsLeft = std::min(numArgs - 3, 16);
callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
- directCode, directMethod);
+ directCode, directMethod, type);
opRegRegImm(cUnit, kOpAdd, rARG3, rSP, startOffset);
LIR* ld = newLIR3(cUnit, kThumb2Vldms, rARG3, fr0, regsLeft);
//TUNING: loosen barrier
ld->defMask = ENCODE_ALL;
setMemRefType(ld, true /* isLoad */, kDalvikReg);
callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
- directCode, directMethod);
+ directCode, directMethod, type);
opRegRegImm(cUnit, kOpAdd, rARG3, rSP, 4 /* Method* */ + (3 * 4));
callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
- directCode, directMethod);
+ directCode, directMethod, type);
LIR* st = newLIR3(cUnit, kThumb2Vstms, rARG3, fr0, regsLeft);
setMemRefType(st, false /* isLoad */, kDalvikReg);
st->defMask = ENCODE_ALL;
callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
- directCode, directMethod);
+ directCode, directMethod, type);
}
#endif
callState = loadArgRegs(cUnit, mir, dInsn, callState, nextCallInsn,
dexIdx, methodIdx, directCode, directMethod,
- skipThis);
+ type, skipThis);
callState = nextCallInsn(cUnit, mir, callState, dexIdx, methodIdx,
- directCode, directMethod);
+ directCode, directMethod, type);
if (pcrLabel) {
*pcrLabel = genNullCheck(cUnit, oatSSASrc(mir,0), rARG1, mir);
}
diff --git a/src/compiler/codegen/MethodCodegenDriver.cc b/src/compiler/codegen/MethodCodegenDriver.cc
index 59aa4ca..8f4df47 100644
--- a/src/compiler/codegen/MethodCodegenDriver.cc
+++ b/src/compiler/codegen/MethodCodegenDriver.cc
@@ -55,6 +55,7 @@
void genInvoke(CompilationUnit* cUnit, MIR* mir, InvokeType type, bool isRange)
{
DecodedInstruction* dInsn = &mir->dalvikInsn;
+ InvokeType originalType = type; // avoiding mutation by ComputeInvokeInfo
int callState = 0;
LIR* nullCk;
LIR** pNullCk = NULL;
@@ -103,16 +104,19 @@
if (!isRange) {
callState = genDalvikArgsNoRange(cUnit, mir, dInsn, callState, pNullCk,
nextCallInsn, dexMethodIdx,
- vtableIdx, directCode, directMethod, skipThis);
+ vtableIdx, directCode, directMethod,
+ originalType, skipThis);
} else {
callState = genDalvikArgsRange(cUnit, mir, dInsn, callState, pNullCk,
nextCallInsn, dexMethodIdx, vtableIdx,
- directCode, directMethod, skipThis);
+ directCode, directMethod, originalType,
+ skipThis);
}
// Finish up any of the call sequence not interleaved in arg loading
while (callState >= 0) {
callState = nextCallInsn(cUnit, mir, callState, dexMethodIdx,
- vtableIdx, directCode, directMethod);
+ vtableIdx, directCode, directMethod,
+ originalType);
}
if (DISPLAY_MISSING_TARGETS) {
genShowTarget(cUnit);
diff --git a/src/dex2oat.cc b/src/dex2oat.cc
index f75aeb7..794c6d2 100644
--- a/src/dex2oat.cc
+++ b/src/dex2oat.cc
@@ -198,16 +198,16 @@
return image_classes.release();
}
- bool CreateOatFile(const std::string& boot_image_option,
- const std::string& host_prefix,
- const std::vector<const DexFile*>& dex_files,
- File* oat_file,
+ const Compiler* CreateOatFile(const std::string& boot_image_option,
+ const std::string& host_prefix,
+ const std::vector<const DexFile*>& dex_files,
+ File* oat_file,
#if defined(ART_USE_LLVM_COMPILER)
- std::string const& elf_filename,
- std::string const& bitcode_filename,
+ std::string const& elf_filename,
+ std::string const& bitcode_filename,
#endif
- bool image,
- const std::set<std::string>* image_classes) {
+ bool image,
+ const std::set<std::string>* image_classes) {
// SirtRef and ClassLoader creation needs to come after Runtime::Create
UniquePtr<SirtRef<ClassLoader> > class_loader(new SirtRef<ClassLoader>(NULL));
if (class_loader.get() == NULL) {
@@ -225,14 +225,18 @@
class_loader.get()->reset(PathClassLoader::AllocCompileTime(class_path_files));
}
- Compiler compiler(instruction_set_, image, thread_count_, support_debugging_, image_classes);
+ UniquePtr<Compiler> compiler(new Compiler(instruction_set_,
+ image,
+ thread_count_,
+ support_debugging_,
+ image_classes));
#if defined(ART_USE_LLVM_COMPILER)
- compiler.SetElfFileName(elf_filename);
- compiler.SetBitcodeFileName(bitcode_filename);
+ compiler->SetElfFileName(elf_filename);
+ compiler->SetBitcodeFileName(bitcode_filename);
#endif
- compiler.CompileAll(class_loader->get(), dex_files);
+ compiler->CompileAll(class_loader->get(), dex_files);
std::string image_file_location;
uint32_t image_file_location_checksum = 0;
@@ -251,20 +255,21 @@
dex_files,
image_file_location_checksum,
image_file_location,
- compiler)) {
+ *compiler.get())) {
LOG(ERROR) << "Failed to create oat file " << oat_file->name();
- return false;
+ return NULL;
}
- return true;
+ return compiler.release();
}
bool CreateImageFile(const std::string& image_filename,
uintptr_t image_base,
const std::set<std::string>* image_classes,
const std::string& oat_filename,
- const std::string& oat_location) {
+ const std::string& oat_location,
+ const Compiler& compiler) {
ImageWriter image_writer(image_classes);
- if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location)) {
+ if (!image_writer.Write(image_filename, image_base, oat_filename, oat_location, compiler)) {
LOG(ERROR) << "Failed to create image file " << image_filename;
return false;
}
@@ -704,16 +709,18 @@
}
}
- if (!dex2oat->CreateOatFile(boot_image_option,
- host_prefix,
- dex_files,
- oat_file.get(),
+ UniquePtr<const Compiler> compiler(dex2oat->CreateOatFile(boot_image_option,
+ host_prefix,
+ dex_files,
+ oat_file.get(),
#if defined(ART_USE_LLVM_COMPILER)
- elf_filename,
- bitcode_filename,
+ elf_filename,
+ bitcode_filename,
#endif
- image,
- image_classes.get())) {
+ image,
+ image_classes.get()));
+
+ if (compiler.get() == NULL) {
LOG(ERROR) << "Failed to create oat file: " << oat_location;
return EXIT_FAILURE;
}
@@ -730,7 +737,8 @@
image_base,
image_classes.get(),
oat_filename,
- oat_location)) {
+ oat_location,
+ *compiler.get())) {
return EXIT_FAILURE;
}
diff --git a/src/image_test.cc b/src/image_test.cc
index cf7c876..5662239 100644
--- a/src/image_test.cc
+++ b/src/image_test.cc
@@ -49,7 +49,8 @@
ScratchFile tmp_image;
const uintptr_t requested_image_base = 0x60000000;
bool success_image = writer.Write(tmp_image.GetFilename(), requested_image_base,
- tmp_oat.GetFilename(), tmp_oat.GetFilename());
+ tmp_oat.GetFilename(), tmp_oat.GetFilename(),
+ *compiler_.get());
ASSERT_TRUE(success_image);
{
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 40f5d5f..fdee834 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -24,6 +24,7 @@
#include "class_linker.h"
#include "class_loader.h"
#include "compiled_method.h"
+#include "compiler.h"
#include "dex_cache.h"
#include "file.h"
#include "globals.h"
@@ -42,7 +43,8 @@
bool ImageWriter::Write(const std::string& image_filename,
uintptr_t image_begin,
const std::string& oat_filename,
- const std::string& oat_location) {
+ const std::string& oat_location,
+ const Compiler& compiler) {
CHECK(!image_filename.empty());
CHECK_NE(image_begin, 0U);
@@ -60,11 +62,12 @@
}
}
- oat_file_.reset(OatFile::Open(oat_filename, oat_location, NULL));
- if (oat_file_.get() == NULL) {
+ oat_file_ = OatFile::Open(oat_filename, oat_location, NULL, true);
+ if (oat_file_ == NULL) {
LOG(ERROR) << "Failed to open oat file " << oat_filename;
return false;
}
+ class_linker->RegisterOatFile(*oat_file_);
PruneNonImageClasses(); // Remove junk
ComputeLazyFieldsForImageClasses(); // Add useful information
@@ -80,6 +83,7 @@
heap->DisableCardMarking();
CalculateNewObjectOffsets();
CopyAndFixupObjects();
+ PatchOatCodeAndMethods(compiler);
UniquePtr<File> file(OS::OpenFile(image_filename.c_str(), true));
if (file.get() == NULL) {
@@ -529,4 +533,70 @@
}
}
+static Method* GetReferrerMethod(const Compiler::PatchInformation* patch) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Method* method = class_linker->ResolveMethod(patch->GetDexFile(),
+ patch->GetReferrerMethodIdx(),
+ patch->GetDexCache(),
+ NULL,
+ patch->GetReferrerIsDirect());
+ CHECK(method != NULL)
+ << patch->GetDexFile().GetLocation() << " " << patch->GetReferrerMethodIdx();
+ return method;
+}
+
+static Method* GetTargetMethod(const Compiler::PatchInformation* patch) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Method* method = class_linker->ResolveMethod(patch->GetDexFile(),
+ patch->GetTargetMethodIdx(),
+ patch->GetDexCache(),
+ NULL,
+ patch->GetTargetIsDirect());
+ CHECK(method != NULL)
+ << patch->GetDexFile().GetLocation() << " " << patch->GetTargetMethodIdx();
+ return method;
+}
+
+void ImageWriter::PatchOatCodeAndMethods(const Compiler& compiler) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+
+ const std::vector<const Compiler::PatchInformation*>& code_to_patch = compiler.GetCodeToPatch();
+ for (size_t i = 0; i < code_to_patch.size(); i++) {
+ const Compiler::PatchInformation* patch = code_to_patch[i];
+ Method* target = GetTargetMethod(patch);
+ uint32_t code = reinterpret_cast<uint32_t>(class_linker->GetOatCodeFor(target));
+ uint32_t code_base = reinterpret_cast<uint32_t>(&oat_file_->GetOatHeader());
+ uint32_t code_offset = code - code_base;
+ SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetOatAddress(code_offset)));
+ }
+
+ const std::vector<const Compiler::PatchInformation*>& methods_to_patch
+ = compiler.GetMethodsToPatch();
+ for (size_t i = 0; i < methods_to_patch.size(); i++) {
+ const Compiler::PatchInformation* patch = methods_to_patch[i];
+ Method* target = GetTargetMethod(patch);
+ SetPatchLocation(patch, reinterpret_cast<uint32_t>(GetImageAddress(target)));
+ }
+}
+
+void ImageWriter::SetPatchLocation(const Compiler::PatchInformation* patch, uint32_t value) {
+ ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+ Method* method = GetReferrerMethod(patch);
+ // Goodbye const, we are about to modify some code.
+ void* code = const_cast<void*>(class_linker->GetOatCodeFor(method));
+ // TODO: make this Thumb2 specific
+ uint8_t* base = reinterpret_cast<uint8_t*>(reinterpret_cast<uint32_t>(code) & ~0x1);
+ uint32_t* patch_location = reinterpret_cast<uint32_t*>(base + patch->GetLiteralOffset());
+#ifndef NDEBUG
+ const DexFile::MethodId& id = patch->GetDexFile().GetMethodId(patch->GetTargetMethodIdx());
+ uint32_t expected = reinterpret_cast<uint32_t>(&id);
+ uint32_t actual = *patch_location;
+ CHECK(actual == expected || actual == value) << std::hex
+ << "actual=" << actual
+ << "expected=" << expected
+ << "value=" << value;
+#endif
+ *patch_location = value;
+}
+
} // namespace art
diff --git a/src/image_writer.h b/src/image_writer.h
index 35a3c02..f62bea1 100644
--- a/src/image_writer.h
+++ b/src/image_writer.h
@@ -24,6 +24,7 @@
#include <set>
#include <string>
+#include "compiler.h"
#include "dex_cache.h"
#include "mem_map.h"
#include "oat_file.h"
@@ -46,7 +47,8 @@
bool Write(const std::string& image_filename,
uintptr_t image_begin,
const std::string& oat_filename,
- const std::string& oat_location);
+ const std::string& oat_location,
+ const Compiler& compiler);
private:
bool AllocMemory();
@@ -137,10 +139,13 @@
void FixupStaticFields(const Class* orig, Class* copy);
void FixupFields(const Object* orig, Object* copy, uint32_t ref_offsets, bool is_static);
+ void PatchOatCodeAndMethods(const Compiler& compiler);
+ void SetPatchLocation(const Compiler::PatchInformation* patch, uint32_t value);
+
std::map<const Object*, size_t> offsets_;
// oat file with code for this image
- UniquePtr<OatFile> oat_file_;
+ OatFile* oat_file_;
// Space we are writing objects from
const Space* source_space_;
diff --git a/src/oat_file.cc b/src/oat_file.cc
index e72944e..6ae502c 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -33,20 +33,22 @@
OatFile* OatFile::Open(const std::string& filename,
const std::string& location,
- byte* requested_base) {
+ byte* requested_base,
+ bool writable) {
CHECK(!location.empty()) << filename;
- UniquePtr<File> file(OS::OpenFile(filename.c_str(), false));
+ UniquePtr<File> file(OS::OpenFile(filename.c_str(), writable, false));
if (file.get() == NULL) {
- return false;
+ return NULL;
}
- return Open(*file.get(), location, requested_base);
+ return Open(*file.get(), location, requested_base, writable);
}
OatFile* OatFile::Open(File& file,
const std::string& location,
- byte* requested_base) {
+ byte* requested_base,
+ bool writable) {
UniquePtr<OatFile> oat_file(new OatFile(location));
- bool success = oat_file->Read(file, requested_base);
+ bool success = oat_file->Map(file, requested_base, writable);
if (!success) {
return NULL;
}
@@ -61,7 +63,7 @@
STLDeleteValues(&oat_dex_files_);
}
-bool OatFile::Read(File& file, byte* requested_base) {
+bool OatFile::Map(File& file, byte* requested_base, bool writable) {
OatHeader oat_header;
bool success = file.ReadFully(&oat_header, sizeof(oat_header));
@@ -70,10 +72,21 @@
return false;
}
- int flags = MAP_PRIVATE | ((requested_base != NULL) ? MAP_FIXED : 0);
+ int flags = 0;
+ int prot = 0;
+ if (writable) {
+ flags |= MAP_SHARED; // So changes will write through to file
+ prot |= (PROT_READ | PROT_WRITE);
+ } else {
+ flags |= MAP_PRIVATE;
+ prot |= PROT_READ;
+ }
+ if (requested_base != NULL) {
+ flags |= MAP_FIXED;
+ }
UniquePtr<MemMap> map(MemMap::MapFileAtAddress(requested_base,
file.Length(),
- PROT_READ,
+ prot,
flags,
file.Fd(),
0));
@@ -89,7 +102,7 @@
if (code_offset < file.Length()) {
byte* code_address = map->Begin() + code_offset;
size_t code_length = file.Length() - code_offset;
- if (mprotect(code_address, code_length, PROT_READ | PROT_EXEC) != 0) {
+ if (mprotect(code_address, code_length, prot | PROT_EXEC) != 0) {
PLOG(ERROR) << "Failed to make oat code executable in " << GetLocation();
return false;
}
diff --git a/src/oat_file.h b/src/oat_file.h
index 9fcba2f..d75c7c7 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -37,12 +37,14 @@
// optionally be used to request where the file should be loaded.
static OatFile* Open(const std::string& filename,
const std::string& location,
- byte* requested_base);
+ byte* requested_base,
+ bool writable=false);
// Open an oat file from an already opened File with the given location.
static OatFile* Open(File& file,
const std::string& location,
- byte* requested_base);
+ byte* requested_base,
+ bool writable=false);
~OatFile();
@@ -219,7 +221,7 @@
private:
explicit OatFile(const std::string& filename);
- bool Read(File& file, byte* requested_base);
+ bool Map(File& file, byte* requested_base, bool writable);
const byte* Begin() const;
const byte* End() const;
diff --git a/src/object.h b/src/object.h
index a609433..62d5fed 100644
--- a/src/object.h
+++ b/src/object.h
@@ -529,7 +529,11 @@
// Returns true if the method is static, private, or a constructor.
bool IsDirect() const {
- return IsStatic() || IsPrivate() || IsConstructor();
+ return IsDirect(GetAccessFlags());
+ }
+
+ static bool IsDirect(uint32_t access_flags) {
+ return (access_flags & (kAccStatic | kAccPrivate | kAccConstructor)) != 0;
}
// Returns true if the method is declared synchronized.
diff --git a/src/os.h b/src/os.h
index e73d9ff..3d7c0fa 100644
--- a/src/os.h
+++ b/src/os.h
@@ -27,7 +27,7 @@
public:
// Open a file. The returned file must be deleted by the caller.
- static File* OpenFile(const char* name, bool writable);
+ static File* OpenFile(const char* name, bool writable, bool create=true);
// Create a file from an already open file descriptor
static File* FileFromFd(const char* name, int fd);
diff --git a/src/os_linux.cc b/src/os_linux.cc
index 5974c00..b91f1ff 100644
--- a/src/os_linux.cc
+++ b/src/os_linux.cc
@@ -25,10 +25,15 @@
namespace art {
-File* OS::OpenFile(const char* name, bool writable) {
- int flags = O_RDONLY;
+File* OS::OpenFile(const char* name, bool writable, bool create) {
+ int flags = 0;
if (writable) {
- flags = (O_RDWR | O_CREAT | O_TRUNC);
+ flags |= O_RDWR;
+ if (create) {
+ flags |= (O_CREAT | O_TRUNC);
+ }
+ } else {
+ flags |= O_RDONLY;
}
int fd = open(name, flags, 0666);
if (fd < 0) {