ValueRecovery.h   [plain text]


/*
 * 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 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 a constant.
    Constant,
    // Don't know how to recover it.
    DontKnow
};

class ValueRecovery {
public:
    ValueRecovery()
        : m_technique(DontKnow)
    {
    }
    
    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;
    }
    
    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 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