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 
operationConvertThis(ExecState * exec,EncodedJSValue encodedOp)39 EncodedJSValue operationConvertThis(ExecState* exec, EncodedJSValue encodedOp)
40 {
41     return JSValue::encode(JSValue::decode(encodedOp).toThisObject(exec));
42 }
43 
operationValueAdd(ExecState * exec,EncodedJSValue encodedOp1,EncodedJSValue encodedOp2)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 
operationGetByVal(ExecState * exec,EncodedJSValue encodedBase,EncodedJSValue encodedProperty)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 
operationGetById(ExecState * exec,EncodedJSValue encodedBase,Identifier * identifier)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>
operationPutByValInternal(ExecState * exec,EncodedJSValue encodedBase,EncodedJSValue encodedProperty,EncodedJSValue encodedValue)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 
operationPutByValStrict(ExecState * exec,EncodedJSValue encodedBase,EncodedJSValue encodedProperty,EncodedJSValue encodedValue)161 void operationPutByValStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
162 {
163     operationPutByValInternal<true>(exec, encodedBase, encodedProperty, encodedValue);
164 }
165 
operationPutByValNonStrict(ExecState * exec,EncodedJSValue encodedBase,EncodedJSValue encodedProperty,EncodedJSValue encodedValue)166 void operationPutByValNonStrict(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty, EncodedJSValue encodedValue)
167 {
168     operationPutByValInternal<false>(exec, encodedBase, encodedProperty, encodedValue);
169 }
170 
operationPutByIdStrict(ExecState * exec,EncodedJSValue encodedValue,EncodedJSValue encodedBase,Identifier * identifier)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 
operationPutByIdNonStrict(ExecState * exec,EncodedJSValue encodedValue,EncodedJSValue encodedBase,Identifier * identifier)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 
operationPutByIdDirectStrict(ExecState * exec,EncodedJSValue encodedValue,EncodedJSValue encodedBase,Identifier * identifier)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 
operationPutByIdDirectNonStrict(ExecState * exec,EncodedJSValue encodedValue,EncodedJSValue encodedBase,Identifier * identifier)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 
operationCompareLess(ExecState * exec,EncodedJSValue encodedOp1,EncodedJSValue encodedOp2)195 bool operationCompareLess(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
196 {
197     return jsLess(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
198 }
199 
operationCompareLessEq(ExecState * exec,EncodedJSValue encodedOp1,EncodedJSValue encodedOp2)200 bool operationCompareLessEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
201 {
202     return jsLessEq(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
203 }
204 
operationCompareEq(ExecState * exec,EncodedJSValue encodedOp1,EncodedJSValue encodedOp2)205 bool operationCompareEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
206 {
207     return JSValue::equal(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
208 }
209 
operationCompareStrictEq(ExecState * exec,EncodedJSValue encodedOp1,EncodedJSValue encodedOp2)210 bool operationCompareStrictEq(ExecState* exec, EncodedJSValue encodedOp1, EncodedJSValue encodedOp2)
211 {
212     return JSValue::strictEqual(exec, JSValue::decode(encodedOp1), JSValue::decode(encodedOp2));
213 }
214 
lookupExceptionHandler(ExecState * exec,ReturnAddressPtr faultLocation)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 
dfgConvertJSValueToNumber(ExecState * exec,EncodedJSValue value)228 double dfgConvertJSValueToNumber(ExecState* exec, EncodedJSValue value)
229 {
230     return JSValue::decode(value).toNumber(exec);
231 }
232 
dfgConvertJSValueToInt32(ExecState * exec,EncodedJSValue value)233 int32_t dfgConvertJSValueToInt32(ExecState* exec, EncodedJSValue value)
234 {
235     return JSValue::decode(value).toInt32(exec);
236 }
237 
dfgConvertJSValueToBoolean(ExecState * exec,EncodedJSValue encodedOp)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