/* * Copyright (C) 2013-2015 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 FTLExitValue_h #define FTLExitValue_h #if ENABLE(FTL_JIT) #include "FTLExitArgument.h" #include "FTLRecoveryOpcode.h" #include "JSCJSValue.h" #include "VirtualRegister.h" #include namespace JSC { class TrackedReferences; namespace FTL { // This is like ValueRecovery, but respects the way that the FTL does OSR // exit: the live non-constant non-flushed values are passed as arguments // to a noreturn tail call. ExitValue is hence mostly responsible for // telling us the mapping between operands in bytecode and the arguments to // the call. enum ExitValueKind { InvalidExitValue, ExitValueDead, ExitValueArgument, ExitValueConstant, ExitValueInJSStack, ExitValueInJSStackAsInt32, ExitValueInJSStackAsInt52, ExitValueInJSStackAsDouble, ExitValueRecovery, ExitValueMaterializeNewObject }; class ExitTimeObjectMaterialization; class ExitValue { public: ExitValue() : m_kind(InvalidExitValue) { } bool operator!() const { return m_kind == InvalidExitValue; } static ExitValue dead() { ExitValue result; result.m_kind = ExitValueDead; return result; } static ExitValue inJSStack(VirtualRegister reg) { ExitValue result; result.m_kind = ExitValueInJSStack; result.u.virtualRegister = reg.offset(); return result; } static ExitValue inJSStackAsInt32(VirtualRegister reg) { ExitValue result; result.m_kind = ExitValueInJSStackAsInt32; result.u.virtualRegister = reg.offset(); return result; } static ExitValue inJSStackAsInt52(VirtualRegister reg) { ExitValue result; result.m_kind = ExitValueInJSStackAsInt52; result.u.virtualRegister = reg.offset(); return result; } static ExitValue inJSStackAsDouble(VirtualRegister reg) { ExitValue result; result.m_kind = ExitValueInJSStackAsDouble; result.u.virtualRegister = reg.offset(); return result; } static ExitValue constant(JSValue value) { ExitValue result; result.m_kind = ExitValueConstant; result.u.constant = JSValue::encode(value); return result; } static ExitValue exitArgument(const ExitArgument& argument) { ExitValue result; result.m_kind = ExitValueArgument; result.u.argument = argument.representation(); return result; } static ExitValue recovery(RecoveryOpcode opcode, unsigned leftArgument, unsigned rightArgument, DataFormat format) { ExitValue result; result.m_kind = ExitValueRecovery; result.u.recovery.opcode = opcode; result.u.recovery.leftArgument = leftArgument; result.u.recovery.rightArgument = rightArgument; result.u.recovery.format = format; return result; } static ExitValue materializeNewObject(ExitTimeObjectMaterialization*); ExitValueKind kind() const { return m_kind; } bool isDead() const { return kind() == ExitValueDead; } bool isInJSStackSomehow() const { switch (kind()) { case ExitValueInJSStack: case ExitValueInJSStackAsInt32: case ExitValueInJSStackAsInt52: case ExitValueInJSStackAsDouble: return true; default: return false; } } bool isConstant() const { return kind() == ExitValueConstant; } bool isArgument() const { return kind() == ExitValueArgument; } bool isRecovery() const { return kind() == ExitValueRecovery; } bool isObjectMaterialization() const { return kind() == ExitValueMaterializeNewObject; } bool hasIndexInStackmapLocations() const { return isArgument() || isRecovery(); } ExitArgument exitArgument() const { ASSERT(isArgument()); return ExitArgument(u.argument); } unsigned leftRecoveryArgument() const { ASSERT(isRecovery()); return u.recovery.leftArgument; } unsigned rightRecoveryArgument() const { ASSERT(isRecovery()); return u.recovery.rightArgument; } void adjustStackmapLocationsIndexByOffset(unsigned offset) { ASSERT(hasIndexInStackmapLocations()); if (isArgument()) u.argument.argument += offset; else { ASSERT(isRecovery()); u.recovery.rightArgument += offset; u.recovery.leftArgument += offset; } } DataFormat recoveryFormat() const { ASSERT(isRecovery()); return static_cast(u.recovery.format); } RecoveryOpcode recoveryOpcode() const { ASSERT(isRecovery()); return static_cast(u.recovery.opcode); } JSValue constant() const { ASSERT(isConstant()); return JSValue::decode(u.constant); } VirtualRegister virtualRegister() const { ASSERT(isInJSStackSomehow()); return VirtualRegister(u.virtualRegister); } ExitTimeObjectMaterialization* objectMaterialization() const { ASSERT(isObjectMaterialization()); return u.newObjectMaterializationData; } ExitValue withVirtualRegister(VirtualRegister virtualRegister) const { ASSERT(isInJSStackSomehow()); ExitValue result; result.m_kind = m_kind; result.u.virtualRegister = virtualRegister.offset(); return result; } ExitValue withLocalsOffset(int offset) const; // If it's in the JSStack somehow, this will tell you what format it's in, in a manner // that is compatible with exitArgument().format(). If it's a constant or it's dead, it // will claim to be a JSValue. If it's an argument then it will tell you the argument's // format. DataFormat dataFormat() const; void dump(PrintStream&) const; void dumpInContext(PrintStream&, DumpContext*) const; void validateReferences(const TrackedReferences&) const; private: ExitValueKind m_kind; union { ExitArgumentRepresentation argument; EncodedJSValue constant; int virtualRegister; struct { uint16_t leftArgument; uint16_t rightArgument; uint16_t opcode; uint16_t format; } recovery; ExitTimeObjectMaterialization* newObjectMaterializationData; } u; }; } } // namespace JSC::FTL #endif // ENABLE(FTL_JIT) #endif // FTLExitValue_h