@@ -2786,7 +2786,7 @@ const artQuickCodeReplacementTrampolineWriters = {
27862786arm64: writeArtQuickCodeReplacementTrampolineArm64
27872787};
278827882789-function writeArtQuickCodeReplacementTrampolineIA32 (trampoline, target, redirectSize, vm) {
2789+function writeArtQuickCodeReplacementTrampolineIA32 (trampoline, target, redirectSize, constraints, vm) {
27902790const threadOffsets = getArtThreadSpec(vm).offset;
27912791const artMethodOffsets = getArtMethodSpec(vm).offset;
27922792@@ -2849,7 +2849,7 @@ function writeArtQuickCodeReplacementTrampolineIA32 (trampoline, target, redirec
28492849return offset;
28502850}
285128512852-function writeArtQuickCodeReplacementTrampolineX64 (trampoline, target, redirectSize, vm) {
2852+function writeArtQuickCodeReplacementTrampolineX64 (trampoline, target, redirectSize, constraints, vm) {
28532853const threadOffsets = getArtThreadSpec(vm).offset;
28542854const artMethodOffsets = getArtMethodSpec(vm).offset;
28552855@@ -2912,7 +2912,7 @@ function writeArtQuickCodeReplacementTrampolineX64 (trampoline, target, redirect
29122912return offset;
29132913}
291429142915-function writeArtQuickCodeReplacementTrampolineArm (trampoline, target, redirectSize, vm) {
2915+function writeArtQuickCodeReplacementTrampolineArm (trampoline, target, redirectSize, constraints, vm) {
29162916const artMethodOffsets = getArtMethodSpec(vm).offset;
2917291729182918const targetAddress = target.and(THUMB_BIT_REMOVAL_MASK);
@@ -2999,7 +2999,7 @@ function writeArtQuickCodeReplacementTrampolineArm (trampoline, target, redirect
29992999return offset;
30003000}
300130013002-function writeArtQuickCodeReplacementTrampolineArm64 (trampoline, target, redirectSize, vm) {
3002+function writeArtQuickCodeReplacementTrampolineArm64 (trampoline, target, redirectSize, { availableScratchRegs }, vm) {
30033003const artMethodOffsets = getArtMethodSpec(vm).offset;
3004300430053005let offset;
@@ -3068,8 +3068,9 @@ function writeArtQuickCodeReplacementTrampolineArm64 (trampoline, target, redire
30683068relocator.writeAll();
3069306930703070if (!relocator.eoi) {
3071-writer.putLdrRegAddress('x17', target.add(offset));
3072-writer.putBrReg('x17');
3071+const scratchReg = Array.from(availableScratchRegs)[0];
3072+writer.putLdrRegAddress(scratchReg, target.add(offset));
3073+writer.putBrReg(scratchReg);
30733074}
3074307530753076writer.putLabel('invoke_replacement');
@@ -3146,7 +3147,7 @@ class ArtQuickCodeInterceptor {
31463147this.overwrittenPrologueLength = 0;
31473148}
314831493149-_canRelocateCode (relocationSize) {
3150+_canRelocateCode (relocationSize, constraints) {
31503151const Writer = thunkWriters[Process.arch];
31513152const Relocator = thunkRelocators[Process.arch];
31523153@@ -3156,14 +3157,44 @@ class ArtQuickCodeInterceptor {
31563157const relocator = new Relocator(quickCodeAddress, writer);
3157315831583159let offset;
3159-do {
3160-offset = relocator.readOne();
3161-} while (offset < relocationSize && !relocator.eoi);
3160+if (Process.arch === 'arm64') {
3161+let availableScratchRegs = new Set(['x16', 'x17']);
3162+3163+do {
3164+const nextOffset = relocator.readOne();
3165+3166+const nextScratchRegs = new Set(availableScratchRegs);
3167+const { read, written } = relocator.input.regsAccessed;
3168+for (const regs of [read, written]) {
3169+for (const reg of regs) {
3170+let name;
3171+if (reg.startsWith('w')) {
3172+name = 'x' + reg.substring(1);
3173+} else {
3174+name = reg;
3175+}
3176+nextScratchRegs.delete(name);
3177+}
3178+}
3179+if (nextScratchRegs.size === 0) {
3180+break;
3181+}
3182+3183+offset = nextOffset;
3184+availableScratchRegs = nextScratchRegs;
3185+} while (offset < relocationSize && !relocator.eoi);
3186+3187+constraints.availableScratchRegs = availableScratchRegs;
3188+} else {
3189+do {
3190+offset = relocator.readOne();
3191+} while (offset < relocationSize && !relocator.eoi);
3192+}
3162319331633194return offset >= relocationSize;
31643195}
316531963166-_createTrampoline () {
3197+_allocateTrampoline () {
31673198if (trampolineAllocator === null) {
31683199const trampolineSize = (pointerSize === 4) ? 128 : 256;
31693200trampolineAllocator = makeCodeAllocator(trampolineSize);
@@ -3173,7 +3204,8 @@ class ArtQuickCodeInterceptor {
3173320431743205let redirectSize, spec;
31753206let alignment = 1;
3176-if (pointerSize === 4 || this._canRelocateCode(maxRedirectSize)) {
3207+const constraints = {};
3208+if (pointerSize === 4 || this._canRelocateCode(maxRedirectSize, constraints)) {
31773209redirectSize = maxRedirectSize;
3178321031793211spec = {};
@@ -3193,19 +3225,21 @@ class ArtQuickCodeInterceptor {
3193322531943226this.redirectSize = redirectSize;
31953227this.trampoline = trampolineAllocator.allocateSlice(spec, alignment);
3228+3229+return constraints;
31963230}
3197323131983232_destroyTrampoline () {
31993233trampolineAllocator.freeSlice(this.trampoline);
32003234}
3201323532023236activate (vm) {
3203-this._createTrampoline();
3237+const constraints = this._allocateTrampoline();
3204323832053239const { trampoline, quickCode, redirectSize } = this;
3206324032073241const writeTrampoline = artQuickCodeReplacementTrampolineWriters[Process.arch];
3208-const prologueLength = writeTrampoline(trampoline, quickCode, redirectSize, vm);
3242+const prologueLength = writeTrampoline(trampoline, quickCode, redirectSize, constraints, vm);
32093243this.overwrittenPrologueLength = prologueLength;
3210324432113245this.overwrittenPrologue = Memory.dup(this.quickCodeAddress, prologueLength);