]>
Commit | Line | Data |
---|---|---|
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 "LLIntSlowPaths.h" | |
28 | #include "Arguments.h" | |
29 | #include "ArrayConstructor.h" | |
30 | #include "CallFrame.h" | |
31 | #include "CommonSlowPaths.h" | |
32 | #include "CommonSlowPathsExceptions.h" | |
33 | #include "ErrorHandlingScope.h" | |
34 | #include "GetterSetter.h" | |
35 | #include "HostCallReturnValue.h" | |
36 | #include "Interpreter.h" | |
37 | #include "JIT.h" | |
38 | #include "JITExceptions.h" | |
39 | #include "JSActivation.h" | |
40 | #include "JSCJSValue.h" | |
41 | #include "JSGlobalObjectFunctions.h" | |
42 | #include "JSNameScope.h" | |
43 | #include "JSPropertyNameIterator.h" | |
44 | #include "JSStackInlines.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 "ProtoCallFrame.h" | |
53 | #include "StructureRareDataInlines.h" | |
54 | #include <wtf/StringPrintStream.h> | |
55 | ||
56 | namespace JSC { namespace LLInt { | |
57 | ||
58 | #define LLINT_BEGIN_NO_SET_PC() \ | |
59 | VM& vm = exec->vm(); \ | |
60 | NativeCallFrameTracer tracer(&vm, exec) | |
61 | ||
62 | #ifndef NDEBUG | |
63 | #define LLINT_SET_PC_FOR_STUBS() do { \ | |
64 | exec->codeBlock()->bytecodeOffset(pc); \ | |
65 | exec->setCurrentVPC(pc + 1); \ | |
66 | } while (false) | |
67 | #else | |
68 | #define LLINT_SET_PC_FOR_STUBS() do { \ | |
69 | exec->setCurrentVPC(pc + 1); \ | |
70 | } while (false) | |
71 | #endif | |
72 | ||
73 | #define LLINT_BEGIN() \ | |
74 | LLINT_BEGIN_NO_SET_PC(); \ | |
75 | LLINT_SET_PC_FOR_STUBS() | |
76 | ||
77 | #define LLINT_OP(index) (exec->uncheckedR(pc[index].u.operand)) | |
78 | #define LLINT_OP_C(index) (exec->r(pc[index].u.operand)) | |
79 | ||
80 | #define LLINT_RETURN_TWO(first, second) do { \ | |
81 | return encodeResult(first, second); \ | |
82 | } while (false) | |
83 | ||
84 | #define LLINT_END_IMPL() LLINT_RETURN_TWO(pc, 0) | |
85 | ||
86 | #define LLINT_THROW(exceptionToThrow) do { \ | |
87 | vm.throwException(exec, exceptionToThrow); \ | |
88 | pc = returnToThrow(exec); \ | |
89 | LLINT_END_IMPL(); \ | |
90 | } while (false) | |
91 | ||
92 | #define LLINT_CHECK_EXCEPTION() do { \ | |
93 | if (UNLIKELY(vm.exception())) { \ | |
94 | pc = returnToThrow(exec); \ | |
95 | LLINT_END_IMPL(); \ | |
96 | } \ | |
97 | } while (false) | |
98 | ||
99 | #define LLINT_END() do { \ | |
100 | LLINT_CHECK_EXCEPTION(); \ | |
101 | LLINT_END_IMPL(); \ | |
102 | } while (false) | |
103 | ||
104 | #define LLINT_BRANCH(opcode, condition) do { \ | |
105 | bool __b_condition = (condition); \ | |
106 | LLINT_CHECK_EXCEPTION(); \ | |
107 | if (__b_condition) \ | |
108 | pc += pc[OPCODE_LENGTH(opcode) - 1].u.operand; \ | |
109 | else \ | |
110 | pc += OPCODE_LENGTH(opcode); \ | |
111 | LLINT_END_IMPL(); \ | |
112 | } while (false) | |
113 | ||
114 | #define LLINT_RETURN(value) do { \ | |
115 | JSValue __r_returnValue = (value); \ | |
116 | LLINT_CHECK_EXCEPTION(); \ | |
117 | LLINT_OP(1) = __r_returnValue; \ | |
118 | LLINT_END_IMPL(); \ | |
119 | } while (false) | |
120 | ||
121 | #define LLINT_RETURN_WITH_PC_ADJUSTMENT(value, pcAdjustment) do { \ | |
122 | JSValue __r_returnValue = (value); \ | |
123 | LLINT_CHECK_EXCEPTION(); \ | |
124 | LLINT_OP(1) = __r_returnValue; \ | |
125 | pc += (pcAdjustment); \ | |
126 | LLINT_END_IMPL(); \ | |
127 | } while (false) | |
128 | ||
129 | #define LLINT_RETURN_PROFILED(opcode, value) do { \ | |
130 | JSValue __rp_returnValue = (value); \ | |
131 | LLINT_CHECK_EXCEPTION(); \ | |
132 | LLINT_OP(1) = __rp_returnValue; \ | |
133 | LLINT_PROFILE_VALUE(opcode, __rp_returnValue); \ | |
134 | LLINT_END_IMPL(); \ | |
135 | } while (false) | |
136 | ||
137 | #define LLINT_PROFILE_VALUE(opcode, value) do { \ | |
138 | pc[OPCODE_LENGTH(opcode) - 1].u.profile->m_buckets[0] = \ | |
139 | JSValue::encode(value); \ | |
140 | } while (false) | |
141 | ||
142 | #define LLINT_CALL_END_IMPL(exec, callTarget) LLINT_RETURN_TWO((callTarget), (exec)) | |
143 | ||
144 | #define LLINT_CALL_THROW(exec, exceptionToThrow) do { \ | |
145 | ExecState* __ct_exec = (exec); \ | |
146 | vm.throwException(__ct_exec, exceptionToThrow); \ | |
147 | LLINT_CALL_END_IMPL(0, callToThrow(__ct_exec)); \ | |
148 | } while (false) | |
149 | ||
150 | #define LLINT_CALL_CHECK_EXCEPTION(exec) do { \ | |
151 | ExecState* __cce_exec = (exec); \ | |
152 | if (UNLIKELY(vm.exception())) \ | |
153 | LLINT_CALL_END_IMPL(0, callToThrow(__cce_exec)); \ | |
154 | } while (false) | |
155 | ||
156 | #define LLINT_CALL_RETURN(exec, callTarget) do { \ | |
157 | ExecState* __cr_exec = (exec); \ | |
158 | void* __cr_callTarget = (callTarget); \ | |
159 | LLINT_CALL_CHECK_EXCEPTION(__cr_exec); \ | |
160 | LLINT_CALL_END_IMPL(__cr_exec, __cr_callTarget); \ | |
161 | } while (false) | |
162 | ||
163 | #define LLINT_RETURN_CALLEE_FRAME(execCallee) do { \ | |
164 | ExecState* __rcf_exec = (execCallee); \ | |
165 | LLINT_RETURN_TWO(pc, __rcf_exec); \ | |
166 | } while (false) | |
167 | ||
168 | ||
169 | extern "C" SlowPathReturnType llint_trace_operand(ExecState* exec, Instruction* pc, int fromWhere, int operand) | |
170 | { | |
171 | LLINT_BEGIN(); | |
172 | dataLogF("%p / %p: executing bc#%zu, op#%u: Trace(%d): %d: %d\n", | |
173 | exec->codeBlock(), | |
174 | exec, | |
175 | static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()), | |
176 | exec->vm().interpreter->getOpcodeID(pc[0].u.opcode), | |
177 | fromWhere, | |
178 | operand, | |
179 | pc[operand].u.operand); | |
180 | LLINT_END(); | |
181 | } | |
182 | ||
183 | extern "C" SlowPathReturnType llint_trace_value(ExecState* exec, Instruction* pc, int fromWhere, int operand) | |
184 | { | |
185 | JSValue value = LLINT_OP_C(operand).jsValue(); | |
186 | union { | |
187 | struct { | |
188 | uint32_t tag; | |
189 | uint32_t payload; | |
190 | } bits; | |
191 | EncodedJSValue asValue; | |
192 | } u; | |
193 | u.asValue = JSValue::encode(value); | |
194 | dataLogF( | |
195 | "%p / %p: executing bc#%zu, op#%u: Trace(%d): %d: %d: %08x:%08x: %s\n", | |
196 | exec->codeBlock(), | |
197 | exec, | |
198 | static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()), | |
199 | exec->vm().interpreter->getOpcodeID(pc[0].u.opcode), | |
200 | fromWhere, | |
201 | operand, | |
202 | pc[operand].u.operand, | |
203 | u.bits.tag, | |
204 | u.bits.payload, | |
205 | toCString(value).data()); | |
206 | LLINT_END_IMPL(); | |
207 | } | |
208 | ||
209 | LLINT_SLOW_PATH_DECL(trace_prologue) | |
210 | { | |
211 | dataLogF("%p / %p: in prologue.\n", exec->codeBlock(), exec); | |
212 | LLINT_END_IMPL(); | |
213 | } | |
214 | ||
215 | static void traceFunctionPrologue(ExecState* exec, const char* comment, CodeSpecializationKind kind) | |
216 | { | |
217 | JSFunction* callee = jsCast<JSFunction*>(exec->callee()); | |
218 | FunctionExecutable* executable = callee->jsExecutable(); | |
219 | CodeBlock* codeBlock = executable->codeBlockFor(kind); | |
220 | dataLogF("%p / %p: in %s of function %p, executable %p; numVars = %u, numParameters = %u, numCalleeRegisters = %u, caller = %p.\n", | |
221 | codeBlock, exec, comment, callee, executable, | |
222 | codeBlock->m_numVars, codeBlock->numParameters(), codeBlock->m_numCalleeRegisters, | |
223 | exec->callerFrame()); | |
224 | } | |
225 | ||
226 | LLINT_SLOW_PATH_DECL(trace_prologue_function_for_call) | |
227 | { | |
228 | traceFunctionPrologue(exec, "call prologue", CodeForCall); | |
229 | LLINT_END_IMPL(); | |
230 | } | |
231 | ||
232 | LLINT_SLOW_PATH_DECL(trace_prologue_function_for_construct) | |
233 | { | |
234 | traceFunctionPrologue(exec, "construct prologue", CodeForConstruct); | |
235 | LLINT_END_IMPL(); | |
236 | } | |
237 | ||
238 | LLINT_SLOW_PATH_DECL(trace_arityCheck_for_call) | |
239 | { | |
240 | traceFunctionPrologue(exec, "call arity check", CodeForCall); | |
241 | LLINT_END_IMPL(); | |
242 | } | |
243 | ||
244 | LLINT_SLOW_PATH_DECL(trace_arityCheck_for_construct) | |
245 | { | |
246 | traceFunctionPrologue(exec, "construct arity check", CodeForConstruct); | |
247 | LLINT_END_IMPL(); | |
248 | } | |
249 | ||
250 | LLINT_SLOW_PATH_DECL(trace) | |
251 | { | |
252 | dataLogF("%p / %p: executing bc#%zu, %s, scope %p, pc = %p\n", | |
253 | exec->codeBlock(), | |
254 | exec, | |
255 | static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()), | |
256 | opcodeNames[exec->vm().interpreter->getOpcodeID(pc[0].u.opcode)], | |
257 | exec->scope(), pc); | |
258 | if (exec->vm().interpreter->getOpcodeID(pc[0].u.opcode) == op_enter) { | |
259 | dataLogF("Frame will eventually return to %p\n", exec->returnPC().value()); | |
260 | *bitwise_cast<volatile char*>(exec->returnPC().value()); | |
261 | } | |
262 | if (exec->vm().interpreter->getOpcodeID(pc[0].u.opcode) == op_ret) { | |
263 | dataLogF("Will be returning to %p\n", exec->returnPC().value()); | |
264 | dataLogF("The new cfr will be %p\n", exec->callerFrame()); | |
265 | } | |
266 | LLINT_END_IMPL(); | |
267 | } | |
268 | ||
269 | LLINT_SLOW_PATH_DECL(special_trace) | |
270 | { | |
271 | dataLogF("%p / %p: executing special case bc#%zu, op#%u, return PC is %p\n", | |
272 | exec->codeBlock(), | |
273 | exec, | |
274 | static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()), | |
275 | exec->vm().interpreter->getOpcodeID(pc[0].u.opcode), | |
276 | exec->returnPC().value()); | |
277 | LLINT_END_IMPL(); | |
278 | } | |
279 | ||
280 | enum EntryKind { Prologue, ArityCheck }; | |
281 | ||
282 | #if ENABLE(JIT) | |
283 | inline bool shouldJIT(ExecState* exec) | |
284 | { | |
285 | // You can modify this to turn off JITting without rebuilding the world. | |
286 | return exec->vm().canUseJIT(); | |
287 | } | |
288 | ||
289 | // Returns true if we should try to OSR. | |
290 | inline bool jitCompileAndSetHeuristics(CodeBlock* codeBlock, ExecState* exec) | |
291 | { | |
292 | VM& vm = exec->vm(); | |
293 | DeferGCForAWhile deferGC(vm.heap); // My callers don't set top callframe, so we don't want to GC here at all. | |
294 | ||
295 | codeBlock->updateAllValueProfilePredictions(); | |
296 | ||
297 | if (!codeBlock->checkIfJITThresholdReached()) { | |
298 | if (Options::verboseOSR()) | |
299 | dataLogF(" JIT threshold should be lifted.\n"); | |
300 | return false; | |
301 | } | |
302 | ||
303 | switch (codeBlock->jitType()) { | |
304 | case JITCode::BaselineJIT: { | |
305 | if (Options::verboseOSR()) | |
306 | dataLogF(" Code was already compiled.\n"); | |
307 | codeBlock->jitSoon(); | |
308 | return true; | |
309 | } | |
310 | case JITCode::InterpreterThunk: { | |
311 | CompilationResult result = JIT::compile(&vm, codeBlock, JITCompilationCanFail); | |
312 | switch (result) { | |
313 | case CompilationFailed: | |
314 | if (Options::verboseOSR()) | |
315 | dataLogF(" JIT compilation failed.\n"); | |
316 | codeBlock->dontJITAnytimeSoon(); | |
317 | return false; | |
318 | case CompilationSuccessful: | |
319 | if (Options::verboseOSR()) | |
320 | dataLogF(" JIT compilation successful.\n"); | |
321 | codeBlock->install(); | |
322 | codeBlock->jitSoon(); | |
323 | return true; | |
324 | default: | |
325 | RELEASE_ASSERT_NOT_REACHED(); | |
326 | return false; | |
327 | } | |
328 | } | |
329 | default: | |
330 | RELEASE_ASSERT_NOT_REACHED(); | |
331 | return false; | |
332 | } | |
333 | } | |
334 | ||
335 | static SlowPathReturnType entryOSR(ExecState* exec, Instruction*, CodeBlock* codeBlock, const char *name, EntryKind kind) | |
336 | { | |
337 | if (Options::verboseOSR()) { | |
338 | dataLog( | |
339 | *codeBlock, ": Entered ", name, " with executeCounter = ", | |
340 | codeBlock->llintExecuteCounter(), "\n"); | |
341 | } | |
342 | ||
343 | if (!shouldJIT(exec)) { | |
344 | codeBlock->dontJITAnytimeSoon(); | |
345 | LLINT_RETURN_TWO(0, 0); | |
346 | } | |
347 | if (!jitCompileAndSetHeuristics(codeBlock, exec)) | |
348 | LLINT_RETURN_TWO(0, 0); | |
349 | ||
350 | if (kind == Prologue) | |
351 | LLINT_RETURN_TWO(codeBlock->jitCode()->executableAddress(), 0); | |
352 | ASSERT(kind == ArityCheck); | |
353 | LLINT_RETURN_TWO(codeBlock->jitCode()->addressForCall( | |
354 | *codeBlock->vm(), codeBlock->ownerExecutable(), MustCheckArity, | |
355 | RegisterPreservationNotRequired).executableAddress(), 0); | |
356 | } | |
357 | #else // ENABLE(JIT) | |
358 | static SlowPathReturnType entryOSR(ExecState* exec, Instruction*, CodeBlock* codeBlock, const char*, EntryKind) | |
359 | { | |
360 | codeBlock->dontJITAnytimeSoon(); | |
361 | LLINT_RETURN_TWO(0, exec); | |
362 | } | |
363 | #endif // ENABLE(JIT) | |
364 | ||
365 | LLINT_SLOW_PATH_DECL(entry_osr) | |
366 | { | |
367 | return entryOSR(exec, pc, exec->codeBlock(), "entry_osr", Prologue); | |
368 | } | |
369 | ||
370 | LLINT_SLOW_PATH_DECL(entry_osr_function_for_call) | |
371 | { | |
372 | return entryOSR(exec, pc, jsCast<JSFunction*>(exec->callee())->jsExecutable()->codeBlockForCall(), "entry_osr_function_for_call", Prologue); | |
373 | } | |
374 | ||
375 | LLINT_SLOW_PATH_DECL(entry_osr_function_for_construct) | |
376 | { | |
377 | return entryOSR(exec, pc, jsCast<JSFunction*>(exec->callee())->jsExecutable()->codeBlockForConstruct(), "entry_osr_function_for_construct", Prologue); | |
378 | } | |
379 | ||
380 | LLINT_SLOW_PATH_DECL(entry_osr_function_for_call_arityCheck) | |
381 | { | |
382 | return entryOSR(exec, pc, jsCast<JSFunction*>(exec->callee())->jsExecutable()->codeBlockForCall(), "entry_osr_function_for_call_arityCheck", ArityCheck); | |
383 | } | |
384 | ||
385 | LLINT_SLOW_PATH_DECL(entry_osr_function_for_construct_arityCheck) | |
386 | { | |
387 | return entryOSR(exec, pc, jsCast<JSFunction*>(exec->callee())->jsExecutable()->codeBlockForConstruct(), "entry_osr_function_for_construct_arityCheck", ArityCheck); | |
388 | } | |
389 | ||
390 | LLINT_SLOW_PATH_DECL(loop_osr) | |
391 | { | |
392 | CodeBlock* codeBlock = exec->codeBlock(); | |
393 | ||
394 | #if ENABLE(JIT) | |
395 | if (Options::verboseOSR()) { | |
396 | dataLog( | |
397 | *codeBlock, ": Entered loop_osr with executeCounter = ", | |
398 | codeBlock->llintExecuteCounter(), "\n"); | |
399 | } | |
400 | ||
401 | if (!shouldJIT(exec)) { | |
402 | codeBlock->dontJITAnytimeSoon(); | |
403 | LLINT_RETURN_TWO(0, 0); | |
404 | } | |
405 | ||
406 | if (!jitCompileAndSetHeuristics(codeBlock, exec)) | |
407 | LLINT_RETURN_TWO(0, 0); | |
408 | ||
409 | ASSERT(codeBlock->jitType() == JITCode::BaselineJIT); | |
410 | ||
411 | Vector<BytecodeAndMachineOffset> map; | |
412 | codeBlock->jitCodeMap()->decode(map); | |
413 | BytecodeAndMachineOffset* mapping = binarySearch<BytecodeAndMachineOffset, unsigned>(map, map.size(), pc - codeBlock->instructions().begin(), BytecodeAndMachineOffset::getBytecodeIndex); | |
414 | ASSERT(mapping); | |
415 | ASSERT(mapping->m_bytecodeIndex == static_cast<unsigned>(pc - codeBlock->instructions().begin())); | |
416 | ||
417 | void* jumpTarget = codeBlock->jitCode()->executableAddressAtOffset(mapping->m_machineCodeOffset); | |
418 | ASSERT(jumpTarget); | |
419 | ||
420 | LLINT_RETURN_TWO(jumpTarget, exec->topOfFrame()); | |
421 | #else // ENABLE(JIT) | |
422 | UNUSED_PARAM(pc); | |
423 | codeBlock->dontJITAnytimeSoon(); | |
424 | LLINT_RETURN_TWO(0, 0); | |
425 | #endif // ENABLE(JIT) | |
426 | } | |
427 | ||
428 | LLINT_SLOW_PATH_DECL(replace) | |
429 | { | |
430 | CodeBlock* codeBlock = exec->codeBlock(); | |
431 | ||
432 | #if ENABLE(JIT) | |
433 | if (Options::verboseOSR()) { | |
434 | dataLog( | |
435 | *codeBlock, ": Entered replace with executeCounter = ", | |
436 | codeBlock->llintExecuteCounter(), "\n"); | |
437 | } | |
438 | ||
439 | if (shouldJIT(exec)) | |
440 | jitCompileAndSetHeuristics(codeBlock, exec); | |
441 | else | |
442 | codeBlock->dontJITAnytimeSoon(); | |
443 | LLINT_END_IMPL(); | |
444 | #else // ENABLE(JIT) | |
445 | codeBlock->dontJITAnytimeSoon(); | |
446 | LLINT_END_IMPL(); | |
447 | #endif // ENABLE(JIT) | |
448 | } | |
449 | ||
450 | LLINT_SLOW_PATH_DECL(stack_check) | |
451 | { | |
452 | LLINT_BEGIN(); | |
453 | #if LLINT_SLOW_PATH_TRACING | |
454 | dataLogF("Checking stack height with exec = %p.\n", exec); | |
455 | dataLogF("CodeBlock = %p.\n", exec->codeBlock()); | |
456 | dataLogF("Num callee registers = %u.\n", exec->codeBlock()->m_numCalleeRegisters); | |
457 | dataLogF("Num vars = %u.\n", exec->codeBlock()->m_numVars); | |
458 | ||
459 | #if ENABLE(LLINT_C_LOOP) | |
460 | dataLogF("Current end is at %p.\n", exec->vm().jsStackLimit()); | |
461 | #else | |
462 | dataLogF("Current end is at %p.\n", exec->vm().stackLimit()); | |
463 | #endif | |
464 | ||
465 | #endif | |
466 | // This stack check is done in the prologue for a function call, and the | |
467 | // CallFrame is not completely set up yet. For example, if the frame needs | |
468 | // an activation object, the activation object will only be set up after | |
469 | // we start executing the function. If we need to throw a StackOverflowError | |
470 | // here, then we need to tell the prologue to start the stack unwinding from | |
471 | // the caller frame (which is fully set up) instead. To do that, we return | |
472 | // the caller's CallFrame in the second return value. | |
473 | // | |
474 | // If the stack check succeeds and we don't need to throw the error, then | |
475 | // we'll return 0 instead. The prologue will check for a non-zero value | |
476 | // when determining whether to set the callFrame or not. | |
477 | ||
478 | // For JIT enabled builds which uses the C stack, the stack is not growable. | |
479 | // Hence, if we get here, then we know a stack overflow is imminent. So, just | |
480 | // throw the StackOverflowError unconditionally. | |
481 | #if !ENABLE(JIT) | |
482 | ASSERT(!vm.interpreter->stack().containsAddress(exec->topOfFrame())); | |
483 | if (LIKELY(vm.interpreter->stack().ensureCapacityFor(exec->topOfFrame()))) | |
484 | LLINT_RETURN_TWO(pc, 0); | |
485 | #endif | |
486 | ||
487 | exec = exec->callerFrame(); | |
488 | vm.topCallFrame = exec; | |
489 | ErrorHandlingScope errorScope(vm); | |
490 | CommonSlowPaths::interpreterThrowInCaller(exec, createStackOverflowError(exec)); | |
491 | pc = returnToThrowForThrownException(exec); | |
492 | LLINT_RETURN_TWO(pc, exec); | |
493 | } | |
494 | ||
495 | LLINT_SLOW_PATH_DECL(slow_path_create_activation) | |
496 | { | |
497 | LLINT_BEGIN(); | |
498 | #if LLINT_SLOW_PATH_TRACING | |
499 | dataLogF("Creating an activation, exec = %p!\n", exec); | |
500 | #endif | |
501 | JSActivation* activation = JSActivation::create(vm, exec, exec->codeBlock()); | |
502 | exec->setScope(activation); | |
503 | LLINT_RETURN(JSValue(activation)); | |
504 | } | |
505 | ||
506 | LLINT_SLOW_PATH_DECL(slow_path_new_object) | |
507 | { | |
508 | LLINT_BEGIN(); | |
509 | LLINT_RETURN(constructEmptyObject(exec, pc[3].u.objectAllocationProfile->structure())); | |
510 | } | |
511 | ||
512 | LLINT_SLOW_PATH_DECL(slow_path_new_array) | |
513 | { | |
514 | LLINT_BEGIN(); | |
515 | LLINT_RETURN(constructArrayNegativeIndexed(exec, pc[4].u.arrayAllocationProfile, bitwise_cast<JSValue*>(&LLINT_OP(2)), pc[3].u.operand)); | |
516 | } | |
517 | ||
518 | LLINT_SLOW_PATH_DECL(slow_path_new_array_with_size) | |
519 | { | |
520 | LLINT_BEGIN(); | |
521 | LLINT_RETURN(constructArrayWithSizeQuirk(exec, pc[3].u.arrayAllocationProfile, exec->lexicalGlobalObject(), LLINT_OP_C(2).jsValue())); | |
522 | } | |
523 | ||
524 | LLINT_SLOW_PATH_DECL(slow_path_new_array_buffer) | |
525 | { | |
526 | LLINT_BEGIN(); | |
527 | LLINT_RETURN(constructArray(exec, pc[4].u.arrayAllocationProfile, exec->codeBlock()->constantBuffer(pc[2].u.operand), pc[3].u.operand)); | |
528 | } | |
529 | ||
530 | LLINT_SLOW_PATH_DECL(slow_path_new_regexp) | |
531 | { | |
532 | LLINT_BEGIN(); | |
533 | RegExp* regExp = exec->codeBlock()->regexp(pc[2].u.operand); | |
534 | if (!regExp->isValid()) | |
535 | LLINT_THROW(createSyntaxError(exec, "Invalid flag supplied to RegExp constructor.")); | |
536 | LLINT_RETURN(RegExpObject::create(vm, exec->lexicalGlobalObject()->regExpStructure(), regExp)); | |
537 | } | |
538 | ||
539 | LLINT_SLOW_PATH_DECL(slow_path_check_has_instance) | |
540 | { | |
541 | LLINT_BEGIN(); | |
542 | ||
543 | JSValue value = LLINT_OP_C(2).jsValue(); | |
544 | JSValue baseVal = LLINT_OP_C(3).jsValue(); | |
545 | if (baseVal.isObject()) { | |
546 | JSObject* baseObject = asObject(baseVal); | |
547 | ASSERT(!baseObject->structure()->typeInfo().implementsDefaultHasInstance()); | |
548 | if (baseObject->structure()->typeInfo().implementsHasInstance()) { | |
549 | JSValue result = jsBoolean(baseObject->methodTable()->customHasInstance(baseObject, exec, value)); | |
550 | LLINT_RETURN_WITH_PC_ADJUSTMENT(result, pc[4].u.operand); | |
551 | } | |
552 | } | |
553 | LLINT_THROW(createInvalidParameterError(exec, "instanceof", baseVal)); | |
554 | } | |
555 | ||
556 | LLINT_SLOW_PATH_DECL(slow_path_instanceof) | |
557 | { | |
558 | LLINT_BEGIN(); | |
559 | JSValue value = LLINT_OP_C(2).jsValue(); | |
560 | JSValue proto = LLINT_OP_C(3).jsValue(); | |
561 | ASSERT(!value.isObject() || !proto.isObject()); | |
562 | LLINT_RETURN(jsBoolean(JSObject::defaultHasInstance(exec, value, proto))); | |
563 | } | |
564 | ||
565 | LLINT_SLOW_PATH_DECL(slow_path_get_by_id) | |
566 | { | |
567 | LLINT_BEGIN(); | |
568 | CodeBlock* codeBlock = exec->codeBlock(); | |
569 | const Identifier& ident = codeBlock->identifier(pc[3].u.operand); | |
570 | JSValue baseValue = LLINT_OP_C(2).jsValue(); | |
571 | PropertySlot slot(baseValue); | |
572 | ||
573 | JSValue result = baseValue.get(exec, ident, slot); | |
574 | LLINT_CHECK_EXCEPTION(); | |
575 | LLINT_OP(1) = result; | |
576 | ||
577 | if (!LLINT_ALWAYS_ACCESS_SLOW | |
578 | && baseValue.isCell() | |
579 | && slot.isCacheable() | |
580 | && slot.slotBase() == baseValue | |
581 | && slot.isCacheableValue()) { | |
582 | ||
583 | JSCell* baseCell = baseValue.asCell(); | |
584 | Structure* structure = baseCell->structure(); | |
585 | ||
586 | if (!structure->isUncacheableDictionary() | |
587 | && !structure->typeInfo().prohibitsPropertyCaching() | |
588 | && !structure->typeInfo().newImpurePropertyFiresWatchpoints()) { | |
589 | ConcurrentJITLocker locker(codeBlock->m_lock); | |
590 | ||
591 | pc[4].u.structure.set( | |
592 | vm, codeBlock->ownerExecutable(), structure); | |
593 | if (isInlineOffset(slot.cachedOffset())) { | |
594 | pc[0].u.opcode = LLInt::getOpcode(op_get_by_id); | |
595 | pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage(); | |
596 | } else { | |
597 | pc[0].u.opcode = LLInt::getOpcode(op_get_by_id_out_of_line); | |
598 | pc[5].u.operand = offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue); | |
599 | } | |
600 | } | |
601 | } | |
602 | ||
603 | if (!LLINT_ALWAYS_ACCESS_SLOW | |
604 | && isJSArray(baseValue) | |
605 | && ident == exec->propertyNames().length) { | |
606 | pc[0].u.opcode = LLInt::getOpcode(op_get_array_length); | |
607 | ArrayProfile* arrayProfile = codeBlock->getOrAddArrayProfile(pc - codeBlock->instructions().begin()); | |
608 | arrayProfile->observeStructure(baseValue.asCell()->structure()); | |
609 | pc[4].u.arrayProfile = arrayProfile; | |
610 | } | |
611 | ||
612 | pc[OPCODE_LENGTH(op_get_by_id) - 1].u.profile->m_buckets[0] = JSValue::encode(result); | |
613 | LLINT_END(); | |
614 | } | |
615 | ||
616 | LLINT_SLOW_PATH_DECL(slow_path_get_arguments_length) | |
617 | { | |
618 | LLINT_BEGIN(); | |
619 | CodeBlock* codeBlock = exec->codeBlock(); | |
620 | const Identifier& ident = codeBlock->identifier(pc[3].u.operand); | |
621 | JSValue baseValue = LLINT_OP(2).jsValue(); | |
622 | PropertySlot slot(baseValue); | |
623 | LLINT_RETURN(baseValue.get(exec, ident, slot)); | |
624 | } | |
625 | ||
626 | LLINT_SLOW_PATH_DECL(slow_path_put_by_id) | |
627 | { | |
628 | LLINT_BEGIN(); | |
629 | CodeBlock* codeBlock = exec->codeBlock(); | |
630 | const Identifier& ident = codeBlock->identifier(pc[2].u.operand); | |
631 | ||
632 | JSValue baseValue = LLINT_OP_C(1).jsValue(); | |
633 | PutPropertySlot slot(baseValue, codeBlock->isStrictMode(), codeBlock->putByIdContext()); | |
634 | if (pc[8].u.operand) | |
635 | asObject(baseValue)->putDirect(vm, ident, LLINT_OP_C(3).jsValue(), slot); | |
636 | else | |
637 | baseValue.put(exec, ident, LLINT_OP_C(3).jsValue(), slot); | |
638 | LLINT_CHECK_EXCEPTION(); | |
639 | ||
640 | if (!LLINT_ALWAYS_ACCESS_SLOW | |
641 | && baseValue.isCell() | |
642 | && slot.isCacheablePut()) { | |
643 | ||
644 | JSCell* baseCell = baseValue.asCell(); | |
645 | Structure* structure = baseCell->structure(); | |
646 | ||
647 | if (!structure->isUncacheableDictionary() | |
648 | && !structure->typeInfo().prohibitsPropertyCaching() | |
649 | && baseCell == slot.base()) { | |
650 | ||
651 | if (slot.type() == PutPropertySlot::NewProperty) { | |
652 | GCSafeConcurrentJITLocker locker(codeBlock->m_lock, vm.heap); | |
653 | ||
654 | if (!structure->isDictionary() && structure->previousID()->outOfLineCapacity() == structure->outOfLineCapacity()) { | |
655 | ASSERT(structure->previousID()->transitionWatchpointSetHasBeenInvalidated()); | |
656 | ||
657 | // This is needed because some of the methods we call | |
658 | // below may GC. | |
659 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id); | |
660 | ||
661 | if (normalizePrototypeChain(exec, baseCell) != InvalidPrototypeChain) { | |
662 | ASSERT(structure->previousID()->isObject()); | |
663 | pc[4].u.structure.set( | |
664 | vm, codeBlock->ownerExecutable(), structure->previousID()); | |
665 | if (isInlineOffset(slot.cachedOffset())) | |
666 | pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage(); | |
667 | else | |
668 | pc[5].u.operand = offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue); | |
669 | pc[6].u.structure.set( | |
670 | vm, codeBlock->ownerExecutable(), structure); | |
671 | StructureChain* chain = structure->prototypeChain(exec); | |
672 | ASSERT(chain); | |
673 | pc[7].u.structureChain.set( | |
674 | vm, codeBlock->ownerExecutable(), chain); | |
675 | ||
676 | if (pc[8].u.operand) { | |
677 | if (isInlineOffset(slot.cachedOffset())) | |
678 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id_transition_direct); | |
679 | else | |
680 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id_transition_direct_out_of_line); | |
681 | } else { | |
682 | if (isInlineOffset(slot.cachedOffset())) | |
683 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id_transition_normal); | |
684 | else | |
685 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id_transition_normal_out_of_line); | |
686 | } | |
687 | } | |
688 | } | |
689 | } else { | |
690 | pc[4].u.structure.set( | |
691 | vm, codeBlock->ownerExecutable(), structure); | |
692 | if (isInlineOffset(slot.cachedOffset())) { | |
693 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id); | |
694 | pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage(); | |
695 | } else { | |
696 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id_out_of_line); | |
697 | pc[5].u.operand = offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue); | |
698 | } | |
699 | } | |
700 | } | |
701 | } | |
702 | ||
703 | LLINT_END(); | |
704 | } | |
705 | ||
706 | LLINT_SLOW_PATH_DECL(slow_path_del_by_id) | |
707 | { | |
708 | LLINT_BEGIN(); | |
709 | CodeBlock* codeBlock = exec->codeBlock(); | |
710 | JSObject* baseObject = LLINT_OP_C(2).jsValue().toObject(exec); | |
711 | bool couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, codeBlock->identifier(pc[3].u.operand)); | |
712 | LLINT_CHECK_EXCEPTION(); | |
713 | if (!couldDelete && codeBlock->isStrictMode()) | |
714 | LLINT_THROW(createTypeError(exec, "Unable to delete property.")); | |
715 | LLINT_RETURN(jsBoolean(couldDelete)); | |
716 | } | |
717 | ||
718 | inline JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript) | |
719 | { | |
720 | if (LIKELY(baseValue.isCell() && subscript.isString())) { | |
721 | VM& vm = exec->vm(); | |
722 | Structure& structure = *baseValue.asCell()->structure(vm); | |
723 | if (JSCell::canUseFastGetOwnProperty(structure)) { | |
724 | if (JSValue result = baseValue.asCell()->fastGetOwnProperty(vm, structure, asString(subscript)->value(exec))) | |
725 | return result; | |
726 | } | |
727 | } | |
728 | ||
729 | if (subscript.isUInt32()) { | |
730 | uint32_t i = subscript.asUInt32(); | |
731 | if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i)) | |
732 | return asString(baseValue)->getIndex(exec, i); | |
733 | ||
734 | return baseValue.get(exec, i); | |
735 | } | |
736 | ||
737 | if (isName(subscript)) | |
738 | return baseValue.get(exec, jsCast<NameInstance*>(subscript.asCell())->privateName()); | |
739 | ||
740 | Identifier property = subscript.toString(exec)->toIdentifier(exec); | |
741 | return baseValue.get(exec, property); | |
742 | } | |
743 | ||
744 | LLINT_SLOW_PATH_DECL(slow_path_get_by_val) | |
745 | { | |
746 | LLINT_BEGIN(); | |
747 | LLINT_RETURN_PROFILED(op_get_by_val, getByVal(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue())); | |
748 | } | |
749 | ||
750 | LLINT_SLOW_PATH_DECL(slow_path_get_argument_by_val) | |
751 | { | |
752 | LLINT_BEGIN(); | |
753 | JSValue arguments = LLINT_OP(2).jsValue(); | |
754 | if (!arguments) { | |
755 | arguments = Arguments::create(vm, exec); | |
756 | LLINT_CHECK_EXCEPTION(); | |
757 | LLINT_OP(2) = arguments; | |
758 | exec->uncheckedR(unmodifiedArgumentsRegister(VirtualRegister(pc[2].u.operand)).offset()) = arguments; | |
759 | } | |
760 | ||
761 | LLINT_RETURN_PROFILED(op_get_argument_by_val, getByVal(exec, arguments, LLINT_OP_C(3).jsValue())); | |
762 | } | |
763 | ||
764 | LLINT_SLOW_PATH_DECL(slow_path_get_by_pname) | |
765 | { | |
766 | LLINT_BEGIN(); | |
767 | LLINT_RETURN(getByVal(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue())); | |
768 | } | |
769 | ||
770 | LLINT_SLOW_PATH_DECL(slow_path_put_by_val) | |
771 | { | |
772 | LLINT_BEGIN(); | |
773 | ||
774 | JSValue baseValue = LLINT_OP_C(1).jsValue(); | |
775 | JSValue subscript = LLINT_OP_C(2).jsValue(); | |
776 | JSValue value = LLINT_OP_C(3).jsValue(); | |
777 | ||
778 | if (LIKELY(subscript.isUInt32())) { | |
779 | uint32_t i = subscript.asUInt32(); | |
780 | if (baseValue.isObject()) { | |
781 | JSObject* object = asObject(baseValue); | |
782 | if (object->canSetIndexQuickly(i)) | |
783 | object->setIndexQuickly(vm, i, value); | |
784 | else | |
785 | object->methodTable()->putByIndex(object, exec, i, value, exec->codeBlock()->isStrictMode()); | |
786 | LLINT_END(); | |
787 | } | |
788 | baseValue.putByIndex(exec, i, value, exec->codeBlock()->isStrictMode()); | |
789 | LLINT_END(); | |
790 | } | |
791 | ||
792 | if (isName(subscript)) { | |
793 | PutPropertySlot slot(baseValue, exec->codeBlock()->isStrictMode()); | |
794 | baseValue.put(exec, jsCast<NameInstance*>(subscript.asCell())->privateName(), value, slot); | |
795 | LLINT_END(); | |
796 | } | |
797 | ||
798 | Identifier property(exec, subscript.toString(exec)->value(exec)); | |
799 | LLINT_CHECK_EXCEPTION(); | |
800 | PutPropertySlot slot(baseValue, exec->codeBlock()->isStrictMode()); | |
801 | baseValue.put(exec, property, value, slot); | |
802 | LLINT_END(); | |
803 | } | |
804 | ||
805 | LLINT_SLOW_PATH_DECL(slow_path_put_by_val_direct) | |
806 | { | |
807 | LLINT_BEGIN(); | |
808 | ||
809 | JSValue baseValue = LLINT_OP_C(1).jsValue(); | |
810 | JSValue subscript = LLINT_OP_C(2).jsValue(); | |
811 | JSValue value = LLINT_OP_C(3).jsValue(); | |
812 | RELEASE_ASSERT(baseValue.isObject()); | |
813 | JSObject* baseObject = asObject(baseValue); | |
814 | if (LIKELY(subscript.isUInt32())) { | |
815 | uint32_t i = subscript.asUInt32(); | |
816 | baseObject->putDirectIndex(exec, i, value); | |
817 | } else if (isName(subscript)) { | |
818 | PutPropertySlot slot(baseObject, exec->codeBlock()->isStrictMode()); | |
819 | baseObject->putDirect(exec->vm(), jsCast<NameInstance*>(subscript.asCell())->privateName(), value, slot); | |
820 | } else { | |
821 | Identifier property(exec, subscript.toString(exec)->value(exec)); | |
822 | if (!exec->vm().exception()) { // Don't put to an object if toString threw an exception. | |
823 | PutPropertySlot slot(baseObject, exec->codeBlock()->isStrictMode()); | |
824 | baseObject->putDirect(exec->vm(), property, value, slot); | |
825 | } | |
826 | } | |
827 | LLINT_END(); | |
828 | } | |
829 | ||
830 | LLINT_SLOW_PATH_DECL(slow_path_del_by_val) | |
831 | { | |
832 | LLINT_BEGIN(); | |
833 | JSValue baseValue = LLINT_OP_C(2).jsValue(); | |
834 | JSObject* baseObject = baseValue.toObject(exec); | |
835 | ||
836 | JSValue subscript = LLINT_OP_C(3).jsValue(); | |
837 | ||
838 | bool couldDelete; | |
839 | ||
840 | uint32_t i; | |
841 | if (subscript.getUInt32(i)) | |
842 | couldDelete = baseObject->methodTable()->deletePropertyByIndex(baseObject, exec, i); | |
843 | else if (isName(subscript)) | |
844 | couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, jsCast<NameInstance*>(subscript.asCell())->privateName()); | |
845 | else { | |
846 | LLINT_CHECK_EXCEPTION(); | |
847 | Identifier property(exec, subscript.toString(exec)->value(exec)); | |
848 | LLINT_CHECK_EXCEPTION(); | |
849 | couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, property); | |
850 | } | |
851 | ||
852 | if (!couldDelete && exec->codeBlock()->isStrictMode()) | |
853 | LLINT_THROW(createTypeError(exec, "Unable to delete property.")); | |
854 | ||
855 | LLINT_RETURN(jsBoolean(couldDelete)); | |
856 | } | |
857 | ||
858 | LLINT_SLOW_PATH_DECL(slow_path_put_by_index) | |
859 | { | |
860 | LLINT_BEGIN(); | |
861 | JSValue arrayValue = LLINT_OP_C(1).jsValue(); | |
862 | ASSERT(isJSArray(arrayValue)); | |
863 | asArray(arrayValue)->putDirectIndex(exec, pc[2].u.operand, LLINT_OP_C(3).jsValue()); | |
864 | LLINT_END(); | |
865 | } | |
866 | ||
867 | LLINT_SLOW_PATH_DECL(slow_path_put_getter_setter) | |
868 | { | |
869 | LLINT_BEGIN(); | |
870 | ASSERT(LLINT_OP(1).jsValue().isObject()); | |
871 | JSObject* baseObj = asObject(LLINT_OP(1).jsValue()); | |
872 | ||
873 | GetterSetter* accessor = GetterSetter::create(vm); | |
874 | LLINT_CHECK_EXCEPTION(); | |
875 | ||
876 | JSValue getter = LLINT_OP(3).jsValue(); | |
877 | JSValue setter = LLINT_OP(4).jsValue(); | |
878 | ASSERT(getter.isObject() || getter.isUndefined()); | |
879 | ASSERT(setter.isObject() || setter.isUndefined()); | |
880 | ASSERT(getter.isObject() || setter.isObject()); | |
881 | ||
882 | if (!getter.isUndefined()) | |
883 | accessor->setGetter(vm, asObject(getter)); | |
884 | if (!setter.isUndefined()) | |
885 | accessor->setSetter(vm, asObject(setter)); | |
886 | baseObj->putDirectAccessor( | |
887 | exec, | |
888 | exec->codeBlock()->identifier(pc[2].u.operand), | |
889 | accessor, Accessor); | |
890 | LLINT_END(); | |
891 | } | |
892 | ||
893 | LLINT_SLOW_PATH_DECL(slow_path_jtrue) | |
894 | { | |
895 | LLINT_BEGIN(); | |
896 | LLINT_BRANCH(op_jtrue, LLINT_OP_C(1).jsValue().toBoolean(exec)); | |
897 | } | |
898 | ||
899 | LLINT_SLOW_PATH_DECL(slow_path_jfalse) | |
900 | { | |
901 | LLINT_BEGIN(); | |
902 | LLINT_BRANCH(op_jfalse, !LLINT_OP_C(1).jsValue().toBoolean(exec)); | |
903 | } | |
904 | ||
905 | LLINT_SLOW_PATH_DECL(slow_path_jless) | |
906 | { | |
907 | LLINT_BEGIN(); | |
908 | LLINT_BRANCH(op_jless, jsLess<true>(exec, LLINT_OP_C(1).jsValue(), LLINT_OP_C(2).jsValue())); | |
909 | } | |
910 | ||
911 | LLINT_SLOW_PATH_DECL(slow_path_jnless) | |
912 | { | |
913 | LLINT_BEGIN(); | |
914 | LLINT_BRANCH(op_jnless, !jsLess<true>(exec, LLINT_OP_C(1).jsValue(), LLINT_OP_C(2).jsValue())); | |
915 | } | |
916 | ||
917 | LLINT_SLOW_PATH_DECL(slow_path_jgreater) | |
918 | { | |
919 | LLINT_BEGIN(); | |
920 | LLINT_BRANCH(op_jgreater, jsLess<false>(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(1).jsValue())); | |
921 | } | |
922 | ||
923 | LLINT_SLOW_PATH_DECL(slow_path_jngreater) | |
924 | { | |
925 | LLINT_BEGIN(); | |
926 | LLINT_BRANCH(op_jngreater, !jsLess<false>(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(1).jsValue())); | |
927 | } | |
928 | ||
929 | LLINT_SLOW_PATH_DECL(slow_path_jlesseq) | |
930 | { | |
931 | LLINT_BEGIN(); | |
932 | LLINT_BRANCH(op_jlesseq, jsLessEq<true>(exec, LLINT_OP_C(1).jsValue(), LLINT_OP_C(2).jsValue())); | |
933 | } | |
934 | ||
935 | LLINT_SLOW_PATH_DECL(slow_path_jnlesseq) | |
936 | { | |
937 | LLINT_BEGIN(); | |
938 | LLINT_BRANCH(op_jnlesseq, !jsLessEq<true>(exec, LLINT_OP_C(1).jsValue(), LLINT_OP_C(2).jsValue())); | |
939 | } | |
940 | ||
941 | LLINT_SLOW_PATH_DECL(slow_path_jgreatereq) | |
942 | { | |
943 | LLINT_BEGIN(); | |
944 | LLINT_BRANCH(op_jgreatereq, jsLessEq<false>(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(1).jsValue())); | |
945 | } | |
946 | ||
947 | LLINT_SLOW_PATH_DECL(slow_path_jngreatereq) | |
948 | { | |
949 | LLINT_BEGIN(); | |
950 | LLINT_BRANCH(op_jngreatereq, !jsLessEq<false>(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(1).jsValue())); | |
951 | } | |
952 | ||
953 | LLINT_SLOW_PATH_DECL(slow_path_switch_imm) | |
954 | { | |
955 | LLINT_BEGIN(); | |
956 | JSValue scrutinee = LLINT_OP_C(3).jsValue(); | |
957 | ASSERT(scrutinee.isDouble()); | |
958 | double value = scrutinee.asDouble(); | |
959 | int32_t intValue = static_cast<int32_t>(value); | |
960 | int defaultOffset = pc[2].u.operand; | |
961 | if (value == intValue) { | |
962 | CodeBlock* codeBlock = exec->codeBlock(); | |
963 | pc += codeBlock->switchJumpTable(pc[1].u.operand).offsetForValue(intValue, defaultOffset); | |
964 | } else | |
965 | pc += defaultOffset; | |
966 | LLINT_END(); | |
967 | } | |
968 | ||
969 | LLINT_SLOW_PATH_DECL(slow_path_switch_char) | |
970 | { | |
971 | LLINT_BEGIN(); | |
972 | JSValue scrutinee = LLINT_OP_C(3).jsValue(); | |
973 | ASSERT(scrutinee.isString()); | |
974 | JSString* string = asString(scrutinee); | |
975 | ASSERT(string->length() == 1); | |
976 | int defaultOffset = pc[2].u.operand; | |
977 | StringImpl* impl = string->value(exec).impl(); | |
978 | CodeBlock* codeBlock = exec->codeBlock(); | |
979 | pc += codeBlock->switchJumpTable(pc[1].u.operand).offsetForValue((*impl)[0], defaultOffset); | |
980 | LLINT_END(); | |
981 | } | |
982 | ||
983 | LLINT_SLOW_PATH_DECL(slow_path_switch_string) | |
984 | { | |
985 | LLINT_BEGIN(); | |
986 | JSValue scrutinee = LLINT_OP_C(3).jsValue(); | |
987 | int defaultOffset = pc[2].u.operand; | |
988 | if (!scrutinee.isString()) | |
989 | pc += defaultOffset; | |
990 | else { | |
991 | CodeBlock* codeBlock = exec->codeBlock(); | |
992 | pc += codeBlock->stringSwitchJumpTable(pc[1].u.operand).offsetForValue(asString(scrutinee)->value(exec).impl(), defaultOffset); | |
993 | } | |
994 | LLINT_END(); | |
995 | } | |
996 | ||
997 | LLINT_SLOW_PATH_DECL(slow_path_new_func) | |
998 | { | |
999 | LLINT_BEGIN(); | |
1000 | CodeBlock* codeBlock = exec->codeBlock(); | |
1001 | ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsActivation() || exec->hasActivation()); | |
1002 | #if LLINT_SLOW_PATH_TRACING | |
1003 | dataLogF("Creating function!\n"); | |
1004 | #endif | |
1005 | LLINT_RETURN(JSFunction::create(vm, codeBlock->functionDecl(pc[2].u.operand), exec->scope())); | |
1006 | } | |
1007 | ||
1008 | LLINT_SLOW_PATH_DECL(slow_path_new_func_exp) | |
1009 | { | |
1010 | LLINT_BEGIN(); | |
1011 | CodeBlock* codeBlock = exec->codeBlock(); | |
1012 | FunctionExecutable* function = codeBlock->functionExpr(pc[2].u.operand); | |
1013 | JSFunction* func = JSFunction::create(vm, function, exec->scope()); | |
1014 | ||
1015 | LLINT_RETURN(func); | |
1016 | } | |
1017 | ||
1018 | static SlowPathReturnType handleHostCall(ExecState* execCallee, Instruction* pc, JSValue callee, CodeSpecializationKind kind) | |
1019 | { | |
1020 | UNUSED_PARAM(pc); | |
1021 | ||
1022 | #if LLINT_SLOW_PATH_TRACING | |
1023 | dataLog("Performing host call.\n"); | |
1024 | #endif | |
1025 | ||
1026 | ExecState* exec = execCallee->callerFrame(); | |
1027 | VM& vm = exec->vm(); | |
1028 | ||
1029 | execCallee->setScope(exec->scope()); | |
1030 | execCallee->setCodeBlock(0); | |
1031 | execCallee->clearReturnPC(); | |
1032 | ||
1033 | if (kind == CodeForCall) { | |
1034 | CallData callData; | |
1035 | CallType callType = getCallData(callee, callData); | |
1036 | ||
1037 | ASSERT(callType != CallTypeJS); | |
1038 | ||
1039 | if (callType == CallTypeHost) { | |
1040 | NativeCallFrameTracer tracer(&vm, execCallee); | |
1041 | execCallee->setCallee(asObject(callee)); | |
1042 | vm.hostCallReturnValue = JSValue::decode(callData.native.function(execCallee)); | |
1043 | ||
1044 | LLINT_CALL_RETURN(execCallee, LLInt::getCodePtr(getHostCallReturnValue)); | |
1045 | } | |
1046 | ||
1047 | #if LLINT_SLOW_PATH_TRACING | |
1048 | dataLog("Call callee is not a function: ", callee, "\n"); | |
1049 | #endif | |
1050 | ||
1051 | ASSERT(callType == CallTypeNone); | |
1052 | LLINT_CALL_THROW(exec, createNotAFunctionError(exec, callee)); | |
1053 | } | |
1054 | ||
1055 | ASSERT(kind == CodeForConstruct); | |
1056 | ||
1057 | ConstructData constructData; | |
1058 | ConstructType constructType = getConstructData(callee, constructData); | |
1059 | ||
1060 | ASSERT(constructType != ConstructTypeJS); | |
1061 | ||
1062 | if (constructType == ConstructTypeHost) { | |
1063 | NativeCallFrameTracer tracer(&vm, execCallee); | |
1064 | execCallee->setCallee(asObject(callee)); | |
1065 | vm.hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee)); | |
1066 | ||
1067 | LLINT_CALL_RETURN(execCallee, LLInt::getCodePtr(getHostCallReturnValue)); | |
1068 | } | |
1069 | ||
1070 | #if LLINT_SLOW_PATH_TRACING | |
1071 | dataLog("Constructor callee is not a function: ", callee, "\n"); | |
1072 | #endif | |
1073 | ||
1074 | ASSERT(constructType == ConstructTypeNone); | |
1075 | LLINT_CALL_THROW(exec, createNotAConstructorError(exec, callee)); | |
1076 | } | |
1077 | ||
1078 | inline SlowPathReturnType setUpCall(ExecState* execCallee, Instruction* pc, CodeSpecializationKind kind, JSValue calleeAsValue, LLIntCallLinkInfo* callLinkInfo = 0) | |
1079 | { | |
1080 | #if LLINT_SLOW_PATH_TRACING | |
1081 | dataLogF("Performing call with recorded PC = %p\n", execCallee->callerFrame()->currentVPC()); | |
1082 | #endif | |
1083 | ||
1084 | JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); | |
1085 | if (!calleeAsFunctionCell) | |
1086 | return handleHostCall(execCallee, pc, calleeAsValue, kind); | |
1087 | ||
1088 | JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); | |
1089 | JSScope* scope = callee->scopeUnchecked(); | |
1090 | VM& vm = *scope->vm(); | |
1091 | execCallee->setScope(scope); | |
1092 | ExecutableBase* executable = callee->executable(); | |
1093 | ||
1094 | MacroAssemblerCodePtr codePtr; | |
1095 | CodeBlock* codeBlock = 0; | |
1096 | if (executable->isHostFunction()) | |
1097 | codePtr = executable->entrypointFor(vm, kind, MustCheckArity, RegisterPreservationNotRequired); | |
1098 | else { | |
1099 | FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); | |
1100 | JSObject* error = functionExecutable->prepareForExecution(execCallee, callee, &scope, kind); | |
1101 | execCallee->setScope(scope); | |
1102 | if (error) | |
1103 | LLINT_CALL_THROW(execCallee->callerFrame(), error); | |
1104 | codeBlock = functionExecutable->codeBlockFor(kind); | |
1105 | ASSERT(codeBlock); | |
1106 | ArityCheckMode arity; | |
1107 | if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) | |
1108 | arity = MustCheckArity; | |
1109 | else | |
1110 | arity = ArityCheckNotRequired; | |
1111 | codePtr = functionExecutable->entrypointFor(vm, kind, arity, RegisterPreservationNotRequired); | |
1112 | } | |
1113 | ||
1114 | ASSERT(!!codePtr); | |
1115 | ||
1116 | if (!LLINT_ALWAYS_ACCESS_SLOW && callLinkInfo) { | |
1117 | ExecState* execCaller = execCallee->callerFrame(); | |
1118 | ||
1119 | CodeBlock* callerCodeBlock = execCaller->codeBlock(); | |
1120 | ||
1121 | ConcurrentJITLocker locker(callerCodeBlock->m_lock); | |
1122 | ||
1123 | if (callLinkInfo->isOnList()) | |
1124 | callLinkInfo->remove(); | |
1125 | callLinkInfo->callee.set(vm, callerCodeBlock->ownerExecutable(), callee); | |
1126 | callLinkInfo->lastSeenCallee.set(vm, callerCodeBlock->ownerExecutable(), callee); | |
1127 | callLinkInfo->machineCodeTarget = codePtr; | |
1128 | if (codeBlock) | |
1129 | codeBlock->linkIncomingCall(execCaller, callLinkInfo); | |
1130 | } | |
1131 | ||
1132 | LLINT_CALL_RETURN(execCallee, codePtr.executableAddress()); | |
1133 | } | |
1134 | ||
1135 | inline SlowPathReturnType genericCall(ExecState* exec, Instruction* pc, CodeSpecializationKind kind) | |
1136 | { | |
1137 | // This needs to: | |
1138 | // - Set up a call frame. | |
1139 | // - Figure out what to call and compile it if necessary. | |
1140 | // - If possible, link the call's inline cache. | |
1141 | // - Return a tuple of machine code address to call and the new call frame. | |
1142 | ||
1143 | JSValue calleeAsValue = LLINT_OP_C(2).jsValue(); | |
1144 | ||
1145 | ExecState* execCallee = exec - pc[4].u.operand; | |
1146 | ||
1147 | execCallee->setArgumentCountIncludingThis(pc[3].u.operand); | |
1148 | execCallee->uncheckedR(JSStack::Callee) = calleeAsValue; | |
1149 | execCallee->setCallerFrame(exec); | |
1150 | ||
1151 | ASSERT(pc[5].u.callLinkInfo); | |
1152 | return setUpCall(execCallee, pc, kind, calleeAsValue, pc[5].u.callLinkInfo); | |
1153 | } | |
1154 | ||
1155 | LLINT_SLOW_PATH_DECL(slow_path_call) | |
1156 | { | |
1157 | LLINT_BEGIN_NO_SET_PC(); | |
1158 | return genericCall(exec, pc, CodeForCall); | |
1159 | } | |
1160 | ||
1161 | LLINT_SLOW_PATH_DECL(slow_path_construct) | |
1162 | { | |
1163 | LLINT_BEGIN_NO_SET_PC(); | |
1164 | return genericCall(exec, pc, CodeForConstruct); | |
1165 | } | |
1166 | ||
1167 | LLINT_SLOW_PATH_DECL(slow_path_size_frame_for_varargs) | |
1168 | { | |
1169 | LLINT_BEGIN(); | |
1170 | // This needs to: | |
1171 | // - Set up a call frame while respecting the variable arguments. | |
1172 | ||
1173 | ExecState* execCallee = sizeFrameForVarargs(exec, &vm.interpreter->stack(), | |
1174 | LLINT_OP_C(4).jsValue(), pc[5].u.operand, pc[6].u.operand); | |
1175 | LLINT_CALL_CHECK_EXCEPTION(exec); | |
1176 | ||
1177 | vm.newCallFrameReturnValue = execCallee; | |
1178 | ||
1179 | LLINT_RETURN_CALLEE_FRAME(execCallee); | |
1180 | } | |
1181 | ||
1182 | LLINT_SLOW_PATH_DECL(slow_path_call_varargs) | |
1183 | { | |
1184 | LLINT_BEGIN_NO_SET_PC(); | |
1185 | // This needs to: | |
1186 | // - Figure out what to call and compile it if necessary. | |
1187 | // - Return a tuple of machine code address to call and the new call frame. | |
1188 | ||
1189 | JSValue calleeAsValue = LLINT_OP_C(2).jsValue(); | |
1190 | ||
1191 | ExecState* execCallee = vm.newCallFrameReturnValue; | |
1192 | ||
1193 | loadVarargs(exec, execCallee, LLINT_OP_C(3).jsValue(), LLINT_OP_C(4).jsValue(), pc[6].u.operand); | |
1194 | LLINT_CALL_CHECK_EXCEPTION(exec); | |
1195 | ||
1196 | execCallee->uncheckedR(JSStack::Callee) = calleeAsValue; | |
1197 | execCallee->setCallerFrame(exec); | |
1198 | exec->setCurrentVPC(pc); | |
1199 | ||
1200 | return setUpCall(execCallee, pc, CodeForCall, calleeAsValue); | |
1201 | } | |
1202 | ||
1203 | LLINT_SLOW_PATH_DECL(slow_path_construct_varargs) | |
1204 | { | |
1205 | LLINT_BEGIN_NO_SET_PC(); | |
1206 | // This needs to: | |
1207 | // - Figure out what to call and compile it if necessary. | |
1208 | // - Return a tuple of machine code address to call and the new call frame. | |
1209 | ||
1210 | JSValue calleeAsValue = LLINT_OP_C(2).jsValue(); | |
1211 | ||
1212 | ExecState* execCallee = vm.newCallFrameReturnValue; | |
1213 | ||
1214 | loadVarargs(exec, execCallee, LLINT_OP_C(3).jsValue(), LLINT_OP_C(4).jsValue(), pc[6].u.operand); | |
1215 | LLINT_CALL_CHECK_EXCEPTION(exec); | |
1216 | ||
1217 | execCallee->uncheckedR(JSStack::Callee) = calleeAsValue; | |
1218 | execCallee->setCallerFrame(exec); | |
1219 | exec->setCurrentVPC(pc); | |
1220 | ||
1221 | return setUpCall(execCallee, pc, CodeForConstruct, calleeAsValue); | |
1222 | } | |
1223 | ||
1224 | LLINT_SLOW_PATH_DECL(slow_path_call_eval) | |
1225 | { | |
1226 | LLINT_BEGIN_NO_SET_PC(); | |
1227 | JSValue calleeAsValue = LLINT_OP(2).jsValue(); | |
1228 | ||
1229 | ExecState* execCallee = exec - pc[4].u.operand; | |
1230 | ||
1231 | execCallee->setArgumentCountIncludingThis(pc[3].u.operand); | |
1232 | execCallee->setCallerFrame(exec); | |
1233 | execCallee->uncheckedR(JSStack::Callee) = calleeAsValue; | |
1234 | execCallee->setScope(exec->scope()); | |
1235 | execCallee->setReturnPC(LLInt::getCodePtr(llint_generic_return_point)); | |
1236 | execCallee->setCodeBlock(0); | |
1237 | exec->setCurrentVPC(pc); | |
1238 | ||
1239 | if (!isHostFunction(calleeAsValue, globalFuncEval)) | |
1240 | return setUpCall(execCallee, pc, CodeForCall, calleeAsValue); | |
1241 | ||
1242 | vm.hostCallReturnValue = eval(execCallee); | |
1243 | LLINT_CALL_RETURN(execCallee, LLInt::getCodePtr(getHostCallReturnValue)); | |
1244 | } | |
1245 | ||
1246 | LLINT_SLOW_PATH_DECL(slow_path_tear_off_activation) | |
1247 | { | |
1248 | LLINT_BEGIN(); | |
1249 | ASSERT(exec->codeBlock()->needsActivation()); | |
1250 | jsCast<JSActivation*>(LLINT_OP(1).jsValue())->tearOff(vm); | |
1251 | LLINT_END(); | |
1252 | } | |
1253 | ||
1254 | LLINT_SLOW_PATH_DECL(slow_path_tear_off_arguments) | |
1255 | { | |
1256 | LLINT_BEGIN(); | |
1257 | ASSERT(exec->codeBlock()->usesArguments()); | |
1258 | Arguments* arguments = jsCast<Arguments*>(exec->uncheckedR(unmodifiedArgumentsRegister(VirtualRegister(pc[1].u.operand)).offset()).jsValue()); | |
1259 | if (JSValue activationValue = LLINT_OP_C(2).jsValue()) | |
1260 | arguments->didTearOffActivation(exec, jsCast<JSActivation*>(activationValue)); | |
1261 | else | |
1262 | arguments->tearOff(exec); | |
1263 | LLINT_END(); | |
1264 | } | |
1265 | ||
1266 | LLINT_SLOW_PATH_DECL(slow_path_strcat) | |
1267 | { | |
1268 | LLINT_BEGIN(); | |
1269 | LLINT_RETURN(jsStringFromRegisterArray(exec, &LLINT_OP(2), pc[3].u.operand)); | |
1270 | } | |
1271 | ||
1272 | LLINT_SLOW_PATH_DECL(slow_path_to_primitive) | |
1273 | { | |
1274 | LLINT_BEGIN(); | |
1275 | LLINT_RETURN(LLINT_OP_C(2).jsValue().toPrimitive(exec)); | |
1276 | } | |
1277 | ||
1278 | LLINT_SLOW_PATH_DECL(slow_path_get_pnames) | |
1279 | { | |
1280 | LLINT_BEGIN(); | |
1281 | JSValue v = LLINT_OP(2).jsValue(); | |
1282 | if (v.isUndefinedOrNull()) { | |
1283 | pc += pc[5].u.operand; | |
1284 | LLINT_END(); | |
1285 | } | |
1286 | ||
1287 | JSObject* o = v.toObject(exec); | |
1288 | Structure* structure = o->structure(); | |
1289 | JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache(); | |
1290 | if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(exec)) | |
1291 | jsPropertyNameIterator = JSPropertyNameIterator::create(exec, o); | |
1292 | ||
1293 | LLINT_OP(1) = JSValue(jsPropertyNameIterator); | |
1294 | LLINT_OP(2) = JSValue(o); | |
1295 | LLINT_OP(3) = Register::withInt(0); | |
1296 | LLINT_OP(4) = Register::withInt(jsPropertyNameIterator->size()); | |
1297 | ||
1298 | pc += OPCODE_LENGTH(op_get_pnames); | |
1299 | LLINT_END(); | |
1300 | } | |
1301 | ||
1302 | LLINT_SLOW_PATH_DECL(slow_path_next_pname) | |
1303 | { | |
1304 | LLINT_BEGIN(); | |
1305 | JSObject* base = asObject(LLINT_OP(2).jsValue()); | |
1306 | JSString* property = asString(LLINT_OP(1).jsValue()); | |
1307 | if (base->hasProperty(exec, Identifier(exec, property->value(exec)))) { | |
1308 | // Go to target. | |
1309 | pc += pc[6].u.operand; | |
1310 | } // Else, don't change the PC, so the interpreter will reloop. | |
1311 | LLINT_END(); | |
1312 | } | |
1313 | ||
1314 | LLINT_SLOW_PATH_DECL(slow_path_push_with_scope) | |
1315 | { | |
1316 | LLINT_BEGIN(); | |
1317 | JSValue v = LLINT_OP_C(1).jsValue(); | |
1318 | JSObject* o = v.toObject(exec); | |
1319 | LLINT_CHECK_EXCEPTION(); | |
1320 | ||
1321 | exec->setScope(JSWithScope::create(exec, o)); | |
1322 | ||
1323 | LLINT_END(); | |
1324 | } | |
1325 | ||
1326 | LLINT_SLOW_PATH_DECL(slow_path_pop_scope) | |
1327 | { | |
1328 | LLINT_BEGIN(); | |
1329 | exec->setScope(exec->scope()->next()); | |
1330 | LLINT_END(); | |
1331 | } | |
1332 | ||
1333 | LLINT_SLOW_PATH_DECL(slow_path_push_name_scope) | |
1334 | { | |
1335 | LLINT_BEGIN(); | |
1336 | CodeBlock* codeBlock = exec->codeBlock(); | |
1337 | JSNameScope* scope = JSNameScope::create(exec, codeBlock->identifier(pc[1].u.operand), LLINT_OP(2).jsValue(), pc[3].u.operand); | |
1338 | exec->setScope(scope); | |
1339 | LLINT_END(); | |
1340 | } | |
1341 | ||
1342 | LLINT_SLOW_PATH_DECL(slow_path_throw) | |
1343 | { | |
1344 | LLINT_BEGIN(); | |
1345 | LLINT_THROW(LLINT_OP_C(1).jsValue()); | |
1346 | } | |
1347 | ||
1348 | LLINT_SLOW_PATH_DECL(slow_path_throw_static_error) | |
1349 | { | |
1350 | LLINT_BEGIN(); | |
1351 | if (pc[2].u.operand) | |
1352 | LLINT_THROW(createReferenceError(exec, errorDescriptionForValue(exec, LLINT_OP_C(1).jsValue())->value(exec))); | |
1353 | else | |
1354 | LLINT_THROW(createTypeError(exec, errorDescriptionForValue(exec, LLINT_OP_C(1).jsValue())->value(exec))); | |
1355 | } | |
1356 | ||
1357 | LLINT_SLOW_PATH_DECL(slow_path_handle_watchdog_timer) | |
1358 | { | |
1359 | LLINT_BEGIN_NO_SET_PC(); | |
1360 | ASSERT(vm.watchdog); | |
1361 | if (UNLIKELY(vm.watchdog->didFire(exec))) | |
1362 | LLINT_THROW(createTerminatedExecutionException(&vm)); | |
1363 | LLINT_RETURN_TWO(0, exec); | |
1364 | } | |
1365 | ||
1366 | LLINT_SLOW_PATH_DECL(slow_path_debug) | |
1367 | { | |
1368 | LLINT_BEGIN(); | |
1369 | int debugHookID = pc[1].u.operand; | |
1370 | vm.interpreter->debug(exec, static_cast<DebugHookID>(debugHookID)); | |
1371 | ||
1372 | LLINT_END(); | |
1373 | } | |
1374 | ||
1375 | LLINT_SLOW_PATH_DECL(slow_path_profile_will_call) | |
1376 | { | |
1377 | LLINT_BEGIN(); | |
1378 | if (LegacyProfiler* profiler = vm.enabledProfiler()) | |
1379 | profiler->willExecute(exec, LLINT_OP(1).jsValue()); | |
1380 | LLINT_END(); | |
1381 | } | |
1382 | ||
1383 | LLINT_SLOW_PATH_DECL(slow_path_profile_did_call) | |
1384 | { | |
1385 | LLINT_BEGIN(); | |
1386 | if (LegacyProfiler* profiler = vm.enabledProfiler()) | |
1387 | profiler->didExecute(exec, LLINT_OP(1).jsValue()); | |
1388 | LLINT_END(); | |
1389 | } | |
1390 | ||
1391 | LLINT_SLOW_PATH_DECL(slow_path_handle_exception) | |
1392 | { | |
1393 | LLINT_BEGIN_NO_SET_PC(); | |
1394 | ASSERT(vm.exception()); | |
1395 | genericUnwind(&vm, exec, vm.exception()); | |
1396 | LLINT_END_IMPL(); | |
1397 | } | |
1398 | ||
1399 | LLINT_SLOW_PATH_DECL(slow_path_resolve_scope) | |
1400 | { | |
1401 | LLINT_BEGIN(); | |
1402 | const Identifier& ident = exec->codeBlock()->identifier(pc[2].u.operand); | |
1403 | LLINT_RETURN(JSScope::resolve(exec, exec->scope(), ident)); | |
1404 | } | |
1405 | ||
1406 | LLINT_SLOW_PATH_DECL(slow_path_get_from_scope) | |
1407 | { | |
1408 | LLINT_BEGIN(); | |
1409 | const Identifier& ident = exec->codeBlock()->identifier(pc[3].u.operand); | |
1410 | JSObject* scope = jsCast<JSObject*>(LLINT_OP(2).jsValue()); | |
1411 | ResolveModeAndType modeAndType(pc[4].u.operand); | |
1412 | ||
1413 | PropertySlot slot(scope); | |
1414 | if (!scope->getPropertySlot(exec, ident, slot)) { | |
1415 | if (modeAndType.mode() == ThrowIfNotFound) | |
1416 | LLINT_RETURN(exec->vm().throwException(exec, createUndefinedVariableError(exec, ident))); | |
1417 | LLINT_RETURN(jsUndefined()); | |
1418 | } | |
1419 | ||
1420 | // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time. | |
1421 | if (slot.isCacheableValue() && slot.slotBase() == scope && scope->structure()->propertyAccessesAreCacheable()) { | |
1422 | if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) { | |
1423 | CodeBlock* codeBlock = exec->codeBlock(); | |
1424 | ConcurrentJITLocker locker(codeBlock->m_lock); | |
1425 | pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure()); | |
1426 | pc[6].u.operand = slot.cachedOffset(); | |
1427 | } | |
1428 | } | |
1429 | ||
1430 | LLINT_RETURN(slot.getValue(exec, ident)); | |
1431 | } | |
1432 | ||
1433 | LLINT_SLOW_PATH_DECL(slow_path_put_to_scope) | |
1434 | { | |
1435 | LLINT_BEGIN(); | |
1436 | CodeBlock* codeBlock = exec->codeBlock(); | |
1437 | const Identifier& ident = codeBlock->identifier(pc[2].u.operand); | |
1438 | JSObject* scope = jsCast<JSObject*>(LLINT_OP(1).jsValue()); | |
1439 | JSValue value = LLINT_OP_C(3).jsValue(); | |
1440 | ResolveModeAndType modeAndType = ResolveModeAndType(pc[4].u.operand); | |
1441 | ||
1442 | if (modeAndType.mode() == ThrowIfNotFound && !scope->hasProperty(exec, ident)) | |
1443 | LLINT_THROW(createUndefinedVariableError(exec, ident)); | |
1444 | ||
1445 | PutPropertySlot slot(scope, codeBlock->isStrictMode()); | |
1446 | scope->methodTable()->put(scope, exec, ident, value, slot); | |
1447 | ||
1448 | // Covers implicit globals. Since they don't exist until they first execute, we didn't know how to cache them at compile time. | |
1449 | if (modeAndType.type() == GlobalProperty || modeAndType.type() == GlobalPropertyWithVarInjectionChecks) { | |
1450 | if (slot.isCacheablePut() && slot.base() == scope && scope->structure()->propertyAccessesAreCacheable()) { | |
1451 | ConcurrentJITLocker locker(codeBlock->m_lock); | |
1452 | pc[5].u.structure.set(exec->vm(), codeBlock->ownerExecutable(), scope->structure()); | |
1453 | pc[6].u.operand = slot.cachedOffset(); | |
1454 | } | |
1455 | } | |
1456 | ||
1457 | LLINT_END(); | |
1458 | } | |
1459 | ||
1460 | extern "C" SlowPathReturnType llint_throw_stack_overflow_error(VM* vm, ProtoCallFrame* protoFrame) | |
1461 | { | |
1462 | ExecState* exec = vm->topCallFrame; | |
1463 | if (!exec) | |
1464 | exec = protoFrame->scope()->globalObject()->globalExec(); | |
1465 | throwStackOverflowError(exec); | |
1466 | return encodeResult(0, 0); | |
1467 | } | |
1468 | ||
1469 | #if !ENABLE(JIT) | |
1470 | extern "C" SlowPathReturnType llint_stack_check_at_vm_entry(VM* vm, Register* newTopOfStack) | |
1471 | { | |
1472 | bool success = vm->interpreter->stack().ensureCapacityFor(newTopOfStack); | |
1473 | return encodeResult(reinterpret_cast<void*>(success), 0); | |
1474 | } | |
1475 | #endif | |
1476 | ||
1477 | extern "C" void llint_write_barrier_slow(ExecState* exec, JSCell* cell) | |
1478 | { | |
1479 | VM& vm = exec->vm(); | |
1480 | vm.heap.writeBarrier(cell); | |
1481 | } | |
1482 | ||
1483 | extern "C" NO_RETURN_DUE_TO_CRASH void llint_crash() | |
1484 | { | |
1485 | CRASH(); | |
1486 | } | |
1487 | ||
1488 | } } // namespace JSC::LLInt |