]> git.saurik.com Git - apple/javascriptcore.git/blame - runtime/CommonSlowPaths.cpp
JavaScriptCore-7600.1.4.11.8.tar.gz
[apple/javascriptcore.git] / runtime / CommonSlowPaths.cpp
CommitLineData
81345200
A
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