mirror of
https://github.com/darlinghq/darling-JavaScriptCore.git
synced 2024-12-03 17:50:42 +00:00
445 lines
12 KiB
C++
445 lines
12 KiB
C++
/*
|
|
* Copyright (C) 2011-2019 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.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "DFGMinifiedID.h"
|
|
#include "DataFormat.h"
|
|
#if ENABLE(JIT)
|
|
#include "GPRInfo.h"
|
|
#include "FPRInfo.h"
|
|
#include "Reg.h"
|
|
#endif
|
|
#include "JSCJSValue.h"
|
|
#include "MacroAssembler.h"
|
|
#include "VirtualRegister.h"
|
|
|
|
namespace JSC {
|
|
|
|
struct DumpContext;
|
|
struct InlineCallFrame;
|
|
|
|
// Describes how to recover a given bytecode virtual register at a given
|
|
// code point.
|
|
enum ValueRecoveryTechnique : uint8_t {
|
|
// It's in a register.
|
|
InGPR,
|
|
UnboxedInt32InGPR,
|
|
UnboxedInt52InGPR,
|
|
UnboxedStrictInt52InGPR,
|
|
UnboxedBooleanInGPR,
|
|
UnboxedCellInGPR,
|
|
#if USE(JSVALUE32_64)
|
|
InPair,
|
|
#endif
|
|
InFPR,
|
|
UnboxedDoubleInFPR,
|
|
// 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,
|
|
Int52DisplacedInJSStack,
|
|
StrictInt52DisplacedInJSStack,
|
|
DoubleDisplacedInJSStack,
|
|
CellDisplacedInJSStack,
|
|
BooleanDisplacedInJSStack,
|
|
// It's an Arguments object. This arises because of the simplified arguments simplification done by the DFG.
|
|
DirectArgumentsThatWereNotCreated,
|
|
ClonedArgumentsThatWereNotCreated,
|
|
// 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(); }
|
|
|
|
#if ENABLE(JIT)
|
|
static ValueRecovery inRegister(Reg reg, DataFormat dataFormat)
|
|
{
|
|
if (reg.isGPR())
|
|
return inGPR(reg.gpr(), dataFormat);
|
|
|
|
ASSERT(reg.isFPR());
|
|
return inFPR(reg.fpr(), dataFormat);
|
|
}
|
|
#endif
|
|
|
|
explicit operator bool() const { return isSet(); }
|
|
|
|
static ValueRecovery inGPR(MacroAssembler::RegisterID gpr, DataFormat dataFormat)
|
|
{
|
|
ASSERT(dataFormat != DataFormatNone);
|
|
#if USE(JSVALUE32_64)
|
|
ASSERT(dataFormat == DataFormatInt32 || dataFormat == DataFormatCell || dataFormat == DataFormatBoolean);
|
|
#endif
|
|
ValueRecovery result;
|
|
if (dataFormat == DataFormatInt32)
|
|
result.m_technique = UnboxedInt32InGPR;
|
|
else if (dataFormat == DataFormatInt52)
|
|
result.m_technique = UnboxedInt52InGPR;
|
|
else if (dataFormat == DataFormatStrictInt52)
|
|
result.m_technique = UnboxedStrictInt52InGPR;
|
|
else if (dataFormat == DataFormatBoolean)
|
|
result.m_technique = UnboxedBooleanInGPR;
|
|
else if (dataFormat == DataFormatCell)
|
|
result.m_technique = UnboxedCellInGPR;
|
|
else
|
|
result.m_technique = InGPR;
|
|
UnionType u;
|
|
u.gpr = gpr;
|
|
result.m_source = WTFMove(u);
|
|
return result;
|
|
}
|
|
|
|
#if USE(JSVALUE32_64)
|
|
static ValueRecovery inPair(MacroAssembler::RegisterID tagGPR, MacroAssembler::RegisterID payloadGPR)
|
|
{
|
|
ValueRecovery result;
|
|
result.m_technique = InPair;
|
|
UnionType u;
|
|
u.pair.tagGPR = tagGPR;
|
|
u.pair.payloadGPR = payloadGPR;
|
|
result.m_source = WTFMove(u);
|
|
return result;
|
|
}
|
|
#endif
|
|
|
|
static ValueRecovery inFPR(MacroAssembler::FPRegisterID fpr, DataFormat dataFormat)
|
|
{
|
|
ASSERT(dataFormat == DataFormatDouble || dataFormat & DataFormatJS);
|
|
ValueRecovery result;
|
|
if (dataFormat == DataFormatDouble)
|
|
result.m_technique = UnboxedDoubleInFPR;
|
|
else
|
|
result.m_technique = InFPR;
|
|
UnionType u;
|
|
u.fpr = fpr;
|
|
result.m_source = WTFMove(u);
|
|
return result;
|
|
}
|
|
|
|
static ValueRecovery displacedInJSStack(VirtualRegister virtualReg, DataFormat dataFormat)
|
|
{
|
|
ValueRecovery result;
|
|
switch (dataFormat) {
|
|
case DataFormatInt32:
|
|
result.m_technique = Int32DisplacedInJSStack;
|
|
break;
|
|
|
|
case DataFormatInt52:
|
|
result.m_technique = Int52DisplacedInJSStack;
|
|
break;
|
|
|
|
case DataFormatStrictInt52:
|
|
result.m_technique = StrictInt52DisplacedInJSStack;
|
|
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;
|
|
}
|
|
UnionType u;
|
|
u.virtualReg = virtualReg.offset();
|
|
result.m_source = WTFMove(u);
|
|
return result;
|
|
}
|
|
|
|
static ValueRecovery constant(JSValue value)
|
|
{
|
|
ValueRecovery result;
|
|
result.m_technique = Constant;
|
|
UnionType u;
|
|
u.constant = JSValue::encode(value);
|
|
result.m_source = WTFMove(u);
|
|
return result;
|
|
}
|
|
|
|
static ValueRecovery directArgumentsThatWereNotCreated(DFG::MinifiedID id)
|
|
{
|
|
ValueRecovery result;
|
|
result.m_technique = DirectArgumentsThatWereNotCreated;
|
|
UnionType u;
|
|
u.nodeID = id.bits();
|
|
result.m_source = WTFMove(u);
|
|
return result;
|
|
}
|
|
|
|
static ValueRecovery clonedArgumentsThatWereNotCreated(DFG::MinifiedID id)
|
|
{
|
|
ValueRecovery result;
|
|
result.m_technique = ClonedArgumentsThatWereNotCreated;
|
|
UnionType u;
|
|
u.nodeID = id.bits();
|
|
result.m_source = WTFMove(u);
|
|
return result;
|
|
}
|
|
|
|
ValueRecoveryTechnique technique() const { return m_technique; }
|
|
|
|
bool isConstant() const { return m_technique == Constant; }
|
|
|
|
bool isInGPR() const
|
|
{
|
|
switch (m_technique) {
|
|
case InGPR:
|
|
case UnboxedInt32InGPR:
|
|
case UnboxedBooleanInGPR:
|
|
case UnboxedCellInGPR:
|
|
case UnboxedInt52InGPR:
|
|
case UnboxedStrictInt52InGPR:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool isInFPR() const
|
|
{
|
|
switch (m_technique) {
|
|
case InFPR:
|
|
case UnboxedDoubleInFPR:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool isInRegisters() const
|
|
{
|
|
return isInJSValueRegs() || isInGPR() || isInFPR();
|
|
}
|
|
|
|
bool isInJSStack() const
|
|
{
|
|
switch (m_technique) {
|
|
case DisplacedInJSStack:
|
|
case Int32DisplacedInJSStack:
|
|
case Int52DisplacedInJSStack:
|
|
case StrictInt52DisplacedInJSStack:
|
|
case DoubleDisplacedInJSStack:
|
|
case CellDisplacedInJSStack:
|
|
case BooleanDisplacedInJSStack:
|
|
return true;
|
|
default:
|
|
return false;
|
|
}
|
|
}
|
|
|
|
DataFormat dataFormat() const
|
|
{
|
|
switch (m_technique) {
|
|
case InGPR:
|
|
case InFPR:
|
|
case DisplacedInJSStack:
|
|
case Constant:
|
|
#if USE(JSVALUE32_64)
|
|
case InPair:
|
|
#endif
|
|
return DataFormatJS;
|
|
case UnboxedInt32InGPR:
|
|
case Int32DisplacedInJSStack:
|
|
return DataFormatInt32;
|
|
case UnboxedInt52InGPR:
|
|
case Int52DisplacedInJSStack:
|
|
return DataFormatInt52;
|
|
case UnboxedStrictInt52InGPR:
|
|
case StrictInt52DisplacedInJSStack:
|
|
return DataFormatStrictInt52;
|
|
case UnboxedBooleanInGPR:
|
|
case BooleanDisplacedInJSStack:
|
|
return DataFormatBoolean;
|
|
case UnboxedCellInGPR:
|
|
case CellDisplacedInJSStack:
|
|
return DataFormatCell;
|
|
case UnboxedDoubleInFPR:
|
|
case DoubleDisplacedInJSStack:
|
|
return DataFormatDouble;
|
|
default:
|
|
return DataFormatNone;
|
|
}
|
|
}
|
|
|
|
MacroAssembler::RegisterID gpr() const
|
|
{
|
|
ASSERT(isInGPR());
|
|
return m_source.get().gpr;
|
|
}
|
|
|
|
#if USE(JSVALUE32_64)
|
|
MacroAssembler::RegisterID tagGPR() const
|
|
{
|
|
ASSERT(m_technique == InPair);
|
|
return m_source.get().pair.tagGPR;
|
|
}
|
|
|
|
MacroAssembler::RegisterID payloadGPR() const
|
|
{
|
|
ASSERT(m_technique == InPair);
|
|
return m_source.get().pair.payloadGPR;
|
|
}
|
|
|
|
bool isInJSValueRegs() const
|
|
{
|
|
return m_technique == InPair;
|
|
}
|
|
|
|
#if ENABLE(JIT)
|
|
JSValueRegs jsValueRegs() const
|
|
{
|
|
ASSERT(isInJSValueRegs());
|
|
return JSValueRegs(tagGPR(), payloadGPR());
|
|
}
|
|
#endif // ENABLE(JIT)
|
|
#else
|
|
bool isInJSValueRegs() const
|
|
{
|
|
return isInGPR();
|
|
}
|
|
#endif // USE(JSVALUE32_64)
|
|
|
|
MacroAssembler::FPRegisterID fpr() const
|
|
{
|
|
ASSERT(isInFPR());
|
|
return m_source.get().fpr;
|
|
}
|
|
|
|
VirtualRegister virtualRegister() const
|
|
{
|
|
ASSERT(isInJSStack());
|
|
return VirtualRegister(m_source.get().virtualReg);
|
|
}
|
|
|
|
ValueRecovery withLocalsOffset(int offset) const
|
|
{
|
|
switch (m_technique) {
|
|
case DisplacedInJSStack:
|
|
case Int32DisplacedInJSStack:
|
|
case DoubleDisplacedInJSStack:
|
|
case CellDisplacedInJSStack:
|
|
case BooleanDisplacedInJSStack:
|
|
case Int52DisplacedInJSStack:
|
|
case StrictInt52DisplacedInJSStack: {
|
|
ValueRecovery result;
|
|
result.m_technique = m_technique;
|
|
UnionType u;
|
|
u.virtualReg = m_source.get().virtualReg + offset;
|
|
result.m_source = WTFMove(u);
|
|
return result;
|
|
}
|
|
|
|
default:
|
|
return *this;
|
|
}
|
|
}
|
|
|
|
JSValue constant() const
|
|
{
|
|
ASSERT(isConstant());
|
|
return JSValue::decode(m_source.get().constant);
|
|
}
|
|
|
|
DFG::MinifiedID nodeID() const
|
|
{
|
|
ASSERT(m_technique == DirectArgumentsThatWereNotCreated || m_technique == ClonedArgumentsThatWereNotCreated);
|
|
return DFG::MinifiedID::fromBits(m_source.get().nodeID);
|
|
}
|
|
|
|
JSValue recover(CallFrame*) const;
|
|
|
|
#if ENABLE(JIT)
|
|
template<typename Func>
|
|
void forEachReg(const Func& func)
|
|
{
|
|
switch (m_technique) {
|
|
case InGPR:
|
|
case UnboxedInt32InGPR:
|
|
case UnboxedBooleanInGPR:
|
|
case UnboxedCellInGPR:
|
|
case UnboxedInt52InGPR:
|
|
case UnboxedStrictInt52InGPR:
|
|
func(gpr());
|
|
return;
|
|
case InFPR:
|
|
case UnboxedDoubleInFPR:
|
|
func(fpr());
|
|
return;
|
|
#if USE(JSVALUE32_64)
|
|
case InPair:
|
|
func(jsValueRegs().payloadGPR());
|
|
func(jsValueRegs().tagGPR());
|
|
return;
|
|
#endif
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
void dumpInContext(PrintStream& out, DumpContext* context) const;
|
|
void dump(PrintStream& out) const;
|
|
#endif
|
|
|
|
private:
|
|
ValueRecoveryTechnique m_technique;
|
|
union UnionType {
|
|
MacroAssembler::RegisterID gpr;
|
|
MacroAssembler::FPRegisterID fpr;
|
|
#if USE(JSVALUE32_64)
|
|
struct {
|
|
MacroAssembler::RegisterID tagGPR;
|
|
MacroAssembler::RegisterID payloadGPR;
|
|
} pair;
|
|
#endif
|
|
int virtualReg;
|
|
EncodedJSValue constant;
|
|
unsigned nodeID;
|
|
};
|
|
Packed<UnionType> m_source;
|
|
};
|
|
static_assert(alignof(ValueRecovery) == 1);
|
|
|
|
} // namespace JSC
|