]>
Commit | Line | Data |
---|---|---|
6fe7ccc8 | 1 | /* |
93a37866 | 2 | * Copyright (C) 2011, 2012, 2013 Apple Inc. All rights reserved. |
6fe7ccc8 A |
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 | ||
29 | #if ENABLE(LLINT) | |
30 | ||
31 | #include "Arguments.h" | |
93a37866 | 32 | #include "ArrayConstructor.h" |
6fe7ccc8 A |
33 | #include "CallFrame.h" |
34 | #include "CommonSlowPaths.h" | |
35 | #include "GetterSetter.h" | |
36 | #include "HostCallReturnValue.h" | |
37 | #include "Interpreter.h" | |
38 | #include "JIT.h" | |
39 | #include "JITDriver.h" | |
40 | #include "JSActivation.h" | |
93a37866 | 41 | #include "JSCJSValue.h" |
6fe7ccc8 | 42 | #include "JSGlobalObjectFunctions.h" |
93a37866 | 43 | #include "JSNameScope.h" |
6fe7ccc8 | 44 | #include "JSPropertyNameIterator.h" |
6fe7ccc8 | 45 | #include "JSString.h" |
93a37866 | 46 | #include "JSWithScope.h" |
6fe7ccc8 A |
47 | #include "LLIntCommon.h" |
48 | #include "LLIntExceptions.h" | |
49 | #include "LowLevelInterpreter.h" | |
93a37866 | 50 | #include "ObjectConstructor.h" |
6fe7ccc8 | 51 | #include "Operations.h" |
93a37866 A |
52 | #include "StructureRareDataInlines.h" |
53 | #include <wtf/StringPrintStream.h> | |
6fe7ccc8 A |
54 | |
55 | namespace JSC { namespace LLInt { | |
56 | ||
57 | #define LLINT_BEGIN_NO_SET_PC() \ | |
93a37866 A |
58 | VM& vm = exec->vm(); \ |
59 | NativeCallFrameTracer tracer(&vm, exec) | |
6fe7ccc8 A |
60 | |
61 | #ifndef NDEBUG | |
62 | #define LLINT_SET_PC_FOR_STUBS() do { \ | |
63 | exec->codeBlock()->bytecodeOffset(pc); \ | |
64 | exec->setCurrentVPC(pc + 1); \ | |
65 | } while (false) | |
66 | #else | |
67 | #define LLINT_SET_PC_FOR_STUBS() do { \ | |
68 | exec->setCurrentVPC(pc + 1); \ | |
69 | } while (false) | |
70 | #endif | |
71 | ||
72 | #define LLINT_BEGIN() \ | |
73 | LLINT_BEGIN_NO_SET_PC(); \ | |
74 | LLINT_SET_PC_FOR_STUBS() | |
75 | ||
76 | #define LLINT_OP(index) (exec->uncheckedR(pc[index].u.operand)) | |
77 | #define LLINT_OP_C(index) (exec->r(pc[index].u.operand)) | |
78 | ||
79 | #define LLINT_RETURN_TWO(first, second) do { \ | |
80 | return encodeResult(first, second); \ | |
81 | } while (false) | |
82 | ||
83 | #define LLINT_END_IMPL() LLINT_RETURN_TWO(pc, exec) | |
84 | ||
85 | #define LLINT_THROW(exceptionToThrow) do { \ | |
93a37866 | 86 | vm.exception = (exceptionToThrow); \ |
6fe7ccc8 A |
87 | pc = returnToThrow(exec, pc); \ |
88 | LLINT_END_IMPL(); \ | |
89 | } while (false) | |
90 | ||
91 | #define LLINT_CHECK_EXCEPTION() do { \ | |
93a37866 | 92 | if (UNLIKELY(vm.exception)) { \ |
6fe7ccc8 A |
93 | pc = returnToThrow(exec, pc); \ |
94 | LLINT_END_IMPL(); \ | |
95 | } \ | |
96 | } while (false) | |
97 | ||
98 | #define LLINT_END() do { \ | |
99 | LLINT_CHECK_EXCEPTION(); \ | |
100 | LLINT_END_IMPL(); \ | |
101 | } while (false) | |
102 | ||
103 | #define LLINT_BRANCH(opcode, condition) do { \ | |
104 | bool __b_condition = (condition); \ | |
105 | LLINT_CHECK_EXCEPTION(); \ | |
106 | if (__b_condition) \ | |
107 | pc += pc[OPCODE_LENGTH(opcode) - 1].u.operand; \ | |
108 | else \ | |
109 | pc += OPCODE_LENGTH(opcode); \ | |
110 | LLINT_END_IMPL(); \ | |
111 | } while (false) | |
112 | ||
113 | #define LLINT_RETURN(value) do { \ | |
114 | JSValue __r_returnValue = (value); \ | |
115 | LLINT_CHECK_EXCEPTION(); \ | |
116 | LLINT_OP(1) = __r_returnValue; \ | |
117 | LLINT_END_IMPL(); \ | |
118 | } while (false) | |
119 | ||
120 | #if ENABLE(VALUE_PROFILER) | |
121 | #define LLINT_RETURN_PROFILED(opcode, value) do { \ | |
122 | JSValue __rp_returnValue = (value); \ | |
123 | LLINT_CHECK_EXCEPTION(); \ | |
124 | LLINT_OP(1) = __rp_returnValue; \ | |
93a37866 | 125 | LLINT_PROFILE_VALUE(opcode, __rp_returnValue); \ |
6fe7ccc8 A |
126 | LLINT_END_IMPL(); \ |
127 | } while (false) | |
93a37866 A |
128 | |
129 | #define LLINT_PROFILE_VALUE(opcode, value) do { \ | |
130 | pc[OPCODE_LENGTH(opcode) - 1].u.profile->m_buckets[0] = \ | |
131 | JSValue::encode(value); \ | |
132 | } while (false) | |
133 | ||
6fe7ccc8 A |
134 | #else // ENABLE(VALUE_PROFILER) |
135 | #define LLINT_RETURN_PROFILED(opcode, value) LLINT_RETURN(value) | |
93a37866 A |
136 | |
137 | #define LLINT_PROFILE_VALUE(opcode, value) do { } while (false) | |
138 | ||
6fe7ccc8 A |
139 | #endif // ENABLE(VALUE_PROFILER) |
140 | ||
141 | #define LLINT_CALL_END_IMPL(exec, callTarget) LLINT_RETURN_TWO((callTarget), (exec)) | |
142 | ||
143 | #define LLINT_CALL_THROW(exec, pc, exceptionToThrow) do { \ | |
144 | ExecState* __ct_exec = (exec); \ | |
145 | Instruction* __ct_pc = (pc); \ | |
93a37866 | 146 | vm.exception = (exceptionToThrow); \ |
6fe7ccc8 A |
147 | LLINT_CALL_END_IMPL(__ct_exec, callToThrow(__ct_exec, __ct_pc)); \ |
148 | } while (false) | |
149 | ||
150 | #define LLINT_CALL_CHECK_EXCEPTION(exec, pc) do { \ | |
151 | ExecState* __cce_exec = (exec); \ | |
152 | Instruction* __cce_pc = (pc); \ | |
93a37866 | 153 | if (UNLIKELY(vm.exception)) \ |
6fe7ccc8 A |
154 | LLINT_CALL_END_IMPL(__cce_exec, callToThrow(__cce_exec, __cce_pc)); \ |
155 | } while (false) | |
156 | ||
157 | #define LLINT_CALL_RETURN(exec, pc, callTarget) do { \ | |
158 | ExecState* __cr_exec = (exec); \ | |
159 | Instruction* __cr_pc = (pc); \ | |
160 | void* __cr_callTarget = (callTarget); \ | |
161 | LLINT_CALL_CHECK_EXCEPTION(__cr_exec->callerFrame(), __cr_pc); \ | |
162 | LLINT_CALL_END_IMPL(__cr_exec, __cr_callTarget); \ | |
163 | } while (false) | |
164 | ||
165 | extern "C" SlowPathReturnType llint_trace_operand(ExecState* exec, Instruction* pc, int fromWhere, int operand) | |
166 | { | |
167 | LLINT_BEGIN(); | |
93a37866 | 168 | dataLogF("%p / %p: executing bc#%zu, op#%u: Trace(%d): %d: %d\n", |
6fe7ccc8 A |
169 | exec->codeBlock(), |
170 | exec, | |
171 | static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()), | |
93a37866 | 172 | exec->vm().interpreter->getOpcodeID(pc[0].u.opcode), |
6fe7ccc8 A |
173 | fromWhere, |
174 | operand, | |
175 | pc[operand].u.operand); | |
176 | LLINT_END(); | |
177 | } | |
178 | ||
179 | extern "C" SlowPathReturnType llint_trace_value(ExecState* exec, Instruction* pc, int fromWhere, int operand) | |
180 | { | |
181 | JSValue value = LLINT_OP_C(operand).jsValue(); | |
182 | union { | |
183 | struct { | |
184 | uint32_t tag; | |
185 | uint32_t payload; | |
186 | } bits; | |
187 | EncodedJSValue asValue; | |
188 | } u; | |
189 | u.asValue = JSValue::encode(value); | |
93a37866 A |
190 | dataLogF( |
191 | "%p / %p: executing bc#%zu, op#%u: Trace(%d): %d: %d: %08x:%08x: %s\n", | |
192 | exec->codeBlock(), | |
193 | exec, | |
194 | static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()), | |
195 | exec->vm().interpreter->getOpcodeID(pc[0].u.opcode), | |
196 | fromWhere, | |
197 | operand, | |
198 | pc[operand].u.operand, | |
199 | u.bits.tag, | |
200 | u.bits.payload, | |
201 | toCString(value).data()); | |
6fe7ccc8 A |
202 | LLINT_END_IMPL(); |
203 | } | |
204 | ||
205 | LLINT_SLOW_PATH_DECL(trace_prologue) | |
206 | { | |
93a37866 | 207 | dataLogF("%p / %p: in prologue.\n", exec->codeBlock(), exec); |
6fe7ccc8 A |
208 | LLINT_END_IMPL(); |
209 | } | |
210 | ||
211 | static void traceFunctionPrologue(ExecState* exec, const char* comment, CodeSpecializationKind kind) | |
212 | { | |
213 | JSFunction* callee = jsCast<JSFunction*>(exec->callee()); | |
214 | FunctionExecutable* executable = callee->jsExecutable(); | |
215 | CodeBlock* codeBlock = &executable->generatedBytecodeFor(kind); | |
93a37866 | 216 | dataLogF("%p / %p: in %s of function %p, executable %p; numVars = %u, numParameters = %u, numCalleeRegisters = %u, caller = %p.\n", |
6fe7ccc8 A |
217 | codeBlock, exec, comment, callee, executable, |
218 | codeBlock->m_numVars, codeBlock->numParameters(), codeBlock->m_numCalleeRegisters, | |
219 | exec->callerFrame()); | |
220 | } | |
221 | ||
222 | LLINT_SLOW_PATH_DECL(trace_prologue_function_for_call) | |
223 | { | |
224 | traceFunctionPrologue(exec, "call prologue", CodeForCall); | |
225 | LLINT_END_IMPL(); | |
226 | } | |
227 | ||
228 | LLINT_SLOW_PATH_DECL(trace_prologue_function_for_construct) | |
229 | { | |
230 | traceFunctionPrologue(exec, "construct prologue", CodeForConstruct); | |
231 | LLINT_END_IMPL(); | |
232 | } | |
233 | ||
234 | LLINT_SLOW_PATH_DECL(trace_arityCheck_for_call) | |
235 | { | |
236 | traceFunctionPrologue(exec, "call arity check", CodeForCall); | |
237 | LLINT_END_IMPL(); | |
238 | } | |
239 | ||
240 | LLINT_SLOW_PATH_DECL(trace_arityCheck_for_construct) | |
241 | { | |
242 | traceFunctionPrologue(exec, "construct arity check", CodeForConstruct); | |
243 | LLINT_END_IMPL(); | |
244 | } | |
245 | ||
246 | LLINT_SLOW_PATH_DECL(trace) | |
247 | { | |
93a37866 | 248 | dataLogF("%p / %p: executing bc#%zu, %s, scope %p\n", |
6fe7ccc8 A |
249 | exec->codeBlock(), |
250 | exec, | |
251 | static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()), | |
93a37866 A |
252 | opcodeNames[exec->vm().interpreter->getOpcodeID(pc[0].u.opcode)], |
253 | exec->scope()); | |
254 | if (exec->vm().interpreter->getOpcodeID(pc[0].u.opcode) == op_ret) { | |
255 | dataLogF("Will be returning to %p\n", exec->returnPC().value()); | |
256 | dataLogF("The new cfr will be %p\n", exec->callerFrame()); | |
6fe7ccc8 A |
257 | } |
258 | LLINT_END_IMPL(); | |
259 | } | |
260 | ||
261 | LLINT_SLOW_PATH_DECL(special_trace) | |
262 | { | |
93a37866 | 263 | dataLogF("%p / %p: executing special case bc#%zu, op#%u, return PC is %p\n", |
6fe7ccc8 A |
264 | exec->codeBlock(), |
265 | exec, | |
266 | static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()), | |
93a37866 | 267 | exec->vm().interpreter->getOpcodeID(pc[0].u.opcode), |
6fe7ccc8 A |
268 | exec->returnPC().value()); |
269 | LLINT_END_IMPL(); | |
270 | } | |
271 | ||
93a37866 | 272 | #if ENABLE(JIT) |
6fe7ccc8 A |
273 | inline bool shouldJIT(ExecState* exec) |
274 | { | |
275 | // You can modify this to turn off JITting without rebuilding the world. | |
93a37866 | 276 | return exec->vm().canUseJIT(); |
6fe7ccc8 A |
277 | } |
278 | ||
279 | // Returns true if we should try to OSR. | |
280 | inline bool jitCompileAndSetHeuristics(CodeBlock* codeBlock, ExecState* exec) | |
281 | { | |
93a37866 A |
282 | codeBlock->updateAllValueProfilePredictions(); |
283 | ||
6fe7ccc8 A |
284 | if (!codeBlock->checkIfJITThresholdReached()) { |
285 | #if ENABLE(JIT_VERBOSE_OSR) | |
93a37866 | 286 | dataLogF(" JIT threshold should be lifted.\n"); |
6fe7ccc8 A |
287 | #endif |
288 | return false; | |
289 | } | |
290 | ||
93a37866 | 291 | CodeBlock::JITCompilationResult result = codeBlock->jitCompile(exec); |
6fe7ccc8 A |
292 | switch (result) { |
293 | case CodeBlock::AlreadyCompiled: | |
294 | #if ENABLE(JIT_VERBOSE_OSR) | |
93a37866 | 295 | dataLogF(" Code was already compiled.\n"); |
6fe7ccc8 A |
296 | #endif |
297 | codeBlock->jitSoon(); | |
298 | return true; | |
299 | case CodeBlock::CouldNotCompile: | |
300 | #if ENABLE(JIT_VERBOSE_OSR) | |
93a37866 | 301 | dataLogF(" JIT compilation failed.\n"); |
6fe7ccc8 A |
302 | #endif |
303 | codeBlock->dontJITAnytimeSoon(); | |
304 | return false; | |
305 | case CodeBlock::CompiledSuccessfully: | |
306 | #if ENABLE(JIT_VERBOSE_OSR) | |
93a37866 | 307 | dataLogF(" JIT compilation successful.\n"); |
6fe7ccc8 A |
308 | #endif |
309 | codeBlock->jitSoon(); | |
310 | return true; | |
311 | } | |
93a37866 | 312 | RELEASE_ASSERT_NOT_REACHED(); |
6fe7ccc8 A |
313 | return false; |
314 | } | |
315 | ||
316 | enum EntryKind { Prologue, ArityCheck }; | |
93a37866 | 317 | static SlowPathReturnType entryOSR(ExecState* exec, Instruction*, CodeBlock* codeBlock, const char *name, EntryKind kind) |
6fe7ccc8 A |
318 | { |
319 | #if ENABLE(JIT_VERBOSE_OSR) | |
93a37866 A |
320 | dataLog(*codeBlock, ": Entered ", name, " with executeCounter = ", codeBlock->llintExecuteCounter(), "\n"); |
321 | #else | |
322 | UNUSED_PARAM(name); | |
6fe7ccc8 A |
323 | #endif |
324 | ||
325 | if (!shouldJIT(exec)) { | |
326 | codeBlock->dontJITAnytimeSoon(); | |
327 | LLINT_RETURN_TWO(0, exec); | |
328 | } | |
329 | if (!jitCompileAndSetHeuristics(codeBlock, exec)) | |
330 | LLINT_RETURN_TWO(0, exec); | |
331 | ||
332 | if (kind == Prologue) | |
333 | LLINT_RETURN_TWO(codeBlock->getJITCode().executableAddressAtOffset(0), exec); | |
334 | ASSERT(kind == ArityCheck); | |
335 | LLINT_RETURN_TWO(codeBlock->getJITCodeWithArityCheck().executableAddress(), exec); | |
336 | } | |
337 | ||
338 | LLINT_SLOW_PATH_DECL(entry_osr) | |
339 | { | |
340 | return entryOSR(exec, pc, exec->codeBlock(), "entry_osr", Prologue); | |
341 | } | |
342 | ||
343 | LLINT_SLOW_PATH_DECL(entry_osr_function_for_call) | |
344 | { | |
345 | return entryOSR(exec, pc, &jsCast<JSFunction*>(exec->callee())->jsExecutable()->generatedBytecodeFor(CodeForCall), "entry_osr_function_for_call", Prologue); | |
346 | } | |
347 | ||
348 | LLINT_SLOW_PATH_DECL(entry_osr_function_for_construct) | |
349 | { | |
350 | return entryOSR(exec, pc, &jsCast<JSFunction*>(exec->callee())->jsExecutable()->generatedBytecodeFor(CodeForConstruct), "entry_osr_function_for_construct", Prologue); | |
351 | } | |
352 | ||
353 | LLINT_SLOW_PATH_DECL(entry_osr_function_for_call_arityCheck) | |
354 | { | |
355 | return entryOSR(exec, pc, &jsCast<JSFunction*>(exec->callee())->jsExecutable()->generatedBytecodeFor(CodeForCall), "entry_osr_function_for_call_arityCheck", ArityCheck); | |
356 | } | |
357 | ||
358 | LLINT_SLOW_PATH_DECL(entry_osr_function_for_construct_arityCheck) | |
359 | { | |
360 | return entryOSR(exec, pc, &jsCast<JSFunction*>(exec->callee())->jsExecutable()->generatedBytecodeFor(CodeForConstruct), "entry_osr_function_for_construct_arityCheck", ArityCheck); | |
361 | } | |
362 | ||
363 | LLINT_SLOW_PATH_DECL(loop_osr) | |
364 | { | |
365 | CodeBlock* codeBlock = exec->codeBlock(); | |
366 | ||
367 | #if ENABLE(JIT_VERBOSE_OSR) | |
93a37866 | 368 | dataLog(*codeBlock, ": Entered loop_osr with executeCounter = ", codeBlock->llintExecuteCounter(), "\n"); |
6fe7ccc8 A |
369 | #endif |
370 | ||
371 | if (!shouldJIT(exec)) { | |
372 | codeBlock->dontJITAnytimeSoon(); | |
373 | LLINT_RETURN_TWO(0, exec); | |
374 | } | |
375 | ||
376 | if (!jitCompileAndSetHeuristics(codeBlock, exec)) | |
377 | LLINT_RETURN_TWO(0, exec); | |
378 | ||
379 | ASSERT(codeBlock->getJITType() == JITCode::BaselineJIT); | |
380 | ||
381 | Vector<BytecodeAndMachineOffset> map; | |
382 | codeBlock->jitCodeMap()->decode(map); | |
93a37866 | 383 | BytecodeAndMachineOffset* mapping = binarySearch<BytecodeAndMachineOffset, unsigned>(map, map.size(), pc - codeBlock->instructions().begin(), BytecodeAndMachineOffset::getBytecodeIndex); |
6fe7ccc8 A |
384 | ASSERT(mapping); |
385 | ASSERT(mapping->m_bytecodeIndex == static_cast<unsigned>(pc - codeBlock->instructions().begin())); | |
386 | ||
387 | void* jumpTarget = codeBlock->getJITCode().executableAddressAtOffset(mapping->m_machineCodeOffset); | |
388 | ASSERT(jumpTarget); | |
389 | ||
390 | LLINT_RETURN_TWO(jumpTarget, exec); | |
391 | } | |
392 | ||
393 | LLINT_SLOW_PATH_DECL(replace) | |
394 | { | |
395 | CodeBlock* codeBlock = exec->codeBlock(); | |
396 | ||
397 | #if ENABLE(JIT_VERBOSE_OSR) | |
93a37866 | 398 | dataLog(*codeBlock, ": Entered replace with executeCounter = ", codeBlock->llintExecuteCounter(), "\n"); |
6fe7ccc8 A |
399 | #endif |
400 | ||
401 | if (shouldJIT(exec)) | |
402 | jitCompileAndSetHeuristics(codeBlock, exec); | |
403 | else | |
404 | codeBlock->dontJITAnytimeSoon(); | |
405 | LLINT_END_IMPL(); | |
406 | } | |
93a37866 | 407 | #endif // ENABLE(JIT) |
6fe7ccc8 | 408 | |
93a37866 | 409 | LLINT_SLOW_PATH_DECL(stack_check) |
6fe7ccc8 A |
410 | { |
411 | LLINT_BEGIN(); | |
412 | #if LLINT_SLOW_PATH_TRACING | |
93a37866 A |
413 | dataLogF("Checking stack height with exec = %p.\n", exec); |
414 | dataLogF("CodeBlock = %p.\n", exec->codeBlock()); | |
415 | dataLogF("Num callee registers = %u.\n", exec->codeBlock()->m_numCalleeRegisters); | |
416 | dataLogF("Num vars = %u.\n", exec->codeBlock()->m_numVars); | |
417 | dataLogF("Current end is at %p.\n", exec->vm().interpreter->stack().end()); | |
6fe7ccc8 | 418 | #endif |
93a37866 A |
419 | ASSERT(&exec->registers()[exec->codeBlock()->m_numCalleeRegisters] > exec->vm().interpreter->stack().end()); |
420 | if (UNLIKELY(!vm.interpreter->stack().grow(&exec->registers()[exec->codeBlock()->m_numCalleeRegisters]))) { | |
6fe7ccc8 A |
421 | ReturnAddressPtr returnPC = exec->returnPC(); |
422 | exec = exec->callerFrame(); | |
93a37866 | 423 | vm.exception = createStackOverflowError(exec); |
6fe7ccc8 A |
424 | interpreterThrowInCaller(exec, returnPC); |
425 | pc = returnToThrowForThrownException(exec); | |
426 | } | |
427 | LLINT_END_IMPL(); | |
428 | } | |
429 | ||
430 | LLINT_SLOW_PATH_DECL(slow_path_call_arityCheck) | |
431 | { | |
432 | LLINT_BEGIN(); | |
93a37866 | 433 | ExecState* newExec = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForCall); |
6fe7ccc8 A |
434 | if (!newExec) { |
435 | ReturnAddressPtr returnPC = exec->returnPC(); | |
436 | exec = exec->callerFrame(); | |
93a37866 | 437 | vm.exception = createStackOverflowError(exec); |
6fe7ccc8 A |
438 | interpreterThrowInCaller(exec, returnPC); |
439 | LLINT_RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec); | |
440 | } | |
441 | LLINT_RETURN_TWO(0, newExec); | |
442 | } | |
443 | ||
444 | LLINT_SLOW_PATH_DECL(slow_path_construct_arityCheck) | |
445 | { | |
446 | LLINT_BEGIN(); | |
93a37866 | 447 | ExecState* newExec = CommonSlowPaths::arityCheckFor(exec, &vm.interpreter->stack(), CodeForConstruct); |
6fe7ccc8 A |
448 | if (!newExec) { |
449 | ReturnAddressPtr returnPC = exec->returnPC(); | |
450 | exec = exec->callerFrame(); | |
93a37866 | 451 | vm.exception = createStackOverflowError(exec); |
6fe7ccc8 A |
452 | interpreterThrowInCaller(exec, returnPC); |
453 | LLINT_RETURN_TWO(bitwise_cast<void*>(static_cast<uintptr_t>(1)), exec); | |
454 | } | |
455 | LLINT_RETURN_TWO(0, newExec); | |
456 | } | |
457 | ||
458 | LLINT_SLOW_PATH_DECL(slow_path_create_activation) | |
459 | { | |
460 | LLINT_BEGIN(); | |
461 | #if LLINT_SLOW_PATH_TRACING | |
93a37866 | 462 | dataLogF("Creating an activation, exec = %p!\n", exec); |
6fe7ccc8 | 463 | #endif |
93a37866 A |
464 | JSActivation* activation = JSActivation::create(vm, exec, exec->codeBlock()); |
465 | exec->setScope(activation); | |
6fe7ccc8 A |
466 | LLINT_RETURN(JSValue(activation)); |
467 | } | |
468 | ||
469 | LLINT_SLOW_PATH_DECL(slow_path_create_arguments) | |
470 | { | |
471 | LLINT_BEGIN(); | |
93a37866 | 472 | JSValue arguments = JSValue(Arguments::create(vm, exec)); |
6fe7ccc8 A |
473 | LLINT_CHECK_EXCEPTION(); |
474 | exec->uncheckedR(pc[1].u.operand) = arguments; | |
475 | exec->uncheckedR(unmodifiedArgumentsRegister(pc[1].u.operand)) = arguments; | |
476 | LLINT_END(); | |
477 | } | |
478 | ||
479 | LLINT_SLOW_PATH_DECL(slow_path_create_this) | |
480 | { | |
481 | LLINT_BEGIN(); | |
93a37866 | 482 | JSFunction* constructor = jsCast<JSFunction*>(LLINT_OP(2).jsValue().asCell()); |
6fe7ccc8 A |
483 | |
484 | #if !ASSERT_DISABLED | |
485 | ConstructData constructData; | |
486 | ASSERT(constructor->methodTable()->getConstructData(constructor, constructData) == ConstructTypeJS); | |
487 | #endif | |
93a37866 A |
488 | |
489 | size_t inlineCapacity = pc[3].u.operand; | |
490 | Structure* structure = constructor->allocationProfile(exec, inlineCapacity)->structure(); | |
6fe7ccc8 A |
491 | LLINT_RETURN(constructEmptyObject(exec, structure)); |
492 | } | |
493 | ||
494 | LLINT_SLOW_PATH_DECL(slow_path_convert_this) | |
495 | { | |
496 | LLINT_BEGIN(); | |
497 | JSValue v1 = LLINT_OP(1).jsValue(); | |
498 | ASSERT(v1.isPrimitive()); | |
93a37866 A |
499 | #if ENABLE(VALUE_PROFILER) |
500 | pc[OPCODE_LENGTH(op_convert_this) - 1].u.profile->m_buckets[0] = | |
501 | JSValue::encode(v1.structureOrUndefined()); | |
502 | #endif | |
6fe7ccc8 A |
503 | LLINT_RETURN(v1.toThisObject(exec)); |
504 | } | |
505 | ||
506 | LLINT_SLOW_PATH_DECL(slow_path_new_object) | |
507 | { | |
508 | LLINT_BEGIN(); | |
93a37866 | 509 | LLINT_RETURN(constructEmptyObject(exec, pc[3].u.objectAllocationProfile->structure())); |
6fe7ccc8 A |
510 | } |
511 | ||
512 | LLINT_SLOW_PATH_DECL(slow_path_new_array) | |
513 | { | |
514 | LLINT_BEGIN(); | |
93a37866 A |
515 | LLINT_RETURN(constructArray(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())); | |
6fe7ccc8 A |
522 | } |
523 | ||
524 | LLINT_SLOW_PATH_DECL(slow_path_new_array_buffer) | |
525 | { | |
526 | LLINT_BEGIN(); | |
93a37866 | 527 | LLINT_RETURN(constructArray(exec, pc[4].u.arrayAllocationProfile, exec->codeBlock()->constantBuffer(pc[2].u.operand), pc[3].u.operand)); |
6fe7ccc8 A |
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.")); | |
93a37866 | 536 | LLINT_RETURN(RegExpObject::create(vm, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->regExpStructure(), regExp)); |
6fe7ccc8 A |
537 | } |
538 | ||
539 | LLINT_SLOW_PATH_DECL(slow_path_not) | |
540 | { | |
541 | LLINT_BEGIN(); | |
542 | LLINT_RETURN(jsBoolean(!LLINT_OP_C(2).jsValue().toBoolean(exec))); | |
543 | } | |
544 | ||
545 | LLINT_SLOW_PATH_DECL(slow_path_eq) | |
546 | { | |
547 | LLINT_BEGIN(); | |
548 | LLINT_RETURN(jsBoolean(JSValue::equal(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue()))); | |
549 | } | |
550 | ||
551 | LLINT_SLOW_PATH_DECL(slow_path_neq) | |
552 | { | |
553 | LLINT_BEGIN(); | |
554 | LLINT_RETURN(jsBoolean(!JSValue::equal(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue()))); | |
555 | } | |
556 | ||
557 | LLINT_SLOW_PATH_DECL(slow_path_stricteq) | |
558 | { | |
559 | LLINT_BEGIN(); | |
560 | LLINT_RETURN(jsBoolean(JSValue::strictEqual(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue()))); | |
561 | } | |
562 | ||
563 | LLINT_SLOW_PATH_DECL(slow_path_nstricteq) | |
564 | { | |
565 | LLINT_BEGIN(); | |
566 | LLINT_RETURN(jsBoolean(!JSValue::strictEqual(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue()))); | |
567 | } | |
568 | ||
569 | LLINT_SLOW_PATH_DECL(slow_path_less) | |
570 | { | |
571 | LLINT_BEGIN(); | |
572 | LLINT_RETURN(jsBoolean(jsLess<true>(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue()))); | |
573 | } | |
574 | ||
575 | LLINT_SLOW_PATH_DECL(slow_path_lesseq) | |
576 | { | |
577 | LLINT_BEGIN(); | |
578 | LLINT_RETURN(jsBoolean(jsLessEq<true>(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue()))); | |
579 | } | |
580 | ||
581 | LLINT_SLOW_PATH_DECL(slow_path_greater) | |
582 | { | |
583 | LLINT_BEGIN(); | |
584 | LLINT_RETURN(jsBoolean(jsLess<false>(exec, LLINT_OP_C(3).jsValue(), LLINT_OP_C(2).jsValue()))); | |
585 | } | |
586 | ||
587 | LLINT_SLOW_PATH_DECL(slow_path_greatereq) | |
588 | { | |
589 | LLINT_BEGIN(); | |
590 | LLINT_RETURN(jsBoolean(jsLessEq<false>(exec, LLINT_OP_C(3).jsValue(), LLINT_OP_C(2).jsValue()))); | |
591 | } | |
592 | ||
593 | LLINT_SLOW_PATH_DECL(slow_path_pre_inc) | |
594 | { | |
595 | LLINT_BEGIN(); | |
596 | LLINT_RETURN(jsNumber(LLINT_OP(1).jsValue().toNumber(exec) + 1)); | |
597 | } | |
598 | ||
599 | LLINT_SLOW_PATH_DECL(slow_path_pre_dec) | |
600 | { | |
601 | LLINT_BEGIN(); | |
602 | LLINT_RETURN(jsNumber(LLINT_OP(1).jsValue().toNumber(exec) - 1)); | |
603 | } | |
604 | ||
93a37866 | 605 | LLINT_SLOW_PATH_DECL(slow_path_to_number) |
6fe7ccc8 A |
606 | { |
607 | LLINT_BEGIN(); | |
608 | LLINT_RETURN(jsNumber(LLINT_OP_C(2).jsValue().toNumber(exec))); | |
609 | } | |
610 | ||
611 | LLINT_SLOW_PATH_DECL(slow_path_negate) | |
612 | { | |
613 | LLINT_BEGIN(); | |
614 | LLINT_RETURN(jsNumber(-LLINT_OP_C(2).jsValue().toNumber(exec))); | |
615 | } | |
616 | ||
617 | LLINT_SLOW_PATH_DECL(slow_path_add) | |
618 | { | |
619 | LLINT_BEGIN(); | |
620 | JSValue v1 = LLINT_OP_C(2).jsValue(); | |
621 | JSValue v2 = LLINT_OP_C(3).jsValue(); | |
622 | ||
623 | #if LLINT_SLOW_PATH_TRACING | |
93a37866 | 624 | dataLog("Trying to add ", v1, " to ", v2, ".\n"); |
6fe7ccc8 A |
625 | #endif |
626 | ||
627 | if (v1.isString() && !v2.isObject()) | |
628 | LLINT_RETURN(jsString(exec, asString(v1), v2.toString(exec))); | |
629 | ||
630 | if (v1.isNumber() && v2.isNumber()) | |
631 | LLINT_RETURN(jsNumber(v1.asNumber() + v2.asNumber())); | |
632 | ||
633 | LLINT_RETURN(jsAddSlowCase(exec, v1, v2)); | |
634 | } | |
635 | ||
93a37866 A |
636 | // The following arithmetic and bitwise operations need to be sure to run |
637 | // toNumber() on their operands in order. (A call to toNumber() is idempotent | |
638 | // if an exception is already set on the ExecState.) | |
639 | ||
6fe7ccc8 A |
640 | LLINT_SLOW_PATH_DECL(slow_path_mul) |
641 | { | |
642 | LLINT_BEGIN(); | |
93a37866 A |
643 | double a = LLINT_OP_C(2).jsValue().toNumber(exec); |
644 | double b = LLINT_OP_C(3).jsValue().toNumber(exec); | |
645 | LLINT_RETURN(jsNumber(a * b)); | |
6fe7ccc8 A |
646 | } |
647 | ||
648 | LLINT_SLOW_PATH_DECL(slow_path_sub) | |
649 | { | |
650 | LLINT_BEGIN(); | |
93a37866 A |
651 | double a = LLINT_OP_C(2).jsValue().toNumber(exec); |
652 | double b = LLINT_OP_C(3).jsValue().toNumber(exec); | |
653 | LLINT_RETURN(jsNumber(a - b)); | |
6fe7ccc8 A |
654 | } |
655 | ||
656 | LLINT_SLOW_PATH_DECL(slow_path_div) | |
657 | { | |
658 | LLINT_BEGIN(); | |
93a37866 A |
659 | double a = LLINT_OP_C(2).jsValue().toNumber(exec); |
660 | double b = LLINT_OP_C(3).jsValue().toNumber(exec); | |
661 | LLINT_RETURN(jsNumber(a / b)); | |
6fe7ccc8 A |
662 | } |
663 | ||
664 | LLINT_SLOW_PATH_DECL(slow_path_mod) | |
665 | { | |
666 | LLINT_BEGIN(); | |
93a37866 A |
667 | double a = LLINT_OP_C(2).jsValue().toNumber(exec); |
668 | double b = LLINT_OP_C(3).jsValue().toNumber(exec); | |
669 | LLINT_RETURN(jsNumber(fmod(a, b))); | |
6fe7ccc8 A |
670 | } |
671 | ||
672 | LLINT_SLOW_PATH_DECL(slow_path_lshift) | |
673 | { | |
674 | LLINT_BEGIN(); | |
93a37866 A |
675 | int32_t a = LLINT_OP_C(2).jsValue().toInt32(exec); |
676 | uint32_t b = LLINT_OP_C(3).jsValue().toUInt32(exec); | |
677 | LLINT_RETURN(jsNumber(a << (b & 31))); | |
6fe7ccc8 A |
678 | } |
679 | ||
680 | LLINT_SLOW_PATH_DECL(slow_path_rshift) | |
681 | { | |
682 | LLINT_BEGIN(); | |
93a37866 A |
683 | int32_t a = LLINT_OP_C(2).jsValue().toInt32(exec); |
684 | uint32_t b = LLINT_OP_C(3).jsValue().toUInt32(exec); | |
685 | LLINT_RETURN(jsNumber(a >> (b & 31))); | |
6fe7ccc8 A |
686 | } |
687 | ||
688 | LLINT_SLOW_PATH_DECL(slow_path_urshift) | |
689 | { | |
690 | LLINT_BEGIN(); | |
93a37866 A |
691 | uint32_t a = LLINT_OP_C(2).jsValue().toUInt32(exec); |
692 | uint32_t b = LLINT_OP_C(3).jsValue().toUInt32(exec); | |
693 | LLINT_RETURN(jsNumber(a >> (b & 31))); | |
6fe7ccc8 A |
694 | } |
695 | ||
696 | LLINT_SLOW_PATH_DECL(slow_path_bitand) | |
697 | { | |
698 | LLINT_BEGIN(); | |
93a37866 A |
699 | int32_t a = LLINT_OP_C(2).jsValue().toInt32(exec); |
700 | int32_t b = LLINT_OP_C(3).jsValue().toInt32(exec); | |
701 | LLINT_RETURN(jsNumber(a & b)); | |
6fe7ccc8 A |
702 | } |
703 | ||
704 | LLINT_SLOW_PATH_DECL(slow_path_bitor) | |
705 | { | |
706 | LLINT_BEGIN(); | |
93a37866 A |
707 | int32_t a = LLINT_OP_C(2).jsValue().toInt32(exec); |
708 | int32_t b = LLINT_OP_C(3).jsValue().toInt32(exec); | |
709 | LLINT_RETURN(jsNumber(a | b)); | |
6fe7ccc8 A |
710 | } |
711 | ||
712 | LLINT_SLOW_PATH_DECL(slow_path_bitxor) | |
713 | { | |
714 | LLINT_BEGIN(); | |
93a37866 A |
715 | int32_t a = LLINT_OP_C(2).jsValue().toInt32(exec); |
716 | int32_t b = LLINT_OP_C(3).jsValue().toInt32(exec); | |
717 | LLINT_RETURN(jsNumber(a ^ b)); | |
6fe7ccc8 A |
718 | } |
719 | ||
720 | LLINT_SLOW_PATH_DECL(slow_path_check_has_instance) | |
721 | { | |
722 | LLINT_BEGIN(); | |
93a37866 A |
723 | |
724 | JSValue value = LLINT_OP_C(2).jsValue(); | |
725 | JSValue baseVal = LLINT_OP_C(3).jsValue(); | |
726 | if (baseVal.isObject()) { | |
727 | JSObject* baseObject = asObject(baseVal); | |
728 | ASSERT(!baseObject->structure()->typeInfo().implementsDefaultHasInstance()); | |
729 | if (baseObject->structure()->typeInfo().implementsHasInstance()) { | |
730 | pc += pc[4].u.operand; | |
731 | LLINT_RETURN(jsBoolean(baseObject->methodTable()->customHasInstance(baseObject, exec, value))); | |
732 | } | |
733 | } | |
6fe7ccc8 A |
734 | LLINT_THROW(createInvalidParamError(exec, "instanceof", baseVal)); |
735 | } | |
736 | ||
737 | LLINT_SLOW_PATH_DECL(slow_path_instanceof) | |
738 | { | |
739 | LLINT_BEGIN(); | |
93a37866 A |
740 | JSValue value = LLINT_OP_C(2).jsValue(); |
741 | JSValue proto = LLINT_OP_C(3).jsValue(); | |
742 | ASSERT(!value.isObject() || !proto.isObject()); | |
743 | LLINT_RETURN(jsBoolean(JSObject::defaultHasInstance(exec, value, proto))); | |
6fe7ccc8 A |
744 | } |
745 | ||
746 | LLINT_SLOW_PATH_DECL(slow_path_typeof) | |
747 | { | |
748 | LLINT_BEGIN(); | |
749 | LLINT_RETURN(jsTypeStringForValue(exec, LLINT_OP_C(2).jsValue())); | |
750 | } | |
751 | ||
752 | LLINT_SLOW_PATH_DECL(slow_path_is_object) | |
753 | { | |
754 | LLINT_BEGIN(); | |
93a37866 | 755 | LLINT_RETURN(jsBoolean(jsIsObjectType(exec, LLINT_OP_C(2).jsValue()))); |
6fe7ccc8 A |
756 | } |
757 | ||
758 | LLINT_SLOW_PATH_DECL(slow_path_is_function) | |
759 | { | |
760 | LLINT_BEGIN(); | |
761 | LLINT_RETURN(jsBoolean(jsIsFunctionType(LLINT_OP_C(2).jsValue()))); | |
762 | } | |
763 | ||
764 | LLINT_SLOW_PATH_DECL(slow_path_in) | |
765 | { | |
766 | LLINT_BEGIN(); | |
767 | LLINT_RETURN(jsBoolean(CommonSlowPaths::opIn(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue()))); | |
768 | } | |
769 | ||
770 | LLINT_SLOW_PATH_DECL(slow_path_resolve) | |
771 | { | |
772 | LLINT_BEGIN(); | |
93a37866 A |
773 | Identifier ident = exec->codeBlock()->identifier(pc[2].u.operand); |
774 | ResolveOperations* operations = pc[3].u.resolveOperations; | |
775 | JSValue result = JSScope::resolve(exec, ident, operations); | |
776 | ASSERT(operations->size()); | |
777 | if (operations->isEmpty()) | |
778 | LLINT_RETURN_PROFILED(op_resolve, result); | |
6fe7ccc8 | 779 | |
93a37866 A |
780 | switch (operations->data()[0].m_operation) { |
781 | case ResolveOperation::GetAndReturnGlobalProperty: | |
782 | pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_global_property); | |
783 | break; | |
6fe7ccc8 | 784 | |
93a37866 A |
785 | case ResolveOperation::GetAndReturnGlobalVar: |
786 | pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_global_var); | |
787 | break; | |
6fe7ccc8 | 788 | |
93a37866 A |
789 | case ResolveOperation::SkipTopScopeNode: |
790 | pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_scoped_var_with_top_scope_check); | |
791 | break; | |
6fe7ccc8 | 792 | |
93a37866 A |
793 | case ResolveOperation::SkipScopes: |
794 | if (operations->data()[0].m_scopesToSkip) | |
795 | pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_scoped_var); | |
796 | else | |
797 | pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_scoped_var_on_top_scope); | |
798 | break; | |
799 | ||
800 | default: | |
801 | break; | |
802 | } | |
803 | LLINT_RETURN_PROFILED(op_resolve, result); | |
6fe7ccc8 A |
804 | } |
805 | ||
93a37866 | 806 | LLINT_SLOW_PATH_DECL(slow_path_put_to_base) |
6fe7ccc8 A |
807 | { |
808 | LLINT_BEGIN(); | |
93a37866 A |
809 | PutToBaseOperation* operation = pc[4].u.putToBaseOperation; |
810 | JSScope::resolvePut(exec, LLINT_OP_C(1).jsValue(), exec->codeBlock()->identifier(pc[2].u.operand), LLINT_OP_C(3).jsValue(), operation); | |
811 | switch (operation->m_kind) { | |
812 | case PutToBaseOperation::VariablePut: | |
813 | pc[0].u.opcode = LLInt::getOpcode(llint_op_put_to_base_variable); | |
814 | break; | |
815 | ||
816 | default: | |
817 | break; | |
818 | } | |
819 | LLINT_END(); | |
6fe7ccc8 A |
820 | } |
821 | ||
822 | LLINT_SLOW_PATH_DECL(slow_path_resolve_base) | |
823 | { | |
824 | LLINT_BEGIN(); | |
825 | Identifier& ident = exec->codeBlock()->identifier(pc[2].u.operand); | |
93a37866 A |
826 | ResolveOperations* operations = pc[4].u.resolveOperations; |
827 | JSValue result; | |
6fe7ccc8 | 828 | if (pc[3].u.operand) { |
93a37866 A |
829 | result = JSScope::resolveBase(exec, ident, true, operations, pc[5].u.putToBaseOperation); |
830 | if (!result) | |
831 | LLINT_THROW(vm.exception); | |
832 | } else | |
833 | result = JSScope::resolveBase(exec, ident, false, operations, pc[5].u.putToBaseOperation); | |
834 | ||
835 | ASSERT(operations->size()); | |
836 | if (operations->isEmpty()) { | |
837 | LLINT_PROFILE_VALUE(op_resolve_base, result); | |
838 | LLINT_RETURN(result); | |
6fe7ccc8 | 839 | } |
6fe7ccc8 | 840 | |
93a37866 A |
841 | switch (operations->data()[0].m_operation) { |
842 | case ResolveOperation::ReturnGlobalObjectAsBase: | |
843 | pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_base_to_global); | |
844 | break; | |
845 | ||
846 | case ResolveOperation::SkipTopScopeNode: | |
847 | pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_base_to_scope_with_top_scope_check); | |
848 | break; | |
849 | ||
850 | case ResolveOperation::SkipScopes: | |
851 | pc[0].u.opcode = LLInt::getOpcode(llint_op_resolve_base_to_scope); | |
852 | break; | |
853 | ||
854 | default: | |
855 | break; | |
856 | } | |
857 | LLINT_PROFILE_VALUE(op_resolve_base, result); | |
858 | LLINT_RETURN(result); | |
6fe7ccc8 A |
859 | } |
860 | ||
861 | LLINT_SLOW_PATH_DECL(slow_path_resolve_with_base) | |
862 | { | |
863 | LLINT_BEGIN(); | |
93a37866 A |
864 | ResolveOperations* operations = pc[4].u.resolveOperations; |
865 | JSValue result = JSScope::resolveWithBase(exec, exec->codeBlock()->identifier(pc[3].u.operand), &LLINT_OP(1), operations, pc[5].u.putToBaseOperation); | |
6fe7ccc8 A |
866 | LLINT_CHECK_EXCEPTION(); |
867 | LLINT_OP(2) = result; | |
93a37866 | 868 | LLINT_PROFILE_VALUE(op_resolve_with_base, result); |
6fe7ccc8 A |
869 | LLINT_END(); |
870 | } | |
871 | ||
872 | LLINT_SLOW_PATH_DECL(slow_path_resolve_with_this) | |
873 | { | |
874 | LLINT_BEGIN(); | |
93a37866 A |
875 | ResolveOperations* operations = pc[4].u.resolveOperations; |
876 | JSValue result = JSScope::resolveWithThis(exec, exec->codeBlock()->identifier(pc[3].u.operand), &LLINT_OP(1), operations); | |
6fe7ccc8 A |
877 | LLINT_CHECK_EXCEPTION(); |
878 | LLINT_OP(2) = result; | |
93a37866 A |
879 | LLINT_PROFILE_VALUE(op_resolve_with_this, result); |
880 | LLINT_END(); | |
881 | } | |
882 | ||
883 | LLINT_SLOW_PATH_DECL(slow_path_init_global_const_check) | |
884 | { | |
885 | LLINT_BEGIN(); | |
886 | CodeBlock* codeBlock = exec->codeBlock(); | |
887 | symbolTablePut(codeBlock->globalObject(), exec, codeBlock->identifier(pc[4].u.operand), LLINT_OP_C(2).jsValue(), true); | |
6fe7ccc8 A |
888 | LLINT_END(); |
889 | } | |
890 | ||
891 | LLINT_SLOW_PATH_DECL(slow_path_get_by_id) | |
892 | { | |
893 | LLINT_BEGIN(); | |
894 | CodeBlock* codeBlock = exec->codeBlock(); | |
895 | Identifier& ident = codeBlock->identifier(pc[3].u.operand); | |
896 | JSValue baseValue = LLINT_OP_C(2).jsValue(); | |
897 | PropertySlot slot(baseValue); | |
898 | ||
899 | JSValue result = baseValue.get(exec, ident, slot); | |
900 | LLINT_CHECK_EXCEPTION(); | |
901 | LLINT_OP(1) = result; | |
93a37866 A |
902 | |
903 | if (!LLINT_ALWAYS_ACCESS_SLOW | |
904 | && baseValue.isCell() | |
6fe7ccc8 A |
905 | && slot.isCacheable() |
906 | && slot.slotBase() == baseValue | |
907 | && slot.cachedPropertyType() == PropertySlot::Value) { | |
908 | ||
909 | JSCell* baseCell = baseValue.asCell(); | |
910 | Structure* structure = baseCell->structure(); | |
911 | ||
912 | if (!structure->isUncacheableDictionary() | |
913 | && !structure->typeInfo().prohibitsPropertyCaching()) { | |
914 | pc[4].u.structure.set( | |
93a37866 A |
915 | vm, codeBlock->ownerExecutable(), structure); |
916 | if (isInlineOffset(slot.cachedOffset())) { | |
917 | pc[0].u.opcode = LLInt::getOpcode(llint_op_get_by_id); | |
918 | pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage(); | |
919 | } else { | |
920 | pc[0].u.opcode = LLInt::getOpcode(llint_op_get_by_id_out_of_line); | |
921 | pc[5].u.operand = offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue); | |
922 | } | |
6fe7ccc8 A |
923 | } |
924 | } | |
925 | ||
93a37866 A |
926 | if (!LLINT_ALWAYS_ACCESS_SLOW |
927 | && isJSArray(baseValue) | |
928 | && ident == exec->propertyNames().length) { | |
929 | pc[0].u.opcode = LLInt::getOpcode(llint_op_get_array_length); | |
930 | #if ENABLE(VALUE_PROFILER) | |
931 | ArrayProfile* arrayProfile = codeBlock->getOrAddArrayProfile(pc - codeBlock->instructions().begin()); | |
932 | arrayProfile->observeStructure(baseValue.asCell()->structure()); | |
933 | pc[4].u.arrayProfile = arrayProfile; | |
934 | #endif | |
935 | } | |
936 | ||
6fe7ccc8 A |
937 | #if ENABLE(VALUE_PROFILER) |
938 | pc[OPCODE_LENGTH(op_get_by_id) - 1].u.profile->m_buckets[0] = JSValue::encode(result); | |
939 | #endif | |
940 | LLINT_END(); | |
941 | } | |
942 | ||
943 | LLINT_SLOW_PATH_DECL(slow_path_get_arguments_length) | |
944 | { | |
945 | LLINT_BEGIN(); | |
946 | CodeBlock* codeBlock = exec->codeBlock(); | |
947 | Identifier& ident = codeBlock->identifier(pc[3].u.operand); | |
948 | JSValue baseValue = LLINT_OP(2).jsValue(); | |
949 | PropertySlot slot(baseValue); | |
950 | LLINT_RETURN(baseValue.get(exec, ident, slot)); | |
951 | } | |
952 | ||
953 | LLINT_SLOW_PATH_DECL(slow_path_put_by_id) | |
954 | { | |
955 | LLINT_BEGIN(); | |
956 | CodeBlock* codeBlock = exec->codeBlock(); | |
957 | Identifier& ident = codeBlock->identifier(pc[2].u.operand); | |
958 | ||
959 | JSValue baseValue = LLINT_OP_C(1).jsValue(); | |
960 | PutPropertySlot slot(codeBlock->isStrictMode()); | |
961 | if (pc[8].u.operand) | |
93a37866 | 962 | asObject(baseValue)->putDirect(vm, ident, LLINT_OP_C(3).jsValue(), slot); |
6fe7ccc8 A |
963 | else |
964 | baseValue.put(exec, ident, LLINT_OP_C(3).jsValue(), slot); | |
965 | LLINT_CHECK_EXCEPTION(); | |
966 | ||
93a37866 A |
967 | if (!LLINT_ALWAYS_ACCESS_SLOW |
968 | && baseValue.isCell() | |
6fe7ccc8 A |
969 | && slot.isCacheable()) { |
970 | ||
971 | JSCell* baseCell = baseValue.asCell(); | |
972 | Structure* structure = baseCell->structure(); | |
973 | ||
974 | if (!structure->isUncacheableDictionary() | |
975 | && !structure->typeInfo().prohibitsPropertyCaching() | |
976 | && baseCell == slot.base()) { | |
977 | ||
978 | if (slot.type() == PutPropertySlot::NewProperty) { | |
93a37866 A |
979 | if (!structure->isDictionary() && structure->previousID()->outOfLineCapacity() == structure->outOfLineCapacity()) { |
980 | ASSERT(structure->previousID()->transitionWatchpointSetHasBeenInvalidated()); | |
981 | ||
6fe7ccc8 A |
982 | // This is needed because some of the methods we call |
983 | // below may GC. | |
93a37866 A |
984 | pc[0].u.opcode = LLInt::getOpcode(llint_op_put_by_id); |
985 | ||
986 | if (normalizePrototypeChain(exec, baseCell) != InvalidPrototypeChain) { | |
987 | ASSERT(structure->previousID()->isObject()); | |
988 | pc[4].u.structure.set( | |
989 | vm, codeBlock->ownerExecutable(), structure->previousID()); | |
990 | if (isInlineOffset(slot.cachedOffset())) | |
991 | pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage(); | |
992 | else | |
993 | pc[5].u.operand = offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue); | |
994 | pc[6].u.structure.set( | |
995 | vm, codeBlock->ownerExecutable(), structure); | |
996 | StructureChain* chain = structure->prototypeChain(exec); | |
997 | ASSERT(chain); | |
998 | pc[7].u.structureChain.set( | |
999 | vm, codeBlock->ownerExecutable(), chain); | |
6fe7ccc8 | 1000 | |
93a37866 A |
1001 | if (pc[8].u.operand) { |
1002 | if (isInlineOffset(slot.cachedOffset())) | |
1003 | pc[0].u.opcode = LLInt::getOpcode(llint_op_put_by_id_transition_direct); | |
1004 | else | |
1005 | pc[0].u.opcode = LLInt::getOpcode(llint_op_put_by_id_transition_direct_out_of_line); | |
1006 | } else { | |
1007 | if (isInlineOffset(slot.cachedOffset())) | |
1008 | pc[0].u.opcode = LLInt::getOpcode(llint_op_put_by_id_transition_normal); | |
1009 | else | |
1010 | pc[0].u.opcode = LLInt::getOpcode(llint_op_put_by_id_transition_normal_out_of_line); | |
1011 | } | |
1012 | } | |
6fe7ccc8 A |
1013 | } |
1014 | } else { | |
6fe7ccc8 | 1015 | pc[4].u.structure.set( |
93a37866 A |
1016 | vm, codeBlock->ownerExecutable(), structure); |
1017 | if (isInlineOffset(slot.cachedOffset())) { | |
1018 | pc[0].u.opcode = LLInt::getOpcode(llint_op_put_by_id); | |
1019 | pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage(); | |
1020 | } else { | |
1021 | pc[0].u.opcode = LLInt::getOpcode(llint_op_put_by_id_out_of_line); | |
1022 | pc[5].u.operand = offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue); | |
1023 | } | |
6fe7ccc8 A |
1024 | } |
1025 | } | |
1026 | } | |
1027 | ||
1028 | LLINT_END(); | |
1029 | } | |
1030 | ||
1031 | LLINT_SLOW_PATH_DECL(slow_path_del_by_id) | |
1032 | { | |
1033 | LLINT_BEGIN(); | |
1034 | CodeBlock* codeBlock = exec->codeBlock(); | |
1035 | JSObject* baseObject = LLINT_OP_C(2).jsValue().toObject(exec); | |
1036 | bool couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, codeBlock->identifier(pc[3].u.operand)); | |
1037 | LLINT_CHECK_EXCEPTION(); | |
1038 | if (!couldDelete && codeBlock->isStrictMode()) | |
1039 | LLINT_THROW(createTypeError(exec, "Unable to delete property.")); | |
1040 | LLINT_RETURN(jsBoolean(couldDelete)); | |
1041 | } | |
1042 | ||
1043 | inline JSValue getByVal(ExecState* exec, JSValue baseValue, JSValue subscript) | |
1044 | { | |
1045 | if (LIKELY(baseValue.isCell() && subscript.isString())) { | |
1046 | if (JSValue result = baseValue.asCell()->fastGetOwnProperty(exec, asString(subscript)->value(exec))) | |
1047 | return result; | |
1048 | } | |
1049 | ||
1050 | if (subscript.isUInt32()) { | |
1051 | uint32_t i = subscript.asUInt32(); | |
1052 | if (isJSString(baseValue) && asString(baseValue)->canGetIndex(i)) | |
1053 | return asString(baseValue)->getIndex(exec, i); | |
1054 | ||
1055 | return baseValue.get(exec, i); | |
1056 | } | |
93a37866 A |
1057 | |
1058 | if (isName(subscript)) | |
1059 | return baseValue.get(exec, jsCast<NameInstance*>(subscript.asCell())->privateName()); | |
6fe7ccc8 A |
1060 | |
1061 | Identifier property(exec, subscript.toString(exec)->value(exec)); | |
1062 | return baseValue.get(exec, property); | |
1063 | } | |
1064 | ||
1065 | LLINT_SLOW_PATH_DECL(slow_path_get_by_val) | |
1066 | { | |
1067 | LLINT_BEGIN(); | |
1068 | LLINT_RETURN_PROFILED(op_get_by_val, getByVal(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue())); | |
1069 | } | |
1070 | ||
1071 | LLINT_SLOW_PATH_DECL(slow_path_get_argument_by_val) | |
1072 | { | |
1073 | LLINT_BEGIN(); | |
1074 | JSValue arguments = LLINT_OP(2).jsValue(); | |
1075 | if (!arguments) { | |
93a37866 | 1076 | arguments = Arguments::create(vm, exec); |
6fe7ccc8 A |
1077 | LLINT_CHECK_EXCEPTION(); |
1078 | LLINT_OP(2) = arguments; | |
1079 | exec->uncheckedR(unmodifiedArgumentsRegister(pc[2].u.operand)) = arguments; | |
1080 | } | |
1081 | ||
93a37866 | 1082 | LLINT_RETURN_PROFILED(op_get_argument_by_val, getByVal(exec, arguments, LLINT_OP_C(3).jsValue())); |
6fe7ccc8 A |
1083 | } |
1084 | ||
1085 | LLINT_SLOW_PATH_DECL(slow_path_get_by_pname) | |
1086 | { | |
1087 | LLINT_BEGIN(); | |
1088 | LLINT_RETURN(getByVal(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue())); | |
1089 | } | |
1090 | ||
1091 | LLINT_SLOW_PATH_DECL(slow_path_put_by_val) | |
1092 | { | |
1093 | LLINT_BEGIN(); | |
1094 | ||
1095 | JSValue baseValue = LLINT_OP_C(1).jsValue(); | |
1096 | JSValue subscript = LLINT_OP_C(2).jsValue(); | |
1097 | JSValue value = LLINT_OP_C(3).jsValue(); | |
1098 | ||
1099 | if (LIKELY(subscript.isUInt32())) { | |
1100 | uint32_t i = subscript.asUInt32(); | |
93a37866 A |
1101 | if (baseValue.isObject()) { |
1102 | JSObject* object = asObject(baseValue); | |
1103 | if (object->canSetIndexQuickly(i)) | |
1104 | object->setIndexQuickly(vm, i, value); | |
6fe7ccc8 | 1105 | else |
93a37866 | 1106 | object->methodTable()->putByIndex(object, exec, i, value, exec->codeBlock()->isStrictMode()); |
6fe7ccc8 A |
1107 | LLINT_END(); |
1108 | } | |
1109 | baseValue.putByIndex(exec, i, value, exec->codeBlock()->isStrictMode()); | |
1110 | LLINT_END(); | |
1111 | } | |
93a37866 A |
1112 | |
1113 | if (isName(subscript)) { | |
1114 | PutPropertySlot slot(exec->codeBlock()->isStrictMode()); | |
1115 | baseValue.put(exec, jsCast<NameInstance*>(subscript.asCell())->privateName(), value, slot); | |
1116 | LLINT_END(); | |
1117 | } | |
1118 | ||
6fe7ccc8 A |
1119 | Identifier property(exec, subscript.toString(exec)->value(exec)); |
1120 | LLINT_CHECK_EXCEPTION(); | |
1121 | PutPropertySlot slot(exec->codeBlock()->isStrictMode()); | |
1122 | baseValue.put(exec, property, value, slot); | |
1123 | LLINT_END(); | |
1124 | } | |
1125 | ||
1126 | LLINT_SLOW_PATH_DECL(slow_path_del_by_val) | |
1127 | { | |
1128 | LLINT_BEGIN(); | |
1129 | JSValue baseValue = LLINT_OP_C(2).jsValue(); | |
1130 | JSObject* baseObject = baseValue.toObject(exec); | |
1131 | ||
1132 | JSValue subscript = LLINT_OP_C(3).jsValue(); | |
1133 | ||
1134 | bool couldDelete; | |
1135 | ||
1136 | uint32_t i; | |
1137 | if (subscript.getUInt32(i)) | |
1138 | couldDelete = baseObject->methodTable()->deletePropertyByIndex(baseObject, exec, i); | |
93a37866 A |
1139 | else if (isName(subscript)) |
1140 | couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, jsCast<NameInstance*>(subscript.asCell())->privateName()); | |
6fe7ccc8 A |
1141 | else { |
1142 | LLINT_CHECK_EXCEPTION(); | |
1143 | Identifier property(exec, subscript.toString(exec)->value(exec)); | |
1144 | LLINT_CHECK_EXCEPTION(); | |
1145 | couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, property); | |
1146 | } | |
1147 | ||
1148 | if (!couldDelete && exec->codeBlock()->isStrictMode()) | |
1149 | LLINT_THROW(createTypeError(exec, "Unable to delete property.")); | |
1150 | ||
1151 | LLINT_RETURN(jsBoolean(couldDelete)); | |
1152 | } | |
1153 | ||
1154 | LLINT_SLOW_PATH_DECL(slow_path_put_by_index) | |
1155 | { | |
1156 | LLINT_BEGIN(); | |
1157 | JSValue arrayValue = LLINT_OP_C(1).jsValue(); | |
1158 | ASSERT(isJSArray(arrayValue)); | |
93a37866 | 1159 | asArray(arrayValue)->putDirectIndex(exec, pc[2].u.operand, LLINT_OP_C(3).jsValue()); |
6fe7ccc8 A |
1160 | LLINT_END(); |
1161 | } | |
1162 | ||
1163 | LLINT_SLOW_PATH_DECL(slow_path_put_getter_setter) | |
1164 | { | |
1165 | LLINT_BEGIN(); | |
1166 | ASSERT(LLINT_OP(1).jsValue().isObject()); | |
1167 | JSObject* baseObj = asObject(LLINT_OP(1).jsValue()); | |
1168 | ||
1169 | GetterSetter* accessor = GetterSetter::create(exec); | |
1170 | LLINT_CHECK_EXCEPTION(); | |
1171 | ||
1172 | JSValue getter = LLINT_OP(3).jsValue(); | |
1173 | JSValue setter = LLINT_OP(4).jsValue(); | |
1174 | ASSERT(getter.isObject() || getter.isUndefined()); | |
1175 | ASSERT(setter.isObject() || setter.isUndefined()); | |
1176 | ASSERT(getter.isObject() || setter.isObject()); | |
1177 | ||
1178 | if (!getter.isUndefined()) | |
93a37866 | 1179 | accessor->setGetter(vm, asObject(getter)); |
6fe7ccc8 | 1180 | if (!setter.isUndefined()) |
93a37866 | 1181 | accessor->setSetter(vm, asObject(setter)); |
6fe7ccc8 | 1182 | baseObj->putDirectAccessor( |
93a37866 | 1183 | exec, |
6fe7ccc8 A |
1184 | exec->codeBlock()->identifier(pc[2].u.operand), |
1185 | accessor, Accessor); | |
1186 | LLINT_END(); | |
1187 | } | |
1188 | ||
6fe7ccc8 A |
1189 | LLINT_SLOW_PATH_DECL(slow_path_jtrue) |
1190 | { | |
1191 | LLINT_BEGIN(); | |
1192 | LLINT_BRANCH(op_jtrue, LLINT_OP_C(1).jsValue().toBoolean(exec)); | |
1193 | } | |
1194 | ||
1195 | LLINT_SLOW_PATH_DECL(slow_path_jfalse) | |
1196 | { | |
1197 | LLINT_BEGIN(); | |
1198 | LLINT_BRANCH(op_jfalse, !LLINT_OP_C(1).jsValue().toBoolean(exec)); | |
1199 | } | |
1200 | ||
1201 | LLINT_SLOW_PATH_DECL(slow_path_jless) | |
1202 | { | |
1203 | LLINT_BEGIN(); | |
1204 | LLINT_BRANCH(op_jless, jsLess<true>(exec, LLINT_OP_C(1).jsValue(), LLINT_OP_C(2).jsValue())); | |
1205 | } | |
1206 | ||
1207 | LLINT_SLOW_PATH_DECL(slow_path_jnless) | |
1208 | { | |
1209 | LLINT_BEGIN(); | |
1210 | LLINT_BRANCH(op_jnless, !jsLess<true>(exec, LLINT_OP_C(1).jsValue(), LLINT_OP_C(2).jsValue())); | |
1211 | } | |
1212 | ||
1213 | LLINT_SLOW_PATH_DECL(slow_path_jgreater) | |
1214 | { | |
1215 | LLINT_BEGIN(); | |
1216 | LLINT_BRANCH(op_jgreater, jsLess<false>(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(1).jsValue())); | |
1217 | } | |
1218 | ||
1219 | LLINT_SLOW_PATH_DECL(slow_path_jngreater) | |
1220 | { | |
1221 | LLINT_BEGIN(); | |
1222 | LLINT_BRANCH(op_jngreater, !jsLess<false>(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(1).jsValue())); | |
1223 | } | |
1224 | ||
1225 | LLINT_SLOW_PATH_DECL(slow_path_jlesseq) | |
1226 | { | |
1227 | LLINT_BEGIN(); | |
1228 | LLINT_BRANCH(op_jlesseq, jsLessEq<true>(exec, LLINT_OP_C(1).jsValue(), LLINT_OP_C(2).jsValue())); | |
1229 | } | |
1230 | ||
1231 | LLINT_SLOW_PATH_DECL(slow_path_jnlesseq) | |
1232 | { | |
1233 | LLINT_BEGIN(); | |
1234 | LLINT_BRANCH(op_jnlesseq, !jsLessEq<true>(exec, LLINT_OP_C(1).jsValue(), LLINT_OP_C(2).jsValue())); | |
1235 | } | |
1236 | ||
1237 | LLINT_SLOW_PATH_DECL(slow_path_jgreatereq) | |
1238 | { | |
1239 | LLINT_BEGIN(); | |
1240 | LLINT_BRANCH(op_jgreatereq, jsLessEq<false>(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(1).jsValue())); | |
1241 | } | |
1242 | ||
1243 | LLINT_SLOW_PATH_DECL(slow_path_jngreatereq) | |
1244 | { | |
1245 | LLINT_BEGIN(); | |
1246 | LLINT_BRANCH(op_jngreatereq, !jsLessEq<false>(exec, LLINT_OP_C(2).jsValue(), LLINT_OP_C(1).jsValue())); | |
1247 | } | |
1248 | ||
1249 | LLINT_SLOW_PATH_DECL(slow_path_switch_imm) | |
1250 | { | |
1251 | LLINT_BEGIN(); | |
1252 | JSValue scrutinee = LLINT_OP_C(3).jsValue(); | |
1253 | ASSERT(scrutinee.isDouble()); | |
1254 | double value = scrutinee.asDouble(); | |
1255 | int32_t intValue = static_cast<int32_t>(value); | |
1256 | int defaultOffset = pc[2].u.operand; | |
1257 | if (value == intValue) { | |
1258 | CodeBlock* codeBlock = exec->codeBlock(); | |
1259 | pc += codeBlock->immediateSwitchJumpTable(pc[1].u.operand).offsetForValue(intValue, defaultOffset); | |
1260 | } else | |
1261 | pc += defaultOffset; | |
1262 | LLINT_END(); | |
1263 | } | |
1264 | ||
1265 | LLINT_SLOW_PATH_DECL(slow_path_switch_char) | |
1266 | { | |
1267 | LLINT_BEGIN(); | |
1268 | JSValue scrutinee = LLINT_OP_C(3).jsValue(); | |
1269 | ASSERT(scrutinee.isString()); | |
1270 | JSString* string = asString(scrutinee); | |
1271 | ASSERT(string->length() == 1); | |
1272 | int defaultOffset = pc[2].u.operand; | |
1273 | StringImpl* impl = string->value(exec).impl(); | |
1274 | CodeBlock* codeBlock = exec->codeBlock(); | |
1275 | pc += codeBlock->characterSwitchJumpTable(pc[1].u.operand).offsetForValue((*impl)[0], defaultOffset); | |
1276 | LLINT_END(); | |
1277 | } | |
1278 | ||
1279 | LLINT_SLOW_PATH_DECL(slow_path_switch_string) | |
1280 | { | |
1281 | LLINT_BEGIN(); | |
1282 | JSValue scrutinee = LLINT_OP_C(3).jsValue(); | |
1283 | int defaultOffset = pc[2].u.operand; | |
1284 | if (!scrutinee.isString()) | |
1285 | pc += defaultOffset; | |
1286 | else { | |
1287 | CodeBlock* codeBlock = exec->codeBlock(); | |
1288 | pc += codeBlock->stringSwitchJumpTable(pc[1].u.operand).offsetForValue(asString(scrutinee)->value(exec).impl(), defaultOffset); | |
1289 | } | |
1290 | LLINT_END(); | |
1291 | } | |
1292 | ||
1293 | LLINT_SLOW_PATH_DECL(slow_path_new_func) | |
1294 | { | |
1295 | LLINT_BEGIN(); | |
1296 | CodeBlock* codeBlock = exec->codeBlock(); | |
1297 | ASSERT(codeBlock->codeType() != FunctionCode | |
1298 | || !codeBlock->needsFullScopeChain() | |
1299 | || exec->uncheckedR(codeBlock->activationRegister()).jsValue()); | |
1300 | #if LLINT_SLOW_PATH_TRACING | |
93a37866 | 1301 | dataLogF("Creating function!\n"); |
6fe7ccc8 | 1302 | #endif |
93a37866 | 1303 | LLINT_RETURN(JSFunction::create(exec, codeBlock->functionDecl(pc[2].u.operand), exec->scope())); |
6fe7ccc8 A |
1304 | } |
1305 | ||
1306 | LLINT_SLOW_PATH_DECL(slow_path_new_func_exp) | |
1307 | { | |
1308 | LLINT_BEGIN(); | |
1309 | CodeBlock* codeBlock = exec->codeBlock(); | |
1310 | FunctionExecutable* function = codeBlock->functionExpr(pc[2].u.operand); | |
93a37866 | 1311 | JSFunction* func = JSFunction::create(exec, function, exec->scope()); |
6fe7ccc8 A |
1312 | |
1313 | LLINT_RETURN(func); | |
1314 | } | |
1315 | ||
1316 | static SlowPathReturnType handleHostCall(ExecState* execCallee, Instruction* pc, JSValue callee, CodeSpecializationKind kind) | |
1317 | { | |
93a37866 A |
1318 | #if LLINT_SLOW_PATH_TRACING |
1319 | dataLog("Performing host call.\n"); | |
1320 | #endif | |
1321 | ||
6fe7ccc8 | 1322 | ExecState* exec = execCallee->callerFrame(); |
93a37866 | 1323 | VM& vm = exec->vm(); |
6fe7ccc8 | 1324 | |
93a37866 | 1325 | execCallee->setScope(exec->scope()); |
6fe7ccc8 A |
1326 | execCallee->setCodeBlock(0); |
1327 | execCallee->clearReturnPC(); | |
1328 | ||
1329 | if (kind == CodeForCall) { | |
1330 | CallData callData; | |
1331 | CallType callType = getCallData(callee, callData); | |
1332 | ||
1333 | ASSERT(callType != CallTypeJS); | |
1334 | ||
1335 | if (callType == CallTypeHost) { | |
93a37866 | 1336 | NativeCallFrameTracer tracer(&vm, execCallee); |
6fe7ccc8 | 1337 | execCallee->setCallee(asObject(callee)); |
93a37866 | 1338 | vm.hostCallReturnValue = JSValue::decode(callData.native.function(execCallee)); |
6fe7ccc8 | 1339 | |
93a37866 | 1340 | LLINT_CALL_RETURN(execCallee, pc, LLInt::getCodePtr(getHostCallReturnValue)); |
6fe7ccc8 A |
1341 | } |
1342 | ||
1343 | #if LLINT_SLOW_PATH_TRACING | |
93a37866 | 1344 | dataLog("Call callee is not a function: ", callee, "\n"); |
6fe7ccc8 A |
1345 | #endif |
1346 | ||
1347 | ASSERT(callType == CallTypeNone); | |
1348 | LLINT_CALL_THROW(exec, pc, createNotAFunctionError(exec, callee)); | |
1349 | } | |
1350 | ||
1351 | ASSERT(kind == CodeForConstruct); | |
1352 | ||
1353 | ConstructData constructData; | |
1354 | ConstructType constructType = getConstructData(callee, constructData); | |
1355 | ||
1356 | ASSERT(constructType != ConstructTypeJS); | |
1357 | ||
1358 | if (constructType == ConstructTypeHost) { | |
93a37866 | 1359 | NativeCallFrameTracer tracer(&vm, execCallee); |
6fe7ccc8 | 1360 | execCallee->setCallee(asObject(callee)); |
93a37866 | 1361 | vm.hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee)); |
6fe7ccc8 | 1362 | |
93a37866 | 1363 | LLINT_CALL_RETURN(execCallee, pc, LLInt::getCodePtr(getHostCallReturnValue)); |
6fe7ccc8 A |
1364 | } |
1365 | ||
1366 | #if LLINT_SLOW_PATH_TRACING | |
93a37866 | 1367 | dataLog("Constructor callee is not a function: ", callee, "\n"); |
6fe7ccc8 A |
1368 | #endif |
1369 | ||
1370 | ASSERT(constructType == ConstructTypeNone); | |
1371 | LLINT_CALL_THROW(exec, pc, createNotAConstructorError(exec, callee)); | |
1372 | } | |
1373 | ||
1374 | inline SlowPathReturnType setUpCall(ExecState* execCallee, Instruction* pc, CodeSpecializationKind kind, JSValue calleeAsValue, LLIntCallLinkInfo* callLinkInfo = 0) | |
1375 | { | |
1376 | #if LLINT_SLOW_PATH_TRACING | |
93a37866 | 1377 | dataLogF("Performing call with recorded PC = %p\n", execCallee->callerFrame()->currentVPC()); |
6fe7ccc8 A |
1378 | #endif |
1379 | ||
1380 | JSCell* calleeAsFunctionCell = getJSFunction(calleeAsValue); | |
1381 | if (!calleeAsFunctionCell) | |
1382 | return handleHostCall(execCallee, pc, calleeAsValue, kind); | |
1383 | ||
1384 | JSFunction* callee = jsCast<JSFunction*>(calleeAsFunctionCell); | |
93a37866 A |
1385 | JSScope* scope = callee->scopeUnchecked(); |
1386 | VM& vm = *scope->vm(); | |
1387 | execCallee->setScope(scope); | |
6fe7ccc8 A |
1388 | ExecutableBase* executable = callee->executable(); |
1389 | ||
1390 | MacroAssemblerCodePtr codePtr; | |
1391 | CodeBlock* codeBlock = 0; | |
1392 | if (executable->isHostFunction()) | |
93a37866 | 1393 | codePtr = executable->hostCodeEntryFor(kind); |
6fe7ccc8 A |
1394 | else { |
1395 | FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); | |
1396 | JSObject* error = functionExecutable->compileFor(execCallee, callee->scope(), kind); | |
1397 | if (error) | |
1398 | LLINT_CALL_THROW(execCallee->callerFrame(), pc, error); | |
1399 | codeBlock = &functionExecutable->generatedBytecodeFor(kind); | |
1400 | ASSERT(codeBlock); | |
1401 | if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) | |
93a37866 | 1402 | codePtr = functionExecutable->jsCodeWithArityCheckEntryFor(kind); |
6fe7ccc8 | 1403 | else |
93a37866 | 1404 | codePtr = functionExecutable->jsCodeEntryFor(kind); |
6fe7ccc8 A |
1405 | } |
1406 | ||
93a37866 | 1407 | if (!LLINT_ALWAYS_ACCESS_SLOW && callLinkInfo) { |
6fe7ccc8 A |
1408 | if (callLinkInfo->isOnList()) |
1409 | callLinkInfo->remove(); | |
1410 | ExecState* execCaller = execCallee->callerFrame(); | |
93a37866 A |
1411 | callLinkInfo->callee.set(vm, execCaller->codeBlock()->ownerExecutable(), callee); |
1412 | callLinkInfo->lastSeenCallee.set(vm, execCaller->codeBlock()->ownerExecutable(), callee); | |
6fe7ccc8 A |
1413 | callLinkInfo->machineCodeTarget = codePtr; |
1414 | if (codeBlock) | |
1415 | codeBlock->linkIncomingCall(callLinkInfo); | |
1416 | } | |
93a37866 | 1417 | |
6fe7ccc8 A |
1418 | LLINT_CALL_RETURN(execCallee, pc, codePtr.executableAddress()); |
1419 | } | |
1420 | ||
1421 | inline SlowPathReturnType genericCall(ExecState* exec, Instruction* pc, CodeSpecializationKind kind) | |
1422 | { | |
1423 | // This needs to: | |
1424 | // - Set up a call frame. | |
1425 | // - Figure out what to call and compile it if necessary. | |
1426 | // - If possible, link the call's inline cache. | |
1427 | // - Return a tuple of machine code address to call and the new call frame. | |
1428 | ||
1429 | JSValue calleeAsValue = LLINT_OP_C(1).jsValue(); | |
1430 | ||
1431 | ExecState* execCallee = exec + pc[3].u.operand; | |
1432 | ||
1433 | execCallee->setArgumentCountIncludingThis(pc[2].u.operand); | |
93a37866 | 1434 | execCallee->uncheckedR(JSStack::Callee) = calleeAsValue; |
6fe7ccc8 A |
1435 | execCallee->setCallerFrame(exec); |
1436 | ||
1437 | ASSERT(pc[4].u.callLinkInfo); | |
1438 | return setUpCall(execCallee, pc, kind, calleeAsValue, pc[4].u.callLinkInfo); | |
1439 | } | |
1440 | ||
1441 | LLINT_SLOW_PATH_DECL(slow_path_call) | |
1442 | { | |
1443 | LLINT_BEGIN_NO_SET_PC(); | |
1444 | return genericCall(exec, pc, CodeForCall); | |
1445 | } | |
1446 | ||
1447 | LLINT_SLOW_PATH_DECL(slow_path_construct) | |
1448 | { | |
1449 | LLINT_BEGIN_NO_SET_PC(); | |
1450 | return genericCall(exec, pc, CodeForConstruct); | |
1451 | } | |
1452 | ||
1453 | LLINT_SLOW_PATH_DECL(slow_path_call_varargs) | |
1454 | { | |
1455 | LLINT_BEGIN(); | |
1456 | // This needs to: | |
1457 | // - Set up a call frame while respecting the variable arguments. | |
1458 | // - Figure out what to call and compile it if necessary. | |
1459 | // - Return a tuple of machine code address to call and the new call frame. | |
1460 | ||
1461 | JSValue calleeAsValue = LLINT_OP_C(1).jsValue(); | |
1462 | ||
1463 | ExecState* execCallee = loadVarargs( | |
93a37866 | 1464 | exec, &vm.interpreter->stack(), |
6fe7ccc8 A |
1465 | LLINT_OP_C(2).jsValue(), LLINT_OP_C(3).jsValue(), pc[4].u.operand); |
1466 | LLINT_CALL_CHECK_EXCEPTION(exec, pc); | |
1467 | ||
93a37866 | 1468 | execCallee->uncheckedR(JSStack::Callee) = calleeAsValue; |
6fe7ccc8 A |
1469 | execCallee->setCallerFrame(exec); |
1470 | exec->setCurrentVPC(pc + OPCODE_LENGTH(op_call_varargs)); | |
1471 | ||
1472 | return setUpCall(execCallee, pc, CodeForCall, calleeAsValue); | |
1473 | } | |
1474 | ||
1475 | LLINT_SLOW_PATH_DECL(slow_path_call_eval) | |
1476 | { | |
1477 | LLINT_BEGIN_NO_SET_PC(); | |
1478 | JSValue calleeAsValue = LLINT_OP(1).jsValue(); | |
1479 | ||
1480 | ExecState* execCallee = exec + pc[3].u.operand; | |
1481 | ||
1482 | execCallee->setArgumentCountIncludingThis(pc[2].u.operand); | |
1483 | execCallee->setCallerFrame(exec); | |
93a37866 A |
1484 | execCallee->uncheckedR(JSStack::Callee) = calleeAsValue; |
1485 | execCallee->setScope(exec->scope()); | |
1486 | execCallee->setReturnPC(LLInt::getCodePtr(llint_generic_return_point)); | |
6fe7ccc8 A |
1487 | execCallee->setCodeBlock(0); |
1488 | exec->setCurrentVPC(pc + OPCODE_LENGTH(op_call_eval)); | |
1489 | ||
1490 | if (!isHostFunction(calleeAsValue, globalFuncEval)) | |
1491 | return setUpCall(execCallee, pc, CodeForCall, calleeAsValue); | |
1492 | ||
93a37866 A |
1493 | vm.hostCallReturnValue = eval(execCallee); |
1494 | LLINT_CALL_RETURN(execCallee, pc, LLInt::getCodePtr(getHostCallReturnValue)); | |
6fe7ccc8 A |
1495 | } |
1496 | ||
1497 | LLINT_SLOW_PATH_DECL(slow_path_tear_off_activation) | |
1498 | { | |
1499 | LLINT_BEGIN(); | |
1500 | ASSERT(exec->codeBlock()->needsFullScopeChain()); | |
93a37866 | 1501 | jsCast<JSActivation*>(LLINT_OP(1).jsValue())->tearOff(vm); |
6fe7ccc8 A |
1502 | LLINT_END(); |
1503 | } | |
1504 | ||
1505 | LLINT_SLOW_PATH_DECL(slow_path_tear_off_arguments) | |
1506 | { | |
1507 | LLINT_BEGIN(); | |
93a37866 A |
1508 | ASSERT(exec->codeBlock()->usesArguments()); |
1509 | Arguments* arguments = jsCast<Arguments*>(exec->uncheckedR(unmodifiedArgumentsRegister(pc[1].u.operand)).jsValue()); | |
1510 | if (JSValue activationValue = LLINT_OP_C(2).jsValue()) | |
1511 | arguments->didTearOffActivation(exec, jsCast<JSActivation*>(activationValue)); | |
1512 | else | |
1513 | arguments->tearOff(exec); | |
6fe7ccc8 A |
1514 | LLINT_END(); |
1515 | } | |
1516 | ||
1517 | LLINT_SLOW_PATH_DECL(slow_path_strcat) | |
1518 | { | |
1519 | LLINT_BEGIN(); | |
1520 | LLINT_RETURN(jsString(exec, &LLINT_OP(2), pc[3].u.operand)); | |
1521 | } | |
1522 | ||
1523 | LLINT_SLOW_PATH_DECL(slow_path_to_primitive) | |
1524 | { | |
1525 | LLINT_BEGIN(); | |
1526 | LLINT_RETURN(LLINT_OP_C(2).jsValue().toPrimitive(exec)); | |
1527 | } | |
1528 | ||
1529 | LLINT_SLOW_PATH_DECL(slow_path_get_pnames) | |
1530 | { | |
1531 | LLINT_BEGIN(); | |
1532 | JSValue v = LLINT_OP(2).jsValue(); | |
1533 | if (v.isUndefinedOrNull()) { | |
1534 | pc += pc[5].u.operand; | |
1535 | LLINT_END(); | |
1536 | } | |
1537 | ||
1538 | JSObject* o = v.toObject(exec); | |
1539 | Structure* structure = o->structure(); | |
1540 | JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache(); | |
1541 | if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(exec)) | |
1542 | jsPropertyNameIterator = JSPropertyNameIterator::create(exec, o); | |
1543 | ||
1544 | LLINT_OP(1) = JSValue(jsPropertyNameIterator); | |
1545 | LLINT_OP(2) = JSValue(o); | |
1546 | LLINT_OP(3) = Register::withInt(0); | |
1547 | LLINT_OP(4) = Register::withInt(jsPropertyNameIterator->size()); | |
1548 | ||
1549 | pc += OPCODE_LENGTH(op_get_pnames); | |
1550 | LLINT_END(); | |
1551 | } | |
1552 | ||
1553 | LLINT_SLOW_PATH_DECL(slow_path_next_pname) | |
1554 | { | |
1555 | LLINT_BEGIN(); | |
1556 | JSObject* base = asObject(LLINT_OP(2).jsValue()); | |
1557 | JSString* property = asString(LLINT_OP(1).jsValue()); | |
1558 | if (base->hasProperty(exec, Identifier(exec, property->value(exec)))) { | |
1559 | // Go to target. | |
1560 | pc += pc[6].u.operand; | |
1561 | } // Else, don't change the PC, so the interpreter will reloop. | |
1562 | LLINT_END(); | |
1563 | } | |
1564 | ||
93a37866 | 1565 | LLINT_SLOW_PATH_DECL(slow_path_push_with_scope) |
6fe7ccc8 A |
1566 | { |
1567 | LLINT_BEGIN(); | |
93a37866 | 1568 | JSValue v = LLINT_OP_C(1).jsValue(); |
6fe7ccc8 A |
1569 | JSObject* o = v.toObject(exec); |
1570 | LLINT_CHECK_EXCEPTION(); | |
1571 | ||
93a37866 | 1572 | exec->setScope(JSWithScope::create(exec, o)); |
6fe7ccc8 A |
1573 | |
1574 | LLINT_END(); | |
1575 | } | |
1576 | ||
1577 | LLINT_SLOW_PATH_DECL(slow_path_pop_scope) | |
1578 | { | |
1579 | LLINT_BEGIN(); | |
93a37866 | 1580 | exec->setScope(exec->scope()->next()); |
6fe7ccc8 A |
1581 | LLINT_END(); |
1582 | } | |
1583 | ||
93a37866 | 1584 | LLINT_SLOW_PATH_DECL(slow_path_push_name_scope) |
6fe7ccc8 A |
1585 | { |
1586 | LLINT_BEGIN(); | |
1587 | CodeBlock* codeBlock = exec->codeBlock(); | |
93a37866 A |
1588 | JSNameScope* scope = JSNameScope::create(exec, codeBlock->identifier(pc[1].u.operand), LLINT_OP(2).jsValue(), pc[3].u.operand); |
1589 | exec->setScope(scope); | |
1590 | LLINT_END(); | |
6fe7ccc8 A |
1591 | } |
1592 | ||
1593 | LLINT_SLOW_PATH_DECL(slow_path_throw) | |
1594 | { | |
1595 | LLINT_BEGIN(); | |
1596 | LLINT_THROW(LLINT_OP_C(1).jsValue()); | |
1597 | } | |
1598 | ||
93a37866 | 1599 | LLINT_SLOW_PATH_DECL(slow_path_throw_static_error) |
6fe7ccc8 A |
1600 | { |
1601 | LLINT_BEGIN(); | |
93a37866 A |
1602 | if (pc[2].u.operand) |
1603 | LLINT_THROW(createReferenceError(exec, LLINT_OP_C(1).jsValue().toString(exec)->value(exec))); | |
1604 | else | |
1605 | LLINT_THROW(createTypeError(exec, LLINT_OP_C(1).jsValue().toString(exec)->value(exec))); | |
1606 | } | |
1607 | ||
1608 | LLINT_SLOW_PATH_DECL(slow_path_handle_watchdog_timer) | |
1609 | { | |
1610 | LLINT_BEGIN_NO_SET_PC(); | |
1611 | if (UNLIKELY(vm.watchdog.didFire(exec))) | |
1612 | LLINT_THROW(createTerminatedExecutionException(&vm)); | |
1613 | LLINT_RETURN_TWO(0, exec); | |
6fe7ccc8 A |
1614 | } |
1615 | ||
1616 | LLINT_SLOW_PATH_DECL(slow_path_debug) | |
1617 | { | |
1618 | LLINT_BEGIN(); | |
1619 | int debugHookID = pc[1].u.operand; | |
1620 | int firstLine = pc[2].u.operand; | |
1621 | int lastLine = pc[3].u.operand; | |
93a37866 A |
1622 | int column = pc[4].u.operand; |
1623 | ||
1624 | vm.interpreter->debug(exec, static_cast<DebugHookID>(debugHookID), firstLine, lastLine, column); | |
6fe7ccc8 A |
1625 | |
1626 | LLINT_END(); | |
1627 | } | |
1628 | ||
1629 | LLINT_SLOW_PATH_DECL(slow_path_profile_will_call) | |
1630 | { | |
1631 | LLINT_BEGIN(); | |
93a37866 A |
1632 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
1633 | profiler->willExecute(exec, LLINT_OP(1).jsValue()); | |
6fe7ccc8 A |
1634 | LLINT_END(); |
1635 | } | |
1636 | ||
1637 | LLINT_SLOW_PATH_DECL(slow_path_profile_did_call) | |
1638 | { | |
1639 | LLINT_BEGIN(); | |
93a37866 A |
1640 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
1641 | profiler->didExecute(exec, LLINT_OP(1).jsValue()); | |
6fe7ccc8 A |
1642 | LLINT_END(); |
1643 | } | |
1644 | ||
1645 | LLINT_SLOW_PATH_DECL(throw_from_native_call) | |
1646 | { | |
1647 | LLINT_BEGIN(); | |
93a37866 | 1648 | ASSERT(vm.exception); |
6fe7ccc8 A |
1649 | LLINT_END(); |
1650 | } | |
1651 | ||
1652 | } } // namespace JSC::LLInt | |
1653 | ||
1654 | #endif // ENABLE(LLINT) |