eb4a8bfdc28646af3419d4d5356d0ae9813a5e14
[WebKit-https.git] / Source / JavaScriptCore / runtime / CommonSlowPaths.cpp
1 /*
2  * Copyright (C) 2011, 2012, 2013 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 "CommonSlowPaths.h"
28
29 #if ENABLE(JIT) || ENABLE(LLINT)
30
31 #include "Arguments.h"
32 #include "ArrayConstructor.h"
33 #include "CallFrame.h"
34 #include "CodeProfiling.h"
35 #include "CommonSlowPathsExceptions.h"
36 #include "GetterSetter.h"
37 #include "HostCallReturnValue.h"
38 #include "Interpreter.h"
39 #include "JIT.h"
40 #include "JITStubs.h"
41 #include "JSActivation.h"
42 #include "JSCJSValue.h"
43 #include "JSGlobalObjectFunctions.h"
44 #include "JSNameScope.h"
45 #include "JSPropertyNameIterator.h"
46 #include "JSString.h"
47 #include "JSWithScope.h"
48 #include "LLIntCommon.h"
49 #include "LLIntExceptions.h"
50 #include "LowLevelInterpreter.h"
51 #include "ObjectConstructor.h"
52 #include "Operations.h"
53 #include "StructureRareDataInlines.h"
54 #include <wtf/StringPrintStream.h>
55
56 namespace JSC {
57
58 #define BEGIN_NO_SET_PC() \
59     VM& vm = exec->vm();      \
60     NativeCallFrameTracer tracer(&vm, exec)
61
62 #ifndef NDEBUG
63 #define SET_PC_FOR_STUBS() do { \
64         exec->codeBlock()->bytecodeOffset(pc); \
65         exec->setCurrentVPC(pc + 1); \
66     } while (false)
67 #else
68 #define SET_PC_FOR_STUBS() do { \
69         exec->setCurrentVPC(pc + 1); \
70     } while (false)
71 #endif
72
73 #if ENABLE(LLINT)
74 #define RETURN_TO_THROW(exec, pc)   pc = LLInt::returnToThrow(exec, pc)
75 #else
76 #define RETURN_TO_THROW(exec, pc)
77 #endif
78
79 #define BEGIN()                           \
80     BEGIN_NO_SET_PC();                    \
81     SET_PC_FOR_STUBS()
82
83 #define OP(index) (exec->uncheckedR(pc[index].u.operand))
84 #define OP_C(index) (exec->r(pc[index].u.operand))
85
86 #define RETURN_TWO(first, second) do {       \
87         return encodeResult(first, second);        \
88     } while (false)
89
90 #define END_IMPL() RETURN_TWO(pc, exec)
91
92 #define THROW(exceptionToThrow) do {                        \
93         vm.throwException(exec, exceptionToThrow);          \
94         RETURN_TO_THROW(exec, pc);                          \
95         END_IMPL();                                         \
96     } while (false)
97
98 #define CHECK_EXCEPTION() do {                    \
99         if (UNLIKELY(vm.exception())) {           \
100             RETURN_TO_THROW(exec, pc);               \
101             END_IMPL();                           \
102         }                                               \
103     } while (false)
104
105 #define END() do {                        \
106         CHECK_EXCEPTION();                \
107         END_IMPL();                       \
108     } while (false)
109
110 #define BRANCH(opcode, condition) do {                      \
111         bool bCondition = (condition);                         \
112         CHECK_EXCEPTION();                                  \
113         if (bCondition)                                        \
114             pc += pc[OPCODE_LENGTH(opcode) - 1].u.operand;        \
115         else                                                      \
116             pc += OPCODE_LENGTH(opcode);                          \
117         END_IMPL();                                         \
118     } while (false)
119
120 #define RETURN(value) do {                \
121         JSValue rReturnValue = (value);      \
122         CHECK_EXCEPTION();                \
123         OP(1) = rReturnValue;          \
124         END_IMPL();                       \
125     } while (false)
126
127 #if ENABLE(VALUE_PROFILER)
128 #define RETURN_PROFILED(opcode, value) do {               \
129         JSValue rpPeturnValue = (value);                     \
130         CHECK_EXCEPTION();                                \
131         OP(1) = rpPeturnValue;                         \
132         PROFILE_VALUE(opcode, rpPeturnValue);          \
133         END_IMPL();                                       \
134     } while (false)
135
136 #define PROFILE_VALUE(opcode, value) do { \
137         pc[OPCODE_LENGTH(opcode) - 1].u.profile->m_buckets[0] = \
138         JSValue::encode(value);                  \
139     } while (false)
140
141 #else // ENABLE(VALUE_PROFILER)
142 #define RETURN_PROFILED(opcode, value) RETURN(value)
143
144 #define PROFILE_VALUE(opcode, value) do { } while (false)
145
146 #endif // ENABLE(VALUE_PROFILER)
147
148 #define CALL_END_IMPL(exec, callTarget) RETURN_TWO((callTarget), (exec))
149
150 #define CALL_THROW(exec, pc, exceptionToThrow) do {               \
151         ExecState* ctExec = (exec);                                  \
152         Instruction* ctPC = (pc);                                    \
153         vm.throwException(exec, exceptionToThrow);                      \
154         CALL_END_IMPL(ctExec, LLInt::callToThrow(ctExec, ctPC)); \
155     } while (false)
156
157 #define CALL_CHECK_EXCEPTION(exec, pc) do {                       \
158         ExecState* cceExec = (exec);                                 \
159         Instruction* ccePC = (pc);                                   \
160         if (UNLIKELY(vm.exception()))                              \
161             CALL_END_IMPL(cceExec, LLInt::callToThrow(cceExec, ccePC)); \
162     } while (false)
163
164 #define CALL_RETURN(exec, pc, callTarget) do {                    \
165         ExecState* crExec = (exec);                                  \
166         Instruction* crPC = (pc);                                    \
167         void* crCallTarget = (callTarget);                           \
168         CALL_CHECK_EXCEPTION(crExec->callerFrame(), crPC);  \
169         CALL_END_IMPL(crExec, crCallTarget);                \
170     } while (false)
171
172 SLOW_PATH_DECL(slow_path_call_arityCheck)
173 {
174     BEGIN();
175     int SlotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForCall);
176     if (SlotsToAdd < 0) {
177         ReturnAddressPtr returnPC = exec->returnPC();
178         exec = exec->callerFrame();
179         vm.throwException(exec, createStackOverflowError(exec));
180         CommonSlowPaths::interpreterThrowInCaller(exec, returnPC);
181         RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec);
182     }
183     RETURN_TWO(0, reinterpret_cast<ExecState*>(SlotsToAdd));
184 }
185
186 SLOW_PATH_DECL(slow_path_construct_arityCheck)
187 {
188     BEGIN();
189     int SlotsToAdd = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForConstruct);
190     if (SlotsToAdd < 0) {
191         ReturnAddressPtr returnPC = exec->returnPC();
192         exec = exec->callerFrame();
193         vm.throwException(exec, createStackOverflowError(exec));
194         CommonSlowPaths::interpreterThrowInCaller(exec, returnPC);
195         RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec);
196     }
197     RETURN_TWO(0, reinterpret_cast<ExecState*>(SlotsToAdd));
198 }
199
200 SLOW_PATH_DECL(slow_path_create_arguments)
201 {
202     BEGIN();
203     JSValue arguments = JSValue(Arguments::create(vm, exec));
204     CHECK_EXCEPTION();
205     exec->uncheckedR(pc[1].u.operand) = arguments;
206     exec->uncheckedR(unmodifiedArgumentsRegister(pc[1].u.operand)) = arguments;
207     END();
208 }
209
210 SLOW_PATH_DECL(slow_path_create_this)
211 {
212     BEGIN();
213     JSFunction* constructor = jsCast<JSFunction*>(OP(2).jsValue().asCell());
214     
215 #if !ASSERT_DISABLED
216     ConstructData constructData;
217     ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS);
218 #endif
219
220     size_t inlineCapacity = pc[3].u.operand;
221     Structure* structure = constructor->allocationProfile(exec, inlineCapacity)->structure();
222     RETURN(constructEmptyObject(exec, structure));
223 }
224
225 SLOW_PATH_DECL(slow_path_to_this)
226 {
227     BEGIN();
228     JSValue v1 = OP(1).jsValue();
229 #if ENABLE(VALUE_PROFILER)
230     pc[OPCODE_LENGTH(op_to_this) - 1].u.profile->m_buckets[0] =
231         JSValue::encode(v1.structureOrUndefined());
232 #endif
233     RETURN(v1.toThis(exec, exec->codeBlock()->isStrictMode() ? StrictMode : NotStrictMode));
234 }
235
236 SLOW_PATH_DECL(slow_path_not)
237 {
238     BEGIN();
239     RETURN(jsBoolean(!OP_C(2).jsValue().toBoolean(exec)));
240 }
241
242 SLOW_PATH_DECL(slow_path_eq)
243 {
244     BEGIN();
245     RETURN(jsBoolean(JSValue::equal(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
246 }
247
248 SLOW_PATH_DECL(slow_path_neq)
249 {
250     BEGIN();
251     RETURN(jsBoolean(!JSValue::equal(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
252 }
253
254 SLOW_PATH_DECL(slow_path_stricteq)
255 {
256     BEGIN();
257     RETURN(jsBoolean(JSValue::strictEqual(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
258 }
259
260 SLOW_PATH_DECL(slow_path_nstricteq)
261 {
262     BEGIN();
263     RETURN(jsBoolean(!JSValue::strictEqual(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
264 }
265
266 SLOW_PATH_DECL(slow_path_less)
267 {
268     BEGIN();
269     RETURN(jsBoolean(jsLess<true>(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
270 }
271
272 SLOW_PATH_DECL(slow_path_lesseq)
273 {
274     BEGIN();
275     RETURN(jsBoolean(jsLessEq<true>(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
276 }
277
278 SLOW_PATH_DECL(slow_path_greater)
279 {
280     BEGIN();
281     RETURN(jsBoolean(jsLess<false>(exec, OP_C(3).jsValue(), OP_C(2).jsValue())));
282 }
283
284 SLOW_PATH_DECL(slow_path_greatereq)
285 {
286     BEGIN();
287     RETURN(jsBoolean(jsLessEq<false>(exec, OP_C(3).jsValue(), OP_C(2).jsValue())));
288 }
289
290 SLOW_PATH_DECL(slow_path_inc)
291 {
292     BEGIN();
293     RETURN(jsNumber(OP(1).jsValue().toNumber(exec) + 1));
294 }
295
296 SLOW_PATH_DECL(slow_path_dec)
297 {
298     BEGIN();
299     RETURN(jsNumber(OP(1).jsValue().toNumber(exec) - 1));
300 }
301
302 SLOW_PATH_DECL(slow_path_to_number)
303 {
304     BEGIN();
305     RETURN(jsNumber(OP_C(2).jsValue().toNumber(exec)));
306 }
307
308 SLOW_PATH_DECL(slow_path_negate)
309 {
310     BEGIN();
311     RETURN(jsNumber(-OP_C(2).jsValue().toNumber(exec)));
312 }
313
314 SLOW_PATH_DECL(slow_path_add)
315 {
316     BEGIN();
317     JSValue v1 = OP_C(2).jsValue();
318     JSValue v2 = OP_C(3).jsValue();
319     
320     if (v1.isString() && !v2.isObject())
321         RETURN(jsString(exec, asString(v1), v2.toString(exec)));
322     
323     if (v1.isNumber() && v2.isNumber())
324         RETURN(jsNumber(v1.asNumber() + v2.asNumber()));
325     
326     RETURN(jsAddSlowCase(exec, v1, v2));
327 }
328
329 // The following arithmetic and bitwise operations need to be sure to run
330 // toNumber() on their operands in order.  (A call to toNumber() is idempotent
331 // if an exception is already set on the ExecState.)
332
333 SLOW_PATH_DECL(slow_path_mul)
334 {
335     BEGIN();
336     double a = OP_C(2).jsValue().toNumber(exec);
337     double b = OP_C(3).jsValue().toNumber(exec);
338     RETURN(jsNumber(a * b));
339 }
340
341 SLOW_PATH_DECL(slow_path_sub)
342 {
343     BEGIN();
344     double a = OP_C(2).jsValue().toNumber(exec);
345     double b = OP_C(3).jsValue().toNumber(exec);
346     RETURN(jsNumber(a - b));
347 }
348
349 SLOW_PATH_DECL(slow_path_div)
350 {
351     BEGIN();
352     double a = OP_C(2).jsValue().toNumber(exec);
353     double b = OP_C(3).jsValue().toNumber(exec);
354     RETURN(jsNumber(a / b));
355 }
356
357 SLOW_PATH_DECL(slow_path_mod)
358 {
359     BEGIN();
360     double a = OP_C(2).jsValue().toNumber(exec);
361     double b = OP_C(3).jsValue().toNumber(exec);
362     RETURN(jsNumber(fmod(a, b)));
363 }
364
365 SLOW_PATH_DECL(slow_path_lshift)
366 {
367     BEGIN();
368     int32_t a = OP_C(2).jsValue().toInt32(exec);
369     uint32_t b = OP_C(3).jsValue().toUInt32(exec);
370     RETURN(jsNumber(a << (b & 31)));
371 }
372
373 SLOW_PATH_DECL(slow_path_rshift)
374 {
375     BEGIN();
376     int32_t a = OP_C(2).jsValue().toInt32(exec);
377     uint32_t b = OP_C(3).jsValue().toUInt32(exec);
378     RETURN(jsNumber(a >> (b & 31)));
379 }
380
381 SLOW_PATH_DECL(slow_path_urshift)
382 {
383     BEGIN();
384     uint32_t a = OP_C(2).jsValue().toUInt32(exec);
385     uint32_t b = OP_C(3).jsValue().toUInt32(exec);
386     RETURN(jsNumber(a >> (b & 31)));
387 }
388
389 SLOW_PATH_DECL(slow_path_bitand)
390 {
391     BEGIN();
392     int32_t a = OP_C(2).jsValue().toInt32(exec);
393     int32_t b = OP_C(3).jsValue().toInt32(exec);
394     RETURN(jsNumber(a & b));
395 }
396
397 SLOW_PATH_DECL(slow_path_bitor)
398 {
399     BEGIN();
400     int32_t a = OP_C(2).jsValue().toInt32(exec);
401     int32_t b = OP_C(3).jsValue().toInt32(exec);
402     RETURN(jsNumber(a | b));
403 }
404
405 SLOW_PATH_DECL(slow_path_bitxor)
406 {
407     BEGIN();
408     int32_t a = OP_C(2).jsValue().toInt32(exec);
409     int32_t b = OP_C(3).jsValue().toInt32(exec);
410     RETURN(jsNumber(a ^ b));
411 }
412
413 SLOW_PATH_DECL(slow_path_typeof)
414 {
415     BEGIN();
416     RETURN(jsTypeStringForValue(exec, OP_C(2).jsValue()));
417 }
418
419 SLOW_PATH_DECL(slow_path_is_object)
420 {
421     BEGIN();
422     RETURN(jsBoolean(jsIsObjectType(exec, OP_C(2).jsValue())));
423 }
424
425 SLOW_PATH_DECL(slow_path_is_function)
426 {
427     BEGIN();
428     RETURN(jsBoolean(jsIsFunctionType(OP_C(2).jsValue())));
429 }
430
431 SLOW_PATH_DECL(slow_path_in)
432 {
433     BEGIN();
434     RETURN(jsBoolean(CommonSlowPaths::opIn(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
435 }
436
437 SLOW_PATH_DECL(slow_path_del_by_val)
438 {
439     BEGIN();
440     JSValue baseValue = OP_C(2).jsValue();
441     JSObject* baseObject = baseValue.toObject(exec);
442     
443     JSValue subscript = OP_C(3).jsValue();
444     
445     bool couldDelete;
446     
447     uint32_t i;
448     if (subscript.getUInt32(i))
449         couldDelete = baseObject->methodTable()->deletePropertyByIndex(baseObject, exec, i);
450     else if (isName(subscript))
451         couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, jsCast<NameInstance*>(subscript.asCell())->privateName());
452     else {
453         CHECK_EXCEPTION();
454         Identifier property(exec, subscript.toString(exec)->value(exec));
455         CHECK_EXCEPTION();
456         couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, property);
457     }
458     
459     if (!couldDelete && exec->codeBlock()->isStrictMode())
460         THROW(createTypeError(exec, "Unable to delete property."));
461     
462     RETURN(jsBoolean(couldDelete));
463 }
464
465 SLOW_PATH_DECL(slow_path_strcat)
466 {
467     BEGIN();
468     RETURN(jsString(exec, &OP(2), pc[3].u.operand));
469 }
470
471 SLOW_PATH_DECL(slow_path_to_primitive)
472 {
473     BEGIN();
474     RETURN(OP_C(2).jsValue().toPrimitive(exec));
475 }
476
477 } // namespace JSC
478
479 #endif // ENABLE(JIT) || ENABLE(LLINT)