]>
Commit | Line | Data |
---|---|---|
6fe7ccc8 | 1 | /* |
81345200 | 2 | * Copyright (C) 2011, 2012, 2013, 2014 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" | |
6fe7ccc8 | 28 | #include "Arguments.h" |
93a37866 | 29 | #include "ArrayConstructor.h" |
6fe7ccc8 A |
30 | #include "CallFrame.h" |
31 | #include "CommonSlowPaths.h" | |
81345200 A |
32 | #include "CommonSlowPathsExceptions.h" |
33 | #include "ErrorHandlingScope.h" | |
6fe7ccc8 A |
34 | #include "GetterSetter.h" |
35 | #include "HostCallReturnValue.h" | |
36 | #include "Interpreter.h" | |
37 | #include "JIT.h" | |
81345200 | 38 | #include "JITExceptions.h" |
6fe7ccc8 | 39 | #include "JSActivation.h" |
93a37866 | 40 | #include "JSCJSValue.h" |
6fe7ccc8 | 41 | #include "JSGlobalObjectFunctions.h" |
93a37866 | 42 | #include "JSNameScope.h" |
6fe7ccc8 | 43 | #include "JSPropertyNameIterator.h" |
81345200 | 44 | #include "JSStackInlines.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" |
81345200 A |
51 | #include "JSCInlines.h" |
52 | #include "ProtoCallFrame.h" | |
93a37866 A |
53 | #include "StructureRareDataInlines.h" |
54 | #include <wtf/StringPrintStream.h> | |
6fe7ccc8 A |
55 | |
56 | namespace JSC { namespace LLInt { | |
57 | ||
58 | #define LLINT_BEGIN_NO_SET_PC() \ | |
93a37866 A |
59 | VM& vm = exec->vm(); \ |
60 | NativeCallFrameTracer tracer(&vm, exec) | |
6fe7ccc8 A |
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 | ||
81345200 | 84 | #define LLINT_END_IMPL() LLINT_RETURN_TWO(pc, 0) |
6fe7ccc8 A |
85 | |
86 | #define LLINT_THROW(exceptionToThrow) do { \ | |
81345200 A |
87 | vm.throwException(exec, exceptionToThrow); \ |
88 | pc = returnToThrow(exec); \ | |
6fe7ccc8 A |
89 | LLINT_END_IMPL(); \ |
90 | } while (false) | |
91 | ||
92 | #define LLINT_CHECK_EXCEPTION() do { \ | |
81345200 A |
93 | if (UNLIKELY(vm.exception())) { \ |
94 | pc = returnToThrow(exec); \ | |
6fe7ccc8 A |
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 | ||
4be4e309 A |
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 | ||
6fe7ccc8 A |
129 | #define LLINT_RETURN_PROFILED(opcode, value) do { \ |
130 | JSValue __rp_returnValue = (value); \ | |
131 | LLINT_CHECK_EXCEPTION(); \ | |
132 | LLINT_OP(1) = __rp_returnValue; \ | |
93a37866 | 133 | LLINT_PROFILE_VALUE(opcode, __rp_returnValue); \ |
6fe7ccc8 A |
134 | LLINT_END_IMPL(); \ |
135 | } while (false) | |
93a37866 A |
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 | ||
6fe7ccc8 A |
142 | #define LLINT_CALL_END_IMPL(exec, callTarget) LLINT_RETURN_TWO((callTarget), (exec)) |
143 | ||
81345200 | 144 | #define LLINT_CALL_THROW(exec, exceptionToThrow) do { \ |
6fe7ccc8 | 145 | ExecState* __ct_exec = (exec); \ |
81345200 A |
146 | vm.throwException(__ct_exec, exceptionToThrow); \ |
147 | LLINT_CALL_END_IMPL(0, callToThrow(__ct_exec)); \ | |
6fe7ccc8 A |
148 | } while (false) |
149 | ||
81345200 | 150 | #define LLINT_CALL_CHECK_EXCEPTION(exec) do { \ |
6fe7ccc8 | 151 | ExecState* __cce_exec = (exec); \ |
81345200 A |
152 | if (UNLIKELY(vm.exception())) \ |
153 | LLINT_CALL_END_IMPL(0, callToThrow(__cce_exec)); \ | |
6fe7ccc8 A |
154 | } while (false) |
155 | ||
81345200 | 156 | #define LLINT_CALL_RETURN(exec, callTarget) do { \ |
6fe7ccc8 | 157 | ExecState* __cr_exec = (exec); \ |
6fe7ccc8 | 158 | void* __cr_callTarget = (callTarget); \ |
81345200 | 159 | LLINT_CALL_CHECK_EXCEPTION(__cr_exec); \ |
6fe7ccc8 A |
160 | LLINT_CALL_END_IMPL(__cr_exec, __cr_callTarget); \ |
161 | } while (false) | |
162 | ||
81345200 A |
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 | ||
6fe7ccc8 A |
169 | extern "C" SlowPathReturnType llint_trace_operand(ExecState* exec, Instruction* pc, int fromWhere, int operand) |
170 | { | |
171 | LLINT_BEGIN(); | |
93a37866 | 172 | dataLogF("%p / %p: executing bc#%zu, op#%u: Trace(%d): %d: %d\n", |
6fe7ccc8 A |
173 | exec->codeBlock(), |
174 | exec, | |
175 | static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()), | |
93a37866 | 176 | exec->vm().interpreter->getOpcodeID(pc[0].u.opcode), |
6fe7ccc8 A |
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); | |
93a37866 A |
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()); | |
6fe7ccc8 A |
206 | LLINT_END_IMPL(); |
207 | } | |
208 | ||
209 | LLINT_SLOW_PATH_DECL(trace_prologue) | |
210 | { | |
93a37866 | 211 | dataLogF("%p / %p: in prologue.\n", exec->codeBlock(), exec); |
6fe7ccc8 A |
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(); | |
81345200 | 219 | CodeBlock* codeBlock = executable->codeBlockFor(kind); |
93a37866 | 220 | dataLogF("%p / %p: in %s of function %p, executable %p; numVars = %u, numParameters = %u, numCalleeRegisters = %u, caller = %p.\n", |
6fe7ccc8 A |
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 | { | |
81345200 | 252 | dataLogF("%p / %p: executing bc#%zu, %s, scope %p, pc = %p\n", |
6fe7ccc8 A |
253 | exec->codeBlock(), |
254 | exec, | |
255 | static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()), | |
93a37866 | 256 | opcodeNames[exec->vm().interpreter->getOpcodeID(pc[0].u.opcode)], |
81345200 A |
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 | } | |
93a37866 A |
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()); | |
6fe7ccc8 A |
265 | } |
266 | LLINT_END_IMPL(); | |
267 | } | |
268 | ||
269 | LLINT_SLOW_PATH_DECL(special_trace) | |
270 | { | |
93a37866 | 271 | dataLogF("%p / %p: executing special case bc#%zu, op#%u, return PC is %p\n", |
6fe7ccc8 A |
272 | exec->codeBlock(), |
273 | exec, | |
274 | static_cast<intptr_t>(pc - exec->codeBlock()->instructions().begin()), | |
93a37866 | 275 | exec->vm().interpreter->getOpcodeID(pc[0].u.opcode), |
6fe7ccc8 A |
276 | exec->returnPC().value()); |
277 | LLINT_END_IMPL(); | |
278 | } | |
279 | ||
81345200 A |
280 | enum EntryKind { Prologue, ArityCheck }; |
281 | ||
93a37866 | 282 | #if ENABLE(JIT) |
6fe7ccc8 A |
283 | inline bool shouldJIT(ExecState* exec) |
284 | { | |
285 | // You can modify this to turn off JITting without rebuilding the world. | |
93a37866 | 286 | return exec->vm().canUseJIT(); |
6fe7ccc8 A |
287 | } |
288 | ||
289 | // Returns true if we should try to OSR. | |
290 | inline bool jitCompileAndSetHeuristics(CodeBlock* codeBlock, ExecState* exec) | |
291 | { | |
81345200 A |
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 | ||
93a37866 A |
295 | codeBlock->updateAllValueProfilePredictions(); |
296 | ||
6fe7ccc8 | 297 | if (!codeBlock->checkIfJITThresholdReached()) { |
81345200 A |
298 | if (Options::verboseOSR()) |
299 | dataLogF(" JIT threshold should be lifted.\n"); | |
6fe7ccc8 A |
300 | return false; |
301 | } | |
81345200 A |
302 | |
303 | switch (codeBlock->jitType()) { | |
304 | case JITCode::BaselineJIT: { | |
305 | if (Options::verboseOSR()) | |
306 | dataLogF(" Code was already compiled.\n"); | |
6fe7ccc8 A |
307 | codeBlock->jitSoon(); |
308 | return true; | |
81345200 A |
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(); | |
6fe7ccc8 | 331 | return false; |
6fe7ccc8 | 332 | } |
6fe7ccc8 A |
333 | } |
334 | ||
93a37866 | 335 | static SlowPathReturnType entryOSR(ExecState* exec, Instruction*, CodeBlock* codeBlock, const char *name, EntryKind kind) |
6fe7ccc8 | 336 | { |
81345200 A |
337 | if (Options::verboseOSR()) { |
338 | dataLog( | |
339 | *codeBlock, ": Entered ", name, " with executeCounter = ", | |
340 | codeBlock->llintExecuteCounter(), "\n"); | |
341 | } | |
6fe7ccc8 A |
342 | |
343 | if (!shouldJIT(exec)) { | |
344 | codeBlock->dontJITAnytimeSoon(); | |
81345200 | 345 | LLINT_RETURN_TWO(0, 0); |
6fe7ccc8 A |
346 | } |
347 | if (!jitCompileAndSetHeuristics(codeBlock, exec)) | |
81345200 | 348 | LLINT_RETURN_TWO(0, 0); |
6fe7ccc8 A |
349 | |
350 | if (kind == Prologue) | |
81345200 | 351 | LLINT_RETURN_TWO(codeBlock->jitCode()->executableAddress(), 0); |
6fe7ccc8 | 352 | ASSERT(kind == ArityCheck); |
81345200 A |
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); | |
6fe7ccc8 | 362 | } |
81345200 | 363 | #endif // ENABLE(JIT) |
6fe7ccc8 A |
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 | { | |
81345200 | 372 | return entryOSR(exec, pc, jsCast<JSFunction*>(exec->callee())->jsExecutable()->codeBlockForCall(), "entry_osr_function_for_call", Prologue); |
6fe7ccc8 A |
373 | } |
374 | ||
375 | LLINT_SLOW_PATH_DECL(entry_osr_function_for_construct) | |
376 | { | |
81345200 | 377 | return entryOSR(exec, pc, jsCast<JSFunction*>(exec->callee())->jsExecutable()->codeBlockForConstruct(), "entry_osr_function_for_construct", Prologue); |
6fe7ccc8 A |
378 | } |
379 | ||
380 | LLINT_SLOW_PATH_DECL(entry_osr_function_for_call_arityCheck) | |
381 | { | |
81345200 | 382 | return entryOSR(exec, pc, jsCast<JSFunction*>(exec->callee())->jsExecutable()->codeBlockForCall(), "entry_osr_function_for_call_arityCheck", ArityCheck); |
6fe7ccc8 A |
383 | } |
384 | ||
385 | LLINT_SLOW_PATH_DECL(entry_osr_function_for_construct_arityCheck) | |
386 | { | |
81345200 | 387 | return entryOSR(exec, pc, jsCast<JSFunction*>(exec->callee())->jsExecutable()->codeBlockForConstruct(), "entry_osr_function_for_construct_arityCheck", ArityCheck); |
6fe7ccc8 A |
388 | } |
389 | ||
390 | LLINT_SLOW_PATH_DECL(loop_osr) | |
391 | { | |
392 | CodeBlock* codeBlock = exec->codeBlock(); | |
81345200 A |
393 | |
394 | #if ENABLE(JIT) | |
395 | if (Options::verboseOSR()) { | |
396 | dataLog( | |
397 | *codeBlock, ": Entered loop_osr with executeCounter = ", | |
398 | codeBlock->llintExecuteCounter(), "\n"); | |
399 | } | |
6fe7ccc8 A |
400 | |
401 | if (!shouldJIT(exec)) { | |
402 | codeBlock->dontJITAnytimeSoon(); | |
81345200 | 403 | LLINT_RETURN_TWO(0, 0); |
6fe7ccc8 A |
404 | } |
405 | ||
406 | if (!jitCompileAndSetHeuristics(codeBlock, exec)) | |
81345200 | 407 | LLINT_RETURN_TWO(0, 0); |
6fe7ccc8 | 408 | |
81345200 | 409 | ASSERT(codeBlock->jitType() == JITCode::BaselineJIT); |
6fe7ccc8 A |
410 | |
411 | Vector<BytecodeAndMachineOffset> map; | |
412 | codeBlock->jitCodeMap()->decode(map); | |
93a37866 | 413 | BytecodeAndMachineOffset* mapping = binarySearch<BytecodeAndMachineOffset, unsigned>(map, map.size(), pc - codeBlock->instructions().begin(), BytecodeAndMachineOffset::getBytecodeIndex); |
6fe7ccc8 A |
414 | ASSERT(mapping); |
415 | ASSERT(mapping->m_bytecodeIndex == static_cast<unsigned>(pc - codeBlock->instructions().begin())); | |
416 | ||
81345200 | 417 | void* jumpTarget = codeBlock->jitCode()->executableAddressAtOffset(mapping->m_machineCodeOffset); |
6fe7ccc8 A |
418 | ASSERT(jumpTarget); |
419 | ||
81345200 A |
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) | |
6fe7ccc8 A |
426 | } |
427 | ||
428 | LLINT_SLOW_PATH_DECL(replace) | |
429 | { | |
430 | CodeBlock* codeBlock = exec->codeBlock(); | |
81345200 A |
431 | |
432 | #if ENABLE(JIT) | |
433 | if (Options::verboseOSR()) { | |
434 | dataLog( | |
435 | *codeBlock, ": Entered replace with executeCounter = ", | |
436 | codeBlock->llintExecuteCounter(), "\n"); | |
437 | } | |
6fe7ccc8 A |
438 | |
439 | if (shouldJIT(exec)) | |
440 | jitCompileAndSetHeuristics(codeBlock, exec); | |
441 | else | |
442 | codeBlock->dontJITAnytimeSoon(); | |
443 | LLINT_END_IMPL(); | |
81345200 A |
444 | #else // ENABLE(JIT) |
445 | codeBlock->dontJITAnytimeSoon(); | |
446 | LLINT_END_IMPL(); | |
93a37866 | 447 | #endif // ENABLE(JIT) |
81345200 | 448 | } |
6fe7ccc8 | 449 | |
93a37866 | 450 | LLINT_SLOW_PATH_DECL(stack_check) |
6fe7ccc8 A |
451 | { |
452 | LLINT_BEGIN(); | |
453 | #if LLINT_SLOW_PATH_TRACING | |
93a37866 A |
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); | |
81345200 A |
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()); | |
6fe7ccc8 | 463 | #endif |
6fe7ccc8 | 464 | |
81345200 A |
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 | |
6fe7ccc8 | 486 | |
81345200 A |
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); | |
6fe7ccc8 A |
493 | } |
494 | ||
495 | LLINT_SLOW_PATH_DECL(slow_path_create_activation) | |
496 | { | |
497 | LLINT_BEGIN(); | |
498 | #if LLINT_SLOW_PATH_TRACING | |
93a37866 | 499 | dataLogF("Creating an activation, exec = %p!\n", exec); |
6fe7ccc8 | 500 | #endif |
93a37866 A |
501 | JSActivation* activation = JSActivation::create(vm, exec, exec->codeBlock()); |
502 | exec->setScope(activation); | |
6fe7ccc8 A |
503 | LLINT_RETURN(JSValue(activation)); |
504 | } | |
505 | ||
6fe7ccc8 A |
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(); | |
81345200 | 515 | LLINT_RETURN(constructArrayNegativeIndexed(exec, pc[4].u.arrayAllocationProfile, bitwise_cast<JSValue*>(&LLINT_OP(2)), pc[3].u.operand)); |
93a37866 A |
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.")); | |
81345200 | 536 | LLINT_RETURN(RegExpObject::create(vm, exec->lexicalGlobalObject()->regExpStructure(), regExp)); |
6fe7ccc8 A |
537 | } |
538 | ||
539 | LLINT_SLOW_PATH_DECL(slow_path_check_has_instance) | |
540 | { | |
541 | LLINT_BEGIN(); | |
93a37866 A |
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()) { | |
4be4e309 A |
549 | JSValue result = jsBoolean(baseObject->methodTable()->customHasInstance(baseObject, exec, value)); |
550 | LLINT_RETURN_WITH_PC_ADJUSTMENT(result, pc[4].u.operand); | |
93a37866 A |
551 | } |
552 | } | |
81345200 | 553 | LLINT_THROW(createInvalidParameterError(exec, "instanceof", baseVal)); |
6fe7ccc8 A |
554 | } |
555 | ||
556 | LLINT_SLOW_PATH_DECL(slow_path_instanceof) | |
557 | { | |
558 | LLINT_BEGIN(); | |
93a37866 A |
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))); | |
6fe7ccc8 A |
563 | } |
564 | ||
6fe7ccc8 A |
565 | LLINT_SLOW_PATH_DECL(slow_path_get_by_id) |
566 | { | |
567 | LLINT_BEGIN(); | |
568 | CodeBlock* codeBlock = exec->codeBlock(); | |
81345200 | 569 | const Identifier& ident = codeBlock->identifier(pc[3].u.operand); |
6fe7ccc8 A |
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; | |
93a37866 A |
576 | |
577 | if (!LLINT_ALWAYS_ACCESS_SLOW | |
578 | && baseValue.isCell() | |
6fe7ccc8 A |
579 | && slot.isCacheable() |
580 | && slot.slotBase() == baseValue | |
81345200 | 581 | && slot.isCacheableValue()) { |
6fe7ccc8 A |
582 | |
583 | JSCell* baseCell = baseValue.asCell(); | |
584 | Structure* structure = baseCell->structure(); | |
585 | ||
586 | if (!structure->isUncacheableDictionary() | |
81345200 A |
587 | && !structure->typeInfo().prohibitsPropertyCaching() |
588 | && !structure->typeInfo().newImpurePropertyFiresWatchpoints()) { | |
589 | ConcurrentJITLocker locker(codeBlock->m_lock); | |
590 | ||
6fe7ccc8 | 591 | pc[4].u.structure.set( |
93a37866 A |
592 | vm, codeBlock->ownerExecutable(), structure); |
593 | if (isInlineOffset(slot.cachedOffset())) { | |
81345200 | 594 | pc[0].u.opcode = LLInt::getOpcode(op_get_by_id); |
93a37866 A |
595 | pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage(); |
596 | } else { | |
81345200 | 597 | pc[0].u.opcode = LLInt::getOpcode(op_get_by_id_out_of_line); |
93a37866 A |
598 | pc[5].u.operand = offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue); |
599 | } | |
6fe7ccc8 A |
600 | } |
601 | } | |
602 | ||
93a37866 A |
603 | if (!LLINT_ALWAYS_ACCESS_SLOW |
604 | && isJSArray(baseValue) | |
605 | && ident == exec->propertyNames().length) { | |
81345200 | 606 | pc[0].u.opcode = LLInt::getOpcode(op_get_array_length); |
93a37866 A |
607 | ArrayProfile* arrayProfile = codeBlock->getOrAddArrayProfile(pc - codeBlock->instructions().begin()); |
608 | arrayProfile->observeStructure(baseValue.asCell()->structure()); | |
609 | pc[4].u.arrayProfile = arrayProfile; | |
93a37866 A |
610 | } |
611 | ||
6fe7ccc8 | 612 | pc[OPCODE_LENGTH(op_get_by_id) - 1].u.profile->m_buckets[0] = JSValue::encode(result); |
6fe7ccc8 A |
613 | LLINT_END(); |
614 | } | |
615 | ||
616 | LLINT_SLOW_PATH_DECL(slow_path_get_arguments_length) | |
617 | { | |
618 | LLINT_BEGIN(); | |
619 | CodeBlock* codeBlock = exec->codeBlock(); | |
81345200 | 620 | const Identifier& ident = codeBlock->identifier(pc[3].u.operand); |
6fe7ccc8 A |
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(); | |
81345200 | 630 | const Identifier& ident = codeBlock->identifier(pc[2].u.operand); |
6fe7ccc8 A |
631 | |
632 | JSValue baseValue = LLINT_OP_C(1).jsValue(); | |
81345200 | 633 | PutPropertySlot slot(baseValue, codeBlock->isStrictMode(), codeBlock->putByIdContext()); |
6fe7ccc8 | 634 | if (pc[8].u.operand) |
93a37866 | 635 | asObject(baseValue)->putDirect(vm, ident, LLINT_OP_C(3).jsValue(), slot); |
6fe7ccc8 A |
636 | else |
637 | baseValue.put(exec, ident, LLINT_OP_C(3).jsValue(), slot); | |
638 | LLINT_CHECK_EXCEPTION(); | |
639 | ||
93a37866 A |
640 | if (!LLINT_ALWAYS_ACCESS_SLOW |
641 | && baseValue.isCell() | |
81345200 | 642 | && slot.isCacheablePut()) { |
6fe7ccc8 A |
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) { | |
81345200 A |
652 | GCSafeConcurrentJITLocker locker(codeBlock->m_lock, vm.heap); |
653 | ||
93a37866 A |
654 | if (!structure->isDictionary() && structure->previousID()->outOfLineCapacity() == structure->outOfLineCapacity()) { |
655 | ASSERT(structure->previousID()->transitionWatchpointSetHasBeenInvalidated()); | |
656 | ||
6fe7ccc8 A |
657 | // This is needed because some of the methods we call |
658 | // below may GC. | |
81345200 | 659 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id); |
93a37866 A |
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); | |
6fe7ccc8 | 675 | |
93a37866 A |
676 | if (pc[8].u.operand) { |
677 | if (isInlineOffset(slot.cachedOffset())) | |
81345200 | 678 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id_transition_direct); |
93a37866 | 679 | else |
81345200 | 680 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id_transition_direct_out_of_line); |
93a37866 A |
681 | } else { |
682 | if (isInlineOffset(slot.cachedOffset())) | |
81345200 | 683 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id_transition_normal); |
93a37866 | 684 | else |
81345200 | 685 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id_transition_normal_out_of_line); |
93a37866 A |
686 | } |
687 | } | |
6fe7ccc8 A |
688 | } |
689 | } else { | |
6fe7ccc8 | 690 | pc[4].u.structure.set( |
93a37866 A |
691 | vm, codeBlock->ownerExecutable(), structure); |
692 | if (isInlineOffset(slot.cachedOffset())) { | |
81345200 | 693 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id); |
93a37866 A |
694 | pc[5].u.operand = offsetInInlineStorage(slot.cachedOffset()) * sizeof(JSValue) + JSObject::offsetOfInlineStorage(); |
695 | } else { | |
81345200 | 696 | pc[0].u.opcode = LLInt::getOpcode(op_put_by_id_out_of_line); |
93a37866 A |
697 | pc[5].u.operand = offsetInButterfly(slot.cachedOffset()) * sizeof(JSValue); |
698 | } | |
6fe7ccc8 A |
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())) { | |
81345200 A |
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 | } | |
6fe7ccc8 A |
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 | } | |
93a37866 A |
736 | |
737 | if (isName(subscript)) | |
738 | return baseValue.get(exec, jsCast<NameInstance*>(subscript.asCell())->privateName()); | |
6fe7ccc8 | 739 | |
81345200 | 740 | Identifier property = subscript.toString(exec)->toIdentifier(exec); |
6fe7ccc8 A |
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) { | |
93a37866 | 755 | arguments = Arguments::create(vm, exec); |
6fe7ccc8 A |
756 | LLINT_CHECK_EXCEPTION(); |
757 | LLINT_OP(2) = arguments; | |
81345200 | 758 | exec->uncheckedR(unmodifiedArgumentsRegister(VirtualRegister(pc[2].u.operand)).offset()) = arguments; |
6fe7ccc8 A |
759 | } |
760 | ||
93a37866 | 761 | LLINT_RETURN_PROFILED(op_get_argument_by_val, getByVal(exec, arguments, LLINT_OP_C(3).jsValue())); |
6fe7ccc8 A |
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(); | |
93a37866 A |
780 | if (baseValue.isObject()) { |
781 | JSObject* object = asObject(baseValue); | |
782 | if (object->canSetIndexQuickly(i)) | |
783 | object->setIndexQuickly(vm, i, value); | |
6fe7ccc8 | 784 | else |
93a37866 | 785 | object->methodTable()->putByIndex(object, exec, i, value, exec->codeBlock()->isStrictMode()); |
6fe7ccc8 A |
786 | LLINT_END(); |
787 | } | |
788 | baseValue.putByIndex(exec, i, value, exec->codeBlock()->isStrictMode()); | |
789 | LLINT_END(); | |
790 | } | |
93a37866 A |
791 | |
792 | if (isName(subscript)) { | |
81345200 | 793 | PutPropertySlot slot(baseValue, exec->codeBlock()->isStrictMode()); |
93a37866 A |
794 | baseValue.put(exec, jsCast<NameInstance*>(subscript.asCell())->privateName(), value, slot); |
795 | LLINT_END(); | |
796 | } | |
797 | ||
6fe7ccc8 A |
798 | Identifier property(exec, subscript.toString(exec)->value(exec)); |
799 | LLINT_CHECK_EXCEPTION(); | |
81345200 | 800 | PutPropertySlot slot(baseValue, exec->codeBlock()->isStrictMode()); |
6fe7ccc8 A |
801 | baseValue.put(exec, property, value, slot); |
802 | LLINT_END(); | |
803 | } | |
804 | ||
81345200 A |
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 | ||
6fe7ccc8 A |
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); | |
93a37866 A |
843 | else if (isName(subscript)) |
844 | couldDelete = baseObject->methodTable()->deleteProperty(baseObject, exec, jsCast<NameInstance*>(subscript.asCell())->privateName()); | |
6fe7ccc8 A |
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)); | |
93a37866 | 863 | asArray(arrayValue)->putDirectIndex(exec, pc[2].u.operand, LLINT_OP_C(3).jsValue()); |
6fe7ccc8 A |
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 | ||
81345200 | 873 | GetterSetter* accessor = GetterSetter::create(vm); |
6fe7ccc8 A |
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()) | |
93a37866 | 883 | accessor->setGetter(vm, asObject(getter)); |
6fe7ccc8 | 884 | if (!setter.isUndefined()) |
93a37866 | 885 | accessor->setSetter(vm, asObject(setter)); |
6fe7ccc8 | 886 | baseObj->putDirectAccessor( |
93a37866 | 887 | exec, |
6fe7ccc8 A |
888 | exec->codeBlock()->identifier(pc[2].u.operand), |
889 | accessor, Accessor); | |
890 | LLINT_END(); | |
891 | } | |
892 | ||
6fe7ccc8 A |
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(); | |
81345200 | 963 | pc += codeBlock->switchJumpTable(pc[1].u.operand).offsetForValue(intValue, defaultOffset); |
6fe7ccc8 A |
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(); | |
81345200 | 979 | pc += codeBlock->switchJumpTable(pc[1].u.operand).offsetForValue((*impl)[0], defaultOffset); |
6fe7ccc8 A |
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(); | |
81345200 | 1001 | ASSERT(codeBlock->codeType() != FunctionCode || !codeBlock->needsActivation() || exec->hasActivation()); |
6fe7ccc8 | 1002 | #if LLINT_SLOW_PATH_TRACING |
93a37866 | 1003 | dataLogF("Creating function!\n"); |
6fe7ccc8 | 1004 | #endif |
81345200 | 1005 | LLINT_RETURN(JSFunction::create(vm, codeBlock->functionDecl(pc[2].u.operand), exec->scope())); |
6fe7ccc8 A |
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); | |
81345200 | 1013 | JSFunction* func = JSFunction::create(vm, function, exec->scope()); |
6fe7ccc8 A |
1014 | |
1015 | LLINT_RETURN(func); | |
1016 | } | |
1017 | ||
1018 | static SlowPathReturnType handleHostCall(ExecState* execCallee, Instruction* pc, JSValue callee, CodeSpecializationKind kind) | |
1019 | { | |
81345200 A |
1020 | UNUSED_PARAM(pc); |
1021 | ||
93a37866 A |
1022 | #if LLINT_SLOW_PATH_TRACING |
1023 | dataLog("Performing host call.\n"); | |
1024 | #endif | |
1025 | ||
6fe7ccc8 | 1026 | ExecState* exec = execCallee->callerFrame(); |
93a37866 | 1027 | VM& vm = exec->vm(); |
6fe7ccc8 | 1028 | |
93a37866 | 1029 | execCallee->setScope(exec->scope()); |
6fe7ccc8 A |
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) { | |
93a37866 | 1040 | NativeCallFrameTracer tracer(&vm, execCallee); |
6fe7ccc8 | 1041 | execCallee->setCallee(asObject(callee)); |
93a37866 | 1042 | vm.hostCallReturnValue = JSValue::decode(callData.native.function(execCallee)); |
6fe7ccc8 | 1043 | |
81345200 | 1044 | LLINT_CALL_RETURN(execCallee, LLInt::getCodePtr(getHostCallReturnValue)); |
6fe7ccc8 A |
1045 | } |
1046 | ||
1047 | #if LLINT_SLOW_PATH_TRACING | |
93a37866 | 1048 | dataLog("Call callee is not a function: ", callee, "\n"); |
6fe7ccc8 A |
1049 | #endif |
1050 | ||
1051 | ASSERT(callType == CallTypeNone); | |
81345200 | 1052 | LLINT_CALL_THROW(exec, createNotAFunctionError(exec, callee)); |
6fe7ccc8 A |
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) { | |
93a37866 | 1063 | NativeCallFrameTracer tracer(&vm, execCallee); |
6fe7ccc8 | 1064 | execCallee->setCallee(asObject(callee)); |
93a37866 | 1065 | vm.hostCallReturnValue = JSValue::decode(constructData.native.function(execCallee)); |
6fe7ccc8 | 1066 | |
81345200 | 1067 | LLINT_CALL_RETURN(execCallee, LLInt::getCodePtr(getHostCallReturnValue)); |
6fe7ccc8 A |
1068 | } |
1069 | ||
1070 | #if LLINT_SLOW_PATH_TRACING | |
93a37866 | 1071 | dataLog("Constructor callee is not a function: ", callee, "\n"); |
6fe7ccc8 A |
1072 | #endif |
1073 | ||
1074 | ASSERT(constructType == ConstructTypeNone); | |
81345200 | 1075 | LLINT_CALL_THROW(exec, createNotAConstructorError(exec, callee)); |
6fe7ccc8 A |
1076 | } |
1077 | ||
1078 | inline SlowPathReturnType setUpCall(ExecState* execCallee, Instruction* pc, CodeSpecializationKind kind, JSValue calleeAsValue, LLIntCallLinkInfo* callLinkInfo = 0) | |
1079 | { | |
1080 | #if LLINT_SLOW_PATH_TRACING | |
93a37866 | 1081 | dataLogF("Performing call with recorded PC = %p\n", execCallee->callerFrame()->currentVPC()); |
6fe7ccc8 A |
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); | |
93a37866 A |
1089 | JSScope* scope = callee->scopeUnchecked(); |
1090 | VM& vm = *scope->vm(); | |
1091 | execCallee->setScope(scope); | |
6fe7ccc8 A |
1092 | ExecutableBase* executable = callee->executable(); |
1093 | ||
1094 | MacroAssemblerCodePtr codePtr; | |
1095 | CodeBlock* codeBlock = 0; | |
1096 | if (executable->isHostFunction()) | |
81345200 | 1097 | codePtr = executable->entrypointFor(vm, kind, MustCheckArity, RegisterPreservationNotRequired); |
6fe7ccc8 A |
1098 | else { |
1099 | FunctionExecutable* functionExecutable = static_cast<FunctionExecutable*>(executable); | |
81345200 A |
1100 | JSObject* error = functionExecutable->prepareForExecution(execCallee, callee, &scope, kind); |
1101 | execCallee->setScope(scope); | |
6fe7ccc8 | 1102 | if (error) |
81345200 A |
1103 | LLINT_CALL_THROW(execCallee->callerFrame(), error); |
1104 | codeBlock = functionExecutable->codeBlockFor(kind); | |
6fe7ccc8 | 1105 | ASSERT(codeBlock); |
81345200 | 1106 | ArityCheckMode arity; |
6fe7ccc8 | 1107 | if (execCallee->argumentCountIncludingThis() < static_cast<size_t>(codeBlock->numParameters())) |
81345200 | 1108 | arity = MustCheckArity; |
6fe7ccc8 | 1109 | else |
81345200 A |
1110 | arity = ArityCheckNotRequired; |
1111 | codePtr = functionExecutable->entrypointFor(vm, kind, arity, RegisterPreservationNotRequired); | |
6fe7ccc8 A |
1112 | } |
1113 | ||
81345200 A |
1114 | ASSERT(!!codePtr); |
1115 | ||
93a37866 | 1116 | if (!LLINT_ALWAYS_ACCESS_SLOW && callLinkInfo) { |
81345200 A |
1117 | ExecState* execCaller = execCallee->callerFrame(); |
1118 | ||
1119 | CodeBlock* callerCodeBlock = execCaller->codeBlock(); | |
1120 | ||
1121 | ConcurrentJITLocker locker(callerCodeBlock->m_lock); | |
1122 | ||
6fe7ccc8 A |
1123 | if (callLinkInfo->isOnList()) |
1124 | callLinkInfo->remove(); | |
81345200 A |
1125 | callLinkInfo->callee.set(vm, callerCodeBlock->ownerExecutable(), callee); |
1126 | callLinkInfo->lastSeenCallee.set(vm, callerCodeBlock->ownerExecutable(), callee); | |
6fe7ccc8 A |
1127 | callLinkInfo->machineCodeTarget = codePtr; |
1128 | if (codeBlock) | |
81345200 | 1129 | codeBlock->linkIncomingCall(execCaller, callLinkInfo); |
6fe7ccc8 | 1130 | } |
93a37866 | 1131 | |
81345200 | 1132 | LLINT_CALL_RETURN(execCallee, codePtr.executableAddress()); |
6fe7ccc8 A |
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 | ||
81345200 | 1143 | JSValue calleeAsValue = LLINT_OP_C(2).jsValue(); |
6fe7ccc8 | 1144 | |
81345200 | 1145 | ExecState* execCallee = exec - pc[4].u.operand; |
6fe7ccc8 | 1146 | |
81345200 | 1147 | execCallee->setArgumentCountIncludingThis(pc[3].u.operand); |
93a37866 | 1148 | execCallee->uncheckedR(JSStack::Callee) = calleeAsValue; |
6fe7ccc8 A |
1149 | execCallee->setCallerFrame(exec); |
1150 | ||
81345200 A |
1151 | ASSERT(pc[5].u.callLinkInfo); |
1152 | return setUpCall(execCallee, pc, kind, calleeAsValue, pc[5].u.callLinkInfo); | |
6fe7ccc8 A |
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 | ||
81345200 | 1167 | LLINT_SLOW_PATH_DECL(slow_path_size_frame_for_varargs) |
6fe7ccc8 A |
1168 | { |
1169 | LLINT_BEGIN(); | |
1170 | // This needs to: | |
1171 | // - Set up a call frame while respecting the variable arguments. | |
81345200 A |
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: | |
6fe7ccc8 A |
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 | ||
81345200 | 1189 | JSValue calleeAsValue = LLINT_OP_C(2).jsValue(); |
6fe7ccc8 | 1190 | |
81345200 A |
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); | |
6fe7ccc8 | 1195 | |
93a37866 | 1196 | execCallee->uncheckedR(JSStack::Callee) = calleeAsValue; |
6fe7ccc8 | 1197 | execCallee->setCallerFrame(exec); |
81345200 | 1198 | exec->setCurrentVPC(pc); |
6fe7ccc8 A |
1199 | |
1200 | return setUpCall(execCallee, pc, CodeForCall, calleeAsValue); | |
1201 | } | |
81345200 A |
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 | ||
6fe7ccc8 A |
1224 | LLINT_SLOW_PATH_DECL(slow_path_call_eval) |
1225 | { | |
1226 | LLINT_BEGIN_NO_SET_PC(); | |
81345200 | 1227 | JSValue calleeAsValue = LLINT_OP(2).jsValue(); |
6fe7ccc8 | 1228 | |
81345200 | 1229 | ExecState* execCallee = exec - pc[4].u.operand; |
6fe7ccc8 | 1230 | |
81345200 | 1231 | execCallee->setArgumentCountIncludingThis(pc[3].u.operand); |
6fe7ccc8 | 1232 | execCallee->setCallerFrame(exec); |
93a37866 A |
1233 | execCallee->uncheckedR(JSStack::Callee) = calleeAsValue; |
1234 | execCallee->setScope(exec->scope()); | |
1235 | execCallee->setReturnPC(LLInt::getCodePtr(llint_generic_return_point)); | |
6fe7ccc8 | 1236 | execCallee->setCodeBlock(0); |
81345200 | 1237 | exec->setCurrentVPC(pc); |
6fe7ccc8 A |
1238 | |
1239 | if (!isHostFunction(calleeAsValue, globalFuncEval)) | |
1240 | return setUpCall(execCallee, pc, CodeForCall, calleeAsValue); | |
1241 | ||
93a37866 | 1242 | vm.hostCallReturnValue = eval(execCallee); |
81345200 | 1243 | LLINT_CALL_RETURN(execCallee, LLInt::getCodePtr(getHostCallReturnValue)); |
6fe7ccc8 A |
1244 | } |
1245 | ||
1246 | LLINT_SLOW_PATH_DECL(slow_path_tear_off_activation) | |
1247 | { | |
1248 | LLINT_BEGIN(); | |
81345200 | 1249 | ASSERT(exec->codeBlock()->needsActivation()); |
93a37866 | 1250 | jsCast<JSActivation*>(LLINT_OP(1).jsValue())->tearOff(vm); |
6fe7ccc8 A |
1251 | LLINT_END(); |
1252 | } | |
1253 | ||
1254 | LLINT_SLOW_PATH_DECL(slow_path_tear_off_arguments) | |
1255 | { | |
1256 | LLINT_BEGIN(); | |
93a37866 | 1257 | ASSERT(exec->codeBlock()->usesArguments()); |
81345200 | 1258 | Arguments* arguments = jsCast<Arguments*>(exec->uncheckedR(unmodifiedArgumentsRegister(VirtualRegister(pc[1].u.operand)).offset()).jsValue()); |
93a37866 A |
1259 | if (JSValue activationValue = LLINT_OP_C(2).jsValue()) |
1260 | arguments->didTearOffActivation(exec, jsCast<JSActivation*>(activationValue)); | |
1261 | else | |
1262 | arguments->tearOff(exec); | |
6fe7ccc8 A |
1263 | LLINT_END(); |
1264 | } | |
1265 | ||
1266 | LLINT_SLOW_PATH_DECL(slow_path_strcat) | |
1267 | { | |
1268 | LLINT_BEGIN(); | |
81345200 | 1269 | LLINT_RETURN(jsStringFromRegisterArray(exec, &LLINT_OP(2), pc[3].u.operand)); |
6fe7ccc8 A |
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 | ||
93a37866 | 1314 | LLINT_SLOW_PATH_DECL(slow_path_push_with_scope) |
6fe7ccc8 A |
1315 | { |
1316 | LLINT_BEGIN(); | |
93a37866 | 1317 | JSValue v = LLINT_OP_C(1).jsValue(); |
6fe7ccc8 A |
1318 | JSObject* o = v.toObject(exec); |
1319 | LLINT_CHECK_EXCEPTION(); | |
1320 | ||
93a37866 | 1321 | exec->setScope(JSWithScope::create(exec, o)); |
6fe7ccc8 A |
1322 | |
1323 | LLINT_END(); | |
1324 | } | |
1325 | ||
1326 | LLINT_SLOW_PATH_DECL(slow_path_pop_scope) | |
1327 | { | |
1328 | LLINT_BEGIN(); | |
93a37866 | 1329 | exec->setScope(exec->scope()->next()); |
6fe7ccc8 A |
1330 | LLINT_END(); |
1331 | } | |
1332 | ||
93a37866 | 1333 | LLINT_SLOW_PATH_DECL(slow_path_push_name_scope) |
6fe7ccc8 A |
1334 | { |
1335 | LLINT_BEGIN(); | |
1336 | CodeBlock* codeBlock = exec->codeBlock(); | |
93a37866 A |
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(); | |
6fe7ccc8 A |
1340 | } |
1341 | ||
1342 | LLINT_SLOW_PATH_DECL(slow_path_throw) | |
1343 | { | |
1344 | LLINT_BEGIN(); | |
1345 | LLINT_THROW(LLINT_OP_C(1).jsValue()); | |
1346 | } | |
1347 | ||
93a37866 | 1348 | LLINT_SLOW_PATH_DECL(slow_path_throw_static_error) |
6fe7ccc8 A |
1349 | { |
1350 | LLINT_BEGIN(); | |
93a37866 | 1351 | if (pc[2].u.operand) |
81345200 | 1352 | LLINT_THROW(createReferenceError(exec, errorDescriptionForValue(exec, LLINT_OP_C(1).jsValue())->value(exec))); |
93a37866 | 1353 | else |
81345200 | 1354 | LLINT_THROW(createTypeError(exec, errorDescriptionForValue(exec, LLINT_OP_C(1).jsValue())->value(exec))); |
93a37866 A |
1355 | } |
1356 | ||
1357 | LLINT_SLOW_PATH_DECL(slow_path_handle_watchdog_timer) | |
1358 | { | |
1359 | LLINT_BEGIN_NO_SET_PC(); | |
81345200 A |
1360 | ASSERT(vm.watchdog); |
1361 | if (UNLIKELY(vm.watchdog->didFire(exec))) | |
93a37866 A |
1362 | LLINT_THROW(createTerminatedExecutionException(&vm)); |
1363 | LLINT_RETURN_TWO(0, exec); | |
6fe7ccc8 A |
1364 | } |
1365 | ||
1366 | LLINT_SLOW_PATH_DECL(slow_path_debug) | |
1367 | { | |
1368 | LLINT_BEGIN(); | |
1369 | int debugHookID = pc[1].u.operand; | |
81345200 | 1370 | vm.interpreter->debug(exec, static_cast<DebugHookID>(debugHookID)); |
6fe7ccc8 A |
1371 | |
1372 | LLINT_END(); | |
1373 | } | |
1374 | ||
1375 | LLINT_SLOW_PATH_DECL(slow_path_profile_will_call) | |
1376 | { | |
1377 | LLINT_BEGIN(); | |
93a37866 A |
1378 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
1379 | profiler->willExecute(exec, LLINT_OP(1).jsValue()); | |
6fe7ccc8 A |
1380 | LLINT_END(); |
1381 | } | |
1382 | ||
1383 | LLINT_SLOW_PATH_DECL(slow_path_profile_did_call) | |
1384 | { | |
1385 | LLINT_BEGIN(); | |
93a37866 A |
1386 | if (LegacyProfiler* profiler = vm.enabledProfiler()) |
1387 | profiler->didExecute(exec, LLINT_OP(1).jsValue()); | |
6fe7ccc8 A |
1388 | LLINT_END(); |
1389 | } | |
1390 | ||
81345200 A |
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) | |
6fe7ccc8 A |
1434 | { |
1435 | LLINT_BEGIN(); | |
81345200 A |
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 | ||
6fe7ccc8 A |
1457 | LLINT_END(); |
1458 | } | |
1459 | ||
81345200 A |
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 | } | |
6fe7ccc8 | 1468 | |
81345200 A |
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 |