]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/CommonSlowPaths.cpp
JavaScriptCore-7600.1.4.16.1.tar.gz
[apple/javascriptcore.git] / runtime / CommonSlowPaths.cpp
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
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 #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
160 static 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
177 SLOW_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
190 SLOW_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
203 SLOW_PATH_DECL(slow_path_touch_entry)
204 {
205 BEGIN();
206 exec->codeBlock()->symbolTable()->m_functionEnteredOnce.touch();
207 END();
208 }
209
210 SLOW_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
218 SLOW_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
228 SLOW_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
243 SLOW_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
254 SLOW_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
263 SLOW_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
274 SLOW_PATH_DECL(slow_path_not)
275 {
276 BEGIN();
277 RETURN(jsBoolean(!OP_C(2).jsValue().toBoolean(exec)));
278 }
279
280 SLOW_PATH_DECL(slow_path_eq)
281 {
282 BEGIN();
283 RETURN(jsBoolean(JSValue::equal(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
284 }
285
286 SLOW_PATH_DECL(slow_path_neq)
287 {
288 BEGIN();
289 RETURN(jsBoolean(!JSValue::equal(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
290 }
291
292 SLOW_PATH_DECL(slow_path_stricteq)
293 {
294 BEGIN();
295 RETURN(jsBoolean(JSValue::strictEqual(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
296 }
297
298 SLOW_PATH_DECL(slow_path_nstricteq)
299 {
300 BEGIN();
301 RETURN(jsBoolean(!JSValue::strictEqual(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
302 }
303
304 SLOW_PATH_DECL(slow_path_less)
305 {
306 BEGIN();
307 RETURN(jsBoolean(jsLess<true>(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
308 }
309
310 SLOW_PATH_DECL(slow_path_lesseq)
311 {
312 BEGIN();
313 RETURN(jsBoolean(jsLessEq<true>(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
314 }
315
316 SLOW_PATH_DECL(slow_path_greater)
317 {
318 BEGIN();
319 RETURN(jsBoolean(jsLess<false>(exec, OP_C(3).jsValue(), OP_C(2).jsValue())));
320 }
321
322 SLOW_PATH_DECL(slow_path_greatereq)
323 {
324 BEGIN();
325 RETURN(jsBoolean(jsLessEq<false>(exec, OP_C(3).jsValue(), OP_C(2).jsValue())));
326 }
327
328 SLOW_PATH_DECL(slow_path_inc)
329 {
330 BEGIN();
331 RETURN(jsNumber(OP(1).jsValue().toNumber(exec) + 1));
332 }
333
334 SLOW_PATH_DECL(slow_path_dec)
335 {
336 BEGIN();
337 RETURN(jsNumber(OP(1).jsValue().toNumber(exec) - 1));
338 }
339
340 SLOW_PATH_DECL(slow_path_to_number)
341 {
342 BEGIN();
343 RETURN(jsNumber(OP_C(2).jsValue().toNumber(exec)));
344 }
345
346 SLOW_PATH_DECL(slow_path_negate)
347 {
348 BEGIN();
349 RETURN(jsNumber(-OP_C(2).jsValue().toNumber(exec)));
350 }
351
352 SLOW_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
371 SLOW_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
379 SLOW_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
387 SLOW_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
395 SLOW_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
403 SLOW_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
411 SLOW_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
419 SLOW_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
427 SLOW_PATH_DECL(slow_path_unsigned)
428 {
429 BEGIN();
430 uint32_t a = OP_C(2).jsValue().toUInt32(exec);
431 RETURN(jsNumber(a));
432 }
433
434 SLOW_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
442 SLOW_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
450 SLOW_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
458 SLOW_PATH_DECL(slow_path_typeof)
459 {
460 BEGIN();
461 RETURN(jsTypeStringForValue(exec, OP_C(2).jsValue()));
462 }
463
464 SLOW_PATH_DECL(slow_path_is_object)
465 {
466 BEGIN();
467 RETURN(jsBoolean(jsIsObjectType(exec, OP_C(2).jsValue())));
468 }
469
470 SLOW_PATH_DECL(slow_path_is_function)
471 {
472 BEGIN();
473 RETURN(jsBoolean(jsIsFunctionType(OP_C(2).jsValue())));
474 }
475
476 SLOW_PATH_DECL(slow_path_in)
477 {
478 BEGIN();
479 RETURN(jsBoolean(CommonSlowPaths::opIn(exec, OP_C(2).jsValue(), OP_C(3).jsValue())));
480 }
481
482 SLOW_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
510 SLOW_PATH_DECL(slow_path_strcat)
511 {
512 BEGIN();
513 RETURN(jsStringFromRegisterArray(exec, &OP(2), pc[3].u.operand));
514 }
515
516 SLOW_PATH_DECL(slow_path_to_primitive)
517 {
518 BEGIN();
519 RETURN(OP_C(2).jsValue().toPrimitive(exec));
520 }
521
522 SLOW_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