Skip to content
Permalink
Browse files
2010-04-22 Gabor Loki <loki@webkit.org>
        Reviewed by Gavin Barraclough.

        Use BLX and BX to keep happy the return stack predictor above ARMv4
        https://bugs.webkit.org/show_bug.cgi?id=37862

        Inspired by Jacob Bramley's patch from JaegerMonkey

        * assembler/ARMAssembler.cpp:
        (JSC::ARMAssembler::executableCopy):
        * assembler/ARMAssembler.h:
        (JSC::ARMAssembler::):
        (JSC::ARMAssembler::bx):
        (JSC::ARMAssembler::blx):
        (JSC::ARMAssembler::loadBranchTarget):
        (JSC::ARMAssembler::jmp):
        (JSC::ARMAssembler::getLdrImmAddress):
        * assembler/MacroAssemblerARM.h:
        (JSC::MacroAssemblerARM::jump):
        (JSC::MacroAssemblerARM::nearCall):
        (JSC::MacroAssemblerARM::call):
        (JSC::MacroAssemblerARM::ret):
        (JSC::MacroAssemblerARM::prepareCall):
        (JSC::MacroAssemblerARM::call32):

Canonical link: https://commits.webkit.org/49372@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@58091 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
eseidel committed Apr 22, 2010
1 parent 9dbe40c commit 7c2c0dab2a914712dabc0a461fe428046f4a82bf
Showing 4 changed files with 110 additions and 19 deletions.
@@ -1,3 +1,29 @@
2010-04-22 Gabor Loki <loki@webkit.org>

Reviewed by Gavin Barraclough.

Use BLX and BX to keep happy the return stack predictor above ARMv4
https://bugs.webkit.org/show_bug.cgi?id=37862

Inspired by Jacob Bramley's patch from JaegerMonkey

* assembler/ARMAssembler.cpp:
(JSC::ARMAssembler::executableCopy):
* assembler/ARMAssembler.h:
(JSC::ARMAssembler::):
(JSC::ARMAssembler::bx):
(JSC::ARMAssembler::blx):
(JSC::ARMAssembler::loadBranchTarget):
(JSC::ARMAssembler::jmp):
(JSC::ARMAssembler::getLdrImmAddress):
* assembler/MacroAssemblerARM.h:
(JSC::MacroAssemblerARM::jump):
(JSC::MacroAssemblerARM::nearCall):
(JSC::MacroAssemblerARM::call):
(JSC::MacroAssemblerARM::ret):
(JSC::MacroAssemblerARM::prepareCall):
(JSC::MacroAssemblerARM::call32):

2010-04-21 Andy Estes <aestes@apple.com>

