JSC should be a triple-tier VM
https://bugs.webkit.org/show_bug.cgi?id=75812
<rdar://problem/10079694>

Source/JavaScriptCore: 

Reviewed by Gavin Barraclough.
        
Implemented an interpreter that uses the JIT's calling convention. This
interpreter is called LLInt, or the Low Level Interpreter. JSC will now
will start by executing code in LLInt and will only tier up to the old
JIT after the code is proven hot.
        
LLInt is written in a modified form of our macro assembly. This new macro
assembly is compiled by an offline assembler (see offlineasm), which
implements many modern conveniences such as a Turing-complete CPS-based
macro language and direct access to relevant C++ type information
(basically offsets of fields and sizes of structs/classes).
        
Code executing in LLInt appears to the rest of the JSC world "as if" it
were executing in the old JIT. Hence, things like exception handling and
cross-execution-engine calls just work and require pretty much no
additional overhead.
        
This interpreter is 2-2.5x faster than our old interpreter on SunSpider,
V8, and Kraken. With triple-tiering turned on, we're neutral on SunSpider,
V8, and Kraken, but appear to get a double-digit improvement on real-world
websites due to a huge reduction in the amount of JIT'ing.
        
* CMakeLists.txt:
* GNUmakefile.am:
* GNUmakefile.list.am:
* JavaScriptCore.pri:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops:
* JavaScriptCore.vcproj/JavaScriptCore/copy-files.cmd:
* JavaScriptCore.xcodeproj/project.pbxproj:
* Target.pri:
* assembler/LinkBuffer.h:
* assembler/MacroAssemblerCodeRef.h:
(MacroAssemblerCodePtr):
(JSC::MacroAssemblerCodePtr::createFromExecutableAddress):
* bytecode/BytecodeConventions.h: Added.
* bytecode/CallLinkStatus.cpp:
(JSC::CallLinkStatus::computeFromLLInt):
(JSC):
(JSC::CallLinkStatus::computeFor):
* bytecode/CallLinkStatus.h:
(JSC::CallLinkStatus::isSet):
(JSC::CallLinkStatus::operator!):
(CallLinkStatus):
* bytecode/CodeBlock.cpp:
(JSC::CodeBlock::dump):
(JSC::CodeBlock::CodeBlock):
(JSC::CodeBlock::~CodeBlock):
(JSC::CodeBlock::finalizeUnconditionally):
(JSC::CodeBlock::stronglyVisitStrongReferences):
(JSC):
(JSC::CodeBlock::unlinkCalls):
(JSC::CodeBlock::unlinkIncomingCalls):
(JSC::CodeBlock::bytecodeOffset):
(JSC::ProgramCodeBlock::jettison):
(JSC::EvalCodeBlock::jettison):
(JSC::FunctionCodeBlock::jettison):
(JSC::ProgramCodeBlock::jitCompileImpl):
(JSC::EvalCodeBlock::jitCompileImpl):
(JSC::FunctionCodeBlock::jitCompileImpl):
* bytecode/CodeBlock.h:
(JSC):
(CodeBlock):
(JSC::CodeBlock::baselineVersion):
(JSC::CodeBlock::linkIncomingCall):
(JSC::CodeBlock::bytecodeOffset):
(JSC::CodeBlock::jitCompile):
(JSC::CodeBlock::hasOptimizedReplacement):
(JSC::CodeBlock::addPropertyAccessInstruction):
(JSC::CodeBlock::addGlobalResolveInstruction):
(JSC::CodeBlock::addLLIntCallLinkInfo):
(JSC::CodeBlock::addGlobalResolveInfo):
(JSC::CodeBlock::numberOfMethodCallLinkInfos):
(JSC::CodeBlock::valueProfilePredictionForBytecodeOffset):
(JSC::CodeBlock::likelyToTakeSlowCase):
(JSC::CodeBlock::couldTakeSlowCase):
(JSC::CodeBlock::likelyToTakeSpecialFastCase):
(JSC::CodeBlock::likelyToTakeDeepestSlowCase):
(JSC::CodeBlock::likelyToTakeAnySlowCase):
(JSC::CodeBlock::addFrequentExitSite):
(JSC::CodeBlock::dontJITAnytimeSoon):
(JSC::CodeBlock::jitAfterWarmUp):
(JSC::CodeBlock::jitSoon):
(JSC::CodeBlock::llintExecuteCounter):
(ProgramCodeBlock):
(EvalCodeBlock):
(FunctionCodeBlock):
* bytecode/GetByIdStatus.cpp:
(JSC::GetByIdStatus::computeFromLLInt):
(JSC):
(JSC::GetByIdStatus::computeFor):
* bytecode/GetByIdStatus.h:
(JSC::GetByIdStatus::GetByIdStatus):
(JSC::GetByIdStatus::wasSeenInJIT):
(GetByIdStatus):
* bytecode/Instruction.h:
(JSC):
(JSC::Instruction::Instruction):
(Instruction):
* bytecode/LLIntCallLinkInfo.h: Added.
(JSC):
(JSC::LLIntCallLinkInfo::LLIntCallLinkInfo):
(LLIntCallLinkInfo):
(JSC::LLIntCallLinkInfo::~LLIntCallLinkInfo):
(JSC::LLIntCallLinkInfo::isLinked):
(JSC::LLIntCallLinkInfo::unlink):
* bytecode/MethodCallLinkStatus.cpp:
(JSC::MethodCallLinkStatus::computeFor):
* bytecode/Opcode.cpp:
(JSC):
* bytecode/Opcode.h:
(JSC):
(JSC::padOpcodeName):
* bytecode/PutByIdStatus.cpp:
(JSC::PutByIdStatus::computeFromLLInt):
(JSC):
(JSC::PutByIdStatus::computeFor):
* bytecode/PutByIdStatus.h:
(PutByIdStatus):
* bytecompiler/BytecodeGenerator.cpp:
(JSC::BytecodeGenerator::emitResolve):
(JSC::BytecodeGenerator::emitResolveWithBase):
(JSC::BytecodeGenerator::emitGetById):
(JSC::BytecodeGenerator::emitPutById):
(JSC::BytecodeGenerator::emitDirectPutById):
(JSC::BytecodeGenerator::emitCall):
(JSC::BytecodeGenerator::emitConstruct):
(JSC::BytecodeGenerator::emitCatch):
* dfg/DFGByteCodeParser.cpp:
(JSC::DFG::ByteCodeParser::getPredictionWithoutOSRExit):
(JSC::DFG::ByteCodeParser::handleInlining):
(JSC::DFG::ByteCodeParser::parseBlock):
* dfg/DFGCapabilities.h:
(JSC::DFG::canCompileOpcode):
* dfg/DFGOSRExitCompiler.cpp:
* dfg/DFGOperations.cpp:
* heap/Heap.h:
(JSC):
(JSC::Heap::firstAllocatorWithoutDestructors):
(Heap):
* heap/MarkStack.cpp:
(JSC::visitChildren):
* heap/MarkedAllocator.h:
(JSC):
(MarkedAllocator):
* heap/MarkedSpace.h:
(JSC):
(MarkedSpace):
(JSC::MarkedSpace::firstAllocator):
* interpreter/CallFrame.cpp:
(JSC):
(JSC::CallFrame::bytecodeOffsetForNonDFGCode):
(JSC::CallFrame::setBytecodeOffsetForNonDFGCode):
(JSC::CallFrame::currentVPC):
(JSC::CallFrame::setCurrentVPC):
(JSC::CallFrame::trueCallerFrame):
* interpreter/CallFrame.h:
(JSC::ExecState::hasReturnPC):
(JSC::ExecState::clearReturnPC):
(ExecState):
(JSC::ExecState::bytecodeOffsetForNonDFGCode):
(JSC::ExecState::currentVPC):
(JSC::ExecState::setCurrentVPC):
* interpreter/Interpreter.cpp:
(JSC::Interpreter::Interpreter):
(JSC::Interpreter::~Interpreter):
(JSC):
(JSC::Interpreter::initialize):
(JSC::Interpreter::isOpcode):
(JSC::Interpreter::unwindCallFrame):
(JSC::getCallerInfo):
(JSC::Interpreter::privateExecute):
(JSC::Interpreter::retrieveLastCaller):
* interpreter/Interpreter.h:
(JSC):
(Interpreter):
(JSC::Interpreter::getOpcode):
(JSC::Interpreter::getOpcodeID):
(JSC::Interpreter::classicEnabled):
* interpreter/RegisterFile.h:
(JSC):
(RegisterFile):
* jit/ExecutableAllocator.h:
(JSC):
* jit/HostCallReturnValue.cpp: Added.
(JSC):
(JSC::getHostCallReturnValueWithExecState):
* jit/HostCallReturnValue.h: Added.
(JSC):
(JSC::initializeHostCallReturnValue):
* jit/JIT.cpp:
(JSC::JIT::privateCompileMainPass):
(JSC::JIT::privateCompileSlowCases):
(JSC::JIT::privateCompile):
* jit/JITCode.h:
(JSC::JITCode::isOptimizingJIT):
(JITCode):
(JSC::JITCode::isBaselineCode):
(JSC::JITCode::JITCode):
* jit/JITDriver.h:
(JSC::jitCompileIfAppropriate):
(JSC::jitCompileFunctionIfAppropriate):
* jit/JITExceptions.cpp:
(JSC::jitThrow):
* jit/JITInlineMethods.h:
(JSC::JIT::updateTopCallFrame):
* jit/JITStubs.cpp:
(JSC::DEFINE_STUB_FUNCTION):
(JSC):
* jit/JITStubs.h:
(JSC):
* jit/JSInterfaceJIT.h:
* llint: Added.
* llint/LLIntCommon.h: Added.
* llint/LLIntData.cpp: Added.
(LLInt):
(JSC::LLInt::Data::Data):
(JSC::LLInt::Data::performAssertions):
(JSC::LLInt::Data::~Data):
* llint/LLIntData.h: Added.
(JSC):
(LLInt):
(Data):
(JSC::LLInt::Data::exceptionInstructions):
(JSC::LLInt::Data::opcodeMap):
(JSC::LLInt::Data::performAssertions):
* llint/LLIntEntrypoints.cpp: Added.
(LLInt):
(JSC::LLInt::getFunctionEntrypoint):
(JSC::LLInt::getEvalEntrypoint):
(JSC::LLInt::getProgramEntrypoint):
* llint/LLIntEntrypoints.h: Added.
(JSC):
(LLInt):
(JSC::LLInt::getEntrypoint):
* llint/LLIntExceptions.cpp: Added.
(LLInt):
(JSC::LLInt::interpreterThrowInCaller):
(JSC::LLInt::returnToThrowForThrownException):
(JSC::LLInt::returnToThrow):
(JSC::LLInt::callToThrow):
* llint/LLIntExceptions.h: Added.
(JSC):
(LLInt):
* llint/LLIntOfflineAsmConfig.h: Added.
* llint/LLIntOffsetsExtractor.cpp: Added.
(JSC):
(LLIntOffsetsExtractor):
(JSC::LLIntOffsetsExtractor::dummy):
(main):
* llint/LLIntSlowPaths.cpp: Added.
(LLInt):
(JSC::LLInt::llint_trace_operand):
(JSC::LLInt::llint_trace_value):
(JSC::LLInt::LLINT_SLOW_PATH_DECL):
(JSC::LLInt::traceFunctionPrologue):
(JSC::LLInt::shouldJIT):
(JSC::LLInt::entryOSR):
(JSC::LLInt::resolveGlobal):
(JSC::LLInt::getByVal):
(JSC::LLInt::handleHostCall):
(JSC::LLInt::setUpCall):
(JSC::LLInt::genericCall):
* llint/LLIntSlowPaths.h: Added.
(JSC):
(LLInt):
* llint/LLIntThunks.cpp: Added.
(LLInt):
(JSC::LLInt::generateThunkWithJumpTo):
(JSC::LLInt::functionForCallEntryThunkGenerator):
(JSC::LLInt::functionForConstructEntryThunkGenerator):
(JSC::LLInt::functionForCallArityCheckThunkGenerator):
(JSC::LLInt::functionForConstructArityCheckThunkGenerator):
(JSC::LLInt::evalEntryThunkGenerator):
(JSC::LLInt::programEntryThunkGenerator):
* llint/LLIntThunks.h: Added.
(JSC):
(LLInt):
* llint/LowLevelInterpreter.asm: Added.
* llint/LowLevelInterpreter.cpp: Added.
* llint/LowLevelInterpreter.h: Added.
* offlineasm: Added.
* offlineasm/armv7.rb: Added.
* offlineasm/asm.rb: Added.
* offlineasm/ast.rb: Added.
* offlineasm/backends.rb: Added.
* offlineasm/generate_offset_extractor.rb: Added.
* offlineasm/instructions.rb: Added.
* offlineasm/offset_extractor_constants.rb: Added.
* offlineasm/offsets.rb: Added.
* offlineasm/opt.rb: Added.
* offlineasm/parser.rb: Added.
* offlineasm/registers.rb: Added.
* offlineasm/self_hash.rb: Added.
* offlineasm/settings.rb: Added.
* offlineasm/transform.rb: Added.
* offlineasm/x86.rb: Added.
* runtime/CodeSpecializationKind.h: Added.
(JSC):
* runtime/CommonSlowPaths.h:
(JSC::CommonSlowPaths::arityCheckFor):
(CommonSlowPaths):
* runtime/Executable.cpp:
(JSC::jettisonCodeBlock):
(JSC):
(JSC::EvalExecutable::jitCompile):
(JSC::samplingDescription):
(JSC::EvalExecutable::compileInternal):
(JSC::ProgramExecutable::jitCompile):
(JSC::ProgramExecutable::compileInternal):
(JSC::FunctionExecutable::baselineCodeBlockFor):
(JSC::FunctionExecutable::jitCompileForCall):
(JSC::FunctionExecutable::jitCompileForConstruct):
(JSC::FunctionExecutable::compileForCallInternal):
(JSC::FunctionExecutable::compileForConstructInternal):
* runtime/Executable.h:
(JSC):
(EvalExecutable):
(ProgramExecutable):
(FunctionExecutable):
(JSC::FunctionExecutable::jitCompileFor):
* runtime/ExecutionHarness.h: Added.
(JSC):
(JSC::prepareForExecution):
(JSC::prepareFunctionForExecution):
* runtime/JSArray.h:
(JSC):
(JSArray):
* runtime/JSCell.h:
(JSC):
(JSCell):
* runtime/JSFunction.h:
(JSC):
(JSFunction):
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData):
* runtime/JSGlobalData.h:
(JSC):
(JSGlobalData):
* runtime/JSGlobalObject.h:
(JSC):
(JSGlobalObject):
* runtime/JSObject.h:
(JSC):
(JSObject):
(JSFinalObject):
* runtime/JSPropertyNameIterator.h:
(JSC):
(JSPropertyNameIterator):
* runtime/JSString.h:
(JSC):
(JSString):
* runtime/JSTypeInfo.h:
(JSC):
(TypeInfo):
* runtime/JSValue.cpp:
(JSC::JSValue::description):
* runtime/JSValue.h:
(LLInt):
(JSValue):
* runtime/JSVariableObject.h:
(JSC):
(JSVariableObject):
* runtime/Options.cpp:
(Options):
(JSC::Options::initializeOptions):
* runtime/Options.h:
(Options):
* runtime/ScopeChain.h:
(JSC):
(ScopeChainNode):
* runtime/Structure.cpp:
(JSC::Structure::addPropertyTransition):
* runtime/Structure.h:
(JSC):
(Structure):
* runtime/StructureChain.h:
(JSC):
(StructureChain):
* wtf/InlineASM.h:
* wtf/Platform.h:
* wtf/SentinelLinkedList.h:
(SentinelLinkedList):
(WTF::SentinelLinkedList::isEmpty):
* wtf/text/StringImpl.h:
(JSC):
(StringImpl):

Source/WebCore: 

Reviewed by Gavin Barraclough.
        
No new tests, because there is no change in behavior.

* CMakeLists.txt:

Source/WebKit: 

Reviewed by Gavin Barraclough.

Changed EFL's build system to include a new directory in JavaScriptCore.
        
* CMakeLists.txt:

Tools: 

Reviewed by Gavin Barraclough.

Changed EFL's build system to include a new directory in JavaScriptCore.

