| /* |
| * 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 <stdio.h> |
| #include <wtf/Platform.h> |
| |
| namespace JSC { |
| |
| // Describes how to recover a given bytecode virtual register at a given |
| // code point. |
| enum ValueRecoveryTechnique { |
| // It's already in the stack at the right location. |
| AlreadyInJSStack, |
| // It's already in the stack but unboxed. |
| AlreadyInJSStackAsUnboxedInt32, |
| AlreadyInJSStackAsUnboxedCell, |
| AlreadyInJSStackAsUnboxedBoolean, |
| AlreadyInJSStackAsUnboxedDouble, |
| // It's in a register. |
| InGPR, |
| UnboxedInt32InGPR, |
| UnboxedBooleanInGPR, |
| #if USE(JSVALUE32_64) |
| InPair, |
| #endif |
| InFPR, |
| UInt32InGPR, |
| // It's in the stack, but at a different location. |
| DisplacedInJSStack, |
| // It's in the stack, at a different location, and it's unboxed. |
| Int32DisplacedInJSStack, |
| DoubleDisplacedInJSStack, |
| CellDisplacedInJSStack, |
| BooleanDisplacedInJSStack, |
| // 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 alreadyInJSStack() |
| { |
| ValueRecovery result; |
| result.m_technique = AlreadyInJSStack; |
| return result; |
| } |
| |
| static ValueRecovery alreadyInJSStackAsUnboxedInt32() |
| { |
| ValueRecovery result; |
| result.m_technique = AlreadyInJSStackAsUnboxedInt32; |
| return result; |
| } |
| |
| static ValueRecovery alreadyInJSStackAsUnboxedCell() |
| { |
| ValueRecovery result; |
| result.m_technique = AlreadyInJSStackAsUnboxedCell; |
| return result; |
| } |
| |
| static ValueRecovery alreadyInJSStackAsUnboxedBoolean() |
| { |
| ValueRecovery result; |
| result.m_technique = AlreadyInJSStackAsUnboxedBoolean; |
| return result; |
| } |
| |
| static ValueRecovery alreadyInJSStackAsUnboxedDouble() |
| { |
| ValueRecovery result; |
| result.m_technique = AlreadyInJSStackAsUnboxedDouble; |
| 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 displacedInJSStack(VirtualRegister virtualReg, DataFormat dataFormat) |
| { |
| ValueRecovery result; |
| switch (dataFormat) { |
| case DataFormatInteger: |
| result.m_technique = Int32DisplacedInJSStack; |
| break; |
| |
| case DataFormatDouble: |
| result.m_technique = DoubleDisplacedInJSStack; |
| break; |
| |
| case DataFormatCell: |
| result.m_technique = CellDisplacedInJSStack; |
| break; |
| |
| case DataFormatBoolean: |
| result.m_technique = BooleanDisplacedInJSStack; |
| break; |
| |
| default: |
| ASSERT(dataFormat != DataFormatNone && dataFormat != DataFormatStorage); |
| result.m_technique = DisplacedInJSStack; |
| 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 isAlreadyInJSStack() const |
| { |
| switch (technique()) { |
| case AlreadyInJSStack: |
| case AlreadyInJSStackAsUnboxedInt32: |
| case AlreadyInJSStackAsUnboxedCell: |
| case AlreadyInJSStackAsUnboxedBoolean: |
| case AlreadyInJSStackAsUnboxedDouble: |
| 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 == DisplacedInJSStack || m_technique == Int32DisplacedInJSStack || m_technique == DoubleDisplacedInJSStack || m_technique == CellDisplacedInJSStack || m_technique == BooleanDisplacedInJSStack); |
| return m_source.virtualReg; |
| } |
| |
| JSValue constant() const |
| { |
| ASSERT(m_technique == Constant); |
| return JSValue::decode(m_source.constant); |
| } |
| |
| void dump(PrintStream& out) const |
| { |
| switch (technique()) { |
| case AlreadyInJSStack: |
| out.printf("-"); |
| break; |
| case AlreadyInJSStackAsUnboxedInt32: |
| out.printf("(int32)"); |
| break; |
| case AlreadyInJSStackAsUnboxedCell: |
| out.printf("(cell)"); |
| break; |
| case AlreadyInJSStackAsUnboxedBoolean: |
| out.printf("(bool)"); |
| break; |
| case AlreadyInJSStackAsUnboxedDouble: |
| out.printf("(double)"); |
| break; |
| case InGPR: |
| out.printf("%%r%d", gpr()); |
| break; |
| case UnboxedInt32InGPR: |
| out.printf("int32(%%r%d)", gpr()); |
| break; |
| case UnboxedBooleanInGPR: |
| out.printf("bool(%%r%d)", gpr()); |
| break; |
| case UInt32InGPR: |
| out.printf("uint32(%%r%d)", gpr()); |
| break; |
| case InFPR: |
| out.printf("%%fr%d", fpr()); |
| break; |
| #if USE(JSVALUE32_64) |
| case InPair: |
| out.printf("pair(%%r%d, %%r%d)", tagGPR(), payloadGPR()); |
| break; |
| #endif |
| case DisplacedInJSStack: |
| out.printf("*%d", virtualRegister()); |
| break; |
| case Int32DisplacedInJSStack: |
| out.printf("*int32(%d)", virtualRegister()); |
| break; |
| case DoubleDisplacedInJSStack: |
| out.printf("*double(%d)", virtualRegister()); |
| break; |
| case CellDisplacedInJSStack: |
| out.printf("*cell(%d)", virtualRegister()); |
| break; |
| case BooleanDisplacedInJSStack: |
| out.printf("*bool(%d)", virtualRegister()); |
| break; |
| case ArgumentsThatWereNotCreated: |
| out.printf("arguments"); |
| break; |
| case Constant: |
| out.print("[", constant(), "]"); |
| break; |
| case DontKnow: |
| out.printf("!"); |
| break; |
| default: |
| out.printf("?%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 |