1/* 2 * Copyright (C) 2013, 2014 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#ifndef FTLExitValue_h 27#define FTLExitValue_h 28 29#if ENABLE(FTL_JIT) 30 31#include "FTLExitArgument.h" 32#include "FTLRecoveryOpcode.h" 33#include "JSCJSValue.h" 34#include "VirtualRegister.h" 35#include <wtf/PrintStream.h> 36 37namespace JSC { namespace FTL { 38 39// This is like ValueRecovery, but respects the way that the FTL does OSR 40// exit: the live non-constant non-flushed values are passed as arguments 41// to a noreturn tail call. ExitValue is hence mostly responsible for 42// telling us the mapping between operands in bytecode and the arguments to 43// the call. 44 45enum ExitValueKind { 46 InvalidExitValue, 47 ExitValueDead, 48 ExitValueArgument, 49 ExitValueConstant, 50 ExitValueInJSStack, 51 ExitValueInJSStackAsInt32, 52 ExitValueInJSStackAsInt52, 53 ExitValueInJSStackAsDouble, 54 ExitValueArgumentsObjectThatWasNotCreated, 55 ExitValueRecovery 56}; 57 58class ExitValue { 59public: 60 ExitValue() 61 : m_kind(InvalidExitValue) 62 { 63 } 64 65 bool operator!() const { return m_kind == InvalidExitValue; } 66 67 static ExitValue dead() 68 { 69 ExitValue result; 70 result.m_kind = ExitValueDead; 71 return result; 72 } 73 74 static ExitValue inJSStack(VirtualRegister reg) 75 { 76 ExitValue result; 77 result.m_kind = ExitValueInJSStack; 78 result.u.virtualRegister = reg.offset(); 79 return result; 80 } 81 82 static ExitValue inJSStackAsInt32(VirtualRegister reg) 83 { 84 ExitValue result; 85 result.m_kind = ExitValueInJSStackAsInt32; 86 result.u.virtualRegister = reg.offset(); 87 return result; 88 } 89 90 static ExitValue inJSStackAsInt52(VirtualRegister reg) 91 { 92 ExitValue result; 93 result.m_kind = ExitValueInJSStackAsInt52; 94 result.u.virtualRegister = reg.offset(); 95 return result; 96 } 97 98 static ExitValue inJSStackAsDouble(VirtualRegister reg) 99 { 100 ExitValue result; 101 result.m_kind = ExitValueInJSStackAsDouble; 102 result.u.virtualRegister = reg.offset(); 103 return result; 104 } 105 106 static ExitValue constant(JSValue value) 107 { 108 ExitValue result; 109 result.m_kind = ExitValueConstant; 110 result.u.constant = JSValue::encode(value); 111 return result; 112 } 113 114 static ExitValue exitArgument(const ExitArgument& argument) 115 { 116 ExitValue result; 117 result.m_kind = ExitValueArgument; 118 result.u.argument = argument.representation(); 119 return result; 120 } 121 122 static ExitValue argumentsObjectThatWasNotCreated() 123 { 124 ExitValue result; 125 result.m_kind = ExitValueArgumentsObjectThatWasNotCreated; 126 return result; 127 } 128 129 static ExitValue recovery(RecoveryOpcode opcode, unsigned leftArgument, unsigned rightArgument, ValueFormat format) 130 { 131 ExitValue result; 132 result.m_kind = ExitValueRecovery; 133 result.u.recovery.opcode = opcode; 134 result.u.recovery.leftArgument = leftArgument; 135 result.u.recovery.rightArgument = rightArgument; 136 result.u.recovery.format = format; 137 return result; 138 } 139 140 ExitValueKind kind() const { return m_kind; } 141 142 bool isDead() const { return kind() == ExitValueDead; } 143 bool isInJSStackSomehow() const 144 { 145 switch (kind()) { 146 case ExitValueInJSStack: 147 case ExitValueInJSStackAsInt32: 148 case ExitValueInJSStackAsInt52: 149 case ExitValueInJSStackAsDouble: 150 return true; 151 default: 152 return false; 153 } 154 } 155 bool isConstant() const { return kind() == ExitValueConstant; } 156 bool isArgument() const { return kind() == ExitValueArgument; } 157 bool isArgumentsObjectThatWasNotCreated() const { return kind() == ExitValueArgumentsObjectThatWasNotCreated; } 158 bool isRecovery() const { return kind() == ExitValueRecovery; } 159 160 ExitArgument exitArgument() const 161 { 162 ASSERT(isArgument()); 163 return ExitArgument(u.argument); 164 } 165 166 unsigned leftRecoveryArgument() const 167 { 168 ASSERT(isRecovery()); 169 return u.recovery.leftArgument; 170 } 171 172 unsigned rightRecoveryArgument() const 173 { 174 ASSERT(isRecovery()); 175 return u.recovery.rightArgument; 176 } 177 178 ValueFormat recoveryFormat() const 179 { 180 ASSERT(isRecovery()); 181 return static_cast<ValueFormat>(u.recovery.format); 182 } 183 184 RecoveryOpcode recoveryOpcode() const 185 { 186 ASSERT(isRecovery()); 187 return static_cast<RecoveryOpcode>(u.recovery.opcode); 188 } 189 190 JSValue constant() const 191 { 192 ASSERT(isConstant()); 193 return JSValue::decode(u.constant); 194 } 195 196 VirtualRegister virtualRegister() const 197 { 198 ASSERT(isInJSStackSomehow()); 199 return VirtualRegister(u.virtualRegister); 200 } 201 202 ExitValue withVirtualRegister(VirtualRegister virtualRegister) 203 { 204 ASSERT(isInJSStackSomehow()); 205 ExitValue result; 206 result.m_kind = m_kind; 207 result.u.virtualRegister = virtualRegister.offset(); 208 return result; 209 } 210 211 // If it's in the JSStack somehow, this will tell you what format it's in, in a manner 212 // that is compatible with exitArgument().format(). If it's a constant or it's dead, it 213 // will claim to be a JSValue. If it's an argument then it will tell you the argument's 214 // format. 215 ValueFormat valueFormat() const 216 { 217 switch (kind()) { 218 case InvalidExitValue: 219 RELEASE_ASSERT_NOT_REACHED(); 220 return InvalidValueFormat; 221 222 case ExitValueDead: 223 case ExitValueConstant: 224 case ExitValueInJSStack: 225 case ExitValueArgumentsObjectThatWasNotCreated: 226 return ValueFormatJSValue; 227 228 case ExitValueArgument: 229 return exitArgument().format(); 230 231 case ExitValueInJSStackAsInt32: 232 return ValueFormatInt32; 233 234 case ExitValueInJSStackAsInt52: 235 return ValueFormatInt52; 236 237 case ExitValueInJSStackAsDouble: 238 return ValueFormatDouble; 239 240 case ExitValueRecovery: 241 return recoveryFormat(); 242 } 243 244 RELEASE_ASSERT_NOT_REACHED(); 245 return InvalidValueFormat; 246 } 247 248 void dump(PrintStream&) const; 249 void dumpInContext(PrintStream&, DumpContext*) const; 250 251private: 252 ExitValueKind m_kind; 253 union { 254 ExitArgumentRepresentation argument; 255 EncodedJSValue constant; 256 int virtualRegister; 257 struct { 258 uint16_t leftArgument; 259 uint16_t rightArgument; 260 uint16_t opcode; 261 uint16_t format; 262 } recovery; 263 } u; 264}; 265 266} } // namespace JSC::FTL 267 268#endif // ENABLE(FTL_JIT) 269 270#endif // FTLExitValue_h 271