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