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