address AbstractInterpreterGenerator::generate_slow_signature_handler() { address entry = __ pc(); __ andr(esp, esp, -16); __ mov(c_rarg3, esp); // rmethod // rlocals // c_rarg3: first stack arg - wordSize // adjust sp __ sub(sp, c_rarg3, 18 * wordSize); __ str(lr, Address(__ pre(sp, -2 * wordSize))); __ call_VM(noreg, CAST_FROM_FN_PTR(address, InterpreterRuntime::slow_signature_handler), rmethod, rlocals, c_rarg3); // r0: result handler // Stack layout: // rsp: return address <- sp // 1 garbage // 8 integer args (if static first is unused) // 1 float/double identifiers // 8 double args // stack args <- esp // garbage // expression stack bottom // bcp (NULL) // ... // Restore LR __ ldr(lr, Address(__ post(sp, 2 * wordSize))); // Do FP first so we can use c_rarg3 as temp __ ldrw(c_rarg3, Address(sp, 9 * wordSize)); // float/double identifiers for (int i = 0; i < Argument::n_float_register_parameters_c; i++) { const FloatRegister r = as_FloatRegister(i); Label d, done; __ tbnz(c_rarg3, i, d); __ ldrs(r, Address(sp, (10 + i) * wordSize)); __ b(done); __ bind(d); __ ldrd(r, Address(sp, (10 + i) * wordSize)); __ bind(done); } // c_rarg0 contains the result from the call of // InterpreterRuntime::slow_signature_handler so we don't touch it // here. It will be loaded with the JNIEnv* later. __ ldr(c_rarg1, Address(sp, 1 * wordSize)); for (int i = c_rarg2->encoding(); i <= c_rarg7->encoding(); i += 2) { Register rm = as_Register(i), rn = as_Register(i+1); __ ldp(rm, rn, Address(sp, i * wordSize)); } __ add(sp, sp, 18 * wordSize); __ ret(lr); return entry; }
VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { const int aarch64_code_length = VtableStub::pd_code_size_limit(true); VtableStub* s = new(aarch64_code_length) VtableStub(true, vtable_index); ResourceMark rm; CodeBuffer cb(s->entry_point(), aarch64_code_length); MacroAssembler* masm = new MacroAssembler(&cb); #ifndef PRODUCT if (CountCompiledCalls) { __ lea(r19, ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr())); __ incrementw(Address(r19)); } #endif // get receiver (need to skip return address on top of stack) assert(VtableStub::receiver_location() == j_rarg0->as_VMReg(), "receiver expected in j_rarg0"); // get receiver klass address npe_addr = __ pc(); __ load_klass(r19, j_rarg0); #ifndef PRODUCT if (DebugVtables) { Label L; // check offset vs vtable length __ ldrw(rscratch1, Address(r19, Klass::vtable_length_offset())); __ cmpw(rscratch1, vtable_index * vtableEntry::size()); __ br(Assembler::GT, L); __ enter(); __ mov(r2, vtable_index); __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), j_rarg0, r2); __ leave(); __ bind(L); } #endif // PRODUCT __ lookup_virtual_method(r19, vtable_index, rmethod); if (DebugVtables) { Label L; __ cbz(rmethod, L); __ ldr(rscratch1, Address(rmethod, Method::from_compiled_offset())); __ cbnz(rscratch1, L); __ stop("Vtable entry is NULL"); __ bind(L); } // r0: receiver klass // rmethod: Method* // r2: receiver address ame_addr = __ pc(); __ ldr(rscratch1, Address(rmethod, Method::from_compiled_offset())); __ br(rscratch1); __ flush(); if (PrintMiscellaneous && (WizardMode || Verbose)) { tty->print_cr("vtable #%d at " PTR_FORMAT "[%d] left over: %d", vtable_index, p2i(s->entry_point()), (int)(s->code_end() - s->entry_point()), (int)(s->code_end() - __ pc())); } guarantee(__ pc() <= s->code_end(), "overflowed buffer"); s->set_exception_points(npe_addr, ame_addr); return s; }
address JNI_FastGetField::generate_fast_get_int_field0(BasicType type) { const char *name; switch (type) { case T_BOOLEAN: name = "jni_fast_GetBooleanField"; break; case T_BYTE: name = "jni_fast_GetByteField"; break; case T_CHAR: name = "jni_fast_GetCharField"; break; case T_SHORT: name = "jni_fast_GetShortField"; break; case T_INT: name = "jni_fast_GetIntField"; break; case T_LONG: name = "jni_fast_GetLongField"; break; case T_FLOAT: name = "jni_fast_GetFloatField"; break; case T_DOUBLE: name = "jni_fast_GetDoubleField"; break; default: ShouldNotReachHere(); } ResourceMark rm; BufferBlob* blob = BufferBlob::create(name, BUFFER_SIZE); CodeBuffer cbuf(blob); MacroAssembler* masm = new MacroAssembler(&cbuf); address fast_entry = __ pc(); Label slow; unsigned long offset; __ adrp(rcounter_addr, SafepointSynchronize::safepoint_counter_addr(), offset); Address safepoint_counter_addr(rcounter_addr, offset); __ ldrw(rcounter, safepoint_counter_addr); __ andw(rscratch1, rcounter, 1); __ cbnzw(rscratch1, slow); __ eor(robj, c_rarg1, rcounter); __ eor(robj, robj, rcounter); // obj, since // robj ^ rcounter ^ rcounter == robj // robj is address dependent on rcounter. __ ldr(robj, Address(robj, 0)); // *obj __ lsr(roffset, c_rarg2, 2); // offset assert(count < LIST_CAPACITY, "LIST_CAPACITY too small"); speculative_load_pclist[count] = __ pc(); // Used by the segfault handler switch (type) { case T_BOOLEAN: __ ldrb (result, Address(robj, roffset)); break; case T_BYTE: __ ldrsb (result, Address(robj, roffset)); break; case T_CHAR: __ ldrh (result, Address(robj, roffset)); break; case T_SHORT: __ ldrsh (result, Address(robj, roffset)); break; case T_FLOAT: __ ldrw (result, Address(robj, roffset)); break; case T_INT: __ ldrsw (result, Address(robj, roffset)); break; case T_DOUBLE: case T_LONG: __ ldr (result, Address(robj, roffset)); break; default: ShouldNotReachHere(); } // counter_addr is address dependent on result. __ eor(rcounter_addr, rcounter_addr, result); __ eor(rcounter_addr, rcounter_addr, result); __ ldrw(rscratch1, safepoint_counter_addr); __ cmpw(rcounter, rscratch1); __ br (Assembler::NE, slow); switch (type) { case T_FLOAT: __ fmovs(v0, result); break; case T_DOUBLE: __ fmovd(v0, result); break; default: __ mov(r0, result); break; } __ ret(lr); slowcase_entry_pclist[count++] = __ pc(); __ bind(slow); address slow_case_addr; switch (type) { case T_BOOLEAN: slow_case_addr = jni_GetBooleanField_addr(); break; case T_BYTE: slow_case_addr = jni_GetByteField_addr(); break; case T_CHAR: slow_case_addr = jni_GetCharField_addr(); break; case T_SHORT: slow_case_addr = jni_GetShortField_addr(); break; case T_INT: slow_case_addr = jni_GetIntField_addr(); break; case T_LONG: slow_case_addr = jni_GetLongField_addr(); break; case T_FLOAT: slow_case_addr = jni_GetFloatField_addr(); break; case T_DOUBLE: slow_case_addr = jni_GetDoubleField_addr(); break; default: ShouldNotReachHere(); } { __ enter(); __ lea(rscratch1, ExternalAddress(slow_case_addr)); __ blr(rscratch1); __ maybe_isb(); __ leave(); __ ret(lr); } __ flush (); return fast_entry; }
static void SubstrateHookFunctionThumb(SubstrateProcessRef process, void *symbol, void *replace, void **result) { if (symbol == NULL) return; uint16_t *area(reinterpret_cast<uint16_t *>(symbol)); unsigned align((reinterpret_cast<uintptr_t>(area) & 0x2) == 0 ? 0 : 1); uint16_t *thumb(area + align); uint32_t *arm(reinterpret_cast<uint32_t *>(thumb + 2)); uint16_t *trail(reinterpret_cast<uint16_t *>(arm + 2)); if ( (align == 0 || area[0] == T$nop) && thumb[0] == T$bx(A$pc) && thumb[1] == T$nop && arm[0] == A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8) ) { if (result != NULL) *result = reinterpret_cast<void *>(arm[1]); SubstrateHookMemory code(process, arm + 1, sizeof(uint32_t) * 1); arm[1] = reinterpret_cast<uint32_t>(replace); return; } size_t required((trail - area) * sizeof(uint16_t)); size_t used(0); while (used < required) used += MSGetInstructionWidthThumb(reinterpret_cast<uint8_t *>(area) + used); used = (used + sizeof(uint16_t) - 1) / sizeof(uint16_t) * sizeof(uint16_t); size_t blank((used - required) / sizeof(uint16_t)); uint16_t backup[used / sizeof(uint16_t)]; memcpy(backup, area, used); if (MSDebug) { char name[16]; sprintf(name, "%p", area); MSLogHexEx(area, used + sizeof(uint16_t), 2, name); } if (result != NULL) { size_t length(used); for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset) if (T$pcrel$ldr(backup[offset])) length += 3 * sizeof(uint16_t); else if (T$pcrel$b(backup[offset])) length += 6 * sizeof(uint16_t); else if (T2$pcrel$b(backup + offset)) { length += 5 * sizeof(uint16_t); ++offset; } else if (T$pcrel$bl(backup + offset)) { length += 5 * sizeof(uint16_t); ++offset; } else if (T$pcrel$cbz(backup[offset])) { length += 16 * sizeof(uint16_t); } else if (T$pcrel$ldrw(backup[offset])) { length += 4 * sizeof(uint16_t); ++offset; } else if (T$pcrel$add(backup[offset])) length += 6 * sizeof(uint16_t); else if (T$32bit$i(backup[offset])) ++offset; unsigned pad((length & 0x2) == 0 ? 0 : 1); length += (pad + 2) * sizeof(uint16_t) + 2 * sizeof(uint32_t); uint16_t *buffer(reinterpret_cast<uint16_t *>(mmap( NULL, length, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0 ))); if (buffer == MAP_FAILED) { MSLog(MSLogLevelError, "MS:Error:mmap() = %d", errno); *result = NULL; return; } if (false) fail: { munmap(buffer, length); *result = NULL; return; } size_t start(pad), end(length / sizeof(uint16_t)); uint32_t *trailer(reinterpret_cast<uint32_t *>(buffer + end)); for (unsigned offset(0); offset != used / sizeof(uint16_t); ++offset) { if (T$pcrel$ldr(backup[offset])) { union { uint16_t value; struct { uint16_t immediate : 8; uint16_t rd : 3; uint16_t : 5; }; } bits = {backup[offset+0]}; buffer[start+0] = T$ldr_rd_$pc_im_4$(bits.rd, T$Label(start+0, end-2) / 4); buffer[start+1] = T$ldr_rd_$rn_im_4$(bits.rd, bits.rd, 0); // XXX: this code "works", but is "wrong": the mechanism is more complex than this *--trailer = ((reinterpret_cast<uint32_t>(area + offset) + 4) & ~0x2) + bits.immediate * 4; start += 2; end -= 2; } else if (T$pcrel$b(backup[offset])) { union { uint16_t value; struct { uint16_t imm8 : 8; uint16_t cond : 4; uint16_t /*1101*/ : 4; }; } bits = {backup[offset+0]}; intptr_t jump(bits.imm8 << 1); jump |= 1; jump <<= 23; jump >>= 23; buffer[start+0] = T$b$_$im(bits.cond, (end-6 - (start+0)) * 2 - 4); *--trailer = reinterpret_cast<uint32_t>(area + offset) + 4 + jump; *--trailer = A$ldr_rd_$rn_im$(A$pc, A$pc, 4 - 8); *--trailer = T$nop << 16 | T$bx(A$pc); start += 1; end -= 6; } else if (T2$pcrel$b(backup + offset)) { union { uint16_t value; struct { uint16_t imm6 : 6; uint16_t cond : 4; uint16_t s : 1; uint16_t : 5; }; } bits = {backup[offset+0]}; union { uint16_t value; struct { uint16_t imm11 : 11; uint16_t j2 : 1; uint16_t a : 1; uint16_t j1 : 1; uint16_t : 2; }; } exts = {backup[offset+1]}; intptr_t jump(1); jump |= exts.imm11 << 1; jump |= bits.imm6 << 12; if (exts.a) { jump |= bits.s << 24; jump |= (~(bits.s ^ exts.j1) & 0x1) << 23; jump |= (~(bits.s ^ exts.j2) & 0x1) << 22; jump |= bits.cond << 18; jump <<= 7; jump >>= 7; } else {