* DumpRenderTree/efl/CMakeLists.txt:



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@108444 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/JavaScriptCore/offlineasm/armv7.rb b/Source/JavaScriptCore/offlineasm/armv7.rb
new file mode 100644
index 0000000..eb8df68
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/armv7.rb
@@ -0,0 +1,1032 @@
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+require "ast"
+require "opt"
+
+class Node
+    def armV7Single
+        doubleOperand = armV7Operand
+        raise "Bogus register name #{doubleOperand}" unless doubleOperand =~ /^d/
+        "s" + ($~.post_match.to_i * 2).to_s
+    end
+end
+
+class SpecialRegister < NoChildren
+    def initialize(name)
+        @name = name
+    end
+    
+    def armV7Operand
+        @name
+    end
+    
+    def address?
+        false
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        false
+    end
+    
+    def register?
+        true
+    end
+end
+
+ARMv7_EXTRA_GPRS = [SpecialRegister.new("r9"), SpecialRegister.new("r8"), SpecialRegister.new("r3")]
+ARMv7_EXTRA_FPRS = [SpecialRegister.new("d7")]
+ARMv7_SCRATCH_FPR = SpecialRegister.new("d8")
+
+def armV7MoveImmediate(value, register)
+    # Currently we only handle the simple cases, and fall back to mov/movt for the complex ones.
+    if value >= 0 && value < 256
+        $asm.puts "movw #{register.armV7Operand}, \##{value}"
+    elsif (~value) >= 0 && (~value) < 256
+        $asm.puts "mvn #{register.armV7Operand}, \##{~value}"
+    else
+        $asm.puts "movw #{register.armV7Operand}, \##{value & 0xffff}"
+        if (value & 0xffff0000) != 0
+            $asm.puts "movt #{register.armV7Operand}, \##{value >> 16}"
+        end
+    end
+end
+
+class RegisterID
+    def armV7Operand
+        case name
+        when "t0", "a0", "r0"
+            "r0"
+        when "t1", "a1", "r1"
+            "r1"
+        when "t2", "a2"
+            "r2"
+        when "a3"
+            "r3"
+        when "t3"
+            "r4"
+        when "t4"
+            "r7"
+        when "cfr"
+            "r5"
+        when "lr"
+            "lr"
+        when "sp"
+            "sp"
+        else
+            raise "Bad register #{name} for ARMv7 at #{codeOriginString}"
+        end
+    end
+end
+
+class FPRegisterID
+    def armV7Operand
+        case name
+        when "ft0", "fr"
+            "d0"
+        when "ft1"
+            "d1"
+        when "ft2"
+            "d2"
+        when "ft3"
+            "d3"
+        when "ft4"
+            "d4"
+        when "ft5"
+            "d5"
+        else
+            raise "Bad register #{name} for ARMv7 at #{codeOriginString}"
+        end
+    end
+end
+
+class Immediate
+    def armV7Operand
+        raise "Invalid immediate #{value} at #{codeOriginString}" if value < 0 or value > 255
+        "\##{value}"
+    end
+end
+
+class Address
+    def armV7Operand
+        raise "Bad offset at #{codeOriginString}" if offset.value < -0xff or offset.value > 0xfff
+        "[#{base.armV7Operand}, \##{offset.value}]"
+    end
+end
+
+class BaseIndex
+    def armV7Operand
+        raise "Bad offset at #{codeOriginString}" if offset.value != 0
+        "[#{base.armV7Operand}, #{index.armV7Operand}, lsl \##{scaleShift}]"
+    end
+end
+
+class AbsoluteAddress
+    def armV7Operand
+        raise "Unconverted absolute address at #{codeOriginString}"
+    end
+end
+
+#
+# Lowering of branch ops. For example:
+#
+# baddiz foo, bar, baz
+#
+# will become:
+#
+# addi foo, bar
+# bz baz
+#
+
+def armV7LowerBranchOps(list)
+    newList = []
+    list.each {
+        | node |
+        if node.is_a? Instruction
+            case node.opcode
+            when /^b(addi|subi|ori|addp)/
+                op = $1
+                branch = "b" + $~.post_match
+                
+                case op
+                when "addi", "addp"
+                    op = "addis"
+                when "subi"
+                    op = "subis"
+                when "ori"
+                    op = "oris"
+                end
+                
+                newList << Instruction.new(node.codeOrigin, op, node.operands[0..-2])
+                newList << Instruction.new(node.codeOrigin, branch, [node.operands[-1]])
+            when "bmulio"
+                tmp1 = Tmp.new(node.codeOrigin, :gpr)
+                tmp2 = Tmp.new(node.codeOrigin, :gpr)
+                newList << Instruction.new(node.codeOrigin, "smulli", [node.operands[0], node.operands[1], node.operands[1], tmp1])
+                newList << Instruction.new(node.codeOrigin, "rshifti", [node.operands[-2], Immediate.new(node.codeOrigin, 31), tmp2])
+                newList << Instruction.new(node.codeOrigin, "bineq", [tmp1, tmp2, node.operands[-1]])
+            when /^bmuli/
+                condition = $~.post_match
+                newList << Instruction.new(node.codeOrigin, "muli", node.operands[0..-2])
+                newList << Instruction.new(node.codeOrigin, "bti" + condition, [node.operands[-2], node.operands[-1]])
+            else
+                newList << node
+            end
+        else
+            newList << node
+        end
+    }
+    newList
+end
+
+#
+# Lowering of shift ops. For example:
+#
+# lshifti foo, bar
+#
+# will become:
+#
+# andi foo, 31, tmp
+# lshifti tmp, bar
+#
+
+def armV7SanitizeShift(operand, list)
+    return operand if operand.immediate?
+    
+    tmp = Tmp.new(operand.codeOrigin, :gpr)
+    list << Instruction.new(operand.codeOrigin, "andi", [operand, Immediate.new(operand.codeOrigin, 31), tmp])
+    tmp
+end
+
+def armV7LowerShiftOps(list)
+    newList = []
+    list.each {
+        | node |
+        if node.is_a? Instruction
+            case node.opcode
+            when "lshifti", "rshifti", "urshifti"
+                if node.operands.size == 2
+                    newList << Instruction.new(node.codeOrigin, node.opcode, [armV7SanitizeShift(node.operands[0], newList), node.operands[1]])
+                else
+                    newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], armV7SanitizeShift(node.operands[1], newList), node.operands[2]])
+                    raise "Wrong number of operands for shift at #{node.codeOriginString}" unless node.operands.size == 3
+                end
+            else
+                newList << node
+            end
+        else
+            newList << node
+        end
+    }
+    newList
+end
+
+#
+# Lowering of malformed addresses. For example:
+#
+# loadp 10000[foo], bar
+#
+# will become:
+#
+# move 10000, tmp
+# addp foo, tmp
+# loadp 0[tmp], bar
+#
+
+class Node
+    def armV7LowerMalformedAddressesRecurse(list)
+        mapChildren {
+            | node |
+            node.armV7LowerMalformedAddressesRecurse(list)
+        }
+    end
+end
+
+class Address
+    def armV7LowerMalformedAddressesRecurse(list)
+        if offset.value < -0xff or offset.value > 0xfff
+            tmp = Tmp.new(codeOrigin, :gpr)
+            list << Instruction.new(codeOrigin, "move", [offset, tmp])
+            list << Instruction.new(codeOrigin, "addp", [base, tmp])
+            Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
+        else
+            self
+        end
+    end
+end
+
+class BaseIndex
+    def armV7LowerMalformedAddressesRecurse(list)
+        if offset.value != 0
+            tmp = Tmp.new(codeOrigin, :gpr)
+            list << Instruction.new(codeOrigin, "move", [offset, tmp])
+            list << Instruction.new(codeOrigin, "addp", [base, tmp])
+            BaseIndex.new(codeOrigin, tmp, index, scale, Immediate.new(codeOrigin, 0))
+        else
+            self
+        end
+    end
+end
+
+class AbsoluteAddress
+    def armV7LowerMalformedAddressesRecurse(list)
+        tmp = Tmp.new(codeOrigin, :gpr)
+        list << Instruction.new(codeOrigin, "move", [address, tmp])
+        Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
+    end
+end
+
+def armV7LowerMalformedAddresses(list)
+    newList = []
+    list.each {
+        | node |
+        newList << node.armV7LowerMalformedAddressesRecurse(newList)
+    }
+    newList
+end
+
+#
+# Lowering of malformed addresses in double loads and stores. For example:
+#
+# loadd [foo, bar, 8], baz
+#
+# becomes:
+#
+# leap [foo, bar, 8], tmp
+# loadd [tmp], baz
+#
+
+class Node
+    def armV7DoubleAddress(list)
+        self
+    end
+end
+
+class BaseIndex
+    def armV7DoubleAddress(list)
+        tmp = Tmp.new(codeOrigin, :gpr)
+        list << Instruction.new(codeOrigin, "leap", [self, tmp])
+        Address.new(codeOrigin, tmp, Immediate.new(codeOrigin, 0))
+    end
+end
+
+def armV7LowerMalformedAddressesDouble(list)
+    newList = []
+    list.each {
+        | node |
+        if node.is_a? Instruction
+            case node.opcode
+            when "loadd"
+                newList << Instruction.new(node.codeOrigin, "loadd", [node.operands[0].armV7DoubleAddress(newList), node.operands[1]])
+            when "stored"
+                newList << Instruction.new(node.codeOrigin, "stored", [node.operands[0], node.operands[1].armV7DoubleAddress(newList)])
+            else
+                newList << node
+            end
+        else
+            newList << node
+        end
+    }
+    newList
+end
+
+#
+# Lowering of misplaced immediates. For example:
+#
+# storei 0, [foo]
+#
+# will become:
+#
+# move 0, tmp
+# storei tmp, [foo]
+#
+
+def armV7LowerMisplacedImmediates(list)
+    newList = []
+    list.each {
+        | node |
+        if node.is_a? Instruction
+            case node.opcode
+            when "storei", "storep"
+                operands = node.operands
+                newOperands = []
+                operands.each {
+                    | operand |
+                    if operand.is_a? Immediate
+                        tmp = Tmp.new(operand.codeOrigin, :gpr)
+                        newList << Instruction.new(operand.codeOrigin, "move", [operand, tmp])
+                        newOperands << tmp
+                    else
+                        newOperands << operand
+                    end
+                }
+                newList << Instruction.new(node.codeOrigin, node.opcode, newOperands)
+            else
+                newList << node
+            end
+        else
+            newList << node
+        end
+    }
+    newList
+end
+
+#
+# Lowering of malformed immediates except when used in a "move" instruction.
+# For example:
+#
+# addp 642641, foo
+#
+# will become:
+#
+# move 642641, tmp
+# addp tmp, foo
+#
+
+class Node
+    def armV7LowerMalformedImmediatesRecurse(list)
+        mapChildren {
+            | node |
+            node.armV7LowerMalformedImmediatesRecurse(list)
+        }
+    end
+end
+
+class Address
+    def armV7LowerMalformedImmediatesRecurse(list)
+        self
+    end
+end
+
+class BaseIndex
+    def armV7LowerMalformedImmediatesRecurse(list)
+        self
+    end
+end
+
+class AbsoluteAddress
+    def armV7LowerMalformedImmediatesRecurse(list)
+        self
+    end
+end
+
+class Immediate
+    def armV7LowerMalformedImmediatesRecurse(list)
+        if value < 0 or value > 255
+            tmp = Tmp.new(codeOrigin, :gpr)
+            list << Instruction.new(codeOrigin, "move", [self, tmp])
+            tmp
+        else
+            self
+        end
+    end
+end
+
+def armV7LowerMalformedImmediates(list)
+    newList = []
+    list.each {
+        | node |
+        if node.is_a? Instruction
+            case node.opcode
+            when "move"
+                newList << node
+            when "addi", "addp", "addis", "subi", "subp", "subis"
+                if node.operands[0].is_a? Immediate and
+                        node.operands[0].value < 0 and
+                        node.operands[0].value >= 255 and
+                        node.operands.size == 2
+                    if node.opcode =~ /add/
+                        newOpcode = "sub" + node.opcode[-1..-1]
+                    else
+                        newOpcode = "add" + node.opcode[-1..-1]
+                    end
+                    newList << Instruction.new(node.codeOrigin, newOpcode,
+                                               [Immediate.new(-node.operands[0].value)] + node.operands[1..-1])
+                else
+                    newList << node.armV7LowerMalformedImmediatesRecurse(newList)
+                end
+            when "muli"
+                if node.operands[0].is_a? Immediate
+                    tmp = Tmp.new(codeOrigin, :gpr)
+                    newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp])
+                    newList << Instruction.new(node.codeOrigin, "muli", [tmp] + node.operands[1..-1])
+                else
+                    newList << node.armV7LowerMalformedImmediatesRecurse(newList)
+                end
+            else
+                newList << node.armV7LowerMalformedImmediatesRecurse(newList)
+            end
+        else
+            newList << node
+        end
+    }
+    newList
+end
+
+#
+# Lowering of misplaced addresses. For example:
+#
+# addi foo, [bar]
+#
+# will become:
+#
+# loadi [bar], tmp
+# addi foo, tmp
+# storei tmp, [bar]
+#
+# Another example:
+#
+# addi [foo], bar
+#
+# will become:
+#
+# loadi [foo], tmp
+# addi tmp, bar
+#
+
+def armV7AsRegister(preList, postList, operand, suffix, needStore)
+    return operand unless operand.address?
+    
+    tmp = Tmp.new(operand.codeOrigin, if suffix == "d" then :fpr else :gpr end)
+    preList << Instruction.new(operand.codeOrigin, "load" + suffix, [operand, tmp])
+    if needStore
+        postList << Instruction.new(operand.codeOrigin, "store" + suffix, [tmp, operand])
+    end
+    tmp
+end
+
+def armV7AsRegisters(preList, postList, operands, suffix)
+    newOperands = []
+    operands.each_with_index {
+        | operand, index |
+        newOperands << armV7AsRegister(preList, postList, operand, suffix, index == operands.size - 1)
+    }
+    newOperands
+end
+
+def armV7LowerMisplacedAddresses(list)
+    newList = []
+    list.each {
+        | node |
+        if node.is_a? Instruction
+            postInstructions = []
+            case node.opcode
+            when "addi", "addp", "addis", "andi", "andp", "lshifti", "muli", "negi", "noti", "ori", "oris",
+                "orp", "rshifti", "urshifti", "subi", "subp", "subis", "xori", "xorp", /^bi/, /^bp/, /^bti/,
+                /^btp/, /^ci/, /^cp/, /^ti/
+                newList << Instruction.new(node.codeOrigin,
+                                           node.opcode,
+                                           armV7AsRegisters(newList, postInstructions, node.operands, "i"))
+            when "bbeq", "bbneq", "bba", "bbaeq", "bbb", "bbbeq", "btbo", "btbz", "btbnz", "tbz", "tbnz",
+                "tbo"
+                newList << Instruction.new(node.codeOrigin,
+                                           node.opcode,
+                                           armV7AsRegisters(newList, postInstructions, node.operands, "b"))
+            when "bbgt", "bbgteq", "bblt", "bblteq", "btbs", "tbs"
+                newList << Instruction.new(node.codeOrigin,
+                                           node.opcode,
+                                           armV7AsRegisters(newList, postInstructions, node.operands, "bs"))
+            when "addd", "divd", "subd", "muld", "sqrtd", /^bd/
+                newList << Instruction.new(node.codeOrigin,
+                                           node.opcode,
+                                           armV7AsRegisters(newList, postInstructions, node.operands, "d"))
+            when "jmp", "call"
+                newList << Instruction.new(node.codeOrigin,
+                                           node.opcode,
+                                           [armV7AsRegister(newList, postInstructions, node.operands[0], "p", false)])
+            else
+                newList << node
+            end
+            newList += postInstructions
+        else
+            newList << node
+        end
+    }
+    newList
+end
+
+#
+# Lowering of register reuse in compare instructions. For example:
+#
+# cieq t0, t1, t0
+#
+# will become:
+#
+# mov tmp, t0
+# cieq tmp, t1, t0
+#
+
+def armV7LowerRegisterReuse(list)
+    newList = []
+    list.each {
+        | node |
+        if node.is_a? Instruction
+            case node.opcode
+            when "cieq", "cineq", "cia", "ciaeq", "cib", "cibeq", "cigt", "cigteq", "cilt", "cilteq",
+                "cpeq", "cpneq", "cpa", "cpaeq", "cpb", "cpbeq", "cpgt", "cpgteq", "cplt", "cplteq",
+                "tio", "tis", "tiz", "tinz", "tbo", "tbs", "tbz", "tbnz"
+                if node.operands.size == 2
+                    if node.operands[0] == node.operands[1]
+                        tmp = Tmp.new(node.codeOrigin, :gpr)
+                        newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp])
+                        newList << Instruction.new(node.codeOrigin, node.opcode, [tmp, node.operands[1]])
+                    else
+                        newList << node
+                    end
+                else
+                    raise "Wrong number of arguments at #{node.codeOriginString}" unless node.operands.size == 3
+                    if node.operands[0] == node.operands[2]
+                        tmp = Tmp.new(node.codeOrigin, :gpr)
+                        newList << Instruction.new(node.codeOrigin, "move", [node.operands[0], tmp])
+                        newList << Instruction.new(node.codeOrigin, node.opcode, [tmp, node.operands[1], node.operands[2]])
+                    elsif node.operands[1] == node.operands[2]
+                        tmp = Tmp.new(node.codeOrigin, :gpr)
+                        newList << Instruction.new(node.codeOrigin, "move", [node.operands[1], tmp])
+                        newList << Instruction.new(node.codeOrigin, node.opcode, [node.operands[0], tmp, node.operands[2]])
+                    else
+                        newList << node
+                    end
+                end
+            else
+                newList << node
+            end
+        else
+            newList << node
+        end
+    }
+    newList
+end
+
+#
+# Lea support.
+#
+
+class Address
+    def armV7EmitLea(destination)
+        if destination == base
+            $asm.puts "adds #{destination.armV7Operand}, \##{offset.value}"
+        else
+            $asm.puts "adds #{destination.armV7Operand}, #{base.armV7Operand}, \##{offset.value}"
+        end
+    end
+end
+
+class BaseIndex
+    def armV7EmitLea(destination)
+        raise "Malformed BaseIndex, offset should be zero at #{codeOriginString}" unless offset.value == 0
+        $asm.puts "add.w #{destination.armV7Operand}, #{base.armV7Operand}, #{index.armV7Operand}, lsl \##{scaleShift}"
+    end
+end
+
+# FIXME: we could support AbsoluteAddress for lea, but we don't.
+
+#
+# Actual lowering code follows.
+#
+
+class Sequence
+    def lowerARMv7
+        myList = @list
+        
+        # Verify that we will only see instructions and labels.
+        myList.each {
+            | node |
+            unless node.is_a? Instruction or
+                    node.is_a? Label or
+                    node.is_a? LocalLabel or
+                    node.is_a? Skip
+                raise "Unexpected #{node.inspect} at #{node.codeOrigin}" 
+            end
+        }
+        
+        myList = armV7LowerBranchOps(myList)
+        myList = armV7LowerShiftOps(myList)
+        myList = armV7LowerMalformedAddresses(myList)
+        myList = armV7LowerMalformedAddressesDouble(myList)
+        myList = armV7LowerMisplacedImmediates(myList)
+        myList = armV7LowerMalformedImmediates(myList)
+        myList = armV7LowerMisplacedAddresses(myList)
+        myList = armV7LowerRegisterReuse(myList)
+        myList = assignRegistersToTemporaries(myList, :gpr, ARMv7_EXTRA_GPRS)
+        myList = assignRegistersToTemporaries(myList, :fpr, ARMv7_EXTRA_FPRS)
+        myList.each {
+            | node |
+            node.lower("ARMv7")
+        }
+    end
+end
+
+def armV7Operands(operands)
+    operands.map{|v| v.armV7Operand}.join(", ")
+end
+
+def armV7FlippedOperands(operands)
+    armV7Operands([operands[-1]] + operands[0..-2])
+end
+
+def emitArmV7Compact(opcode2, opcode3, operands)
+    if operands.size == 3
+        $asm.puts "#{opcode3} #{armV7FlippedOperands(operands)}"
+    else
+        raise unless operands.size == 2
+        raise unless operands[1].is_a? RegisterID
+        if operands[0].is_a? Immediate
+            $asm.puts "#{opcode3} #{operands[1].armV7Operand}, #{operands[1].armV7Operand}, #{operands[0].armV7Operand}"
+        else
+            $asm.puts "#{opcode2} #{armV7FlippedOperands(operands)}"
+        end
+    end
+end
+
+def emitArmV7(opcode, operands)
+    if operands.size == 3
+        $asm.puts "#{opcode} #{armV7FlippedOperands(operands)}"
+    else
+        raise unless operands.size == 2
+        $asm.puts "#{opcode} #{operands[1].armV7Operand}, #{operands[1].armV7Operand}, #{operands[0].armV7Operand}"
+    end
+end
+
+def emitArmV7DoubleBranch(branchOpcode, operands)
+    $asm.puts "vcmpe.f64 #{armV7Operands(operands[0..1])}"
+    $asm.puts "vmrs apsr_nzcv, fpscr"
+    $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
+end
+
+def emitArmV7Test(operands)
+    value = operands[0]
+    case operands.size
+    when 2
+        mask = Immediate.new(codeOrigin, -1)
+    when 3
+        mask = operands[1]
+    else
+        raise "Expected 2 or 3 operands but got #{operands.size} at #{codeOriginString}"
+    end
+    
+    if mask.is_a? Immediate and mask.value == -1
+        $asm.puts "tst #{value.armV7Operand}, #{value.armV7Operand}"
+    elsif mask.is_a? Immediate
+        $asm.puts "tst.w #{value.armV7Operand}, #{mask.armV7Operand}"
+    else
+        $asm.puts "tst #{value.armV7Operand}, #{mask.armV7Operand}"
+    end
+end
+
+def emitArmV7Compare(operands, code)
+    $asm.puts "movs #{operands[2].armV7Operand}, \#0"
+    $asm.puts "cmp #{operands[0].armV7Operand}, #{operands[1].armV7Operand}"
+    $asm.puts "it #{code}"
+    $asm.puts "mov#{code} #{operands[2].armV7Operand}, \#1"
+end
+
+def emitArmV7TestSet(operands, code)
+    $asm.puts "movs #{operands[-1].armV7Operand}, \#0"
+    emitArmV7Test(operands)
+    $asm.puts "it #{code}"
+    $asm.puts "mov#{code} #{operands[-1].armV7Operand}, \#1"
+end
+
+class Instruction
+    def lowerARMv7
+        $asm.comment codeOriginString
+        case opcode
+        when "addi", "addp", "addis"
+            if opcode == "addis"
+                suffix = "s"
+            else
+                suffix = ""
+            end
+            if operands.size == 3 and operands[0].is_a? Immediate
+                raise unless operands[1].is_a? RegisterID
+                raise unless operands[2].is_a? RegisterID
+                if operands[0].value == 0 and suffix.empty?
+                    unless operands[1] == operands[2]
+                        $asm.puts "mov #{operands[2].armV7Operand}, #{operands[1].armV7Operand}"
+                    end
+                else
+                    $asm.puts "adds #{operands[2].armV7Operand}, #{operands[1].armV7Operand}, #{operands[0].armV7Operand}"
+                end
+            elsif operands.size == 3 and operands[0].is_a? RegisterID
+                raise unless operands[1].is_a? RegisterID
+                raise unless operands[2].is_a? RegisterID
+                $asm.puts "adds #{armV7FlippedOperands(operands)}"
+            else
+                if operands[0].is_a? Immediate
+                    unless Immediate.new(nil, 0) == operands[0]
+                        $asm.puts "adds #{armV7FlippedOperands(operands)}"
+                    end
+                else
+                    $asm.puts "add#{suffix} #{armV7FlippedOperands(operands)}"
+                end
+            end
+        when "andi", "andp"
+            emitArmV7Compact("ands", "and", operands)
+        when "ori", "orp"
+            emitArmV7Compact("orrs", "orr", operands)
+        when "oris"
+            emitArmV7Compact("orrs", "orrs", operands)
+        when "xori", "xorp"
+            emitArmV7Compact("eors", "eor", operands)
+        when "lshifti"
+            emitArmV7Compact("lsls", "lsls", operands)
+        when "rshifti"
+            emitArmV7Compact("asrs", "asrs", operands)
+        when "urshifti"
+            emitArmV7Compact("lsrs", "lsrs", operands)
+        when "muli"
+            if operands.size == 2 or operands[0] == operands[2] or operands[1] == operands[2]
+                emitArmV7("muls", operands)
+            else
+                $asm.puts "mov #{operands[2].armV7Operand}, #{operands[0].armV7Operand}"
+                $asm.puts "muls #{operands[2].armV7Operand}, #{operands[2].armV7Operand}, #{operands[1].armV7Operand}"
+            end
+        when "subi", "subp", "subis"
+            emitArmV7Compact("subs", "subs", operands)
+        when "negi"
+            $asm.puts "rsbs #{operands[0].armV7Operand}, #{operands[0].armV7Operand}, \#0"
+        when "noti"
+            $asm.puts "mvns #{operands[0].armV7Operand}, #{operands[0].armV7Operand}"
+        when "loadi", "loadp"
+            $asm.puts "ldr #{armV7FlippedOperands(operands)}"
+        when "storei", "storep"
+            $asm.puts "str #{armV7Operands(operands)}"
+        when "loadb"
+            $asm.puts "ldrb #{armV7FlippedOperands(operands)}"
+        when "loadbs"
+            $asm.puts "ldrsb.w #{armV7FlippedOperands(operands)}"
+        when "storeb"
+            $asm.puts "strb #{armV7Operands(operands)}"
+        when "loadh"
+            $asm.puts "ldrh #{armV7FlippedOperands(operands)}"
+        when "loadhs"
+            $asm.puts "ldrsh.w #{armV7FlippedOperands(operands)}"
+        when "storeh"
+            $asm.puts "strh #{armV7Operands(operands)}"
+        when "loadd"
+            $asm.puts "vldr.64 #{armV7FlippedOperands(operands)}"
+        when "stored"
+            $asm.puts "vstr.64 #{armV7Operands(operands)}"
+        when "addd"
+            emitArmV7("vadd.f64", operands)
+        when "divd"
+            emitArmV7("vdiv.f64", operands)
+        when "subd"
+            emitArmV7("vsub.f64", operands)
+        when "muld"
+            emitArmV7("vmul.f64", operands)
+        when "sqrtd"
+            $asm.puts "vsqrt.f64 #{armV7FlippedOperands(operands)}"
+        when "ci2d"
+            $asm.puts "vmov #{operands[1].armV7Single}, #{operands[0].armV7Operand}"
+            $asm.puts "vcvt.f64.s32 #{operands[1].armV7Operand}, #{operands[1].armV7Single}"
+        when "bdeq"
+            emitArmV7DoubleBranch("beq", operands)
+        when "bdneq"
+            $asm.puts "vcmpe.f64 #{armV7Operands(operands[0..1])}"
+            $asm.puts "vmrs apsr_nzcv, fpscr"
+            isUnordered = LocalLabel.unique("bdneq")
+            $asm.puts "bvs #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
+            $asm.puts "bne #{operands[2].asmLabel}"
+            isUnordered.lower("ARMv7")
+        when "bdgt"
+            emitArmV7DoubleBranch("bgt", operands)
+        when "bdgteq"
+            emitArmV7DoubleBranch("bge", operands)
+        when "bdlt"
+            emitArmV7DoubleBranch("bmi", operands)
+        when "bdlteq"
+            emitArmV7DoubleBranch("bls", operands)
+        when "bdequn"
+            $asm.puts "vcmpe.f64 #{armV7Operands(operands[0..1])}"
+            $asm.puts "vmrs apsr_nzcv, fpscr"
+            $asm.puts "bvs #{operands[2].asmLabel}"
+            $asm.puts "beq #{operands[2].asmLabel}"
+        when "bdnequn"
+            emitArmV7DoubleBranch("bne", operands)
+        when "bdgtun"
+            emitArmV7DoubleBranch("bhi", operands)
+        when "bdgtequn"
+            emitArmV7DoubleBranch("bpl", operands)
+        when "bdltun"
+            emitArmV7DoubleBranch("blt", operands)
+        when "bdltequn"
+            emitArmV7DoubleBranch("ble", operands)
+        when "btd2i"
+            # FIXME: may be a good idea to just get rid of this instruction, since the interpreter
+            # currently does not use it.
+            raise "ARMv7 does not support this opcode yet, #{codeOrigin}"
+        when "td2i"
+            $asm.puts "vcvt.s32.f64 #{ARMv7_SCRATCH_FPR.armV7Single}, #{operands[0].armV7Operand}"
+            $asm.puts "vmov #{operands[1].armV7Operand}, #{ARMv7_SCRATCH_FPR.armV7Single}"
+        when "bcd2i"
+            $asm.puts "vcvt.s32.f64 #{ARMv7_SCRATCH_FPR.armV7Single}, #{operands[0].armV7Operand}"
+            $asm.puts "vmov #{operands[1].armV7Operand}, #{ARMv7_SCRATCH_FPR.armV7Single}"
+            $asm.puts "vcvt.f64.s32 #{ARMv7_SCRATCH_FPR.armV7Operand}, #{ARMv7_SCRATCH_FPR.armV7Single}"
+            emitArmV7DoubleBranch("bne", [ARMv7_SCRATCH_FPR, operands[0], operands[2]])
+            $asm.puts "tst #{operands[1].armV7Operand}, #{operands[1].armV7Operand}"
+            $asm.puts "beq #{operands[2].asmLabel}"
+        when "movdz"
+            # FIXME: either support this or remove it.
+            raise "ARMv7 does not support this opcode yet, #{codeOrigin}"
+        when "pop"
+            $asm.puts "pop #{operands[0].armV7Operand}"
+        when "push"
+            $asm.puts "push #{operands[0].armV7Operand}"
+        when "move", "sxi2p", "zxi2p"
+            if operands[0].is_a? Immediate
+                armV7MoveImmediate(operands[0].value, operands[1])
+            else
+                $asm.puts "mov #{armV7FlippedOperands(operands)}"
+            end
+        when "nop"
+            $asm.puts "nop"
+        when "bieq", "bpeq", "bbeq"
+            if Immediate.new(nil, 0) == operands[0]
+                $asm.puts "tst #{operands[1].armV7Operand}, #{operands[1].armV7Operand}"
+            elsif Immediate.new(nil, 0) == operands[1]
+                $asm.puts "tst #{operands[0].armV7Operand}, #{operands[0].armV7Operand}"
+            else
+                $asm.puts "cmp #{armV7Operands(operands[0..1])}"
+            end
+            $asm.puts "beq #{operands[2].asmLabel}"
+        when "bineq", "bpneq", "bbneq"
+            if Immediate.new(nil, 0) == operands[0]
+                $asm.puts "tst #{operands[1].armV7Operand}, #{operands[1].armV7Operand}"
+            elsif Immediate.new(nil, 0) == operands[1]
+                $asm.puts "tst #{operands[0].armV7Operand}, #{operands[0].armV7Operand}"
+            else
+                $asm.puts "cmp #{armV7Operands(operands[0..1])}"
+            end
+            $asm.puts "bne #{operands[2].asmLabel}"
+        when "bia", "bpa", "bba"
+            $asm.puts "cmp #{armV7Operands(operands[0..1])}"
+            $asm.puts "bhi #{operands[2].asmLabel}"
+        when "biaeq", "bpaeq", "bbaeq"
+            $asm.puts "cmp #{armV7Operands(operands[0..1])}"
+            $asm.puts "bhs #{operands[2].asmLabel}"
+        when "bib", "bpb", "bbb"
+            $asm.puts "cmp #{armV7Operands(operands[0..1])}"
+            $asm.puts "blo #{operands[2].asmLabel}"
+        when "bibeq", "bpbeq", "bbbeq"
+            $asm.puts "cmp #{armV7Operands(operands[0..1])}"
+            $asm.puts "bls #{operands[2].asmLabel}"
+        when "bigt", "bpgt", "bbgt"
+            $asm.puts "cmp #{armV7Operands(operands[0..1])}"
+            $asm.puts "bgt #{operands[2].asmLabel}"
+        when "bigteq", "bpgteq", "bbgteq"
+            $asm.puts "cmp #{armV7Operands(operands[0..1])}"
+            $asm.puts "bge #{operands[2].asmLabel}"
+        when "bilt", "bplt", "bblt"
+            $asm.puts "cmp #{armV7Operands(operands[0..1])}"
+            $asm.puts "blt #{operands[2].asmLabel}"
+        when "bilteq", "bplteq", "bblteq"
+            $asm.puts "cmp #{armV7Operands(operands[0..1])}"
+            $asm.puts "ble #{operands[2].asmLabel}"
+        when "btiz", "btpz", "btbz"
+            emitArmV7Test(operands)
+            $asm.puts "beq #{operands[-1].asmLabel}"
+        when "btinz", "btpnz", "btbnz"
+            emitArmV7Test(operands)
+            $asm.puts "bne #{operands[-1].asmLabel}"
+        when "btio", "btpo", "btbo"
+            emitArmV7Test(operands)
+            $asm.puts "bvs #{operands[-1].asmLabel}"
+        when "btis", "btps", "btbs"
+            emitArmV7Test(operands)
+            $asm.puts "bmi #{operands[-1].asmLabel}"
+        when "jmp"
+            if operands[0].label?
+                $asm.puts "b #{operands[0].asmLabel}"
+            else
+                $asm.puts "mov pc, #{operands[0].armV7Operand}"
+            end
+        when "call"
+            if operands[0].label?
+                $asm.puts "blx #{operands[0].asmLabel}"
+            else
+                $asm.puts "blx #{operands[0].armV7Operand}"
+            end
+        when "break"
+            $asm.puts "bkpt"
+        when "ret"
+            $asm.puts "bx lr"
+        when "cieq", "cpeq"
+            emitArmV7Compare(operands, "eq")
+        when "cineq", "cpneq"
+            emitArmV7Compare(operands, "ne")
+        when "cia", "cpa"
+            emitArmV7Compare(operands, "hi")
+        when "ciaeq", "cpaeq"
+            emitArmV7Compare(operands, "hs")
+        when "cib", "cpb"
+            emitArmV7Compare(operands, "lo")
+        when "cibeq", "cpbeq"
+            emitArmV7Compare(operands, "ls")
+        when "cigt", "cpgt"
+            emitArmV7Compare(operands, "gt")
+        when "cigteq", "cpgteq"
+            emitArmV7Compare(operands, "ge")
+        when "cilt", "cplt"
+            emitArmV7Compare(operands, "lt")
+        when "cilteq", "cplteq"
+            emitArmV7Compare(operands, "le")
+        when "tio", "tbo"
+            emitArmV7TestSet(operands, "vs")
+        when "tis", "tbs"
+            emitArmV7TestSet(operands, "mi")
+        when "tiz", "tbz"
+            emitArmV7TestSet(operands, "eq")
+        when "tinz", "tbnz"
+            emitArmV7TestSet(operands, "ne")
+        when "peek"
+            $asm.puts "ldr #{operands[1].armV7Operand}, [sp, \##{operands[0].value * 4}]"
+        when "poke"
+            $asm.puts "str #{operands[1].armV7Operand}, [sp, \##{operands[0].value * 4}]"
+        when "fii2d"
+            $asm.puts "vmov #{operands[2].armV7Operand}, #{operands[0].armV7Operand}, #{operands[1].armV7Operand}"
+        when "fd2ii"
+            $asm.puts "vmov #{operands[1].armV7Operand}, #{operands[2].armV7Operand}, #{operands[0].armV7Operand}"
+        when "bo"
+            $asm.puts "bvs #{operands[0].asmLabel}"
+        when "bs"
+            $asm.puts "bmi #{operands[0].asmLabel}"
+        when "bz"
+            $asm.puts "beq #{operands[0].asmLabel}"
+        when "bnz"
+            $asm.puts "bne #{operands[0].asmLabel}"
+        when "leai", "leap"
+            operands[0].armV7EmitLea(operands[1])
+        when "smulli"
+            raise "Wrong number of arguments to smull in #{self.inspect} at #{codeOriginString}" unless operands.length == 4
+            $asm.puts "smull #{operands[2].armV7Operand}, #{operands[3].armV7Operand}, #{operands[0].armV7Operand}, #{operands[1].armV7Operand}"
+        else
+            raise "Unhandled opcode #{opcode} at #{codeOriginString}"
+        end
+    end
+end
+
diff --git a/Source/JavaScriptCore/offlineasm/asm.rb b/Source/JavaScriptCore/offlineasm/asm.rb
new file mode 100644
index 0000000..a93a8c5
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/asm.rb
@@ -0,0 +1,176 @@
+#!/usr/bin/env ruby
+
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+$: << File.dirname(__FILE__)
+
+require "backends"
+require "digest/sha1"
+require "offsets"
+require "parser"
+require "self_hash"
+require "settings"
+require "transform"
+
+class Assembler
+    def initialize(outp)
+        @outp = outp
+        @state = :cpp
+        @commentState = :none
+        @comment = nil
+    end
+    
+    def enterAsm
+        @outp.puts "asm ("
+        @state = :asm
+    end
+    
+    def leaveAsm
+        putsLastComment
+        @outp.puts ");"
+        @state = :cpp
+    end
+    
+    def inAsm
+        enterAsm
+        yield
+        leaveAsm
+    end
+    
+    def lastComment
+        if @comment
+            result = "// #{@comment}"
+        else
+            result = ""
+        end
+        @commentState = :none
+        @comment = nil
+        result
+    end
+    
+    def putsLastComment
+        comment = lastComment
+        unless comment.empty?
+            @outp.puts comment
+        end
+    end
+    
+    def puts(*line)
+        raise unless @state == :asm
+        @outp.puts("\"\\t" + line.join('') + "\\n\" #{lastComment}")
+    end
+    
+    def print(line)
+        raise unless @state == :asm
+        @outp.print("\"" + line + "\"")
+    end
+    
+    def putsLabel(labelName)
+        raise unless @state == :asm
+        @outp.puts("OFFLINE_ASM_GLOBAL_LABEL(#{labelName}) #{lastComment}")
+    end
+    
+    def putsLocalLabel(labelName)
+        raise unless @state == :asm
+        @outp.puts("LOCAL_LABEL_STRING(#{labelName}) \":\\n\" #{lastComment}")
+    end
+    
+    def self.labelReference(labelName)
+        "\" SYMBOL_STRING(#{labelName}) \""
+    end
+    
+    def self.localLabelReference(labelName)
+        "\" LOCAL_LABEL_STRING(#{labelName}) \""
+    end
+    
+    def comment(text)
+        case @commentState
+        when :none
+            @comment = text
+            @commentState = :one
+        when :one
+            @outp.puts "// #{@comment}"
+            @outp.puts "// #{text}"
+            @comment = nil
+            @commentState = :many
+        when :many
+            @outp.puts "// #{text}"
+        else
+            raise
+        end
+    end
+end
+
+asmFile = ARGV.shift
+offsetsFile = ARGV.shift
+outputFlnm = ARGV.shift
+
+$stderr.puts "offlineasm: Parsing #{asmFile} and #{offsetsFile} and creating assembly file #{outputFlnm}."
+
+configurationList = offsetsAndConfigurationIndex(offsetsFile)
+inputData = IO::read(asmFile)
+
+inputHash =
+    "// offlineasm input hash: " + Digest::SHA1.hexdigest(inputData) +
+    " " + Digest::SHA1.hexdigest(configurationList.map{|v| (v[0] + [v[1]]).join(' ')}.join(' ')) +
+    " " + selfHash
+
+if FileTest.exist? outputFlnm
+    File.open(outputFlnm, "r") {
+        | inp |
+        firstLine = inp.gets
+        if firstLine and firstLine.chomp == inputHash
+            $stderr.puts "offlineasm: Nothing changed."
+            exit 0
+        end
+    }
+end
+
+File.open(outputFlnm, "w") {
+    | outp |
+    $output = outp
+    $output.puts inputHash
+    
+    $asm = Assembler.new($output)
+    
+    ast = parse(lex(inputData))
+    
+    configurationList.each {
+        | configuration |
+        offsetsList = configuration[0]
+        configIndex = configuration[1]
+        forSettings(computeSettingsCombinations(ast)[configIndex], ast) {
+            | concreteSettings, lowLevelAST, backend |
+            lowLevelAST = lowLevelAST.resolve(*buildOffsetsMap(lowLevelAST, offsetsList))
+            emitCodeInConfiguration(concreteSettings, lowLevelAST, backend) {
+                $asm.inAsm {
+                    lowLevelAST.lower(backend)
+                }
+            }
+        }
+    }
+}
+
+$stderr.puts "offlineasm: Assembly file #{outputFlnm} successfully generated."
+
diff --git a/Source/JavaScriptCore/offlineasm/ast.rb b/Source/JavaScriptCore/offlineasm/ast.rb
new file mode 100644
index 0000000..f67b0fc
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/ast.rb
@@ -0,0 +1,1039 @@
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+#
+# Base utility types for the AST.
+#
+
+# Valid methods for Node:
+#
+# node.children -> Returns an array of immediate children.
+#
+# node.descendents -> Returns an array of all strict descendants (children
+#     and children of children, transitively).
+#
+# node.flatten -> Returns an array containing the strict descendants and
+#     the node itself.
+#
+# node.filter(type) -> Returns an array containing those elements in
+#     node.flatten that are of the given type (is_a? type returns true).
+#
+# node.mapChildren{|v| ...} -> Returns a new node with all children
+#     replaced according to the given block.
+#
+# Examples:
+#
+# node.filter(Setting).uniq -> Returns all of the settings that the AST's
+#     IfThenElse blocks depend on.
+#
+# node.filter(StructOffset).uniq -> Returns all of the structure offsets
+#     that the AST depends on.
+
+class Node
+    attr_reader :codeOrigin
+    
+    def initialize(codeOrigin)
+        @codeOrigin = codeOrigin
+    end
+    
+    def codeOriginString
+        "line number #{@codeOrigin}"
+    end
+    
+    def descendants
+        children.collect{|v| v.flatten}.flatten
+    end
+    
+    def flatten
+        [self] + descendants
+    end
+    
+    def filter(type)
+        flatten.select{|v| v.is_a? type}
+    end
+end
+
+class NoChildren < Node
+    def initialize(codeOrigin)
+        super(codeOrigin)
+    end
+    
+    def children
+        []
+    end
+    
+    def mapChildren
+        self
+    end
+end
+
+class StructOffsetKey
+    attr_reader :struct, :field
+    
+    def initialize(struct, field)
+        @struct = struct
+        @field = field
+    end
+    
+    def hash
+        @struct.hash + @field.hash * 3
+    end
+    
+    def eql?(other)
+        @struct == other.struct and @field == other.field
+    end
+end
+
+#
+# AST nodes.
+#
+
+class StructOffset < NoChildren
+    attr_reader :struct, :field
+    
+    def initialize(codeOrigin, struct, field)
+        super(codeOrigin)
+        @struct = struct
+        @field = field
+    end
+    
+    @@mapping = {}
+    
+    def self.forField(codeOrigin, struct, field)
+        key = StructOffsetKey.new(struct, field)
+        
+        unless @@mapping[key]
+            @@mapping[key] = StructOffset.new(codeOrigin, struct, field)
+        end
+        @@mapping[key]
+    end
+    
+    def dump
+        "#{struct}::#{field}"
+    end
+    
+    def <=>(other)
+        if @struct != other.struct
+            return @struct <=> other.struct
+        end
+        @field <=> other.field
+    end
+    
+    def address?
+        false
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        true
+    end
+    
+    def register?
+        false
+    end
+end
+
+class Sizeof < NoChildren
+    attr_reader :struct
+    
+    def initialize(codeOrigin, struct)
+        super(codeOrigin)
+        @struct = struct
+    end
+    
+    @@mapping = {}
+    
+    def self.forName(codeOrigin, struct)
+        unless @@mapping[struct]
+            @@mapping[struct] = Sizeof.new(codeOrigin, struct)
+        end
+        @@mapping[struct]
+    end
+    
+    def dump
+        "sizeof #{@struct}"
+    end
+    
+    def <=>(other)
+        @struct <=> other.struct
+    end
+    
+    def address?
+        false
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        true
+    end
+    
+    def register?
+        false
+    end
+end
+
+class Immediate < NoChildren
+    attr_reader :value
+    
+    def initialize(codeOrigin, value)
+        super(codeOrigin)
+        @value = value
+        raise "Bad immediate value #{value.inspect} at #{codeOriginString}" unless value.is_a? Integer
+    end
+    
+    def dump
+        "#{value}"
+    end
+    
+    def ==(other)
+        other.is_a? Immediate and other.value == @value
+    end
+    
+    def address?
+        false
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        true
+    end
+    
+    def register?
+        false
+    end
+end
+
+class AddImmediates < Node
+    attr_reader :left, :right
+    
+    def initialize(codeOrigin, left, right)
+        super(codeOrigin)
+        @left = left
+        @right = right
+    end
+    
+    def children
+        [@left, @right]
+    end
+    
+    def mapChildren
+        AddImmediates.new(codeOrigin, (yield @left), (yield @right))
+    end
+    
+    def dump
+        "(#{left.dump} + #{right.dump})"
+    end
+    
+    def address?
+        false
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        true
+    end
+    
+    def register?
+        false
+    end
+end
+
+class SubImmediates < Node
+    attr_reader :left, :right
+    
+    def initialize(codeOrigin, left, right)
+        super(codeOrigin)
+        @left = left
+        @right = right
+    end
+    
+    def children
+        [@left, @right]
+    end
+    
+    def mapChildren
+        SubImmediates.new(codeOrigin, (yield @left), (yield @right))
+    end
+    
+    def dump
+        "(#{left.dump} - #{right.dump})"
+    end
+    
+    def address?
+        false
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        true
+    end
+    
+    def register?
+        false
+    end
+end
+
+class MulImmediates < Node
+    attr_reader :left, :right
+    
+    def initialize(codeOrigin, left, right)
+        super(codeOrigin)
+        @left = left
+        @right = right
+    end
+    
+    def children
+        [@left, @right]
+    end
+    
+    def mapChildren
+        MulImmediates.new(codeOrigin, (yield @left), (yield @right))
+    end
+    
+    def dump
+        "(#{left.dump} * #{right.dump})"
+    end
+    
+    def address?
+        false
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        true
+    end
+    
+    def register?
+        false
+    end
+end
+
+class NegImmediate < Node
+    attr_reader :child
+    
+    def initialize(codeOrigin, child)
+        super(codeOrigin)
+        @child = child
+    end
+    
+    def children
+        [@child]
+    end
+    
+    def mapChildren
+        NegImmediate.new(codeOrigin, (yield @child))
+    end
+    
+    def dump
+        "(-#{@child.dump})"
+    end
+    
+    def address?
+        false
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        true
+    end
+    
+    def register?
+        false
+    end
+end
+
+class RegisterID < NoChildren
+    attr_reader :name
+    
+    def initialize(codeOrigin, name)
+        super(codeOrigin)
+        @name = name
+    end
+    
+    @@mapping = {}
+    
+    def self.forName(codeOrigin, name)
+        unless @@mapping[name]
+            @@mapping[name] = RegisterID.new(codeOrigin, name)
+        end
+        @@mapping[name]
+    end
+    
+    def dump
+        name
+    end
+    
+    def address?
+        false
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        false
+    end
+    
+    def register?
+        true
+    end
+end
+
+class FPRegisterID < NoChildren
+    attr_reader :name
+    
+    def initialize(codeOrigin, name)
+        super(codeOrigin)
+        @name = name
+    end
+    
+    @@mapping = {}
+    
+    def self.forName(codeOrigin, name)
+        unless @@mapping[name]
+            @@mapping[name] = FPRegisterID.new(codeOrigin, name)
+        end
+        @@mapping[name]
+    end
+    
+    def dump
+        name
+    end
+    
+    def address?
+        false
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        false
+    end
+    
+    def register?
+        true
+    end
+end
+
+class Variable < NoChildren
+    attr_reader :name
+    
+    def initialize(codeOrigin, name)
+        super(codeOrigin)
+        @name = name
+    end
+    
+    @@mapping = {}
+    
+    def self.forName(codeOrigin, name)
+        unless @@mapping[name]
+            @@mapping[name] = Variable.new(codeOrigin, name)
+        end
+        @@mapping[name]
+    end
+    
+    def dump
+        name
+    end
+end
+
+class Address < Node
+    attr_reader :base, :offset
+    
+    def initialize(codeOrigin, base, offset)
+        super(codeOrigin)
+        @base = base
+        @offset = offset
+        raise "Bad base for address #{base.inspect} at #{codeOriginString}" unless base.is_a? Variable or base.register?
+        raise "Bad offset for address #{offset.inspect} at #{codeOriginString}" unless offset.is_a? Variable or offset.immediate?
+    end
+    
+    def children
+        [@base, @offset]
+    end
+    
+    def mapChildren
+        Address.new(codeOrigin, (yield @base), (yield @offset))
+    end
+    
+    def dump
+        "#{offset.dump}[#{base.dump}]"
+    end
+    
+    def address?
+        true
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        false
+    end
+    
+    def register?
+        false
+    end
+end
+
+class BaseIndex < Node
+    attr_reader :base, :index, :scale, :offset
+    
+    def initialize(codeOrigin, base, index, scale, offset)
+        super(codeOrigin)
+        @base = base
+        @index = index
+        @scale = scale
+        raise unless [1, 2, 4, 8].member? @scale
+        @offset = offset
+    end
+    
+    def scaleShift
+        case scale
+        when 1
+            0
+        when 2
+            1
+        when 4
+            2
+        when 8
+            3
+        else
+            raise "Bad scale at #{codeOriginString}"
+        end
+    end
+    
+    def children
+        [@base, @index, @offset]
+    end
+    
+    def mapChildren
+        BaseIndex.new(codeOrigin, (yield @base), (yield @index), @scale, (yield @offset))
+    end
+    
+    def dump
+        "#{offset.dump}[#{base.dump}, #{index.dump}, #{scale}]"
+    end
+    
+    def address?
+        true
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        false
+    end
+    
+    def register?
+        false
+    end
+end
+
+class AbsoluteAddress < NoChildren
+    attr_reader :address
+    
+    def initialize(codeOrigin, address)
+        super(codeOrigin)
+        @address = address
+    end
+    
+    def dump
+        "#{address.dump}[]"
+    end
+    
+    def address?
+        true
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        false
+    end
+    
+    def register?
+        false
+    end
+end
+
+class Instruction < Node
+    attr_reader :opcode, :operands
+    
+    def initialize(codeOrigin, opcode, operands)
+        super(codeOrigin)
+        @opcode = opcode
+        @operands = operands
+    end
+    
+    def children
+        operands
+    end
+    
+    def mapChildren(&proc)
+        Instruction.new(codeOrigin, @opcode, @operands.map(&proc))
+    end
+    
+    def dump
+        "\t" + opcode.to_s + " " + operands.collect{|v| v.dump}.join(", ")
+    end
+end
+
+class Error < NoChildren
+    def initialize(codeOrigin)
+        super(codeOrigin)
+    end
+    
+    def dump
+        "\terror"
+    end
+end
+
+class ConstDecl < Node
+    attr_reader :variable, :value
+    
+    def initialize(codeOrigin, variable, value)
+        super(codeOrigin)
+        @variable = variable
+        @value = value
+    end
+    
+    def children
+        [@variable, @value]
+    end
+    
+    def mapChildren
+        ConstDecl.new(codeOrigin, (yield @variable), (yield @value))
+    end
+    
+    def dump
+        "const #{@variable.dump} = #{@value.dump}"
+    end
+end
+
+$labelMapping = {}
+
+class Label < NoChildren
+    attr_reader :name
+    
+    def initialize(codeOrigin, name)
+        super(codeOrigin)
+        @name = name
+    end
+    
+    def self.forName(codeOrigin, name)
+        if $labelMapping[name]
+            raise "Label name collision: #{name}" unless $labelMapping[name].is_a? Label
+        else
+            $labelMapping[name] = Label.new(codeOrigin, name)
+        end
+        $labelMapping[name]
+    end
+    
+    def dump
+        "#{name}:"
+    end
+end
+
+class LocalLabel < NoChildren
+    attr_reader :name
+    
+    def initialize(codeOrigin, name)
+        super(codeOrigin)
+        @name = name
+    end
+
+    @@uniqueNameCounter = 0
+    
+    def self.forName(codeOrigin, name)
+        if $labelMapping[name]
+            raise "Label name collision: #{name}" unless $labelMapping[name].is_a? LocalLabel
+        else
+            $labelMapping[name] = LocalLabel.new(codeOrigin, name)
+        end
+        $labelMapping[name]
+    end
+    
+    def self.unique(comment)
+        newName = "_#{comment}"
+        if $labelMapping[newName]
+            while $labelMapping[newName = "_#{@@uniqueNameCounter}_#{comment}"]
+                @@uniqueNameCounter += 1
+            end
+        end
+        forName(nil, newName)
+    end
+    
+    def cleanName
+        if name =~ /^\./
+            "_" + name[1..-1]
+        else
+            name
+        end
+    end
+    
+    def dump
+        "#{name}:"
+    end
+end
+
+class LabelReference < Node
+    attr_reader :label
+    
+    def initialize(codeOrigin, label)
+        super(codeOrigin)
+        @label = label
+    end
+    
+    def children
+        [@label]
+    end
+    
+    def mapChildren
+        LabelReference.new(codeOrigin, (yield @label))
+    end
+    
+    def name
+        label.name
+    end
+    
+    def dump
+        label.name
+    end
+    
+    def address?
+        false
+    end
+    
+    def label?
+        true
+    end
+end
+
+class LocalLabelReference < NoChildren
+    attr_reader :label
+    
+    def initialize(codeOrigin, label)
+        super(codeOrigin)
+        @label = label
+    end
+    
+    def children
+        [@label]
+    end
+    
+    def mapChildren
+        LocalLabelReference.new(codeOrigin, (yield @label))
+    end
+    
+    def name
+        label.name
+    end
+    
+    def dump
+        label.name
+    end
+    
+    def address?
+        false
+    end
+    
+    def label?
+        true
+    end
+end
+
+class Sequence < Node
+    attr_reader :list
+    
+    def initialize(codeOrigin, list)
+        super(codeOrigin)
+        @list = list
+    end
+    
+    def children
+        list
+    end
+    
+    def mapChildren(&proc)
+        Sequence.new(codeOrigin, @list.map(&proc))
+    end
+    
+    def dump
+        list.collect{|v| v.dump}.join("\n")
+    end
+end
+
+class True < NoChildren
+    def initialize
+        super(nil)
+    end
+    
+    @@instance = True.new
+    
+    def self.instance
+        @@instance
+    end
+    
+    def value
+        true
+    end
+    
+    def dump
+        "true"
+    end
+end
+
+class False < NoChildren
+    def initialize
+        super(nil)
+    end
+    
+    @@instance = False.new
+    
+    def self.instance
+        @@instance
+    end
+    
+    def value
+        false
+    end
+    
+    def dump
+        "false"
+    end
+end
+
+class TrueClass
+    def asNode
+        True.instance
+    end
+end
+
+class FalseClass
+    def asNode
+        False.instance
+    end
+end
+
+class Setting < NoChildren
+    attr_reader :name
+    
+    def initialize(codeOrigin, name)
+        super(codeOrigin)
+        @name = name
+    end
+    
+    @@mapping = {}
+    
+    def self.forName(codeOrigin, name)
+        unless @@mapping[name]
+            @@mapping[name] = Setting.new(codeOrigin, name)
+        end
+        @@mapping[name]
+    end
+    
+    def dump
+        name
+    end
+end
+
+class And < Node
+    attr_reader :left, :right
+    
+    def initialize(codeOrigin, left, right)
+        super(codeOrigin)
+        @left = left
+        @right = right
+    end
+    
+    def children
+        [@left, @right]
+    end
+    
+    def mapChildren
+        And.new(codeOrigin, (yield @left), (yield @right))
+    end
+    
+    def dump
+        "(#{left.dump} and #{right.dump})"
+    end
+end
+
+class Or < Node
+    attr_reader :left, :right
+    
+    def initialize(codeOrigin, left, right)
+        super(codeOrigin)
+        @left = left
+        @right = right
+    end
+    
+    def children
+        [@left, @right]
+    end
+    
+    def mapChildren
+        Or.new(codeOrigin, (yield @left), (yield @right))
+    end
+    
+    def dump
+        "(#{left.dump} or #{right.dump})"
+    end
+end
+
+class Not < Node
+    attr_reader :child
+    
+    def initialize(codeOrigin, child)
+        super(codeOrigin)
+        @child = child
+    end
+    
+    def children
+        [@left, @right]
+    end
+    
+    def mapChildren
+        Not.new(codeOrigin, (yield @child))
+    end
+    
+    def dump
+        "(not #{child.dump})"
+    end
+end
+
+class Skip < NoChildren
+    def initialize(codeOrigin)
+        super(codeOrigin)
+    end
+    
+    def dump
+        "\tskip"
+    end
+end
+
+class IfThenElse < Node
+    attr_reader :predicate, :thenCase
+    attr_accessor :elseCase
+    
+    def initialize(codeOrigin, predicate, thenCase)
+        super(codeOrigin)
+        @predicate = predicate
+        @thenCase = thenCase
+        @elseCase = Skip.new(codeOrigin)
+    end
+    
+    def children
+        if @elseCase
+            [@predicate, @thenCase, @elseCase]
+        else
+            [@predicate, @thenCase]
+        end
+    end
+    
+    def mapChildren
+        IfThenElse.new(codeOrigin, (yield @predicate), (yield @thenCase), (yield @elseCase))
+    end
+    
+    def dump
+        "if #{predicate.dump}\n" + thenCase.dump + "\nelse\n" + elseCase.dump + "\nend"
+    end
+end
+
+class Macro < Node
+    attr_reader :name, :variables, :body
+    
+    def initialize(codeOrigin, name, variables, body)
+        super(codeOrigin)
+        @name = name
+        @variables = variables
+        @body = body
+    end
+    
+    def children
+        @variables + [@body]
+    end
+    
+    def mapChildren
+        Macro.new(codeOrigin, @name, @variables.map{|v| yield v}, (yield @body))
+    end
+    
+    def dump
+        "macro #{name}(" + variables.collect{|v| v.dump}.join(", ") + ")\n" + body.dump + "\nend"
+    end
+end
+
+class MacroCall < Node
+    attr_reader :name, :operands
+    
+    def initialize(codeOrigin, name, operands)
+        super(codeOrigin)
+        @name = name
+        @operands = operands
+        raise unless @operands
+        @operands.each{|v| raise unless v}
+    end
+    
+    def children
+        @operands
+    end
+    
+    def mapChildren(&proc)
+        MacroCall.new(codeOrigin, @name, @operands.map(&proc))
+    end
+    
+    def dump
+        "\t#{name}(" + operands.collect{|v| v.dump}.join(", ") + ")"
+    end
+end
+
diff --git a/Source/JavaScriptCore/offlineasm/backends.rb b/Source/JavaScriptCore/offlineasm/backends.rb
new file mode 100644
index 0000000..2c65b51
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/backends.rb
@@ -0,0 +1,96 @@
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+require "armv7"
+require "ast"
+require "x86"
+
+BACKENDS =
+    [
+     "X86",
+     "ARMv7"
+    ]
+
+# Keep the set of working backends separate from the set of backends that might be
+# supported. This is great because the BACKENDS list is almost like a reserved
+# words list, in that it causes settings resolution to treat those words specially.
+# Hence this lets us set aside the name of a backend we might want to support in
+# the future while not actually supporting the backend yet.
+WORKING_BACKENDS =
+    [
+     "X86",
+     "ARMv7"
+    ]
+
+BACKEND_PATTERN = Regexp.new('\\A(' + BACKENDS.join(')|(') + ')\\Z')
+
+class Node
+    def lower(name)
+        send("lower" + name)
+    end
+end
+
+# Overrides for lower() for those nodes that are backend-agnostic
+
+class Label
+    def lower(name)
+        $asm.putsLabel(self.name[1..-1])
+    end
+end
+
+class LocalLabel
+    def lower(name)
+        $asm.putsLocalLabel "_offlineasm_#{self.name[1..-1]}"
+    end
+end
+
+class LabelReference
+    def asmLabel
+        Assembler.labelReference(name[1..-1])
+    end
+end
+
+class LocalLabelReference
+    def asmLabel
+        Assembler.localLabelReference("_offlineasm_"+name[1..-1])
+    end
+end
+
+class Skip
+    def lower(name)
+    end
+end
+
+class Sequence
+    def lower(name)
+        if respond_to? "lower#{name}"
+            send("lower#{name}")
+        else
+            @list.each {
+                | node |
+                node.lower(name)
+            }
+        end
+    end
+end
+
diff --git a/Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb b/Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb
new file mode 100644
index 0000000..8bdf450
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/generate_offset_extractor.rb
@@ -0,0 +1,146 @@
+#!/usr/bin/env ruby
+
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+$: << File.dirname(__FILE__)
+
+require "backends"
+require "digest/sha1"
+require "offsets"
+require "parser"
+require "self_hash"
+require "settings"
+require "transform"
+
+inputFlnm = ARGV.shift
+outputFlnm = ARGV.shift
+
+$stderr.puts "offlineasm: Parsing #{inputFlnm} and creating offset extractor #{outputFlnm}."
+
+def emitMagicNumber
+    OFFSET_MAGIC_NUMBERS.each {
+        | number |
+        $output.puts "#{number},"
+    }
+end
+
+inputData = IO::read(inputFlnm)
+inputHash = "// offlineasm input hash: #{Digest::SHA1.hexdigest(inputData)} #{selfHash}"
+
+if FileTest.exist? outputFlnm
+    File.open(outputFlnm, "r") {
+        | inp |
+        firstLine = inp.gets
+        if firstLine and firstLine.chomp == inputHash
+            $stderr.puts "offlineasm: Nothing changed."
+            exit 0
+        end
+    }
+end
+
+originalAST = parse(lex(inputData))
+
+#
+# Optimize the AST to make configuration extraction faster. This reduces the AST to a form
+# that only contains the things that matter for our purposes: offsets, sizes, and if
+# statements.
+#
+
+class Node
+    def offsetsPruneTo(sequence)
+        children.each {
+            | child |
+            child.offsetsPruneTo(sequence)
+        }
+    end
+    
+    def offsetsPrune
+        result = Sequence.new(codeOrigin, [])
+        offsetsPruneTo(result)
+        result
+    end
+end
+
+class IfThenElse
+    def offsetsPruneTo(sequence)
+        ifThenElse = IfThenElse.new(codeOrigin, predicate, thenCase.offsetsPrune)
+        ifThenElse.elseCase = elseCase.offsetsPrune
+        sequence.list << ifThenElse
+    end
+end
+
+class StructOffset
+    def offsetsPruneTo(sequence)
+        sequence.list << self
+    end
+end
+
+class Sizeof
+    def offsetsPruneTo(sequence)
+        sequence.list << self
+    end
+end
+
+prunedAST = originalAST.offsetsPrune
+
+File.open(outputFlnm, "w") {
+    | outp |
+    $output = outp
+    outp.puts inputHash
+    length = 0
+    emitCodeInAllConfigurations(prunedAST) {
+        | settings, ast, backend, index |
+        offsetsList = ast.filter(StructOffset).uniq.sort
+        sizesList = ast.filter(Sizeof).uniq.sort
+        length += OFFSET_HEADER_MAGIC_NUMBERS.size + (OFFSET_MAGIC_NUMBERS.size + 1) * (1 + offsetsList.size + sizesList.size)
+    }
+    outp.puts "static const unsigned extractorTable[#{length}] = {"
+    emitCodeInAllConfigurations(prunedAST) {
+        | settings, ast, backend, index |
+        OFFSET_HEADER_MAGIC_NUMBERS.each {
+            | number |
+            $output.puts "#{number},"
+        }
+
+        offsetsList = ast.filter(StructOffset).uniq.sort
+        sizesList = ast.filter(Sizeof).uniq.sort
+        
+        emitMagicNumber
+        outp.puts "#{index},"
+        offsetsList.each {
+            | offset |
+            emitMagicNumber
+            outp.puts "OFFLINE_ASM_OFFSETOF(#{offset.struct}, #{offset.field}),"
+        }
+        sizesList.each {
+            | offset |
+            emitMagicNumber
+            outp.puts "sizeof(#{offset.struct}),"
+        }
+    }
+    outp.puts "};"
+}
+
+$stderr.puts "offlineasm: offset extractor #{outputFlnm} successfully generated."
+
diff --git a/Source/JavaScriptCore/offlineasm/instructions.rb b/Source/JavaScriptCore/offlineasm/instructions.rb
new file mode 100644
index 0000000..497b473
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/instructions.rb
@@ -0,0 +1,217 @@
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+# Interesting invariant, which we take advantage of: branching instructions
+# always begin with "b", and no non-branching instructions begin with "b".
+# Terminal instructions are "jmp" and "ret".
+
+MACRO_INSTRUCTIONS =
+    [
+     "addi",
+     "andi",
+     "lshifti",
+     "muli",
+     "negi",
+     "noti",
+     "ori",
+     "rshifti",
+     "urshifti",
+     "subi",
+     "xori",
+     "loadi",
+     "loadb",
+     "loadbs",
+     "loadh",
+     "loadhs",
+     "storei",
+     "storeb",
+     "loadd",
+     "moved",
+     "stored",
+     "addd",
+     "divd",
+     "subd",
+     "muld",
+     "sqrtd",
+     "ci2d",
+     "fii2d", # usage: fii2d <gpr with least significant bits>, <gpr with most significant bits>, <fpr>
+     "fd2ii", # usage: fd2ii <fpr>, <gpr with least significant bits>, <gpr with most significant bits>
+     "bdeq",
+     "bdneq",
+     "bdgt",
+     "bdgteq",
+     "bdlt",
+     "bdlteq",
+     "bdequn",
+     "bdnequn",
+     "bdgtun",
+     "bdgtequn",
+     "bdltun",
+     "bdltequn",
+     "btd2i",
+     "td2i",
+     "bcd2i",
+     "movdz",
+     "pop",
+     "push",
+     "move",
+     "sxi2p",
+     "zxi2p",
+     "nop",
+     "bieq",
+     "bineq",
+     "bia",
+     "biaeq",
+     "bib",
+     "bibeq",
+     "bigt",
+     "bigteq",
+     "bilt",
+     "bilteq",
+     "bbeq",
+     "bbneq",
+     "bba",
+     "bbaeq",
+     "bbb",
+     "bbbeq",
+     "bbgt",
+     "bbgteq",
+     "bblt",
+     "bblteq",
+     "btio",
+     "btis",
+     "btiz",
+     "btinz",
+     "btbo",
+     "btbs",
+     "btbz",
+     "btbnz",
+     "jmp",
+     "baddio",
+     "baddis",
+     "baddiz",
+     "baddinz",
+     "bsubio",
+     "bsubis",
+     "bsubiz",
+     "bsubinz",
+     "bmulio",
+     "bmulis",
+     "bmuliz",
+     "bmulinz",
+     "borio",
+     "boris",
+     "boriz",
+     "borinz",
+     "break",
+     "call",
+     "ret",
+     "cieq",
+     "cineq",
+     "cia",
+     "ciaeq",
+     "cib",
+     "cibeq",
+     "cigt",
+     "cigteq",
+     "cilt",
+     "cilteq",
+     "tio",
+     "tis",
+     "tiz",
+     "tinz",
+     "tbo",
+     "tbs",
+     "tbz",
+     "tbnz",
+     "peek",
+     "poke",
+     "bpeq",
+     "bpneq",
+     "bpa",
+     "bpaeq",
+     "bpb",
+     "bpbeq",
+     "bpgt",
+     "bpgteq",
+     "bplt",
+     "bplteq",
+     "addp",
+     "andp",
+     "orp",
+     "subp",
+     "xorp",
+     "loadp",
+     "cpeq",
+     "cpneq",
+     "cpa",
+     "cpaeq",
+     "cpb",
+     "cpbeq",
+     "cpgt",
+     "cpgteq",
+     "cplt",
+     "cplteq",
+     "storep",
+     "btpo",
+     "btps",
+     "btpz",
+     "btpnz",
+     "baddpo",
+     "baddps",
+     "baddpz",
+     "baddpnz",
+     "bo",
+     "bs",
+     "bz",
+     "bnz",
+     "leai",
+     "leap",
+    ]
+
+X86_INSTRUCTIONS =
+    [
+     "cdqi",
+     "idivi"
+    ]
+
+ARMv7_INSTRUCTIONS =
+    [
+     "smulli",
+     "addis",
+     "subis",
+     "oris"
+    ]
+
+INSTRUCTIONS = MACRO_INSTRUCTIONS + X86_INSTRUCTIONS + ARMv7_INSTRUCTIONS
+
+INSTRUCTION_PATTERN = Regexp.new('\\A((' + INSTRUCTIONS.join(')|(') + '))\\Z')
+
+def isBranch(instruction)
+    instruction =~ /^b/
+end
+
+def hasFallThrough(instruction)
+    instruction != "ret" and instruction != "jmp"
+end
+
diff --git a/Source/JavaScriptCore/offlineasm/offsets.rb b/Source/JavaScriptCore/offlineasm/offsets.rb
new file mode 100644
index 0000000..21e1706
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/offsets.rb
@@ -0,0 +1,173 @@
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+require "ast"
+
+OFFSET_HEADER_MAGIC_NUMBERS = [ 0x9e43fd66, 0x4379bfba ]
+OFFSET_MAGIC_NUMBERS = [ 0xec577ac7, 0x0ff5e755 ]
+
+#
+# offsetsList(ast)
+# sizesList(ast)
+#
+# Returns a list of offsets and sizes used by the AST.
+#
+
+def offsetsList(ast)
+    ast.filter(StructOffset).uniq.sort
+end
+
+def sizesList(ast)
+    ast.filter(Sizeof).uniq.sort
+end
+
+#
+# offsetsAndConfigurationIndex(ast, file) ->
+#     [[offsets, index], ...]
+#
+# Parses the offsets from a file and returns a list of offsets and the
+# index of the configuration that is valid in this build target.
+#
+
+def offsetsAndConfigurationIndex(file)
+    endiannessMarkerBytes = nil
+    result = []
+    
+    def readInt(endianness, bytes)
+        if endianness == :little
+            # Little endian
+            (bytes[0] << 0 |
+             bytes[1] << 8 |
+             bytes[2] << 16 |
+             bytes[3] << 24)
+        else
+            # Big endian
+            (bytes[0] << 24 |
+             bytes[1] << 16 |
+             bytes[2] << 8 |
+             bytes[3] << 0)
+        end
+    end
+    
+    def prepareMagic(endianness, numbers)
+        magicBytes = []
+        numbers.each {
+            | number |
+            currentBytes = []
+            4.times {
+                currentBytes << (number & 0xff)
+                number >>= 8
+            }
+            if endianness == :big
+                currentBytes.reverse!
+            end
+            magicBytes += currentBytes
+        }
+        magicBytes
+    end
+    
+    fileBytes = []
+    
+    File.open(file, "r") {
+        | inp |
+        loop {
+            byte = inp.getbyte
+            break unless byte
+            fileBytes << byte
+        }
+    }
+    
+    def sliceByteArrays(byteArray, pattern)
+        result = []
+        lastSlicePoint = 0
+        (byteArray.length - pattern.length + 1).times {
+            | index |
+            foundOne = true
+            pattern.length.times {
+                | subIndex |
+                if byteArray[index + subIndex] != pattern[subIndex]
+                    foundOne = false
+                    break
+                end
+            }
+            if foundOne
+                result << byteArray[lastSlicePoint...index]
+                lastSlicePoint = index + pattern.length
+            end
+        }
+        
+        result << byteArray[lastSlicePoint...(byteArray.length)]
+        
+        result
+    end
+    
+    [:little, :big].each {
+        | endianness |
+        headerMagicBytes = prepareMagic(endianness, OFFSET_HEADER_MAGIC_NUMBERS)
+        magicBytes = prepareMagic(endianness, OFFSET_MAGIC_NUMBERS)
+        
+        bigArray = sliceByteArrays(fileBytes, headerMagicBytes)
+        unless bigArray.size <= 1
+            bigArray[1..-1].each {
+                | configArray |
+                array = sliceByteArrays(configArray, magicBytes)
+                index = readInt(endianness, array[1])
+                offsets = []
+                array[2..-1].each {
+                    | data |
+                    offsets << readInt(endianness, data)
+                }
+                result << [offsets, index]
+            }
+        end
+    }
+    
+    raise unless result.length >= 1
+    raise if result.map{|v| v[1]}.uniq.size < result.map{|v| v[1]}.size
+    
+    result
+end
+
+#
+# buildOffsetsMap(ast, offsetsList) -> [offsets, sizes]
+#
+# Builds a mapping between StructOffset nodes and their values.
+#
+
+def buildOffsetsMap(ast, offsetsList)
+    offsetsMap = {}
+    sizesMap = {}
+    astOffsetsList = offsetsList(ast)
+    astSizesList = sizesList(ast)
+    raise unless astOffsetsList.size + astSizesList.size == offsetsList.size
+    offsetsList(ast).each_with_index {
+        | structOffset, index |
+        offsetsMap[structOffset] = offsetsList.shift
+    }
+    sizesList(ast).each_with_index {
+        | sizeof, index |
+        sizesMap[sizeof] = offsetsList.shift
+    }
+    [offsetsMap, sizesMap]
+end
+
diff --git a/Source/JavaScriptCore/offlineasm/opt.rb b/Source/JavaScriptCore/offlineasm/opt.rb
new file mode 100644
index 0000000..3170d3a
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/opt.rb
@@ -0,0 +1,134 @@
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+require "ast"
+
+#
+# "Optimization" passes. These are used to lower the representation for
+# backends that cannot handle some of our higher-level instructions.
+#
+
+#
+# A temporary - a variable that will be allocated to a register after we're
+# done.
+#
+
+class Node
+    def replaceTemporariesWithRegisters(kind)
+        mapChildren {
+            | node |
+            node.replaceTemporariesWithRegisters(kind)
+        }
+    end
+end
+
+class Tmp < NoChildren
+    attr_reader :firstMention, :lastMention
+    attr_reader :kind
+    attr_accessor :register
+
+    def initialize(codeOrigin, kind)
+        super(codeOrigin)
+        @kind = kind
+    end
+    
+    def dump
+        "$tmp#{object_id}"
+    end
+    
+    def mention!(position)
+        if not @firstMention or position < @firstMention
+            @firstMention = position
+        end
+        if not @lastMention or position > @lastMention
+            @lastMention = position
+        end
+    end
+    
+    def replaceTemporariesWithRegisters(kind)
+        if @kind == kind
+            raise "Did not allocate register to temporary at #{codeOriginString}" unless @register
+            @register
+        else
+            self
+        end
+    end
+    
+    def address?
+        false
+    end
+    
+    def label?
+        false
+    end
+    
+    def immediate?
+        false
+    end
+    
+    def register?
+        true
+    end
+end
+
+# Assign registers to temporaries, by finding which temporaries interfere
+# with each other. Note that this relies on temporary live ranges not crossing
+# basic block boundaries.
+
+def assignRegistersToTemporaries(list, kind, registers)
+    list.each_with_index {
+        | node, index |
+        node.filter(Tmp).uniq.each {
+            | tmp |
+            if tmp.kind == kind
+                tmp.mention! index
+            end
+        }
+    }
+    
+    freeRegisters = registers.dup
+    list.each_with_index {
+        | node, index |
+        tmpList = node.filter(Tmp).uniq
+        tmpList.each {
+            | tmp |
+            if tmp.kind == kind and tmp.firstMention == index
+                raise "Could not allocate register to temporary at #{node.codeOriginString}" if freeRegisters.empty?
+                tmp.register = freeRegisters.pop
+            end
+        }
+        tmpList.each {
+            | tmp |
+            if tmp.kind == kind and tmp.lastMention == index
+                freeRegisters.push tmp.register
+                raise "Register allocation inconsistency at #{node.codeOriginString}" if freeRegisters.size > registers.size
+            end
+        }
+    }
+    
+    list.map {
+        | node |
+        node.replaceTemporariesWithRegisters(kind)
+    }
+end
+
diff --git a/Source/JavaScriptCore/offlineasm/parser.rb b/Source/JavaScriptCore/offlineasm/parser.rb
new file mode 100644
index 0000000..f0e4b00
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/parser.rb
@@ -0,0 +1,586 @@
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+require "ast"
+require "instructions"
+require "registers"
+
+class Token
+    attr_reader :codeOrigin, :string
+    
+    def initialize(codeOrigin, string)
+        @codeOrigin = codeOrigin
+        @string = string
+    end
+    
+    def ==(other)
+        if other.is_a? Token
+            @string == other.string
+        else
+            @string == other
+        end
+    end
+    
+    def =~(other)
+        @string =~ other
+    end
+    
+    def to_s
+        "#{@string.inspect} at line #{codeOrigin}"
+    end
+    
+    def parseError(*comment)
+        if comment.empty?
+            raise "Parse error: #{to_s}"
+        else
+            raise "Parse error: #{to_s}: #{comment[0]}"
+        end
+    end
+end
+
+#
+# The lexer. Takes a string and returns an array of tokens.
+#
+
+def lex(str)
+    result = []
+    lineNumber = 1
+    while not str.empty?
+        case str
+        when /\A\#([^\n]*)/
+            # comment, ignore
+        when /\A\n/
+            result << Token.new(lineNumber, $&)
+            lineNumber += 1
+        when /\A[a-zA-Z]([a-zA-Z0-9_]*)/
+            result << Token.new(lineNumber, $&)
+        when /\A\.([a-zA-Z0-9_]*)/
+            result << Token.new(lineNumber, $&)
+        when /\A_([a-zA-Z0-9_]*)/
+            result << Token.new(lineNumber, $&)
+        when /\A([ \t]+)/
+            # whitespace, ignore
+        when /\A0x([0-9a-fA-F]+)/
+            result << Token.new(lineNumber, $&.hex.to_s)
+        when /\A0([0-7]+)/
+            result << Token.new(lineNumber, $&.oct.to_s)
+        when /\A([0-9]+)/
+            result << Token.new(lineNumber, $&)
+        when /\A::/
+            result << Token.new(lineNumber, $&)
+        when /\A[:,\(\)\[\]=\+\-*]/
+            result << Token.new(lineNumber, $&)
+        else
+            raise "Lexer error at line number #{lineNumber}, unexpected sequence #{str[0..20].inspect}"
+        end
+        str = $~.post_match
+    end
+    result
+end
+
+#
+# Token identification.
+#
+
+def isRegister(token)
+    token =~ REGISTER_PATTERN
+end
+
+def isInstruction(token)
+    token =~ INSTRUCTION_PATTERN
+end
+
+def isKeyword(token)
+    token =~ /\A((true)|(false)|(if)|(then)|(else)|(elsif)|(end)|(and)|(or)|(not)|(macro)|(const)|(sizeof)|(error))\Z/ or
+        token =~ REGISTER_PATTERN or
+        token =~ INSTRUCTION_PATTERN
+end
+
+def isIdentifier(token)
+    token =~ /\A[a-zA-Z]([a-zA-Z0-9_]*)\Z/ and not isKeyword(token)
+end
+
+def isLabel(token)
+    token =~ /\A_([a-zA-Z0-9_]*)\Z/
+end
+
+def isLocalLabel(token)
+    token =~ /\A\.([a-zA-Z0-9_]*)\Z/
+end
+
+def isVariable(token)
+    isIdentifier(token) or isRegister(token)
+end
+
+def isInteger(token)
+    token =~ /\A[0-9]/
+end
+
+#
+# The parser. Takes an array of tokens and returns an AST. Methods
+# other than parse(tokens) are not for public consumption.
+#
+
+class Parser
+    def initialize(tokens)
+        @tokens = tokens
+        @idx = 0
+    end
+    
+    def parseError(*comment)
+        if @tokens[@idx]
+            @tokens[@idx].parseError(*comment)
+        else
+            if comment.empty?
+                raise "Parse error at end of file"
+            else
+                raise "Parse error at end of file: #{comment[0]}"
+            end
+        end
+    end
+    
+    def consume(regexp)
+        if regexp
+            parseError unless @tokens[@idx] =~ regexp
+        else
+            parseError unless @idx == @tokens.length
+        end
+        @idx += 1
+    end
+    
+    def skipNewLine
+        while @tokens[@idx] == "\n"
+            @idx += 1
+        end
+    end
+    
+    def parsePredicateAtom
+        if @tokens[@idx] == "not"
+            @idx += 1
+            parsePredicateAtom
+        elsif @tokens[@idx] == "("
+            @idx += 1
+            skipNewLine
+            result = parsePredicate
+            parseError unless @tokens[@idx] == ")"
+            @idx += 1
+            result
+        elsif @tokens[@idx] == "true"
+            result = True.instance
+            @idx += 1
+            result
+        elsif @tokens[@idx] == "false"
+            result = False.instance
+            @idx += 1
+            result
+        elsif isIdentifier @tokens[@idx]
+            result = Setting.forName(@tokens[@idx].codeOrigin, @tokens[@idx].string)
+            @idx += 1
+            result
+        else
+            parseError
+        end
+    end
+    
+    def parsePredicateAnd
+        result = parsePredicateAtom
+        while @tokens[@idx] == "and"
+            codeOrigin = @tokens[@idx].codeOrigin
+            @idx += 1
+            skipNewLine
+            right = parsePredicateAtom
+            result = And.new(codeOrigin, result, right)
+        end
+        result
+    end
+    
+    def parsePredicate
+        # some examples of precedence:
+        # not a and b -> (not a) and b
+        # a and b or c -> (a and b) or c
+        # a or b and c -> a or (b and c)
+        
+        result = parsePredicateAnd
+        while @tokens[@idx] == "or"
+            codeOrigin = @tokens[@idx].codeOrigin
+            @idx += 1
+            skipNewLine
+            right = parsePredicateAnd
+            result = Or.new(codeOrigin, result, right)
+        end
+        result
+    end
+    
+    def parseVariable
+        if isRegister(@tokens[@idx])
+            if @tokens[@idx] =~ FPR_PATTERN
+                result = FPRegisterID.forName(@tokens[@idx].codeOrigin, @tokens[@idx].string)
+            else
+                result = RegisterID.forName(@tokens[@idx].codeOrigin, @tokens[@idx].string)
+            end
+        elsif isIdentifier(@tokens[@idx])
+            result = Variable.forName(@tokens[@idx].codeOrigin, @tokens[@idx].string)
+        else
+            parseError
+        end
+        @idx += 1
+        result
+    end
+    
+    def parseAddress(offset)
+        parseError unless @tokens[@idx] == "["
+        codeOrigin = @tokens[@idx].codeOrigin
+        
+        # Three possibilities:
+        # []       -> AbsoluteAddress
+        # [a]      -> Address
+        # [a,b]    -> BaseIndex with scale = 1
+        # [a,b,c]  -> BaseIndex
+        
+        @idx += 1
+        if @tokens[@idx] == "]"
+            @idx += 1
+            return AbsoluteAddress.new(codeOrigin, offset)
+        end
+        a = parseVariable
+        if @tokens[@idx] == "]"
+            result = Address.new(codeOrigin, a, offset)
+        else
+            parseError unless @tokens[@idx] == ","
+            @idx += 1
+            b = parseVariable
+            if @tokens[@idx] == "]"
+                result = BaseIndex.new(codeOrigin, a, b, 1, offset)
+            else
+                parseError unless @tokens[@idx] == ","
+                @idx += 1
+                parseError unless ["1", "2", "4", "8"].member? @tokens[@idx].string
+                c = @tokens[@idx].string.to_i
+                @idx += 1
+                parseError unless @tokens[@idx] == "]"
+                result = BaseIndex.new(codeOrigin, a, b, c, offset)
+            end
+        end
+        @idx += 1
+        result
+    end
+    
+    def parseColonColon
+        skipNewLine
+        codeOrigin = @tokens[@idx].codeOrigin
+        parseError unless isIdentifier @tokens[@idx]
+        names = [@tokens[@idx].string]
+        @idx += 1
+        while @tokens[@idx] == "::"
+            @idx += 1
+            parseError unless isIdentifier @tokens[@idx]
+            names << @tokens[@idx].string
+            @idx += 1
+        end
+        raise if names.empty?
+        [codeOrigin, names]
+    end
+    
+    def parseExpressionAtom
+        skipNewLine
+        if @tokens[@idx] == "-"
+            @idx += 1
+            NegImmediate.new(@tokens[@idx - 1].codeOrigin, parseExpressionAtom)
+        elsif @tokens[@idx] == "("
+            @idx += 1
+            result = parseExpression
+            parseError unless @tokens[@idx] == ")"
+            @idx += 1
+            result
+        elsif isInteger @tokens[@idx]
+            result = Immediate.new(@tokens[@idx].codeOrigin, @tokens[@idx].string.to_i)
+            @idx += 1
+            result
+        elsif isIdentifier @tokens[@idx]
+            codeOrigin, names = parseColonColon
+            if names.size > 1
+                StructOffset.forField(codeOrigin, names[0..-2].join('::'), names[-1])
+            else
+                Variable.forName(codeOrigin, names[0])
+            end
+        elsif isRegister @tokens[@idx]
+            parseVariable
+        elsif @tokens[@idx] == "sizeof"
+            @idx += 1
+            codeOrigin, names = parseColonColon
+            Sizeof.forName(codeOrigin, names.join('::'))
+        else
+            parseError
+        end
+    end
+    
+    def parseExpressionMul
+        skipNewLine
+        result = parseExpressionAtom
+        while @tokens[@idx] == "*"
+            if @tokens[@idx] == "*"
+                @idx += 1
+                result = MulImmediates.new(@tokens[@idx - 1].codeOrigin, result, parseExpressionAtom)
+            else
+                raise
+            end
+        end
+        result
+    end
+    
+    def couldBeExpression
+        @tokens[@idx] == "-" or @tokens[@idx] == "sizeof" or isInteger(@tokens[@idx]) or isVariable(@tokens[@idx]) or @tokens[@idx] == "("
+    end
+    
+    def parseExpression
+        skipNewLine
+        result = parseExpressionMul
+        while @tokens[@idx] == "+" or @tokens[@idx] == "-"
+            if @tokens[@idx] == "+"
+                @idx += 1
+                result = AddImmediates.new(@tokens[@idx - 1].codeOrigin, result, parseExpressionMul)
+            elsif @tokens[@idx] == "-"
+                @idx += 1
+                result = SubImmediates.new(@tokens[@idx - 1].codeOrigin, result, parseExpressionMul)
+            else
+                raise
+            end
+        end
+        result
+    end
+    
+    def parseOperand(comment)
+        skipNewLine
+        if couldBeExpression
+            expr = parseExpression
+            if @tokens[@idx] == "["
+                parseAddress(expr)
+            else
+                expr
+            end
+        elsif @tokens[@idx] == "["
+            parseAddress(Immediate.new(@tokens[@idx].codeOrigin, 0))
+        elsif isLabel @tokens[@idx]
+            result = LabelReference.new(@tokens[@idx].codeOrigin, Label.forName(@tokens[@idx].codeOrigin, @tokens[@idx].string))
+            @idx += 1
+            result
+        elsif isLocalLabel @tokens[@idx]
+            result = LocalLabelReference.new(@tokens[@idx].codeOrigin, LocalLabel.forName(@tokens[@idx].codeOrigin, @tokens[@idx].string))
+            @idx += 1
+            result
+        else
+            parseError(comment)
+        end
+    end
+    
+    def parseMacroVariables
+        skipNewLine
+        consume(/\A\(\Z/)
+        variables = []
+        loop {
+            skipNewLine
+            if @tokens[@idx] == ")"
+                @idx += 1
+                break
+            elsif isIdentifier(@tokens[@idx])
+                variables << Variable.forName(@tokens[@idx].codeOrigin, @tokens[@idx].string)
+                @idx += 1
+                skipNewLine
+                if @tokens[@idx] == ")"
+                    @idx += 1
+                    break
+                elsif @tokens[@idx] == ","
+                    @idx += 1
+                else
+                    parseError
+                end
+            else
+                parseError
+            end
+        }
+        variables
+    end
+    
+    def parseSequence(final, comment)
+        firstCodeOrigin = @tokens[@idx].codeOrigin
+        list = []
+        loop {
+            if (@idx == @tokens.length and not final) or (final and @tokens[@idx] =~ final)
+                break
+            elsif @tokens[@idx] == "\n"
+                # ignore
+                @idx += 1
+            elsif @tokens[@idx] == "const"
+                @idx += 1
+                parseError unless isVariable @tokens[@idx]
+                variable = Variable.forName(@tokens[@idx].codeOrigin, @tokens[@idx].string)
+                @idx += 1
+                parseError unless @tokens[@idx] == "="
+                @idx += 1
+                value = parseOperand("while inside of const #{variable.name}")
+                list << ConstDecl.new(@tokens[@idx].codeOrigin, variable, value)
+            elsif @tokens[@idx] == "error"
+                list << Error.new(@tokens[@idx].codeOrigin)
+                @idx += 1
+            elsif @tokens[@idx] == "if"
+                codeOrigin = @tokens[@idx].codeOrigin
+                @idx += 1
+                skipNewLine
+                predicate = parsePredicate
+                consume(/\A((then)|(\n))\Z/)
+                skipNewLine
+                ifThenElse = IfThenElse.new(codeOrigin, predicate, parseSequence(/\A((else)|(end)|(elsif))\Z/, "while inside of \"if #{predicate.dump}\""))
+                list << ifThenElse
+                while @tokens[@idx] == "elsif"
+                    codeOrigin = @tokens[@idx].codeOrigin
+                    @idx += 1
+                    skipNewLine
+                    predicate = parsePredicate
+                    consume(/\A((then)|(\n))\Z/)
+                    skipNewLine
+                    elseCase = IfThenElse.new(codeOrigin, predicate, parseSequence(/\A((else)|(end)|(elsif))\Z/, "while inside of \"if #{predicate.dump}\""))
+                    ifThenElse.elseCase = elseCase
+                    ifThenElse = elseCase
+                end
+                if @tokens[@idx] == "else"
+                    @idx += 1
+                    ifThenElse.elseCase = parseSequence(/\Aend\Z/, "while inside of else case for \"if #{predicate.dump}\"")
+                    @idx += 1
+                else
+                    parseError unless @tokens[@idx] == "end"
+                    @idx += 1
+                end
+            elsif @tokens[@idx] == "macro"
+                codeOrigin = @tokens[@idx].codeOrigin
+                @idx += 1
+                skipNewLine
+                parseError unless isIdentifier(@tokens[@idx])
+                name = @tokens[@idx].string
+                @idx += 1
+                variables = parseMacroVariables
+                body = parseSequence(/\Aend\Z/, "while inside of macro #{name}")
+                @idx += 1
+                list << Macro.new(codeOrigin, name, variables, body)
+            elsif isInstruction @tokens[@idx]
+                codeOrigin = @tokens[@idx].codeOrigin
+                name = @tokens[@idx].string
+                @idx += 1
+                if (not final and @idx == @tokens.size) or (final and @tokens[@idx] =~ final)
+                    # Zero operand instruction, and it's the last one.
+                    list << Instruction.new(codeOrigin, name, [])
+                    break
+                elsif @tokens[@idx] == "\n"
+                    # Zero operand instruction.
+                    list << Instruction.new(codeOrigin, name, [])
+                    @idx += 1
+                else
+                    # It's definitely an instruction, and it has at least one operand.
+                    operands = []
+                    endOfSequence = false
+                    loop {
+                        operands << parseOperand("while inside of instruction #{name}")
+                        if (not final and @idx == @tokens.size) or (final and @tokens[@idx] =~ final)
+                            # The end of the instruction and of the sequence.
+                            endOfSequence = true
+                            break
+                        elsif @tokens[@idx] == ","
+                            # Has another operand.
+                            @idx += 1
+                        elsif @tokens[@idx] == "\n"
+                            # The end of the instruction.
+                            @idx += 1
+                            break
+                        else
+                            parseError("Expected a comma, newline, or #{final} after #{operands.last.dump}")
+                        end
+                    }
+                    list << Instruction.new(codeOrigin, name, operands)
+                    if endOfSequence
+                        break
+                    end
+                end
+            elsif isIdentifier @tokens[@idx]
+                codeOrigin = @tokens[@idx].codeOrigin
+                name = @tokens[@idx].string
+                @idx += 1
+                if @tokens[@idx] == "("
+                    # Macro invocation.
+                    @idx += 1
+                    operands = []
+                    skipNewLine
+                    if @tokens[@idx] == ")"
+                        @idx += 1
+                    else
+                        loop {
+                            skipNewLine
+                            if @tokens[@idx] == "macro"
+                                # It's a macro lambda!
+                                codeOriginInner = @tokens[@idx].codeOrigin
+                                @idx += 1
+                                variables = parseMacroVariables
+                                body = parseSequence(/\Aend\Z/, "while inside of anonymous macro passed as argument to #{name}")
+                                @idx += 1
+                                operands << Macro.new(codeOriginInner, nil, variables, body)
+                            else
+                                operands << parseOperand("while inside of macro call to #{name}")
+                            end
+                            skipNewLine
+                            if @tokens[@idx] == ")"
+                                @idx += 1
+                                break
+                            elsif @tokens[@idx] == ","
+                                @idx += 1
+                            else
+                                parseError "Unexpected #{@tokens[@idx].string.inspect} while parsing invocation of macro #{name}"
+                            end
+                        }
+                    end
+                    list << MacroCall.new(codeOrigin, name, operands)
+                else
+                    parseError "Expected \"(\" after #{name}"
+                end
+            elsif isLabel @tokens[@idx] or isLocalLabel @tokens[@idx]
+                codeOrigin = @tokens[@idx].codeOrigin
+                name = @tokens[@idx].string
+                @idx += 1
+                parseError unless @tokens[@idx] == ":"
+                # It's a label.
+                if isLabel name
+                    list << Label.forName(codeOrigin, name)
+                else
+                    list << LocalLabel.forName(codeOrigin, name)
+                end
+                @idx += 1
+            else
+                parseError "Expecting terminal #{final} #{comment}"
+            end
+        }
+        Sequence.new(firstCodeOrigin, list)
+    end
+end
+
+def parse(tokens)
+    parser = Parser.new(tokens)
+    parser.parseSequence(nil, "")
+end
+
diff --git a/Source/JavaScriptCore/offlineasm/registers.rb b/Source/JavaScriptCore/offlineasm/registers.rb
new file mode 100644
index 0000000..75fae41
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/registers.rb
@@ -0,0 +1,60 @@
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+GPRS =
+    [
+     "t0",
+     "t1",
+     "t2",
+     "t3",
+     "t4",
+     "cfr",
+     "a0",
+     "a1",
+     "r0",
+     "r1",
+     "sp",
+     "lr"
+    ]
+
+FPRS =
+    [
+     "ft0",
+     "ft1",
+     "ft2",
+     "ft3",
+     "ft4",
+     "ft5",
+     "fa0",
+     "fa1",
+     "fa2",
+     "fa3",
+     "fr"
+    ]
+
+REGISTERS = GPRS + FPRS
+
+GPR_PATTERN = Regexp.new('\\A((' + GPRS.join(')|(') + '))\\Z')
+FPR_PATTERN = Regexp.new('\\A((' + FPRS.join(')|(') + '))\\Z')
+
+REGISTER_PATTERN = Regexp.new('\\A((' + REGISTERS.join(')|(') + '))\\Z')
diff --git a/Source/JavaScriptCore/offlineasm/self_hash.rb b/Source/JavaScriptCore/offlineasm/self_hash.rb
new file mode 100644
index 0000000..a7b51e1
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/self_hash.rb
@@ -0,0 +1,46 @@
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+require "digest/sha1"
+require "pathname"
+
+#
+# selfHash -> SHA1 hexdigest
+#
+# Returns a hash of the offlineasm source code. This allows dependency
+# tracking for not just changes in input, but also changes in the assembler
+# itself.
+#
+
+def selfHash
+    contents = ""
+    myPath = Pathname.new(__FILE__).dirname
+    Dir.foreach(myPath) {
+        | entry |
+        if entry =~ /\.rb$/
+            contents += IO::read(myPath + entry)
+        end
+    }
+    return Digest::SHA1.hexdigest(contents)
+end
+
diff --git a/Source/JavaScriptCore/offlineasm/settings.rb b/Source/JavaScriptCore/offlineasm/settings.rb
new file mode 100644
index 0000000..3459818
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/settings.rb
@@ -0,0 +1,205 @@
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+require "ast"
+require "backends"
+require "parser"
+require "transform"
+
+#
+# computeSettingsCombinations(ast) -> settingsCombiations
+#
+# Computes an array of settings maps, where a settings map constitutes
+# a configuration for the assembly code being generated. The map
+# contains key value pairs where keys are settings names (strings) and
+# the values are booleans (true for enabled, false for disabled).
+#
+
+def computeSettingsCombinations(ast)
+    settingsCombinations = []
+    
+    def settingsCombinator(settingsCombinations, mapSoFar, remaining)
+        if remaining.empty?
+            settingsCombinations << mapSoFar
+            return
+        end
+        
+        newMap = mapSoFar.dup
+        newMap[remaining[0]] = true
+        settingsCombinator(settingsCombinations, newMap, remaining[1..-1])
+        
+        newMap = mapSoFar.dup
+        newMap[remaining[0]] = false
+        settingsCombinator(settingsCombinations, newMap, remaining[1..-1])
+    end
+    
+    settingsCombinator(settingsCombinations, {}, (ast.filter(Setting).uniq.collect{|v| v.name} + ["X86", "ARMv7"]).uniq)
+    
+    settingsCombinations
+end
+
+#
+# forSettings(concreteSettings, ast) {
+#     | concreteSettings, lowLevelAST, backend | ... }
+#
+# Determines if the settings combination is valid, and if so, calls
+# the block with the information you need to generate code.
+#
+
+def forSettings(concreteSettings, ast)
+    # Check which architectures this combinator claims to support.
+    numClaimedBackends = 0
+    selectedBackend = nil
+    BACKENDS.each {
+        | backend |
+        isSupported = concreteSettings[backend]
+        raise unless isSupported != nil
+        numClaimedBackends += if isSupported then 1 else 0 end
+        if isSupported
+            selectedBackend = backend
+        end
+    }
+    
+    return if numClaimedBackends > 1
+    
+    # Resolve the AST down to a low-level form (no macros or conditionals).
+    lowLevelAST = ast.resolveSettings(concreteSettings)
+    
+    yield concreteSettings, lowLevelAST, selectedBackend
+end
+
+#
+# forEachValidSettingsCombination(ast) {
+#     | concreteSettings, ast, backend, index | ... }
+#
+# forEachValidSettingsCombination(ast, settingsCombinations) {
+#     | concreteSettings, ast, backend, index | ... }
+#
+# Executes the given block for each valid settings combination in the
+# settings map. The ast passed into the block is resolved
+# (ast.resolve) against the settings.
+#
+# The first form will call computeSettingsCombinations(ast) for you.
+#
+
+def forEachValidSettingsCombination(ast, *optionalSettingsCombinations)
+    raise if optionalSettingsCombinations.size > 1
+    
+    if optionalSettingsCombinations.empty?
+        settingsCombinations = computeSettingsCombinations(ast)
+    else
+        settingsCombinations = optionalSettingsCombiations[0]
+    end
+    
+    settingsCombinations.each_with_index {
+        | concreteSettings, index |
+        forSettings(concreteSettings, ast) {
+            | concreteSettings_, lowLevelAST, backend |
+            yield concreteSettings, lowLevelAST, backend, index
+        }
+    }
+end
+
+#
+# cppSettingsTest(concreteSettings)
+#
+# Returns the C++ code used to test if we are in a configuration that
+# corresponds to the given concrete settings.
+#
+
+def cppSettingsTest(concreteSettings)
+    "#if " + concreteSettings.to_a.collect{
+        | pair |
+        (if pair[1]
+             ""
+         else
+             "!"
+         end) + "OFFLINE_ASM_" + pair[0]
+    }.join(" && ")
+end
+
+#
+# isASTErroneous(ast)
+#
+# Tests to see if the AST claims that there is an error - i.e. if the
+# user's code, after settings resolution, has Error nodes.
+#
+
+def isASTErroneous(ast)
+    not ast.filter(Error).empty?
+end
+
+#
+# assertConfiguration(concreteSettings)
+#
+# Emits a check that asserts that we're using the given configuration.
+#
+
+def assertConfiguration(concreteSettings)
+    $output.puts cppSettingsTest(concreteSettings)
+    $output.puts "#else"
+    $output.puts "#error \"Configuration mismatch.\""
+    $output.puts "#endif"
+end
+
+#
+# emitCodeInConfiguration(concreteSettings, ast, backend) {
+#     | concreteSettings, ast, backend | ... }
+#
+# Emits all relevant guards to see if the configuration holds and
+# calls the block if the configuration is not erroneous.
+#
+
+def emitCodeInConfiguration(concreteSettings, ast, backend)
+    $output.puts cppSettingsTest(concreteSettings)
+    
+    if isASTErroneous(ast)
+        $output.puts "#error \"Invalid configuration.\""
+    elsif not WORKING_BACKENDS.include? backend
+        $output.puts "#error \"This backend is not supported yet.\""
+    else
+        yield concreteSettings, ast, backend
+    end
+    
+    $output.puts "#endif"
+end
+
+#
+# emitCodeInAllConfigurations(ast) {
+#     | concreteSettings, ast, backend, index | ... }
+#
+# Emits guard codes for all valid configurations, and calls the block
+# for those configurations that are valid and not erroneous.
+#
+
+def emitCodeInAllConfigurations(ast)
+    forEachValidSettingsCombination(ast) {
+        | concreteSettings, lowLevelAST, backend, index |
+        $output.puts cppSettingsTest(concreteSettings)
+        yield concreteSettings, lowLevelAST, backend, index
+        $output.puts "#endif"
+    }
+end
+
+
+
diff --git a/Source/JavaScriptCore/offlineasm/transform.rb b/Source/JavaScriptCore/offlineasm/transform.rb
new file mode 100644
index 0000000..5f5024d
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/transform.rb
@@ -0,0 +1,342 @@
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+require "ast"
+
+#
+# node.resolveSettings(settings)
+#
+# Construct a new AST that does not have any IfThenElse nodes by
+# substituting concrete boolean values for each Setting.
+#
+
+class Node
+    def resolveSettings(settings)
+        mapChildren {
+            | child |
+            child.resolveSettings(settings)
+        }
+    end
+end
+
+class True
+    def resolveSettings(settings)
+        self
+    end
+end
+
+class False
+    def resolveSettings(settings)
+        self
+    end
+end
+
+class Setting
+    def resolveSettings(settings)
+        settings[@name].asNode
+    end
+end
+
+class And
+    def resolveSettings(settings)
+        (@left.resolveSettings(settings).value and @right.resolveSettings(settings).value).asNode
+    end
+end
+
+class Or
+    def resolveSettings(settings)
+        (@left.resolveSettings(settings).value or @right.resolveSettings(settings).value).asNode
+    end
+end
+
+class Not
+    def resolveSettings(settings)
+        (not @child.resolveSettings(settings).value).asNode
+    end
+end
+
+class IfThenElse
+    def resolveSettings(settings)
+        if @predicate.resolveSettings(settings).value
+            @thenCase.resolveSettings(settings)
+        else
+            @elseCase.resolveSettings(settings)
+        end
+    end
+end
+
+class Sequence
+    def resolveSettings(settings)
+        newList = []
+        @list.each {
+            | item |
+            item = item.resolveSettings(settings)
+            if item.is_a? Sequence
+                newList += item.list
+            else
+                newList << item
+            end
+        }
+        Sequence.new(codeOrigin, newList)
+    end
+end
+
+#
+# node.demacroify(macros)
+# node.substitute(mapping)
+#
+# demacroify() constructs a new AST that does not have any Macro
+# nodes, while substitute() replaces Variable nodes with the given
+# nodes in the mapping.
+#
+
+class Node
+    def demacroify(macros)
+        mapChildren {
+            | child |
+            child.demacroify(macros)
+        }
+    end
+    
+    def substitute(mapping)
+        mapChildren {
+            | child |
+            child.substitute(mapping)
+        }
+    end
+    
+    def substituteLabels(mapping)
+        mapChildren {
+            | child |
+            child.substituteLabels(mapping)
+        }
+    end
+end
+
+class Macro
+    def substitute(mapping)
+        myMapping = {}
+        mapping.each_pair {
+            | key, value |
+            unless @variables.include? key
+                myMapping[key] = value
+            end
+        }
+        mapChildren {
+            | child |
+            child.substitute(myMapping)
+        }
+    end
+end
+
+class Variable
+    def substitute(mapping)
+        if mapping[self]
+            mapping[self]
+        else
+            self
+        end
+    end
+end
+
+class LocalLabel
+    def substituteLabels(mapping)
+        if mapping[self]
+            mapping[self]
+        else
+            self
+        end
+    end
+end
+
+class Sequence
+    def substitute(constants)
+        newList = []
+        myConstants = constants.dup
+        @list.each {
+            | item |
+            if item.is_a? ConstDecl
+                myConstants[item.variable] = item.value.substitute(myConstants)
+            else
+                newList << item.substitute(myConstants)
+            end
+        }
+        Sequence.new(codeOrigin, newList)
+    end
+    
+    def renameLabels(comment)
+        mapping = {}
+        
+        @list.each {
+            | item |
+            if item.is_a? LocalLabel
+                mapping[item] = LocalLabel.unique(if comment then comment + "_" else "" end + item.cleanName)
+            end
+        }
+        
+        substituteLabels(mapping)
+    end
+    
+    def demacroify(macros)
+        myMacros = macros.dup
+        @list.each {
+            | item |
+            if item.is_a? Macro
+                myMacros[item.name] = item
+            end
+        }
+        newList = []
+        @list.each {
+            | item |
+            if item.is_a? Macro
+                # Ignore.
+            elsif item.is_a? MacroCall
+                mapping = {}
+                myMyMacros = myMacros.dup
+                raise "Could not find macro #{item.name} at #{item.codeOriginString}" unless myMacros[item.name]
+                raise "Argument count mismatch for call to #{item.name} at #{item.codeOriginString}" unless item.operands.size == myMacros[item.name].variables.size
+                item.operands.size.times {
+                    | idx |
+                    if item.operands[idx].is_a? Variable and myMacros[item.operands[idx].name]
+                        myMyMacros[myMacros[item.name].variables[idx].name] = myMacros[item.operands[idx].name]
+                        mapping[myMacros[item.name].variables[idx].name] = nil
+                    elsif item.operands[idx].is_a? Macro
+                        myMyMacros[myMacros[item.name].variables[idx].name] = item.operands[idx]
+                        mapping[myMacros[item.name].variables[idx].name] = nil
+                    else
+                        myMyMacros[myMacros[item.name].variables[idx]] = nil
+                        mapping[myMacros[item.name].variables[idx]] = item.operands[idx]
+                    end
+                }
+                newList += myMacros[item.name].body.substitute(mapping).demacroify(myMyMacros).renameLabels(item.name).list
+            else
+                newList << item.demacroify(myMacros)
+            end
+        }
+        Sequence.new(codeOrigin, newList).substitute({})
+    end
+end
+
+#
+# node.resolveOffsets(offsets, sizes)
+#
+# Construct a new AST that has offset values instead of symbolic
+# offsets.
+#
+
+class Node
+    def resolveOffsets(offsets, sizes)
+        mapChildren {
+            | child |
+            child.resolveOffsets(offsets, sizes)
+        }
+    end
+end
+
+class StructOffset
+    def resolveOffsets(offsets, sizes)
+        if offsets[self]
+            Immediate.new(codeOrigin, offsets[self])
+        else
+            self
+        end
+    end
+end
+
+class Sizeof
+    def resolveOffsets(offsets, sizes)
+        if sizes[self]
+            Immediate.new(codeOrigin, sizes[self])
+        else
+            puts "Could not find #{self.inspect} in #{sizes.keys.inspect}"
+            puts "sizes = #{sizes.inspect}"
+            self
+        end
+    end
+end
+
+#
+# node.fold
+#
+# Resolve constant references and compute arithmetic expressions.
+#
+
+class Node
+    def fold
+        mapChildren {
+            | child |
+            child.fold
+        }
+    end
+end
+
+class AddImmediates
+    def fold
+        @left = @left.fold
+        @right = @right.fold
+        return self unless @left.is_a? Immediate
+        return self unless @right.is_a? Immediate
+        Immediate.new(codeOrigin, @left.value + @right.value)
+    end
+end
+
+class SubImmediates
+    def fold
+        @left = @left.fold
+        @right = @right.fold
+        return self unless @left.is_a? Immediate
+        return self unless @right.is_a? Immediate
+        Immediate.new(codeOrigin, @left.value - @right.value)
+    end
+end
+
+class MulImmediates
+    def fold
+        @left = @left.fold
+        @right = @right.fold
+        return self unless @left.is_a? Immediate
+        return self unless @right.is_a? Immediate
+        Immediate.new(codeOrigin, @left.value * @right.value)
+    end
+end
+
+class NegImmediate
+    def fold
+        @child = @child.fold
+        return self unless @child.is_a? Immediate
+        Immediate.new(codeOrigin, -@child.value)
+    end
+end
+
+#
+# node.resolveAfterSettings(offsets, sizes)
+#
+# Compile assembly against a set of offsets.
+#
+
+class Node
+    def resolve(offsets, sizes)
+        demacroify({}).resolveOffsets(offsets, sizes).fold
+    end
+end
+
diff --git a/Source/JavaScriptCore/offlineasm/x86.rb b/Source/JavaScriptCore/offlineasm/x86.rb
new file mode 100644
index 0000000..b89f2d9
--- /dev/null
+++ b/Source/JavaScriptCore/offlineasm/x86.rb
@@ -0,0 +1,681 @@
+# Copyright (C) 2011 Apple Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+class RegisterID
+    def supports8BitOnX86
+        case name
+        when "t0", "a0", "r0", "t1", "a1", "r1", "t2", "t3"
+            true
+        when "t4", "cfr"
+            false
+        else
+            raise
+        end
+    end
+    
+    def x86Operand(kind)
+        case name
+        when "t0", "a0", "r0"
+            case kind
+            when :byte
+                "%al"
+            when :half
+                "%ax"
+            when :int
+                "%eax"
+            else
+                raise
+            end
+        when "t1", "a1", "r1"
+            case kind
+            when :byte
+                "%dl"
+            when :half
+                "%dx"
+            when :int
+                "%edx"
+            else
+                raise
+            end
+        when "t2"
+            case kind
+            when :byte
+                "%cl"
+            when :half
+                "%cx"
+            when :int
+                "%ecx"
+            else
+                raise
+            end
+        when "t3"
+            case kind
+            when :byte
+                "%bl"
+            when :half
+                "%bx"
+            when :int
+                "%ebx"
+            else
+                raise
+            end
+        when "t4"
+            case kind
+            when :byte
+                "%sil"
+            when :half
+                "%si"
+            when :int
+                "%esi"
+            else
+                raise
+            end
+        when "cfr"
+            case kind
+            when :byte
+                "%dil"
+            when :half
+                "%di"
+            when :int
+                "%edi"
+            else
+                raise
+            end
+        when "sp"
+            case kind
+            when :byte
+                "%spl"
+            when :half
+                "%sp"
+            when :int
+                "%esp"
+            else
+                raise
+            end
+        else
+            raise "Bad register #{name} for X86 at #{codeOriginString}"
+        end
+    end
+    def x86CallOperand(kind)
+        "*#{x86Operand(kind)}"
+    end
+end
+
+class FPRegisterID
+    def x86Operand(kind)
+        raise unless kind == :double
+        case name
+        when "ft0", "fa0", "fr"
+            "%xmm0"
+        when "ft1", "fa1"
+            "%xmm1"
+        when "ft2", "fa2"
+            "%xmm2"
+        when "ft3", "fa3"
+            "%xmm3"
+        when "ft4"
+            "%xmm4"
+        when "ft5"
+            "%xmm5"
+        else
+            raise "Bad register #{name} for X86 at #{codeOriginString}"
+        end
+    end
+    def x86CallOperand(kind)
+        "*#{x86Operand(kind)}"
+    end
+end
+
+class Immediate
+    def x86Operand(kind)
+        "$#{value}"
+    end
+    def x86CallOperand(kind)
+        "#{value}"
+    end
+end
+
+class Address
+    def supports8BitOnX86
+        true
+    end
+    
+    def x86Operand(kind)
+        "#{offset.value}(#{base.x86Operand(:int)})"
+    end
+    def x86CallOperand(kind)
+        "*#{x86Operand(kind)}"
+    end
+end
+
+class BaseIndex
+    def supports8BitOnX86
+        true
+    end
+    
+    def x86Operand(kind)
+        "#{offset.value}(#{base.x86Operand(:int)}, #{index.x86Operand(:int)}, #{scale})"
+    end
+
+    def x86CallOperand(kind)
+        "*#{x86operand(kind)}"
+    end
+end
+
+class AbsoluteAddress
+    def supports8BitOnX86
+        true
+    end
+    
+    def x86Operand(kind)
+        "#{address.value}"
+    end
+
+    def x86CallOperand(kind)
+        "*#{address.value}"
+    end
+end
+
+class LabelReference
+    def x86CallOperand(kind)
+        asmLabel
+    end
+end
+
+class LocalLabelReference
+    def x86CallOperand(kind)
+        asmLabel
+    end
+end
+
+class Instruction
+    def x86Operands(*kinds)
+        raise unless kinds.size == operands.size
+        result = []
+        kinds.size.times {
+            | idx |
+            result << operands[idx].x86Operand(kinds[idx])
+        }
+        result.join(", ")
+    end
+
+    def x86Suffix(kind)
+        case kind
+        when :byte
+            "b"
+        when :half
+            "w"
+        when :int
+            "l"
+        when :double
+            "sd"
+        else
+            raise
+        end
+    end
+    
+    def handleX86OpWithNumOperands(opcode, kind, numOperands)
+        if numOperands == 3
+            if operands[0] == operands[2]
+                $asm.puts "#{opcode} #{operands[1].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
+            elsif operands[1] == operands[2]
+                $asm.puts "#{opcode} #{operands[0].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
+            else
+                $asm.puts "mov#{x86Suffix(kind)} #{operands[0].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
+                $asm.puts "#{opcode} #{operands[1].x86Operand(kind)}, #{operands[2].x86Operand(kind)}"
+            end
+        else
+            $asm.puts "#{opcode} #{operands[0].x86Operand(kind)}, #{operands[1].x86Operand(kind)}"
+        end
+    end
+    
+    def handleX86Op(opcode, kind)
+        handleX86OpWithNumOperands(opcode, kind, operands.size)
+    end
+    
+    def handleX86Shift(opcode, kind)
+        if operands[0].is_a? Immediate or operands[0] == RegisterID.forName(nil, "t2")
+            $asm.puts "#{opcode} #{operands[0].x86Operand(:byte)}, #{operands[1].x86Operand(kind)}"
+        else
+            $asm.puts "xchgl #{operands[0].x86Operand(:int)}, %ecx"
+            $asm.puts "#{opcode} %cl, #{operands[1].x86Operand(kind)}"
+            $asm.puts "xchgl #{operands[0].x86Operand(:int)}, %ecx"
+        end
+    end
+    
+    def handleX86DoubleBranch(branchOpcode, mode)
+        case mode
+        when :normal
+            $asm.puts "ucomisd #{operands[1].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
+        when :reverse
+            $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
+        else
+            raise mode.inspect
+        end
+        $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
+    end
+    
+    def handleX86IntCompare(opcodeSuffix, kind)
+        if operands[0].is_a? Immediate and operands[0].value == 0 and operands[1].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
+            $asm.puts "test#{x86Suffix(kind)} #{operands[1].x86Operand(kind)}"
+        elsif operands[1].is_a? Immediate and operands[1].value == 0 and operands[0].is_a? RegisterID and (opcodeSuffix == "e" or opcodeSuffix == "ne")
+            $asm.puts "test#{x86Suffix(kind)} #{operands[0].x86Operand(kind)}"
+        else
+            $asm.puts "cmp#{x86Suffix(kind)} #{operands[1].x86Operand(kind)}, #{operands[0].x86Operand(kind)}"
+        end
+    end
+    
+    def handleX86IntBranch(branchOpcode, kind)
+        handleX86IntCompare(branchOpcode[1..-1], kind)
+        $asm.puts "#{branchOpcode} #{operands[2].asmLabel}"
+    end
+    
+    def handleX86Set(setOpcode, operand)
+        if operand.supports8BitOnX86
+            $asm.puts "#{setOpcode} #{operand.x86Operand(:byte)}"
+            $asm.puts "movzbl #{operand.x86Operand(:byte)}, #{operand.x86Operand(:int)}"
+        else
+            $asm.puts "xchgl #{operand.x86Operand(:int)}, %eax"
+            $asm.puts "#{setOpcode} %al"
+            $asm.puts "movzbl %al, %eax"
+            $asm.puts "xchgl #{operand.x86Operand(:int)}, %eax"
+        end
+    end
+    
+    def handleX86IntCompareSet(setOpcode, kind)
+        handleX86IntCompare(setOpcode[3..-1], kind)
+        handleX86Set(setOpcode, operands[2])
+    end
+    
+    def handleX86Test(kind)
+        value = operands[0]
+        case operands.size
+        when 2
+            mask = Immediate.new(codeOrigin, -1)
+        when 3
+            mask = operands[1]
+        else
+            raise "Expected 2 or 3 operands, but got #{operands.size} at #{codeOriginString}"
+        end
+        
+        if mask.is_a? Immediate and mask.value == -1
+            if value.is_a? RegisterID
+                $asm.puts "test#{x86Suffix(kind)} #{value.x86Operand(kind)}, #{value.x86Operand(kind)}"
+            else
+                $asm.puts "cmp#{x86Suffix(kind)} $0, #{value.x86Operand(kind)}"
+            end
+        else
+            $asm.puts "test#{x86Suffix(kind)} #{mask.x86Operand(kind)}, #{value.x86Operand(kind)}"
+        end
+    end
+    
+    def handleX86BranchTest(branchOpcode, kind)
+        handleX86Test(kind)
+        $asm.puts "#{branchOpcode} #{operands.last.asmLabel}"
+    end
+    
+    def handleX86SetTest(setOpcode, kind)
+        handleX86Test(kind)
+        handleX86Set(setOpcode, operands.last)
+    end
+    
+    def handleX86OpBranch(opcode, branchOpcode, kind)
+        handleX86OpWithNumOperands(opcode, kind, operands.size - 1)
+        case operands.size
+        when 4
+            jumpTarget = operands[3]
+        when 3
+            jumpTarget = operands[2]
+        else
+            raise self.inspect
+        end
+        $asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
+    end
+    
+    def handleX86SubBranch(branchOpcode, kind)
+        if operands.size == 4 and operands[1] == operands[2]
+            $asm.puts "negl #{operands[2].x86Operand(:int)}"
+            $asm.puts "addl #{operands[0].x86Operand(:int)}, #{operands[2].x86Operand(:int)}"
+        else
+            handleX86OpWithNumOperands("sub#{x86Suffix(kind)}", kind, operands.size - 1)
+        end
+        case operands.size
+        when 4
+            jumpTarget = operands[3]
+        when 3
+            jumpTarget = operands[2]
+        else
+            raise self.inspect
+        end
+        $asm.puts "#{branchOpcode} #{jumpTarget.asmLabel}"
+    end
+    
+    def lowerX86
+        $asm.comment codeOriginString
+        case opcode
+        when "addi", "addp"
+            if operands.size == 3 and operands[0].is_a? Immediate
+                raise unless operands[1].is_a? RegisterID
+                raise unless operands[2].is_a? RegisterID
+                if operands[0].value == 0
+                    unless operands[1] == operands[2]
+                        $asm.puts "movl #{operands[1].x86Operand(:int)}, #{operands[2].x86Operand(:int)}"
+                    end
+                else
+                    $asm.puts "leal #{operands[0].value}(#{operands[1].x86Operand(:int)}), #{operands[2].x86Operand(:int)}"
+                end
+            elsif operands.size == 3 and operands[0].is_a? RegisterID
+                raise unless operands[1].is_a? RegisterID
+                raise unless operands[2].is_a? RegisterID
+                $asm.puts "leal (#{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:int)}), #{operands[2].x86Operand(:int)}"
+            else
+                unless Immediate.new(nil, 0) == operands[0]
+                    $asm.puts "addl #{x86Operands(:int, :int)}"
+                end
+            end
+        when "andi", "andp"
+            handleX86Op("andl", :int)
+        when "lshifti"
+            handleX86Shift("sall", :int)
+        when "muli"
+            if operands.size == 3 and operands[0].is_a? Immediate
+                $asm.puts "imull #{x86Operands(:int, :int, :int)}"
+            else
+                # FIXME: could do some peephole in case the left operand is immediate and it's
+                # a power of two.
+                handleX86Op("imull", :int)
+            end
+        when "negi"
+            $asm.puts "negl #{x86Operands(:int)}"
+        when "noti"
+            $asm.puts "notl #{x86Operands(:int)}"
+        when "ori", "orp"
+            handleX86Op("orl", :int)
+        when "rshifti"
+            handleX86Shift("sarl", :int)
+        when "urshifti"
+            handleX86Shift("shrl", :int)
+        when "subi", "subp"
+            if operands.size == 3 and operands[1] == operands[2]
+                $asm.puts "negl #{operands[2].x86Operand(:int)}"
+                $asm.puts "addl #{operands[0].x86Operand(:int)}, #{operands[2].x86Operand(:int)}"
+            else
+                handleX86Op("subl", :int)
+            end
+        when "xori", "xorp"
+            handleX86Op("xorl", :int)
+        when "loadi", "storei", "loadp", "storep"
+            $asm.puts "movl #{x86Operands(:int, :int)}"
+        when "loadb"
+            $asm.puts "movzbl #{operands[0].x86Operand(:byte)}, #{operands[1].x86Operand(:int)}"
+        when "loadbs"
+            $asm.puts "movsbl #{operands[0].x86Operand(:byte)}, #{operands[1].x86Operand(:int)}"
+        when "loadh"
+            $asm.puts "movzwl #{operands[0].x86Operand(:half)}, #{operands[1].x86Operand(:int)}"
+        when "loadhs"
+            $asm.puts "movswl #{operands[0].x86Operand(:half)}, #{operands[1].x86Operand(:int)}"
+        when "storeb"
+            $asm.puts "movb #{x86Operands(:byte, :byte)}"
+        when "loadd", "moved", "stored"
+            $asm.puts "movsd #{x86Operands(:double, :double)}"
+        when "addd"
+            $asm.puts "addsd #{x86Operands(:double, :double)}"
+        when "divd"
+            $asm.puts "divsd #{x86Operands(:double, :double)}"
+        when "subd"
+            $asm.puts "subsd #{x86Operands(:double, :double)}"
+        when "muld"
+            $asm.puts "mulsd #{x86Operands(:double, :double)}"
+        when "sqrtd"
+            $asm.puts "sqrtsd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
+        when "ci2d"
+            $asm.puts "cvtsi2sd #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:double)}"
+        when "bdeq"
+            isUnordered = LocalLabel.unique("bdeq")
+            $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
+            $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
+            $asm.puts "je #{LabelReference.new(codeOrigin, operands[2]).asmLabel}"
+            isUnordered.lower("X86")
+        when "bdneq"
+            handleX86DoubleBranch("jne", :normal)
+        when "bdgt"
+            handleX86DoubleBranch("ja", :normal)
+        when "bdgteq"
+            handleX86DoubleBranch("jae", :normal)
+        when "bdlt"
+            handleX86DoubleBranch("ja", :reverse)
+        when "bdlteq"
+            handleX86DoubleBranch("jae", :reverse)
+        when "bdequn"
+            handleX86DoubleBranch("je", :normal)
+        when "bdnequn"
+            isUnordered = LocalLabel.unique("bdnequn")
+            isEqual = LocalLabel.unique("bdnequn")
+            $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:double)}"
+            $asm.puts "jp #{LabelReference.new(codeOrigin, isUnordered).asmLabel}"
+            $asm.puts "je #{LabelReference.new(codeOrigin, isEqual).asmLabel}"
+            isUnordered.lower("X86")
+            $asm.puts "jmp #{operands[2].asmLabel}"
+            isEqual.lower("X86")
+        when "bdgtun"
+            handleX86DoubleBranch("jb", :reverse)
+        when "bdgtequn"
+            handleX86DoubleBranch("jbe", :reverse)
+        when "bdltun"
+            handleX86DoubleBranch("jb", :normal)
+        when "bdltequn"
+            handleX86DoubleBranch("jbe", :normal)
+        when "btd2i"
+            $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
+            $asm.puts "cmpl $0x80000000 #{operands[1].x86Operand(:int)}"
+            $asm.puts "je #{operands[2].asmLabel}"
+        when "td2i"
+            $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
+        when "bcd2i"
+            $asm.puts "cvttsd2si #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
+            $asm.puts "testl #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
+            $asm.puts "je #{operands[2].asmLabel}"
+            $asm.puts "cvtsi2sd #{operands[1].x86Operand(:int)}, %xmm7"
+            $asm.puts "ucomisd #{operands[0].x86Operand(:double)}, %xmm7"
+            $asm.puts "jp #{operands[2].asmLabel}"
+            $asm.puts "jne #{operands[2].asmLabel}"
+        when "movdz"
+            $asm.puts "xorpd #{operands[0].x86Operand(:double)}, #{operands[0].x86Operand(:double)}"
+        when "pop"
+            $asm.puts "pop #{operands[0].x86Operand(:int)}"
+        when "push"
+            $asm.puts "push #{operands[0].x86Operand(:int)}"
+        when "move", "sxi2p", "zxi2p"
+            if Immediate.new(nil, 0) == operands[0] and operands[1].is_a? RegisterID
+                $asm.puts "xorl #{operands[1].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
+            elsif operands[0] != operands[1]
+                $asm.puts "movl #{x86Operands(:int, :int)}"
+            end
+        when "nop"
+            $asm.puts "nop"
+        when "bieq", "bpeq"
+            handleX86IntBranch("je", :int)
+        when "bineq", "bpneq"
+            handleX86IntBranch("jne", :int)
+        when "bia", "bpa"
+            handleX86IntBranch("ja", :int)
+        when "biaeq", "bpaeq"
+            handleX86IntBranch("jae", :int)
+        when "bib", "bpb"
+            handleX86IntBranch("jb", :int)
+        when "bibeq", "bpbeq"
+            handleX86IntBranch("jbe", :int)
+        when "bigt", "bpgt"
+            handleX86IntBranch("jg", :int)
+        when "bigteq", "bpgteq"
+            handleX86IntBranch("jge", :int)
+        when "bilt", "bplt"
+            handleX86IntBranch("jl", :int)
+        when "bilteq", "bplteq"
+            handleX86IntBranch("jle", :int)
+        when "bbeq"
+            handleX86IntBranch("je", :byte)
+        when "bbneq"
+            handleX86IntBranch("jne", :byte)
+        when "bba"
+            handleX86IntBranch("ja", :byte)
+        when "bbaeq"
+            handleX86IntBranch("jae", :byte)
+        when "bbb"
+            handleX86IntBranch("jb", :byte)
+        when "bbbeq"
+            handleX86IntBranch("jbe", :byte)
+        when "bbgt"
+            handleX86IntBranch("jg", :byte)
+        when "bbgteq"
+            handleX86IntBranch("jge", :byte)
+        when "bblt"
+            handleX86IntBranch("jl", :byte)
+        when "bblteq"
+            handleX86IntBranch("jlteq", :byte)
+        when "btio", "btpo"
+            handleX86BranchTest("jo", :int)
+        when "btis", "btps"
+            handleX86BranchTest("js", :int)
+        when "btiz", "btpz"
+            handleX86BranchTest("jz", :int)
+        when "btinz", "btpnz"
+            handleX86BranchTest("jnz", :int)
+        when "btbo"
+            handleX86BranchTest("jo", :byte)
+        when "btbs"
+            handleX86BranchTest("js", :byte)
+        when "btbz"
+            handleX86BranchTest("jz", :byte)
+        when "btbnz"
+            handleX86BranchTest("jnz", :byte)
+        when "jmp"
+            $asm.puts "jmp #{operands[0].x86CallOperand(:int)}"
+        when "baddio", "baddpo"
+            handleX86OpBranch("addl", "jo", :int)
+        when "baddis", "baddps"
+            handleX86OpBranch("addl", "js", :int)
+        when "baddiz", "baddpz"
+            handleX86OpBranch("addl", "jz", :int)
+        when "baddinz", "baddpnz"
+            handleX86OpBranch("addl", "jnz", :int)
+        when "bsubio"
+            handleX86SubBranch("jo", :int)
+        when "bsubis"
+            handleX86SubBranch("js", :int)
+        when "bsubiz"
+            handleX86SubBranch("jz", :int)
+        when "bsubinz"
+            handleX86SubBranch("jnz", :int)
+        when "bmulio"
+            handleX86OpBranch("imull", "jo", :int)
+        when "bmulis"
+            handleX86OpBranch("imull", "js", :int)
+        when "bmuliz"
+            handleX86OpBranch("imull", "jz", :int)
+        when "bmulinz"
+            handleX86OpBranch("imull", "jnz", :int)
+        when "borio"
+            handleX86OpBranch("orl", "jo", :int)
+        when "boris"
+            handleX86OpBranch("orl", "js", :int)
+        when "boriz"
+            handleX86OpBranch("orl", "jz", :int)
+        when "borinz"
+            handleX86OpBranch("orl", "jnz", :int)
+        when "break"
+            $asm.puts "int $3"
+        when "call"
+            $asm.puts "call #{operands[0].x86CallOperand(:int)}"
+        when "ret"
+            $asm.puts "ret"
+        when "cieq", "cpeq"
+            handleX86IntCompareSet("sete", :int)
+        when "cineq", "cpneq"
+            handleX86IntCompareSet("setne", :int)
+        when "cia", "cpa"
+            handleX86IntCompareSet("seta", :int)
+        when "ciaeq", "cpaeq"
+            handleX86IntCompareSet("setae", :int)
+        when "cib", "cpb"
+            handleX86IntCompareSet("setb", :int)
+        when "cibeq", "cpbeq"
+            handleX86IntCompareSet("setbe", :int)
+        when "cigt", "cpgt"
+            handleX86IntCompareSet("setg", :int)
+        when "cigteq", "cpgteq"
+            handleX86IntCompareSet("setge", :int)
+        when "cilt", "cplt"
+            handleX86IntCompareSet("setl", :int)
+        when "cilteq", "cplteq"
+            handleX86IntCompareSet("setle", :int)
+        when "tio"
+            handleX86SetTest("seto", :int)
+        when "tis"
+            handleX86SetTest("sets", :int)
+        when "tiz"
+            handleX86SetTest("setz", :int)
+        when "tinz"
+            handleX86SetTest("setnz", :int)
+        when "tbo"
+            handleX86SetTest("seto", :byte)
+        when "tbs"
+            handleX86SetTest("sets", :byte)
+        when "tbz"
+            handleX86SetTest("setz", :byte)
+        when "tbnz"
+            handleX86SetTest("setnz", :byte)
+        when "peek"
+            $asm.puts "movl #{operands[0].value * 4}(%esp), #{operands[1].x86Operand(:int)}"
+        when "poke"
+            $asm.puts "movl #{operands[0].x86Operand(:int)}, #{operands[1].value * 4}(%esp)"
+        when "cdqi"
+            $asm.puts "cdq"
+        when "idivi"
+            $asm.puts "idivl #{operands[0].x86Operand(:int)}"
+        when "fii2d"
+            $asm.puts "movd #{operands[0].x86Operand(:int)}, #{operands[2].x86Operand(:double)}"
+            $asm.puts "movd #{operands[1].x86Operand(:int)}, %xmm7"
+            $asm.puts "psllq $32, %xmm7"
+            $asm.puts "por %xmm7, #{operands[2].x86Operand(:double)}"
+        when "fd2ii"
+            $asm.puts "movd #{operands[0].x86Operand(:double)}, #{operands[1].x86Operand(:int)}"
+            $asm.puts "movsd #{operands[0].x86Operand(:double)}, %xmm7"
+            $asm.puts "psrlq $32, %xmm7"
+            $asm.puts "movsd %xmm7, #{operands[2].x86Operand(:int)}"
+        when "bo"
+            $asm.puts "jo #{operands[0].asmLabel}"
+        when "bs"
+            $asm.puts "js #{operands[0].asmLabel}"
+        when "bz"
+            $asm.puts "jz #{operands[0].asmLabel}"
+        when "bnz"
+            $asm.puts "jnz #{operands[0].asmLabel}"
+        when "leai", "leap"
+            $asm.puts "leal #{operands[0].x86Operand(:int)}, #{operands[1].x86Operand(:int)}"
+        else
+            raise "Bad opcode: #{opcode}"
+        end
+    end
+end
+