Skip to content

Commit

Permalink
android: Fix IP0/IP1 register clobber on arm64
Browse files Browse the repository at this point in the history
We need to determine which of these the ART quick code is using, picking
the one unused, and also make sure we don't relocate code beyond the
point where both registers are taken.
  • Loading branch information
oleavr committed Jun 3, 2022
1 parent c87109d commit d4d2a42
Showing 1 changed file with 48 additions and 14 deletions.
62 changes: 48 additions & 14 deletions lib/android.js
Original file line number Diff line number Diff line change
Expand Up @@ -2786,7 +2786,7 @@ const artQuickCodeReplacementTrampolineWriters = {
arm64: writeArtQuickCodeReplacementTrampolineArm64
};

function writeArtQuickCodeReplacementTrampolineIA32 (trampoline, target, redirectSize, vm) {
function writeArtQuickCodeReplacementTrampolineIA32 (trampoline, target, redirectSize, constraints, vm) {
const threadOffsets = getArtThreadSpec(vm).offset;
const artMethodOffsets = getArtMethodSpec(vm).offset;

Expand Down Expand Up @@ -2849,7 +2849,7 @@ function writeArtQuickCodeReplacementTrampolineIA32 (trampoline, target, redirec
return offset;
}

function writeArtQuickCodeReplacementTrampolineX64 (trampoline, target, redirectSize, vm) {
function writeArtQuickCodeReplacementTrampolineX64 (trampoline, target, redirectSize, constraints, vm) {
const threadOffsets = getArtThreadSpec(vm).offset;
const artMethodOffsets = getArtMethodSpec(vm).offset;

Expand Down Expand Up @@ -2912,7 +2912,7 @@ function writeArtQuickCodeReplacementTrampolineX64 (trampoline, target, redirect
return offset;
}

function writeArtQuickCodeReplacementTrampolineArm (trampoline, target, redirectSize, vm) {
function writeArtQuickCodeReplacementTrampolineArm (trampoline, target, redirectSize, constraints, vm) {
const artMethodOffsets = getArtMethodSpec(vm).offset;

const targetAddress = target.and(THUMB_BIT_REMOVAL_MASK);
Expand Down Expand Up @@ -2999,7 +2999,7 @@ function writeArtQuickCodeReplacementTrampolineArm (trampoline, target, redirect
return offset;
}

function writeArtQuickCodeReplacementTrampolineArm64 (trampoline, target, redirectSize, vm) {
function writeArtQuickCodeReplacementTrampolineArm64 (trampoline, target, redirectSize, { availableScratchRegs }, vm) {
const artMethodOffsets = getArtMethodSpec(vm).offset;

let offset;
Expand Down Expand Up @@ -3068,8 +3068,9 @@ function writeArtQuickCodeReplacementTrampolineArm64 (trampoline, target, redire
relocator.writeAll();

if (!relocator.eoi) {
writer.putLdrRegAddress('x17', target.add(offset));
writer.putBrReg('x17');
const scratchReg = Array.from(availableScratchRegs)[0];
writer.putLdrRegAddress(scratchReg, target.add(offset));
writer.putBrReg(scratchReg);
}

writer.putLabel('invoke_replacement');
Expand Down Expand Up @@ -3146,7 +3147,7 @@ class ArtQuickCodeInterceptor {
this.overwrittenPrologueLength = 0;
}

_canRelocateCode (relocationSize) {
_canRelocateCode (relocationSize, constraints) {
const Writer = thunkWriters[Process.arch];
const Relocator = thunkRelocators[Process.arch];

Expand All @@ -3156,14 +3157,44 @@ class ArtQuickCodeInterceptor {
const relocator = new Relocator(quickCodeAddress, writer);

let offset;
do {
offset = relocator.readOne();
} while (offset < relocationSize && !relocator.eoi);
if (Process.arch === 'arm64') {
let availableScratchRegs = new Set(['x16', 'x17']);

do {
const nextOffset = relocator.readOne();

const nextScratchRegs = new Set(availableScratchRegs);
const { read, written } = relocator.input.regsAccessed;
for (const regs of [read, written]) {
for (const reg of regs) {
let name;
if (reg.startsWith('w')) {
name = 'x' + reg.substring(1);
} else {
name = reg;
}
nextScratchRegs.delete(name);
}
}
if (nextScratchRegs.size === 0) {
break;
}

offset = nextOffset;
availableScratchRegs = nextScratchRegs;
} while (offset < relocationSize && !relocator.eoi);

constraints.availableScratchRegs = availableScratchRegs;
} else {
do {
offset = relocator.readOne();
} while (offset < relocationSize && !relocator.eoi);
}

return offset >= relocationSize;
}

_createTrampoline () {
_allocateTrampoline () {
if (trampolineAllocator === null) {
const trampolineSize = (pointerSize === 4) ? 128 : 256;
trampolineAllocator = makeCodeAllocator(trampolineSize);
Expand All @@ -3173,7 +3204,8 @@ class ArtQuickCodeInterceptor {

let redirectSize, spec;
let alignment = 1;
if (pointerSize === 4 || this._canRelocateCode(maxRedirectSize)) {
const constraints = {};
if (pointerSize === 4 || this._canRelocateCode(maxRedirectSize, constraints)) {
redirectSize = maxRedirectSize;

spec = {};
Expand All @@ -3193,19 +3225,21 @@ class ArtQuickCodeInterceptor {

this.redirectSize = redirectSize;
this.trampoline = trampolineAllocator.allocateSlice(spec, alignment);

return constraints;
}

_destroyTrampoline () {
trampolineAllocator.freeSlice(this.trampoline);
}

activate (vm) {
this._createTrampoline();
const constraints = this._allocateTrampoline();

const { trampoline, quickCode, redirectSize } = this;

const writeTrampoline = artQuickCodeReplacementTrampolineWriters[Process.arch];
const prologueLength = writeTrampoline(trampoline, quickCode, redirectSize, vm);
const prologueLength = writeTrampoline(trampoline, quickCode, redirectSize, constraints, vm);
this.overwrittenPrologueLength = prologueLength;

this.overwrittenPrologue = Memory.dup(this.quickCodeAddress, prologueLength);
Expand Down

0 comments on commit d4d2a42

Please sign in to comment.