Home | History | Annotate | Download | only in dfg
      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