Rubber stamped by Mark Rowe.
@@ -357,7 +357,7 @@ void* ARMAssembler::executableCopy(ExecutablePool* allocator)
int pos = (*iter) & (~0x1);
ARMWord* ldrAddr = reinterpret_cast<ARMWord*>(data + pos);
ARMWord* addr = getLdrImmAddress(ldrAddr);
if (*addr != 0xffffffff) {
if (*addr != InvalidBranchTarget) {
if (!(*iter & 1)) {
int diff = reinterpret_cast<ARMWord*>(data + *addr) - (ldrAddr + DefaultPrefetching);

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009 University of Szeged
* Copyright (C) 2009, 2010 University of Szeged
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -131,6 +131,9 @@ namespace JSC {
FDTR = 0x0d000b00,
B = 0x0a000000,
BL = 0x0b000000,
#if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__)
BX = 0x012fff10,
#endif
FMSR = 0x0e000a10,
FMRS = 0x0e100a10,
FSITOD = 0x0eb80bc0,
@@ -139,6 +142,7 @@ namespace JSC {
#if WTF_ARM_ARCH_AT_LEAST(5)
CLZ = 0x016f0f10,
BKPT = 0xe120070,
BLX = 0x012fff30,
#endif
#if WTF_ARM_ARCH_AT_LEAST(7)
MOVW = 0x03000000,
@@ -182,6 +186,7 @@ namespace JSC {
};

static const ARMWord INVALID_IMM = 0xf0000000;
static const ARMWord InvalidBranchTarget = 0xffffffff;
static const int DefaultPrefetching = 2;

class JmpSrc {
@@ -547,6 +552,30 @@ namespace JSC {
#endif
}

void bx(int rm, Condition cc = AL)
{
#if WTF_ARM_ARCH_AT_LEAST(5) || defined(__ARM_ARCH_4T__)
emitInst(static_cast<ARMWord>(cc) | BX, 0, 0, RM(rm));
#else
mov_r(ARMRegisters::pc, RM(rm), cc);
#endif
}

JmpSrc blx(int rm, Condition cc = AL)
{
#if WTF_ARM_ARCH_AT_LEAST(5)
int s = m_buffer.uncheckedSize();
emitInst(static_cast<ARMWord>(cc) | BLX, 0, 0, RM(rm));
#else
ASSERT(rm != 14);
ensureSpace(2 * sizeof(ARMWord), 0);
mov_r(ARMRegisters::lr, ARMRegisters::pc, cc);
int s = m_buffer.uncheckedSize();
bx(rm, cc);
#endif
return JmpSrc(s);
}

static ARMWord lsl(int reg, ARMWord value)
{
ASSERT(reg <= ARMRegisters::pc);
@@ -619,21 +648,34 @@ namespace JSC {
return label();
}

JmpSrc jmp(Condition cc = AL, int useConstantPool = 0)
JmpSrc loadBranchTarget(int rd, Condition cc = AL, int useConstantPool = 0)
{
ensureSpace(sizeof(ARMWord), sizeof(ARMWord));
int s = m_buffer.uncheckedSize();
ldr_un_imm(ARMRegisters::pc, 0xffffffff, cc);
ldr_un_imm(rd, InvalidBranchTarget, cc);
m_jumps.append(s | (useConstantPool & 0x1));
return JmpSrc(s);
}

JmpSrc jmp(Condition cc = AL, int useConstantPool = 0)
{
return loadBranchTarget(ARMRegisters::pc, cc, useConstantPool);
}

void* executableCopy(ExecutablePool* allocator);

// Patching helpers

static ARMWord* getLdrImmAddress(ARMWord* insn)
{
#if WTF_ARM_ARCH_AT_LEAST(5)
// Check for call
if ((*insn & 0x0f7f0000) != 0x051f0000) {
// Must be BLX
ASSERT((*insn & 0x012fff30) == 0x012fff30);
insn--;
}
#endif
// Must be an ldr ..., [pc +/- imm]
ASSERT((*insn & 0x0f7f0000) == 0x051f0000);

@@ -1,6 +1,6 @@
/*
* Copyright (C) 2008 Apple Inc.
* Copyright (C) 2009 University of Szeged
* Copyright (C) 2009, 2010 University of Szeged
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -474,7 +474,7 @@ class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> {

void jump(RegisterID target)
{
move(target, ARMRegisters::pc);
m_assembler.bx(target);
}

void jump(Address address)
@@ -566,14 +566,19 @@ class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> {

Call nearCall()
{
#if WTF_ARM_ARCH_AT_LEAST(5)
ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord));
m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true);
return Call(m_assembler.blx(ARMRegisters::S1), Call::LinkableNear);
#else
prepareCall();
return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::LinkableNear);
#endif
}

Call call(RegisterID target)
{
prepareCall();
move(ARMRegisters::pc, target);
m_assembler.blx(target);
JmpSrc jmpSrc;
return Call(jmpSrc, Call::None);
}
@@ -585,7 +590,7 @@ class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> {

void ret()
{
m_assembler.mov_r(ARMRegisters::pc, linkRegister);
m_assembler.bx(linkRegister);
}

void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest)
@@ -681,8 +686,14 @@ class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> {

Call call()
{
#if WTF_ARM_ARCH_AT_LEAST(5)
ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord));
m_assembler.loadBranchTarget(ARMRegisters::S1, ARMAssembler::AL, true);
return Call(m_assembler.blx(ARMRegisters::S1), Call::Linkable);
#else
prepareCall();
return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::Linkable);
#endif
}

Call tailRecursiveCall()
@@ -886,44 +897,56 @@ class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> {

void prepareCall()
{
#if WTF_ARM_ARCH_VERSION < 5
ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord));

m_assembler.mov_r(linkRegister, ARMRegisters::pc);
#endif
}

void call32(RegisterID base, int32_t offset)
{
#if WTF_ARM_ARCH_AT_LEAST(5)
int targetReg = ARMRegisters::S1;
#else
int targetReg = ARMRegisters::pc;
#endif
int tmpReg = ARMRegisters::S1;

if (base == ARMRegisters::sp)
offset += 4;

if (offset >= 0) {
if (offset <= 0xfff) {
prepareCall();
m_assembler.dtr_u(true, ARMRegisters::pc, base, offset);
m_assembler.dtr_u(true, targetReg, base, offset);
} else if (offset <= 0xfffff) {
m_assembler.add_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
m_assembler.add_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
prepareCall();
m_assembler.dtr_u(true, ARMRegisters::pc, ARMRegisters::S0, offset & 0xfff);
m_assembler.dtr_u(true, targetReg, tmpReg, offset & 0xfff);
} else {
ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0);
ARMWord reg = m_assembler.getImm(offset, tmpReg);
prepareCall();
m_assembler.dtr_ur(true, ARMRegisters::pc, base, reg);
m_assembler.dtr_ur(true, targetReg, base, reg);
}
} else {
offset = -offset;
if (offset <= 0xfff) {
prepareCall();
m_assembler.dtr_d(true, ARMRegisters::pc, base, offset);
m_assembler.dtr_d(true, targetReg, base, offset);
} else if (offset <= 0xfffff) {
m_assembler.sub_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
m_assembler.sub_r(tmpReg, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8));
prepareCall();
m_assembler.dtr_d(true, ARMRegisters::pc, ARMRegisters::S0, offset & 0xfff);
m_assembler.dtr_d(true, targetReg, tmpReg, offset & 0xfff);
} else {
ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0);
ARMWord reg = m_assembler.getImm(offset, tmpReg);
prepareCall();
m_assembler.dtr_dr(true, ARMRegisters::pc, base, reg);
m_assembler.dtr_dr(true, targetReg, base, reg);
}
}
#if WTF_ARM_ARCH_AT_LEAST(5)
m_assembler.blx(targetReg);
#endif
}

private:

0 comments on commit 7c2c0da

Please sign in to comment.