diff options
author | Steve Block <steveblock@google.com> | 2011-05-25 19:08:45 +0100 |
---|---|---|
committer | Steve Block <steveblock@google.com> | 2011-06-08 13:51:31 +0100 |
commit | 2bde8e466a4451c7319e3a072d118917957d6554 (patch) | |
tree | 28f4a1b869a513e565c7760d0e6a06e7cf1fe95a /Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp | |
parent | 6939c99b71d9372d14a0c74a772108052e8c48c8 (diff) | |
download | external_webkit-2bde8e466a4451c7319e3a072d118917957d6554.zip external_webkit-2bde8e466a4451c7319e3a072d118917957d6554.tar.gz external_webkit-2bde8e466a4451c7319e3a072d118917957d6554.tar.bz2 |
Merge WebKit at r82507: Initial merge by git
Change-Id: I60ce9d780725b58b45e54165733a8ffee23b683e
Diffstat (limited to 'Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp')
-rw-r--r-- | Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp | 563 |
1 files changed, 563 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp b/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp new file mode 100644 index 0000000..b945b5a --- /dev/null +++ b/Source/JavaScriptCore/dfg/DFGJITCodeGenerator.cpp @@ -0,0 +1,563 @@ +/* + * 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. ``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 + * 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. + */ + +#include "config.h" +#include "DFGJITCodeGenerator.h" + +#if ENABLE(DFG_JIT) + +#include "DFGNonSpeculativeJIT.h" +#include "DFGSpeculativeJIT.h" +#include "LinkBuffer.h" + +namespace JSC { namespace DFG { + +GPRReg JITCodeGenerator::fillInteger(NodeIndex nodeIndex, DataFormat& returnFormat) +{ + Node& node = m_jit.graph()[nodeIndex]; + VirtualRegister virtualRegister = node.virtualRegister; + GenerationInfo& info = m_generationInfo[virtualRegister]; + + if (info.registerFormat() == DataFormatNone) { + GPRReg gpr = allocate(); + JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr); + + if (node.isConstant()) { + m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); + if (isInt32Constant(nodeIndex)) { + m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), reg); + info.fillInteger(gpr); + returnFormat = DataFormatInteger; + return gpr; + } + if (isDoubleConstant(nodeIndex)) { + JSValue jsValue = jsNumber(valueOfDoubleConstant(nodeIndex)); + m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), reg); + } else { + ASSERT(isJSConstant(nodeIndex)); + JSValue jsValue = valueOfJSConstant(nodeIndex); + m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), reg); + } + } else if (node.isArgument()) { + m_gprs.retain(gpr, virtualRegister, SpillOrderArgument); + m_jit.loadPtr(m_jit.addressForArgument(m_jit.graph()[nodeIndex].argumentNumber()), reg); + } else { + ASSERT(info.spillFormat() == DataFormatJS || info.spillFormat() == DataFormatJSInteger); + m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); + m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), reg); + } + + // Since we statically know that we're filling an integer, and values + // in the RegisterFile are boxed, this must be DataFormatJSInteger. + // We will check this with a jitAssert below. + info.fillJSValue(gpr, DataFormatJSInteger); + unlock(gpr); + } + + switch (info.registerFormat()) { + case DataFormatNone: + // Should have filled, above. + case DataFormatJSDouble: + case DataFormatDouble: + case DataFormatJS: + case DataFormatCell: + case DataFormatJSCell: + // Should only be calling this function if we know this operand to be integer. + ASSERT_NOT_REACHED(); + + case DataFormatJSInteger: { + GPRReg gpr = info.gpr(); + m_gprs.lock(gpr); + m_jit.jitAssertIsJSInt32(gpr); + returnFormat = DataFormatJSInteger; + return gpr; + } + + case DataFormatInteger: { + GPRReg gpr = info.gpr(); + m_gprs.lock(gpr); + m_jit.jitAssertIsInt32(gpr); + returnFormat = DataFormatInteger; + return gpr; + } + } + + ASSERT_NOT_REACHED(); + return InvalidGPRReg; +} + +FPRReg JITCodeGenerator::fillDouble(NodeIndex nodeIndex) +{ + Node& node = m_jit.graph()[nodeIndex]; + VirtualRegister virtualRegister = node.virtualRegister; + GenerationInfo& info = m_generationInfo[virtualRegister]; + + if (info.registerFormat() == DataFormatNone) { + GPRReg gpr = allocate(); + JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr); + + if (node.isConstant()) { + if (isInt32Constant(nodeIndex)) { + // FIXME: should not be reachable? + m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), reg); + m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); + info.fillInteger(gpr); + unlock(gpr); + } else if (isDoubleConstant(nodeIndex)) { + FPRReg fpr = fprAllocate(); + m_jit.move(MacroAssembler::ImmPtr(reinterpret_cast<void*>(reinterpretDoubleToIntptr(valueOfDoubleConstant(nodeIndex)))), reg); + m_jit.movePtrToDouble(reg, JITCompiler::fprToRegisterID(fpr)); + unlock(gpr); + + m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); + info.fillDouble(fpr); + return fpr; + } else { + // FIXME: should not be reachable? + ASSERT(isJSConstant(nodeIndex)); + JSValue jsValue = valueOfJSConstant(nodeIndex); + m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), reg); + m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); + info.fillJSValue(gpr, DataFormatJS); + unlock(gpr); + } + } else if (node.isArgument()) { + m_gprs.retain(gpr, virtualRegister, SpillOrderArgument); + m_jit.loadPtr(m_jit.addressForArgument(m_jit.graph()[nodeIndex].argumentNumber()), reg); + info.fillJSValue(gpr, DataFormatJS); + unlock(gpr); + } else { + DataFormat spillFormat = info.spillFormat(); + ASSERT(spillFormat & DataFormatJS); + m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); + m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), reg); + info.fillJSValue(gpr, m_isSpeculative ? spillFormat : DataFormatJS); + unlock(gpr); + } + } + + switch (info.registerFormat()) { + case DataFormatNone: + // Should have filled, above. + case DataFormatCell: + case DataFormatJSCell: + // Should only be calling this function if we know this operand to be numeric. + ASSERT_NOT_REACHED(); + + case DataFormatJS: { + GPRReg jsValueGpr = info.gpr(); + m_gprs.lock(jsValueGpr); + FPRReg fpr = fprAllocate(); + GPRReg tempGpr = allocate(); // FIXME: can we skip this allocation on the last use of the virtual register? + + JITCompiler::RegisterID jsValueReg = JITCompiler::gprToRegisterID(jsValueGpr); + JITCompiler::FPRegisterID fpReg = JITCompiler::fprToRegisterID(fpr); + JITCompiler::RegisterID tempReg = JITCompiler::gprToRegisterID(tempGpr); + + JITCompiler::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueReg, JITCompiler::tagTypeNumberRegister); + + m_jit.jitAssertIsJSDouble(jsValueGpr); + + // First, if we get here we have a double encoded as a JSValue + m_jit.move(jsValueReg, tempReg); + m_jit.addPtr(JITCompiler::tagTypeNumberRegister, tempReg); + m_jit.movePtrToDouble(tempReg, fpReg); + JITCompiler::Jump hasUnboxedDouble = m_jit.jump(); + + // Finally, handle integers. + isInteger.link(&m_jit); + m_jit.convertInt32ToDouble(jsValueReg, fpReg); + hasUnboxedDouble.link(&m_jit); + + m_gprs.release(jsValueGpr); + m_gprs.unlock(jsValueGpr); + m_gprs.unlock(tempGpr); + m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); + info.fillDouble(fpr); + return fpr; + } + + case DataFormatJSInteger: + case DataFormatInteger: { + FPRReg fpr = fprAllocate(); + GPRReg gpr = info.gpr(); + m_gprs.lock(gpr); + JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr); + JITCompiler::FPRegisterID fpReg = JITCompiler::fprToRegisterID(fpr); + + m_jit.convertInt32ToDouble(reg, fpReg); + + m_gprs.release(gpr); + m_gprs.unlock(gpr); + m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); + info.fillDouble(fpr); + return fpr; + } + + // Unbox the double + case DataFormatJSDouble: { + GPRReg gpr = info.gpr(); + FPRReg fpr = unboxDouble(gpr); + + m_gprs.release(gpr); + m_fprs.retain(fpr, virtualRegister, SpillOrderDouble); + + info.fillDouble(fpr); + return fpr; + } + + case DataFormatDouble: { + FPRReg fpr = info.fpr(); + m_fprs.lock(fpr); + return fpr; + } + } + + ASSERT_NOT_REACHED(); + return InvalidFPRReg; +} + +GPRReg JITCodeGenerator::fillJSValue(NodeIndex nodeIndex) +{ + Node& node = m_jit.graph()[nodeIndex]; + VirtualRegister virtualRegister = node.virtualRegister; + GenerationInfo& info = m_generationInfo[virtualRegister]; + + switch (info.registerFormat()) { + case DataFormatNone: { + GPRReg gpr = allocate(); + JITCompiler::RegisterID reg = JITCompiler::gprToRegisterID(gpr); + + if (node.isConstant()) { + if (isInt32Constant(nodeIndex)) { + info.fillJSValue(gpr, DataFormatJSInteger); + JSValue jsValue = jsNumber(valueOfInt32Constant(nodeIndex)); + m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), reg); + } else if (isDoubleConstant(nodeIndex)) { + info.fillJSValue(gpr, DataFormatJSDouble); + JSValue jsValue(JSValue::EncodeAsDouble, valueOfDoubleConstant(nodeIndex)); + m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), reg); + } else { + ASSERT(isJSConstant(nodeIndex)); + JSValue jsValue = valueOfJSConstant(nodeIndex); + m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), reg); + info.fillJSValue(gpr, DataFormatJS); + } + + m_gprs.retain(gpr, virtualRegister, SpillOrderConstant); + } else if (node.isArgument()) { + m_gprs.retain(gpr, virtualRegister, SpillOrderArgument); + m_jit.loadPtr(m_jit.addressForArgument(m_jit.graph()[nodeIndex].argumentNumber()), reg); + info.fillJSValue(gpr, DataFormatJS); + } else { + DataFormat spillFormat = info.spillFormat(); + ASSERT(spillFormat & DataFormatJS); + m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled); + m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), reg); + info.fillJSValue(gpr, m_isSpeculative ? spillFormat : DataFormatJS); + } + return gpr; + } + + case DataFormatInteger: { + GPRReg gpr = info.gpr(); + m_gprs.lock(gpr); + m_jit.orPtr(JITCompiler::tagTypeNumberRegister, JITCompiler::gprToRegisterID(gpr)); + info.fillJSValue(gpr, DataFormatJSInteger); + return gpr; + } + + case DataFormatDouble: { + FPRReg fpr = info.fpr(); + GPRReg gpr = boxDouble(fpr); + + // Update all info + info.fillJSValue(gpr, DataFormatJSDouble); + m_fprs.release(fpr); + m_gprs.retain(gpr, virtualRegister, SpillOrderJS); + + return gpr; + } + + case DataFormatCell: + // No retag required on JSVALUE64! + case DataFormatJS: + case DataFormatJSInteger: + case DataFormatJSDouble: + case DataFormatJSCell: { + GPRReg gpr = info.gpr(); + m_gprs.lock(gpr); + return gpr; + } + } + + ASSERT_NOT_REACHED(); + return InvalidGPRReg; +} + +void JITCodeGenerator::useChildren(Node& node) +{ + NodeIndex child1 = node.child1; + if (child1 == NoNode) { + ASSERT(node.child2 == NoNode && node.child3 == NoNode); + return; + } + use(child1); + + NodeIndex child2 = node.child2; + if (child2 == NoNode) { + ASSERT(node.child3 == NoNode); + return; + } + use(child2); + + NodeIndex child3 = node.child3; + if (child3 == NoNode) + return; + use(child3); +} + +#ifndef NDEBUG +static const char* dataFormatString(DataFormat format) +{ + // These values correspond to the DataFormat enum. + const char* strings[] = { + "[ ]", + "[ i]", + "[ d]", + "[ c]", + "Err!", + "Err!", + "Err!", + "Err!", + "[J ]", + "[Ji]", + "[Jd]", + "[Jc]", + "Err!", + "Err!", + "Err!", + "Err!", + }; + return strings[format]; +} + +void JITCodeGenerator::dump(const char* label) +{ + if (label) + fprintf(stderr, "<%s>\n", label); + + fprintf(stderr, " gprs:\n"); + m_gprs.dump(); + fprintf(stderr, " fprs:\n"); + m_fprs.dump(); + fprintf(stderr, " VirtualRegisters:\n"); + for (unsigned i = 0; i < m_generationInfo.size(); ++i) { + GenerationInfo& info = m_generationInfo[i]; + if (info.alive()) + fprintf(stderr, " % 3d:%s%s\n", i, dataFormatString(info.registerFormat()), dataFormatString(info.spillFormat())); + else + fprintf(stderr, " % 3d:[__][__]\n", i); + } + if (label) + fprintf(stderr, "</%s>\n", label); +} +#endif + + +#if DFG_CONSISTENCY_CHECK +void JITCodeGenerator::checkConsistency() +{ + VirtualRegister grpContents[numberOfGPRs]; + VirtualRegister frpContents[numberOfFPRs]; + + for (unsigned i = 0; i < numberOfGPRs; ++i) + grpContents[i] = InvalidVirtualRegister; + for (unsigned i = 0; i < numberOfFPRs; ++i) + frpContents[i] = InvalidVirtualRegister; + for (unsigned i = 0; i < m_generationInfo.size(); ++i) { + GenerationInfo& info = m_generationInfo[i]; + if (!info.alive()) + continue; + switch (info.registerFormat()) { + case DataFormatNone: + break; + case DataFormatInteger: + case DataFormatCell: + case DataFormatJS: + case DataFormatJSInteger: + case DataFormatJSDouble: + case DataFormatJSCell: { + GPRReg gpr = info.gpr(); + ASSERT(gpr != InvalidGPRReg); + grpContents[gpr] = (VirtualRegister)i; + break; + } + case DataFormatDouble: { + FPRReg fpr = info.fpr(); + ASSERT(fpr != InvalidFPRReg); + frpContents[fpr] = (VirtualRegister)i; + break; + } + } + } + + for (GPRReg i = gpr0; i < numberOfGPRs; next(i)) { + if (m_gprs.isLocked(i) || m_gprs.name(i) != grpContents[i]) { + dump(); + CRASH(); + } + } + for (FPRReg i = fpr0; i < numberOfFPRs; next(i)) { + if (m_fprs.isLocked(i) || m_fprs.name(i) != frpContents[i]) { + dump(); + CRASH(); + } + } +} +#endif + +GPRTemporary::GPRTemporary(JITCodeGenerator* jit) + : m_jit(jit) + , m_gpr(InvalidGPRReg) +{ + m_gpr = m_jit->allocate(); +} + +GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateIntegerOperand& op1) + : m_jit(jit) + , m_gpr(InvalidGPRReg) +{ + // locking into a register may free for reuse! + op1.gpr(); + if (m_jit->canReuse(op1.index())) + m_gpr = m_jit->reuse(op1.gpr()); + else + m_gpr = m_jit->allocate(); +} + +GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateIntegerOperand& op1, SpeculateIntegerOperand& op2) + : m_jit(jit) + , m_gpr(InvalidGPRReg) +{ + // locking into a register may free for reuse! + op1.gpr(); + op2.gpr(); + if (m_jit->canReuse(op1.index())) + m_gpr = m_jit->reuse(op1.gpr()); + else if (m_jit->canReuse(op2.index())) + m_gpr = m_jit->reuse(op2.gpr()); + else + m_gpr = m_jit->allocate(); +} + +GPRTemporary::GPRTemporary(JITCodeGenerator* jit, IntegerOperand& op1) + : m_jit(jit) + , m_gpr(InvalidGPRReg) +{ + // locking into a register may free for reuse! + op1.gpr(); + if (m_jit->canReuse(op1.index())) + m_gpr = m_jit->reuse(op1.gpr()); + else + m_gpr = m_jit->allocate(); +} + +GPRTemporary::GPRTemporary(JITCodeGenerator* jit, IntegerOperand& op1, IntegerOperand& op2) + : m_jit(jit) + , m_gpr(InvalidGPRReg) +{ + // locking into a register may free for reuse! + op1.gpr(); + op2.gpr(); + if (m_jit->canReuse(op1.index())) + m_gpr = m_jit->reuse(op1.gpr()); + else if (m_jit->canReuse(op2.index())) + m_gpr = m_jit->reuse(op2.gpr()); + else + m_gpr = m_jit->allocate(); +} + +GPRTemporary::GPRTemporary(JITCodeGenerator* jit, SpeculateCellOperand& op1) + : m_jit(jit) + , m_gpr(InvalidGPRReg) +{ + // locking into a register may free for reuse! + op1.gpr(); + if (m_jit->canReuse(op1.index())) + m_gpr = m_jit->reuse(op1.gpr()); + else + m_gpr = m_jit->allocate(); +} + +GPRTemporary::GPRTemporary(JITCodeGenerator* jit, JSValueOperand& op1) + : m_jit(jit) + , m_gpr(InvalidGPRReg) +{ + // locking into a register may free for reuse! + op1.gpr(); + if (m_jit->canReuse(op1.index())) + m_gpr = m_jit->reuse(op1.gpr()); + else + m_gpr = m_jit->allocate(); +} + +FPRTemporary::FPRTemporary(JITCodeGenerator* jit) + : m_jit(jit) + , m_fpr(InvalidFPRReg) +{ + m_fpr = m_jit->fprAllocate(); +} + +FPRTemporary::FPRTemporary(JITCodeGenerator* jit, DoubleOperand& op1) + : m_jit(jit) + , m_fpr(InvalidFPRReg) +{ + // locking into a register may free for reuse! + op1.fpr(); + if (m_jit->canReuse(op1.index())) + m_fpr = m_jit->reuse(op1.fpr()); + else + m_fpr = m_jit->fprAllocate(); +} + +FPRTemporary::FPRTemporary(JITCodeGenerator* jit, DoubleOperand& op1, DoubleOperand& op2) + : m_jit(jit) + , m_fpr(InvalidFPRReg) +{ + // locking into a register may free for reuse! + op1.fpr(); + op2.fpr(); + if (m_jit->canReuse(op1.index())) + m_fpr = m_jit->reuse(op1.fpr()); + else if (m_jit->canReuse(op2.index())) + m_fpr = m_jit->reuse(op2.fpr()); + else + m_fpr = m_jit->fprAllocate(); +} + +} } // namespace JSC::DFG + +#endif |