/* * 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. */ #ifndef ValueRecovery_h #define ValueRecovery_h #include "DataFormat.h" #include "JSValue.h" #include "MacroAssembler.h" #include "VirtualRegister.h" #include #include namespace JSC { // Describes how to recover a given bytecode virtual register at a given // code point. enum ValueRecoveryTechnique { // It's already in the register file at the right location. AlreadyInRegisterFile, // It's already in the register file but unboxed. AlreadyInRegisterFileAsUnboxedInt32, AlreadyInRegisterFileAsUnboxedCell, AlreadyInRegisterFileAsUnboxedBoolean, AlreadyInRegisterFileAsUnboxedDouble, // It's in a register. InGPR, UnboxedInt32InGPR, UnboxedBooleanInGPR, #if USE(JSVALUE32_64) InPair, #endif InFPR, UInt32InGPR, // It's in the register file, but at a different location. DisplacedInRegisterFile, // It's in the register file, at a different location, and it's unboxed. Int32DisplacedInRegisterFile, DoubleDisplacedInRegisterFile, CellDisplacedInRegisterFile, BooleanDisplacedInRegisterFile, // It's an Arguments object. ArgumentsThatWereNotCreated, // It's a constant. Constant, // Don't know how to recover it. DontKnow }; class ValueRecovery { public: ValueRecovery() : m_technique(DontKnow) { } bool isSet() const { return m_technique != DontKnow; } bool operator!() const { return !isSet(); } static ValueRecovery alreadyInRegisterFile() { ValueRecovery result; result.m_technique = AlreadyInRegisterFile; return result; } static ValueRecovery alreadyInRegisterFileAsUnboxedInt32() { ValueRecovery result; result.m_technique = AlreadyInRegisterFileAsUnboxedInt32; return result; } static ValueRecovery alreadyInRegisterFileAsUnboxedCell() { ValueRecovery result; result.m_technique = AlreadyInRegisterFileAsUnboxedCell; return result; } static ValueRecovery alreadyInRegisterFileAsUnboxedBoolean() { ValueRecovery result; result.m_technique = AlreadyInRegisterFileAsUnboxedBoolean; return result; } static ValueRecovery alreadyInRegisterFileAsUnboxedDouble() { ValueRecovery result; result.m_technique = AlreadyInRegisterFileAsUnboxedDouble; return result; } static ValueRecovery inGPR(MacroAssembler::RegisterID gpr, DataFormat dataFormat) { ASSERT(dataFormat != DataFormatNone); #if USE(JSVALUE32_64) ASSERT(dataFormat == DataFormatInteger || dataFormat == DataFormatCell || dataFormat == DataFormatBoolean); #endif ValueRecovery result; if (dataFormat == DataFormatInteger) result.m_technique = UnboxedInt32InGPR; else if (dataFormat == DataFormatBoolean) result.m_technique = UnboxedBooleanInGPR; else result.m_technique = InGPR; result.m_source.gpr = gpr; return result; } static ValueRecovery uint32InGPR(MacroAssembler::RegisterID gpr) { ValueRecovery result; result.m_technique = UInt32InGPR; result.m_source.gpr = gpr; return result; } #if USE(JSVALUE32_64) static ValueRecovery inPair(MacroAssembler::RegisterID tagGPR, MacroAssembler::RegisterID payloadGPR) { ValueRecovery result; result.m_technique = InPair; result.m_source.pair.tagGPR = tagGPR; result.m_source.pair.payloadGPR = payloadGPR; return result; } #endif static ValueRecovery inFPR(MacroAssembler::FPRegisterID fpr) { ValueRecovery result; result.m_technique = InFPR; result.m_source.fpr = fpr; return result; } static ValueRecovery displacedInRegisterFile(VirtualRegister virtualReg, DataFormat dataFormat) { ValueRecovery result; switch (dataFormat) { case DataFormatInteger: result.m_technique = Int32DisplacedInRegisterFile; break; case DataFormatDouble: result.m_technique = DoubleDisplacedInRegisterFile; break; case DataFormatCell: result.m_technique = CellDisplacedInRegisterFile; break; case DataFormatBoolean: result.m_technique = BooleanDisplacedInRegisterFile; break; default: ASSERT(dataFormat != DataFormatNone && dataFormat != DataFormatStorage); result.m_technique = DisplacedInRegisterFile; break; } result.m_source.virtualReg = virtualReg; return result; } static ValueRecovery constant(JSValue value) { ValueRecovery result; result.m_technique = Constant; result.m_source.constant = JSValue::encode(value); return result; } static ValueRecovery argumentsThatWereNotCreated() { ValueRecovery result; result.m_technique = ArgumentsThatWereNotCreated; return result; } ValueRecoveryTechnique technique() const { return m_technique; } bool isConstant() const { return m_technique == Constant; } bool isInRegisters() const { switch (m_technique) { case InGPR: case UnboxedInt32InGPR: case UnboxedBooleanInGPR: #if USE(JSVALUE32_64) case InPair: #endif case InFPR: return true; default: return false; } } bool isAlreadyInRegisterFile() const { switch (technique()) { case AlreadyInRegisterFile: case AlreadyInRegisterFileAsUnboxedInt32: case AlreadyInRegisterFileAsUnboxedCell: case AlreadyInRegisterFileAsUnboxedBoolean: case AlreadyInRegisterFileAsUnboxedDouble: return true; default: return false; } } MacroAssembler::RegisterID gpr() const { ASSERT(m_technique == InGPR || m_technique == UnboxedInt32InGPR || m_technique == UnboxedBooleanInGPR || m_technique == UInt32InGPR); return m_source.gpr; } #if USE(JSVALUE32_64) MacroAssembler::RegisterID tagGPR() const { ASSERT(m_technique == InPair); return m_source.pair.tagGPR; } MacroAssembler::RegisterID payloadGPR() const { ASSERT(m_technique == InPair); return m_source.pair.payloadGPR; } #endif MacroAssembler::FPRegisterID fpr() const { ASSERT(m_technique == InFPR); return m_source.fpr; } VirtualRegister virtualRegister() const { ASSERT(m_technique == DisplacedInRegisterFile || m_technique == Int32DisplacedInRegisterFile || m_technique == DoubleDisplacedInRegisterFile || m_technique == CellDisplacedInRegisterFile || m_technique == BooleanDisplacedInRegisterFile); return m_source.virtualReg; } JSValue constant() const { ASSERT(m_technique == Constant); return JSValue::decode(m_source.constant); } void dump(FILE* out) const { switch (technique()) { case AlreadyInRegisterFile: fprintf(out, "-"); break; case AlreadyInRegisterFileAsUnboxedInt32: fprintf(out, "(int32)"); break; case AlreadyInRegisterFileAsUnboxedCell: fprintf(out, "(cell)"); break; case AlreadyInRegisterFileAsUnboxedBoolean: fprintf(out, "(bool)"); break; case AlreadyInRegisterFileAsUnboxedDouble: fprintf(out, "(double)"); break; case InGPR: fprintf(out, "%%r%d", gpr()); break; case UnboxedInt32InGPR: fprintf(out, "int32(%%r%d)", gpr()); break; case UnboxedBooleanInGPR: fprintf(out, "bool(%%r%d)", gpr()); break; case UInt32InGPR: fprintf(out, "uint32(%%r%d)", gpr()); break; case InFPR: fprintf(out, "%%fr%d", fpr()); break; #if USE(JSVALUE32_64) case InPair: fprintf(out, "pair(%%r%d, %%r%d)", tagGPR(), payloadGPR()); break; #endif case DisplacedInRegisterFile: fprintf(out, "*%d", virtualRegister()); break; case Int32DisplacedInRegisterFile: fprintf(out, "*int32(%d)", virtualRegister()); break; case DoubleDisplacedInRegisterFile: fprintf(out, "*double(%d)", virtualRegister()); break; case CellDisplacedInRegisterFile: fprintf(out, "*cell(%d)", virtualRegister()); break; case BooleanDisplacedInRegisterFile: fprintf(out, "*bool(%d)", virtualRegister()); break; case ArgumentsThatWereNotCreated: fprintf(out, "arguments"); break; case Constant: fprintf(out, "[%s]", constant().description()); break; case DontKnow: fprintf(out, "!"); break; default: fprintf(out, "?%d", technique()); break; } } private: ValueRecoveryTechnique m_technique; union { MacroAssembler::RegisterID gpr; MacroAssembler::FPRegisterID fpr; #if USE(JSVALUE32_64) struct { MacroAssembler::RegisterID tagGPR; MacroAssembler::RegisterID payloadGPR; } pair; #endif VirtualRegister virtualReg; EncodedJSValue constant; } m_source; }; } // namespace JSC #endif // ValueRecovery_h