1 /* 2 * Copyright (C) 2011 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 #include "config.h" 27 #include "DFGOperations.h" 28 29 #if ENABLE(DFG_JIT) 30 31 #include "CodeBlock.h" 32 #include "Interpreter.h" 33 #include "JSByteArray.h" 34 #include "JSGlobalData.h" 35 #include "Operations.h" 36 37 namespace JSC { namespace DFG { 38 39 EncodedJSValue operationConvertThis(ExecState* exec, EncodedJSValue encodedOp) 40 { 41 return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec)); 42 } 43 44 EncodedJSValue operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) 45 { 46 JSValue op1 = JSValue::decode(encodedOp1); 47 JSValue op2 = JSValue::decode(encodedOp2); 48 49 if (op1.isInt32() && op2.isInt32()) { 50 int64_t result64 = static_cast<int64_t>(op1.asInt32()) + static_cast<int64_t>(op2.asInt32()); 51 int32_t result32 = static_cast<int32_t>(result64); 52 if (LIKELY(result32 == result64)) 53 return JSValue::encode(jsNumber(result32)); 54 return JSValue::encode(jsNumber((double)result64)); 55 } 56 57 double number1; 58 double number2; 59 if (op1.getNumber(number1) && op2.getNumber(number2)) 60 return JSValue::encode(jsNumber(number1 + number2)); 61 62 return JSValue::encode(jsAddSlowCase(exec, op1, op2)); 63 } 64 65 EncodedJSValue operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) 66 { 67 JSValue baseValue = JSValue::decode(encodedBase); 68 JSValue property = JSValue::decode(encodedProperty); 69 70 if (LIKELY(baseValue.isCell())) { 71 JSCell* base = baseValue.asCell(); 72 73 if (property.isUInt32()) { 74 JSGlobalData* globalData = &exec->globalData(); 75 uint32_t i = property.asUInt32(); 76 77 // FIXME: the JIT used to handle these in compiled code! 78 if (isJSArray(globalData, base) && asArray(base)->canGetIndex(i)) 79 return JSValue::encode(asArray(base)->getIndex(i)); 80 81 // FIXME: the JITstub used to relink this to an optimized form! 82 if (isJSString(globalData, base) && asString(base)->canGetIndex(i)) 83 return JSValue::encode(asString(base)->getIndex(exec, i)); 84 85 // FIXME: the JITstub used to relink this to an optimized form! 86 if (isJSByteArray(globalData, base) && asByteArray(base)->canAccessIndex(i)) 87 return JSValue::encode(asByteArray(base)->getIndex(exec, i)); 88 89 return JSValue::encode(baseValue.get(exec, i)); 90 } 91 92 if (property.isString()) { 93 Identifier propertyName(exec, asString(property)->value(exec)); 94 PropertySlot slot(base); 95 if (base->fastGetOwnPropertySlot(exec, propertyName, slot)) 96 return JSValue::encode(slot.getValue(exec, propertyName)); 97 } 98 } 99 100 Identifier ident(exec, property.toString(exec)); 101 return JSValue::encode(baseValue.get(exec, ident)); 102 } 103 104 EncodedJSValue operationGetById(ExecState* exec, EncodedJSValue encodedBase, Identifier* identifier) 105 { 106 JSValue baseValue = JSValue::decode(encodedBase); 107 PropertySlot slot(baseValue); 108 return JSValue::encode(baseValue.get(exec, *identifier, slot)); 109 } 110 111 template<bool strict> 112 ALWAYS_INLINE static void operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) 113 { 114 JSGlobalData* globalData = &exec->globalData(); 115 116 JSValue baseValue = JSValue::decode(encodedBase); 117 JSValue property = JSValue::decode(encodedProperty); 118 JSValue value = JSValue::decode(encodedValue); 119 120 if (LIKELY(property.isUInt32())) { 121 uint32_t i = property.asUInt32(); 122 123 if (isJSArray(globalData, baseValue)) { 124 JSArray* jsArray = asArray(baseValue); 125 if (jsArray->canSetIndex(i)) { 126 jsArray->setIndex(*globalData, i, value); 127 return; 128 } 129 130 jsArray->JSArray::put(exec, i, value); 131 return; 132 } 133 134 if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { 135 JSByteArray* jsByteArray = asByteArray(baseValue); 136 // FIXME: the JITstub used to relink this to an optimized form! 137 if (value.isInt32()) { 138 jsByteArray->setIndex(i, value.asInt32()); 139 return; 140 } 141 142 double dValue = 0; 143 if (value.getNumber(dValue)) { 144 jsByteArray->setIndex(i, dValue); 145 return; 146 } 147 } 148 149 baseValue.put(exec, i, value); 150 return; 151 } 152 153 // Don't put to an object if toString throws an exception. 154 Identifier ident(exec, property.toString(exec)); 155 if (!globalData->exception) { 156 PutPropertySlot slot(strict); 157 baseValue.put(exec, ident, value, slot); 158 } 159 } 160 161 void operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) 162 { 163 operationPutByValInternal<true>(exec, encodedBase, encodedProperty, encodedValue); 164 } 165 166 void operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) 167 { 168 operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue); 169 } 170 171 void operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier) 172 { 173 PutPropertySlot slot(true); 174 JSValue::decode(encodedBase).put(exec, *identifier, JSValue::decode(encodedValue), slot); 175 } 176 177 void operationPutByIdNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier) 178 { 179 PutPropertySlot slot(false); 180 JSValue::decode(encodedBase).put(exec, *identifier, JSValue::decode(encodedValue), slot); 181 } 182 183 void operationPutByIdDirectStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier) 184 { 185 PutPropertySlot slot(true); 186 JSValue::decode(encodedBase).putDirect(exec, *identifier, JSValue::decode(encodedValue), slot); 187 } 188 189 void operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier) 190 { 191 PutPropertySlot slot(false); 192 JSValue::decode(encodedBase).putDirect(exec, *identifier, JSValue::decode(encodedValue), slot); 193 } 194 195 bool operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) 196 { 197 return jsLess(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); 198 } 199 200 bool operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) 201 { 202 return jsLessEq(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); 203 } 204 205 bool operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) 206 { 207 return JSValue::equal(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); 208 } 209 210 bool operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) 211 { 212 return JSValue::strictEqual(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); 213 } 214 215 DFGHandler lookupExceptionHandler(ExecState* exec, ReturnAddressPtr faultLocation) 216 { 217 JSValue exceptionValue = exec->exception(); 218 ASSERT(exceptionValue); 219 220 unsigned vPCIndex = exec->codeBlock()->bytecodeOffset(faultLocation); 221 HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, vPCIndex); 222 223 void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught; 224 ASSERT(catchRoutine); 225 return DFGHandler(exec, catchRoutine); 226 } 227 228 double dfgConvertJSValueToNumber(ExecState* exec, EncodedJSValue value) 229 { 230 return JSValue::decode(value).toNumber(exec); 231 } 232 233 int32_t dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value) 234 { 235 return JSValue::decode(value).toInt32(exec); 236 } 237 238 bool dfgConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp) 239 { 240 return JSValue::decode(encodedOp).toBoolean(exec); 241 } 242 243 } } // namespace JSC::DFG 244 245 #endif 246