/* * 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. */ #include "config.h" #include "DFGOperations.h" #if ENABLE(DFG_JIT) #include "CodeBlock.h" #include "Interpreter.h" #include "JSByteArray.h" #include "JSGlobalData.h" #include "Operations.h" namespace JSC { namespace DFG { EncodedJSValue operationConvertThis(ExecState* exec, EncodedJSValue encodedOp) { return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec)); } EncodedJSValue operationValueAdd(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { JSValue op1 = JSValue::decode(encodedOp1); JSValue op2 = JSValue::decode(encodedOp2); if (op1.isInt32() && op2.isInt32()) { int64_t result64 = static_cast(op1.asInt32()) + static_cast(op2.asInt32()); int32_t result32 = static_cast(result64); if (LIKELY(result32 == result64)) return JSValue::encode(jsNumber(result32)); return JSValue::encode(jsNumber((double)result64)); } double number1; double number2; if (op1.getNumber(number1) && op2.getNumber(number2)) return JSValue::encode(jsNumber(number1 + number2)); return JSValue::encode(jsAddSlowCase(exec, op1, op2)); } EncodedJSValue operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) { JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); if (LIKELY(baseValue.isCell())) { JSCell* base = baseValue.asCell(); if (property.isUInt32()) { JSGlobalData* globalData = &exec->globalData(); uint32_t i = property.asUInt32(); // FIXME: the JIT used to handle these in compiled code! if (isJSArray(globalData, base) && asArray(base)->canGetIndex(i)) return JSValue::encode(asArray(base)->getIndex(i)); // FIXME: the JITstub used to relink this to an optimized form! if (isJSString(globalData, base) && asString(base)->canGetIndex(i)) return JSValue::encode(asString(base)->getIndex(exec, i)); // FIXME: the JITstub used to relink this to an optimized form! if (isJSByteArray(globalData, base) && asByteArray(base)->canAccessIndex(i)) return JSValue::encode(asByteArray(base)->getIndex(exec, i)); return JSValue::encode(baseValue.get(exec, i)); } if (property.isString()) { Identifier propertyName(exec, asString(property)->value(exec)); PropertySlot slot(base); if (base->fastGetOwnPropertySlot(exec, propertyName, slot)) return JSValue::encode(slot.getValue(exec, propertyName)); } } Identifier ident(exec, property.toString(exec)); return JSValue::encode(baseValue.get(exec, ident)); } EncodedJSValue operationGetById(ExecState* exec, EncodedJSValue encodedBase, Identifier* identifier) { JSValue baseValue = JSValue::decode(encodedBase); PropertySlot slot(baseValue); return JSValue::encode(baseValue.get(exec, *identifier, slot)); } template ALWAYS_INLINE static void operationPutByValInternal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { JSGlobalData* globalData = &exec->globalData(); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); JSValue value = JSValue::decode(encodedValue); if (LIKELY(property.isUInt32())) { uint32_t i = property.asUInt32(); if (isJSArray(globalData, baseValue)) { JSArray* jsArray = asArray(baseValue); if (jsArray->canSetIndex(i)) { jsArray->setIndex(*globalData, i, value); return; } jsArray->JSArray::put(exec, i, value); return; } if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { JSByteArray* jsByteArray = asByteArray(baseValue); // FIXME: the JITstub used to relink this to an optimized form! if (value.isInt32()) { jsByteArray->setIndex(i, value.asInt32()); return; } double dValue = 0; if (value.getNumber(dValue)) { jsByteArray->setIndex(i, dValue); return; } } baseValue.put(exec, i, value); return; } // Don't put to an object if toString throws an exception. Identifier ident(exec, property.toString(exec)); if (!globalData->exception) { PutPropertySlot slot(strict); baseValue.put(exec, ident, value, slot); } } void operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { operationPutByValInternal(exec, encodedBase, encodedProperty, encodedValue); } void operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue) { operationPutByValInternal(exec, encodedBase, encodedProperty, encodedValue); } void operationPutByIdStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier) { PutPropertySlot slot(true); JSValue::decode(encodedBase).put(exec, *identifier, JSValue::decode(encodedValue), slot); } void operationPutByIdNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier) { PutPropertySlot slot(false); JSValue::decode(encodedBase).put(exec, *identifier, JSValue::decode(encodedValue), slot); } void operationPutByIdDirectStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier) { PutPropertySlot slot(true); JSValue::decode(encodedBase).putDirect(exec, *identifier, JSValue::decode(encodedValue), slot); } void operationPutByIdDirectNonStrict(ExecState* exec, EncodedJSValue encodedValue, EncodedJSValue encodedBase, Identifier* identifier) { PutPropertySlot slot(false); JSValue::decode(encodedBase).putDirect(exec, *identifier, JSValue::decode(encodedValue), slot); } bool operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { return jsLess(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); } bool operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { return jsLessEq(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); } bool operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { return JSValue::equal(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); } bool operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2) { return JSValue::strictEqual(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2)); } DFGHandler lookupExceptionHandler(ExecState* exec, ReturnAddressPtr faultLocation) { JSValue exceptionValue = exec->exception(); ASSERT(exceptionValue); unsigned vPCIndex = exec->codeBlock()->bytecodeOffset(faultLocation); HandlerInfo* handler = exec->globalData().interpreter->throwException(exec, exceptionValue, vPCIndex); void* catchRoutine = handler ? handler->nativeCode.executableAddress() : (void*)ctiOpThrowNotCaught; ASSERT(catchRoutine); return DFGHandler(exec, catchRoutine); } double dfgConvertJSValueToNumber(ExecState* exec, EncodedJSValue value) { return JSValue::decode(value).toNumber(exec); } int32_t dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value) { return JSValue::decode(value).toInt32(exec); } bool dfgConvertJSValueToBoolean(ExecState* exec, EncodedJSValue encodedOp) { return JSValue::decode(encodedOp).toBoolean(exec); } } } // namespace JSC::DFG #endif