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