+++ /dev/null
-/*
- * 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();
-
- if (node.isConstant()) {
- m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
- if (isInt32Constant(nodeIndex)) {
- m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
- info.fillInteger(gpr);
- returnFormat = DataFormatInteger;
- return gpr;
- }
- if (isDoubleConstant(nodeIndex)) {
- JSValue jsValue = jsNumber(valueOfDoubleConstant(nodeIndex));
- m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
- } else {
- ASSERT(isJSConstant(nodeIndex));
- JSValue jsValue = valueOfJSConstant(nodeIndex);
- m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
- }
- } else {
- ASSERT(info.spillFormat() == DataFormatJS || info.spillFormat() == DataFormatJSInteger);
- m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
- m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
- }
-
- // 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();
-
- if (node.isConstant()) {
- if (isInt32Constant(nodeIndex)) {
- // FIXME: should not be reachable?
- m_jit.move(MacroAssembler::Imm32(valueOfInt32Constant(nodeIndex)), gpr);
- 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)))), gpr);
- m_jit.movePtrToDouble(gpr, 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)), gpr);
- m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
- 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), gpr);
- 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::Jump isInteger = m_jit.branchPtr(MacroAssembler::AboveOrEqual, jsValueGpr, GPRInfo::tagTypeNumberRegister);
-
- m_jit.jitAssertIsJSDouble(jsValueGpr);
-
- // First, if we get here we have a double encoded as a JSValue
- m_jit.move(jsValueGpr, tempGpr);
- m_jit.addPtr(GPRInfo::tagTypeNumberRegister, tempGpr);
- m_jit.movePtrToDouble(tempGpr, fpr);
- JITCompiler::Jump hasUnboxedDouble = m_jit.jump();
-
- // Finally, handle integers.
- isInteger.link(&m_jit);
- m_jit.convertInt32ToDouble(jsValueGpr, fpr);
- 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);
-
- m_jit.convertInt32ToDouble(gpr, fpr);
-
- 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();
-
- if (node.isConstant()) {
- if (isInt32Constant(nodeIndex)) {
- info.fillJSValue(gpr, DataFormatJSInteger);
- JSValue jsValue = jsNumber(valueOfInt32Constant(nodeIndex));
- m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
- } else if (isDoubleConstant(nodeIndex)) {
- info.fillJSValue(gpr, DataFormatJSDouble);
- JSValue jsValue(JSValue::EncodeAsDouble, valueOfDoubleConstant(nodeIndex));
- m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
- } else {
- ASSERT(isJSConstant(nodeIndex));
- JSValue jsValue = valueOfJSConstant(nodeIndex);
- m_jit.move(MacroAssembler::ImmPtr(JSValue::encode(jsValue)), gpr);
- info.fillJSValue(gpr, DataFormatJS);
- }
-
- m_gprs.retain(gpr, virtualRegister, SpillOrderConstant);
- } else {
- DataFormat spillFormat = info.spillFormat();
- ASSERT(spillFormat & DataFormatJS);
- m_gprs.retain(gpr, virtualRegister, SpillOrderSpilled);
- m_jit.loadPtr(JITCompiler::addressFor(virtualRegister), gpr);
- info.fillJSValue(gpr, m_isSpeculative ? spillFormat : DataFormatJS);
- }
- return gpr;
- }
-
- case DataFormatInteger: {
- GPRReg gpr = info.gpr();
- // If the register has already been locked we need to take a copy.
- // If not, we'll zero extend in place, so mark on the info that this is now type DataFormatInteger, not DataFormatJSInteger.
- if (m_gprs.isLocked(gpr)) {
- GPRReg result = allocate();
- m_jit.orPtr(GPRInfo::tagTypeNumberRegister, gpr, result);
- return result;
- }
- m_gprs.lock(gpr);
- m_jit.orPtr(GPRInfo::tagTypeNumberRegister, 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", i, dataFormatString(info.registerFormat()), dataFormatString(info.spillFormat()));
- else
- fprintf(stderr, " % 3d:[__][__]", i);
- if (info.registerFormat() == DataFormatDouble)
- fprintf(stderr, ":fpr%d\n", info.fpr());
- else if (info.registerFormat() != DataFormatNone) {
- ASSERT(info.gpr() != InvalidGPRReg);
- fprintf(stderr, ":%s\n", GPRInfo::debugName(info.gpr()));
- } else
- fprintf(stderr, "\n");
- }
- if (label)
- fprintf(stderr, "</%s>\n", label);
-}
-#endif
-
-
-#if DFG_CONSISTENCY_CHECK
-void JITCodeGenerator::checkConsistency()
-{
- bool failed = false;
-
- for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
- if (iter.isLocked()) {
- fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: gpr %s is locked.\n", iter.debugName());
- failed = true;
- }
- }
- for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
- if (iter.isLocked()) {
- fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: fpr %s is locked.\n", iter.debugName());
- failed = true;
- }
- }
-
- for (unsigned i = 0; i < m_generationInfo.size(); ++i) {
- VirtualRegister virtualRegister = (VirtualRegister)i;
- GenerationInfo& info = m_generationInfo[virtualRegister];
- 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);
- if (m_gprs.name(gpr) != virtualRegister) {
- fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (gpr %s).\n", virtualRegister, GPRInfo::debugName(gpr));
- failed = true;
- }
- break;
- }
- case DataFormatDouble: {
- FPRReg fpr = info.fpr();
- ASSERT(fpr != InvalidFPRReg);
- if (m_fprs.name(fpr) != virtualRegister) {
- fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for virtual register %d (fpr %s).\n", virtualRegister, FPRInfo::debugName(fpr));
- failed = true;
- }
- break;
- }
- }
- }
-
- for (gpr_iterator iter = m_gprs.begin(); iter != m_gprs.end(); ++iter) {
- VirtualRegister virtualRegister = iter.name();
- if (virtualRegister == InvalidVirtualRegister)
- continue;
-
- GenerationInfo& info = m_generationInfo[virtualRegister];
- if (iter.regID() != info.gpr()) {
- fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for gpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
- failed = true;
- }
- }
-
- for (fpr_iterator iter = m_fprs.begin(); iter != m_fprs.end(); ++iter) {
- VirtualRegister virtualRegister = iter.name();
- if (virtualRegister == InvalidVirtualRegister)
- continue;
-
- GenerationInfo& info = m_generationInfo[virtualRegister];
- if (iter.regID() != info.fpr()) {
- fprintf(stderr, "DFG_CONSISTENCY_CHECK failed: name mismatch for fpr %s (virtual register %d).\n", iter.debugName(), virtualRegister);
- failed = true;
- }
- }
-
- if (failed) {
- 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)
-{
- 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)
-{
- 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)
-{
- 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)
-{
- 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)
-{
- 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)
-{
- 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)
-{
- 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)
-{
- 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