source: webkit/trunk/JavaScriptCore/jit/JITStubs.cpp@ 46149

Last change on this file since 46149 was 45039, checked in by [email protected], 16 years ago

<rdar://problem/6992806> REGRESSION: Enumeration can skip new properties in cases of prototypes that have more than 64 (26593)
<https://bugs.webkit.org/show_bug.cgi?id=26593>

Reviewed by Gavin Barraclough.

Add tests to ensure we correctly invalidate caching that depends on structure chains
that include dictionaries.

File size: 95.0 KB
Line 
1/*
2 * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Cameron Zwarich <[email protected]>
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include "config.h"
31#include "JITStubs.h"
32
33#if ENABLE(JIT)
34
35#include "Arguments.h"
36#include "CallFrame.h"
37#include "CodeBlock.h"
38#include "Collector.h"
39#include "Debugger.h"
40#include "ExceptionHelpers.h"
41#include "GlobalEvalFunction.h"
42#include "JIT.h"
43#include "JSActivation.h"
44#include "JSArray.h"
45#include "JSByteArray.h"
46#include "JSFunction.h"
47#include "JSNotAnObject.h"
48#include "JSPropertyNameIterator.h"
49#include "JSStaticScopeObject.h"
50#include "JSString.h"
51#include "ObjectPrototype.h"
52#include "Operations.h"
53#include "Parser.h"
54#include "Profiler.h"
55#include "RegExpObject.h"
56#include "RegExpPrototype.h"
57#include "Register.h"
58#include "SamplingTool.h"
59#include <stdio.h>
60
61using namespace std;
62
63namespace JSC {
64
65
66#if PLATFORM(DARWIN) || PLATFORM(WIN_OS)
67#define SYMBOL_STRING(name) "_" #name
68#else
69#define SYMBOL_STRING(name) #name
70#endif
71
72#if COMPILER(GCC) && PLATFORM(X86)
73
74// These ASSERTs remind you that, if you change the layout of JITStackFrame, you
75// need to change the assembly trampolines below to match.
76COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x38, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
77COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x30, JITStackFrame_code_offset_matches_ctiTrampoline);
78COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x1c, JITStackFrame_stub_argument_space_matches_ctiTrampoline);
79
80asm volatile (
81".globl " SYMBOL_STRING(ctiTrampoline) "\n"
82SYMBOL_STRING(ctiTrampoline) ":" "\n"
83 "pushl %ebp" "\n"
84 "movl %esp, %ebp" "\n"
85 "pushl %esi" "\n"
86 "pushl %edi" "\n"
87 "pushl %ebx" "\n"
88 "subl $0x1c, %esp" "\n"
89 "movl $512, %esi" "\n"
90 "movl 0x38(%esp), %edi" "\n"
91 "call *0x30(%esp)" "\n"
92 "addl $0x1c, %esp" "\n"
93 "popl %ebx" "\n"
94 "popl %edi" "\n"
95 "popl %esi" "\n"
96 "popl %ebp" "\n"
97 "ret" "\n"
98);
99
100asm volatile (
101".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
102SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
103#if !USE(JIT_STUB_ARGUMENT_VA_LIST)
104 "movl %esp, %ecx" "\n"
105#endif
106 "call " SYMBOL_STRING(cti_vm_throw) "\n"
107 "addl $0x1c, %esp" "\n"
108 "popl %ebx" "\n"
109 "popl %edi" "\n"
110 "popl %esi" "\n"
111 "popl %ebp" "\n"
112 "ret" "\n"
113);
114
115asm volatile (
116".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
117SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
118 "addl $0x1c, %esp" "\n"
119 "popl %ebx" "\n"
120 "popl %edi" "\n"
121 "popl %esi" "\n"
122 "popl %ebp" "\n"
123 "ret" "\n"
124);
125
126#elif COMPILER(GCC) && PLATFORM(X86_64)
127
128#if USE(JIT_STUB_ARGUMENT_VA_LIST)
129#error "JIT_STUB_ARGUMENT_VA_LIST not supported on x86-64."
130#endif
131
132// These ASSERTs remind you that, if you change the layout of JITStackFrame, you
133// need to change the assembly trampolines below to match.
134COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x90, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
135COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x80, JITStackFrame_code_offset_matches_ctiTrampoline);
136COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x48, JITStackFrame_stub_argument_space_matches_ctiTrampoline);
137
138asm volatile (
139".globl " SYMBOL_STRING(ctiTrampoline) "\n"
140SYMBOL_STRING(ctiTrampoline) ":" "\n"
141 "pushq %rbp" "\n"
142 "movq %rsp, %rbp" "\n"
143 "pushq %r12" "\n"
144 "pushq %r13" "\n"
145 "pushq %r14" "\n"
146 "pushq %r15" "\n"
147 "pushq %rbx" "\n"
148 "subq $0x48, %rsp" "\n"
149 "movq $512, %r12" "\n"
150 "movq $0xFFFF000000000000, %r14" "\n"
151 "movq $0xFFFF000000000002, %r15" "\n"
152 "movq 0x90(%rsp), %r13" "\n"
153 "call *0x80(%rsp)" "\n"
154 "addq $0x48, %rsp" "\n"
155 "popq %rbx" "\n"
156 "popq %r15" "\n"
157 "popq %r14" "\n"
158 "popq %r13" "\n"
159 "popq %r12" "\n"
160 "popq %rbp" "\n"
161 "ret" "\n"
162);
163
164asm volatile (
165".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
166SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
167 "movq %rsp, %rdi" "\n"
168 "call " SYMBOL_STRING(cti_vm_throw) "\n"
169 "addq $0x48, %rsp" "\n"
170 "popq %rbx" "\n"
171 "popq %r15" "\n"
172 "popq %r14" "\n"
173 "popq %r13" "\n"
174 "popq %r12" "\n"
175 "popq %rbp" "\n"
176 "ret" "\n"
177);
178
179asm volatile (
180".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
181SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
182 "addq $0x48, %rsp" "\n"
183 "popq %rbx" "\n"
184 "popq %r15" "\n"
185 "popq %r14" "\n"
186 "popq %r13" "\n"
187 "popq %r12" "\n"
188 "popq %rbp" "\n"
189 "ret" "\n"
190);
191
192#elif COMPILER(GCC) && PLATFORM_ARM_ARCH(7)
193
194#if USE(JIT_STUB_ARGUMENT_VA_LIST)
195#error "JIT_STUB_ARGUMENT_VA_LIST not supported on ARMv7."
196#endif
197
198asm volatile (
199".text" "\n"
200".align 2" "\n"
201".globl " SYMBOL_STRING(ctiTrampoline) "\n"
202".thumb" "\n"
203".thumb_func " SYMBOL_STRING(ctiTrampoline) "\n"
204SYMBOL_STRING(ctiTrampoline) ":" "\n"
205 "sub sp, sp, #0x3c" "\n"
206 "str lr, [sp, #0x20]" "\n"
207 "str r4, [sp, #0x24]" "\n"
208 "str r5, [sp, #0x28]" "\n"
209 "str r6, [sp, #0x2c]" "\n"
210 "str r1, [sp, #0x30]" "\n"
211 "str r2, [sp, #0x34]" "\n"
212 "str r3, [sp, #0x38]" "\n"
213 "cpy r5, r2" "\n"
214 "mov r6, #512" "\n"
215 "blx r0" "\n"
216 "ldr r6, [sp, #0x2c]" "\n"
217 "ldr r5, [sp, #0x28]" "\n"
218 "ldr r4, [sp, #0x24]" "\n"
219 "ldr lr, [sp, #0x20]" "\n"
220 "add sp, sp, #0x3c" "\n"
221 "bx lr" "\n"
222);
223
224asm volatile (
225".text" "\n"
226".align 2" "\n"
227".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
228".thumb" "\n"
229".thumb_func " SYMBOL_STRING(ctiVMThrowTrampoline) "\n"
230SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n"
231 "cpy r0, sp" "\n"
232 "bl " SYMBOL_STRING(cti_vm_throw) "\n"
233 "ldr r6, [sp, #0x2c]" "\n"
234 "ldr r5, [sp, #0x28]" "\n"
235 "ldr r4, [sp, #0x24]" "\n"
236 "ldr lr, [sp, #0x20]" "\n"
237 "add sp, sp, #0x3c" "\n"
238 "bx lr" "\n"
239);
240
241asm volatile (
242".text" "\n"
243".align 2" "\n"
244".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
245".thumb" "\n"
246".thumb_func " SYMBOL_STRING(ctiOpThrowNotCaught) "\n"
247SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n"
248 "ldr r6, [sp, #0x2c]" "\n"
249 "ldr r5, [sp, #0x28]" "\n"
250 "ldr r4, [sp, #0x24]" "\n"
251 "ldr lr, [sp, #0x20]" "\n"
252 "add sp, sp, #0x3c" "\n"
253 "bx lr" "\n"
254);
255
256#elif COMPILER(MSVC)
257
258#if USE(JIT_STUB_ARGUMENT_VA_LIST)
259#error "JIT_STUB_ARGUMENT_VA_LIST configuration not supported on MSVC."
260#endif
261
262// These ASSERTs remind you that, if you change the layout of JITStackFrame, you
263// need to change the assembly trampolines below to match.
264COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x38, JITStackFrame_callFrame_offset_matches_ctiTrampoline);
265COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x30, JITStackFrame_code_offset_matches_ctiTrampoline);
266COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x1c, JITStackFrame_stub_argument_space_matches_ctiTrampoline);
267
268extern "C" {
269
270 __declspec(naked) EncodedJSValue ctiTrampoline(void* code, RegisterFile*, CallFrame*, JSValue* exception, Profiler**, JSGlobalData*)
271 {
272 __asm {
273 push ebp;
274 mov ebp, esp;
275 push esi;
276 push edi;
277 push ebx;
278 sub esp, 0x1c;
279 mov esi, 512;
280 mov ecx, esp;
281 mov edi, [esp + 0x38];
282 call [esp + 0x30];
283 add esp, 0x1c;
284 pop ebx;
285 pop edi;
286 pop esi;
287 pop ebp;
288 ret;
289 }
290 }
291
292 __declspec(naked) void ctiVMThrowTrampoline()
293 {
294 __asm {
295 mov ecx, esp;
296 call JITStubs::cti_vm_throw;
297 add esp, 0x1c;
298 pop ebx;
299 pop edi;
300 pop esi;
301 pop ebp;
302 ret;
303 }
304 }
305
306 __declspec(naked) void ctiOpThrowNotCaught()
307 {
308 __asm {
309 add esp, 0x1c;
310 pop ebx;
311 pop edi;
312 pop esi;
313 pop ebp;
314 ret;
315 }
316 }
317}
318
319#endif
320
321#if ENABLE(OPCODE_SAMPLING)
322 #define CTI_SAMPLER stackFrame.globalData->interpreter->sampler()
323#else
324 #define CTI_SAMPLER 0
325#endif
326
327JITThunks::JITThunks(JSGlobalData* globalData)
328{
329 JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_ctiArrayLengthTrampoline, &m_ctiStringLengthTrampoline, &m_ctiVirtualCallPreLink, &m_ctiVirtualCallLink, &m_ctiVirtualCall, &m_ctiNativeCallThunk);
330
331#if PLATFORM_ARM_ARCH(7)
332 // Unfortunate the arm compiler does not like the use of offsetof on JITStackFrame (since it contains non POD types),
333 // and the OBJECT_OFFSETOF macro does not appear constantish enough for it to be happy with its use in COMPILE_ASSERT
334 // macros.
335 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedReturnAddress) == 0x20);
336 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR4) == 0x24);
337 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR5) == 0x28);
338 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, preservedR6) == 0x2c);
339
340 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, registerFile) == 0x30);
341 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == 0x34);
342 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, exception) == 0x38);
343 // The fifth argument is the first item already on the stack.
344 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == 0x3c);
345
346 ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == 0x1C);
347#endif
348}
349
350#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
351
352NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const PutPropertySlot& slot)
353{
354 // The interpreter checks for recursion here; I do not believe this can occur in CTI.
355
356 if (!baseValue.isCell())
357 return;
358
359 // Uncacheable: give up.
360 if (!slot.isCacheable()) {
361 ctiPatchCallByReturnAddress(returnAddress, FunctionPtr(JITStubs::cti_op_put_by_id_generic));
362 return;
363 }
364
365 JSCell* baseCell = asCell(baseValue);
366 Structure* structure = baseCell->structure();
367
368 if (structure->isDictionary()) {
369 ctiPatchCallByReturnAddress(returnAddress, FunctionPtr(JITStubs::cti_op_put_by_id_generic));
370 return;
371 }
372
373 // If baseCell != base, then baseCell must be a proxy for another object.
374 if (baseCell != slot.base()) {
375 ctiPatchCallByReturnAddress(returnAddress, FunctionPtr(JITStubs::cti_op_put_by_id_generic));
376 return;
377 }
378
379 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(returnAddress);
380
381 // Cache hit: Specialize instruction and ref Structures.
382
383 // Structure transition, cache transition info
384 if (slot.type() == PutPropertySlot::NewProperty) {
385 StructureChain* prototypeChain = structure->prototypeChain(callFrame);
386 if (!prototypeChain->isCacheable()) {
387 ctiPatchCallByReturnAddress(returnAddress, FunctionPtr(JITStubs::cti_op_put_by_id_generic));
388 return;
389 }
390 stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain);
391 JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress);
392 return;
393 }
394
395 stubInfo->initPutByIdReplace(structure);
396
397 JIT::patchPutByIdReplace(stubInfo, structure, slot.cachedOffset(), returnAddress);
398}
399
400NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* codeBlock, ReturnAddressPtr returnAddress, JSValue baseValue, const Identifier& propertyName, const PropertySlot& slot)
401{
402 // FIXME: Write a test that proves we need to check for recursion here just
403 // like the interpreter does, then add a check for recursion.
404
405 // FIXME: Cache property access for immediates.
406 if (!baseValue.isCell()) {
407 ctiPatchCallByReturnAddress(returnAddress, FunctionPtr(JITStubs::cti_op_get_by_id_generic));
408 return;
409 }
410
411 JSGlobalData* globalData = &callFrame->globalData();
412
413 if (isJSArray(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
414 JIT::compilePatchGetArrayLength(callFrame->scopeChain()->globalData, codeBlock, returnAddress);
415 return;
416 }
417
418 if (isJSString(globalData, baseValue) && propertyName == callFrame->propertyNames().length) {
419 // The tradeoff of compiling an patched inline string length access routine does not seem
420 // to pay off, so we currently only do this for arrays.
421 ctiPatchCallByReturnAddress(returnAddress, globalData->jitStubs.ctiStringLengthTrampoline());
422 return;
423 }
424
425 // Uncacheable: give up.
426 if (!slot.isCacheable()) {
427 ctiPatchCallByReturnAddress(returnAddress, FunctionPtr(JITStubs::cti_op_get_by_id_generic));
428 return;
429 }
430
431 JSCell* baseCell = asCell(baseValue);
432 Structure* structure = baseCell->structure();
433
434 if (structure->isDictionary()) {
435 ctiPatchCallByReturnAddress(returnAddress, FunctionPtr(JITStubs::cti_op_get_by_id_generic));
436 return;
437 }
438
439 // In the interpreter the last structure is trapped here; in CTI we use the
440 // *_second method to achieve a similar (but not quite the same) effect.
441
442 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(returnAddress);
443
444 // Cache hit: Specialize instruction and ref Structures.
445
446 if (slot.slotBase() == baseValue) {
447 // set this up, so derefStructures can do it's job.
448 stubInfo->initGetByIdSelf(structure);
449
450 JIT::patchGetByIdSelf(stubInfo, structure, slot.cachedOffset(), returnAddress);
451 return;
452 }
453
454 if (slot.slotBase() == structure->prototypeForLookup(callFrame)) {
455 ASSERT(slot.slotBase().isObject());
456
457 JSObject* slotBaseObject = asObject(slot.slotBase());
458
459 // Since we're accessing a prototype in a loop, it's a good bet that it
460 // should not be treated as a dictionary.
461 if (slotBaseObject->structure()->isDictionary())
462 slotBaseObject->setStructure(Structure::fromDictionaryTransition(slotBaseObject->structure()));
463
464 stubInfo->initGetByIdProto(structure, slotBaseObject->structure());
465
466 JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), slot.cachedOffset(), returnAddress);
467 return;
468 }
469
470 size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot);
471 if (!count) {
472 stubInfo->opcodeID = op_get_by_id_generic;
473 return;
474 }
475
476 StructureChain* prototypeChain = structure->prototypeChain(callFrame);
477 if (!prototypeChain->isCacheable()) {
478 ctiPatchCallByReturnAddress(returnAddress, FunctionPtr(JITStubs::cti_op_get_by_id_generic));
479 return;
480 }
481 stubInfo->initGetByIdChain(structure, prototypeChain);
482 JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, slot.cachedOffset(), returnAddress);
483}
484
485#endif
486
487#if USE(JIT_STUB_ARGUMENT_VA_LIST)
488#define SETUP_VA_LISTL_ARGS va_list vl_args; va_start(vl_args, args)
489#else
490#define SETUP_VA_LISTL_ARGS
491#endif
492
493#ifndef NDEBUG
494
495extern "C" {
496
497static void jscGeneratedNativeCode()
498{
499 // When executing a JIT stub function (which might do an allocation), we hack the return address
500 // to pretend to be executing this function, to keep stack logging tools from blowing out
501 // memory.
502}
503
504}
505
506struct StackHack {
507 ALWAYS_INLINE StackHack(JITStackFrame& stackFrame)
508 : stackFrame(stackFrame)
509 , savedReturnAddress(*stackFrame.returnAddressSlot())
510 {
511 *stackFrame.returnAddressSlot() = ReturnAddressPtr(FunctionPtr(jscGeneratedNativeCode));
512 }
513
514 ALWAYS_INLINE ~StackHack()
515 {
516 *stackFrame.returnAddressSlot() = savedReturnAddress;
517 }
518
519 JITStackFrame& stackFrame;
520 ReturnAddressPtr savedReturnAddress;
521};
522
523#define STUB_INIT_STACK_FRAME(stackFrame) SETUP_VA_LISTL_ARGS; JITStackFrame& stackFrame = *reinterpret_cast<JITStackFrame*>(STUB_ARGS); StackHack stackHack(stackFrame)
524#define STUB_SET_RETURN_ADDRESS(returnAddress) stackHack.savedReturnAddress = ReturnAddressPtr(returnAddress)
525#define STUB_RETURN_ADDRESS stackHack.savedReturnAddress
526
527#else
528
529#define STUB_INIT_STACK_FRAME(stackFrame) SETUP_VA_LISTL_ARGS; JITStackFrame& stackFrame = *reinterpret_cast<JITStackFrame*>(STUB_ARGS)
530#define STUB_SET_RETURN_ADDRESS(returnAddress) *stackFrame.returnAddressSlot() = ReturnAddressPtr(returnAddress)
531#define STUB_RETURN_ADDRESS *stackFrame.returnAddressSlot()
532
533#endif
534
535// The reason this is not inlined is to avoid having to do a PIC branch
536// to get the address of the ctiVMThrowTrampoline function. It's also
537// good to keep the code size down by leaving as much of the exception
538// handling code out of line as possible.
539static NEVER_INLINE void returnToThrowTrampoline(JSGlobalData* globalData, ReturnAddressPtr exceptionLocation, ReturnAddressPtr& returnAddressSlot)
540{
541 ASSERT(globalData->exception);
542 globalData->exceptionLocation = exceptionLocation;
543 returnAddressSlot = ReturnAddressPtr(FunctionPtr(ctiVMThrowTrampoline));
544}
545
546static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalData* globalData, ReturnAddressPtr exceptionLocation, ReturnAddressPtr& returnAddressSlot)
547{
548 globalData->exception = createStackOverflowError(callFrame);
549 returnToThrowTrampoline(globalData, exceptionLocation, returnAddressSlot);
550}
551
552#define VM_THROW_EXCEPTION() \
553 do { \
554 VM_THROW_EXCEPTION_AT_END(); \
555 return 0; \
556 } while (0)
557#define VM_THROW_EXCEPTION_AT_END() \
558 returnToThrowTrampoline(stackFrame.globalData, STUB_RETURN_ADDRESS, STUB_RETURN_ADDRESS)
559
560#define CHECK_FOR_EXCEPTION() \
561 do { \
562 if (UNLIKELY(stackFrame.globalData->exception != JSValue())) \
563 VM_THROW_EXCEPTION(); \
564 } while (0)
565#define CHECK_FOR_EXCEPTION_AT_END() \
566 do { \
567 if (UNLIKELY(stackFrame.globalData->exception != JSValue())) \
568 VM_THROW_EXCEPTION_AT_END(); \
569 } while (0)
570#define CHECK_FOR_EXCEPTION_VOID() \
571 do { \
572 if (UNLIKELY(stackFrame.globalData->exception != JSValue())) { \
573 VM_THROW_EXCEPTION_AT_END(); \
574 return; \
575 } \
576 } while (0)
577
578namespace JITStubs {
579
580#if PLATFORM_ARM_ARCH(7)
581
582#define DEFINE_STUB_FUNCTION(rtype, op) \
583 extern "C" { \
584 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \
585 }; \
586 asm volatile ( \
587 ".text" "\n" \
588 ".align 2" "\n" \
589 ".globl " SYMBOL_STRING(cti_##op) "\n" \
590 ".thumb" "\n" \
591 ".thumb_func " SYMBOL_STRING(cti_##op) "\n" \
592 SYMBOL_STRING(cti_##op) ":" "\n" \
593 "str lr, [sp, #0x1c]" "\n" \
594 "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \
595 "ldr lr, [sp, #0x1c]" "\n" \
596 "bx lr" "\n" \
597 ); \
598 rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) \
599
600#else
601#define DEFINE_STUB_FUNCTION(rtype, op) rtype JIT_STUB cti_##op(STUB_ARGS_DECLARATION)
602#endif
603
604DEFINE_STUB_FUNCTION(JSObject*, op_convert_this)
605{
606 STUB_INIT_STACK_FRAME(stackFrame);
607
608 JSValue v1 = stackFrame.args[0].jsValue();
609 CallFrame* callFrame = stackFrame.callFrame;
610
611 JSObject* result = v1.toThisObject(callFrame);
612 CHECK_FOR_EXCEPTION_AT_END();
613 return result;
614}
615
616DEFINE_STUB_FUNCTION(void, op_end)
617{
618 STUB_INIT_STACK_FRAME(stackFrame);
619
620 ScopeChainNode* scopeChain = stackFrame.callFrame->scopeChain();
621 ASSERT(scopeChain->refCount > 1);
622 scopeChain->deref();
623}
624
625DEFINE_STUB_FUNCTION(EncodedJSValue, op_add)
626{
627 STUB_INIT_STACK_FRAME(stackFrame);
628
629 JSValue v1 = stackFrame.args[0].jsValue();
630 JSValue v2 = stackFrame.args[1].jsValue();
631
632 double left;
633 double right = 0.0;
634
635 bool rightIsNumber = v2.getNumber(right);
636 if (rightIsNumber && v1.getNumber(left))
637 return JSValue::encode(jsNumber(stackFrame.globalData, left + right));
638
639 CallFrame* callFrame = stackFrame.callFrame;
640
641 bool leftIsString = v1.isString();
642 if (leftIsString && v2.isString()) {
643 RefPtr<UString::Rep> value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep());
644 if (UNLIKELY(!value)) {
645 throwOutOfMemoryError(callFrame);
646 VM_THROW_EXCEPTION();
647 }
648
649 return JSValue::encode(jsString(stackFrame.globalData, value.release()));
650 }
651
652 if (rightIsNumber & leftIsString) {
653 RefPtr<UString::Rep> value = v2.isInt32Fast() ?
654 concatenate(asString(v1)->value().rep(), v2.getInt32Fast()) :
655 concatenate(asString(v1)->value().rep(), right);
656
657 if (UNLIKELY(!value)) {
658 throwOutOfMemoryError(callFrame);
659 VM_THROW_EXCEPTION();
660 }
661 return JSValue::encode(jsString(stackFrame.globalData, value.release()));
662 }
663
664 // All other cases are pretty uncommon
665 JSValue result = jsAddSlowCase(callFrame, v1, v2);
666 CHECK_FOR_EXCEPTION_AT_END();
667 return JSValue::encode(result);
668}
669
670DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_inc)
671{
672 STUB_INIT_STACK_FRAME(stackFrame);
673
674 JSValue v = stackFrame.args[0].jsValue();
675
676 CallFrame* callFrame = stackFrame.callFrame;
677 JSValue result = jsNumber(stackFrame.globalData, v.toNumber(callFrame) + 1);
678 CHECK_FOR_EXCEPTION_AT_END();
679 return JSValue::encode(result);
680}
681
682DEFINE_STUB_FUNCTION(int, timeout_check)
683{
684 STUB_INIT_STACK_FRAME(stackFrame);
685
686 JSGlobalData* globalData = stackFrame.globalData;
687 TimeoutChecker& timeoutChecker = globalData->timeoutChecker;
688
689 if (timeoutChecker.didTimeOut(stackFrame.callFrame)) {
690 globalData->exception = createInterruptedExecutionException(globalData);
691 VM_THROW_EXCEPTION_AT_END();
692 }
693
694 return timeoutChecker.ticksUntilNextCheck();
695}
696
697DEFINE_STUB_FUNCTION(void, register_file_check)
698{
699 STUB_INIT_STACK_FRAME(stackFrame);
700
701 if (LIKELY(stackFrame.registerFile->grow(&stackFrame.callFrame->registers()[stackFrame.callFrame->codeBlock()->m_numCalleeRegisters])))
702 return;
703
704 // Rewind to the previous call frame because op_call already optimistically
705 // moved the call frame forward.
706 CallFrame* oldCallFrame = stackFrame.callFrame->callerFrame();
707 stackFrame.callFrame = oldCallFrame;
708 throwStackOverflowError(oldCallFrame, stackFrame.globalData, ReturnAddressPtr(oldCallFrame->returnPC()), STUB_RETURN_ADDRESS);
709}
710
711DEFINE_STUB_FUNCTION(int, op_loop_if_less)
712{
713 STUB_INIT_STACK_FRAME(stackFrame);
714
715 JSValue src1 = stackFrame.args[0].jsValue();
716 JSValue src2 = stackFrame.args[1].jsValue();
717 CallFrame* callFrame = stackFrame.callFrame;
718
719 bool result = jsLess(callFrame, src1, src2);
720 CHECK_FOR_EXCEPTION_AT_END();
721 return result;
722}
723
724DEFINE_STUB_FUNCTION(int, op_loop_if_lesseq)
725{
726 STUB_INIT_STACK_FRAME(stackFrame);
727
728 JSValue src1 = stackFrame.args[0].jsValue();
729 JSValue src2 = stackFrame.args[1].jsValue();
730 CallFrame* callFrame = stackFrame.callFrame;
731
732 bool result = jsLessEq(callFrame, src1, src2);
733 CHECK_FOR_EXCEPTION_AT_END();
734 return result;
735}
736
737DEFINE_STUB_FUNCTION(JSObject*, op_new_object)
738{
739 STUB_INIT_STACK_FRAME(stackFrame);
740
741 return constructEmptyObject(stackFrame.callFrame);
742}
743
744DEFINE_STUB_FUNCTION(void, op_put_by_id_generic)
745{
746 STUB_INIT_STACK_FRAME(stackFrame);
747
748 PutPropertySlot slot;
749 stackFrame.args[0].jsValue().put(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot);
750 CHECK_FOR_EXCEPTION_AT_END();
751}
752
753DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_generic)
754{
755 STUB_INIT_STACK_FRAME(stackFrame);
756
757 CallFrame* callFrame = stackFrame.callFrame;
758 Identifier& ident = stackFrame.args[1].identifier();
759
760 JSValue baseValue = stackFrame.args[0].jsValue();
761 PropertySlot slot(baseValue);
762 JSValue result = baseValue.get(callFrame, ident, slot);
763
764 CHECK_FOR_EXCEPTION_AT_END();
765 return JSValue::encode(result);
766}
767
768#if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS)
769
770DEFINE_STUB_FUNCTION(void, op_put_by_id)
771{
772 STUB_INIT_STACK_FRAME(stackFrame);
773
774 CallFrame* callFrame = stackFrame.callFrame;
775 Identifier& ident = stackFrame.args[1].identifier();
776
777 PutPropertySlot slot;
778 stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot);
779
780 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_id_second));
781
782 CHECK_FOR_EXCEPTION_AT_END();
783}
784
785DEFINE_STUB_FUNCTION(void, op_put_by_id_second)
786{
787 STUB_INIT_STACK_FRAME(stackFrame);
788
789 PutPropertySlot slot;
790 stackFrame.args[0].jsValue().put(stackFrame.callFrame, stackFrame.args[1].identifier(), stackFrame.args[2].jsValue(), slot);
791 JITThunks::tryCachePutByID(stackFrame.callFrame, stackFrame.callFrame->codeBlock(), STUB_RETURN_ADDRESS, stackFrame.args[0].jsValue(), slot);
792 CHECK_FOR_EXCEPTION_AT_END();
793}
794
795DEFINE_STUB_FUNCTION(void, op_put_by_id_fail)
796{
797 STUB_INIT_STACK_FRAME(stackFrame);
798
799 CallFrame* callFrame = stackFrame.callFrame;
800 Identifier& ident = stackFrame.args[1].identifier();
801
802 PutPropertySlot slot;
803 stackFrame.args[0].jsValue().put(callFrame, ident, stackFrame.args[2].jsValue(), slot);
804
805 CHECK_FOR_EXCEPTION_AT_END();
806}
807
808
809DEFINE_STUB_FUNCTION(EncodedJSValue, op_put_by_id_transition_realloc)
810{
811 STUB_INIT_STACK_FRAME(stackFrame);
812
813 JSValue baseValue = stackFrame.args[0].jsValue();
814 int32_t oldSize = stackFrame.args[1].int32();
815 int32_t newSize = stackFrame.args[2].int32();
816
817 ASSERT(baseValue.isObject());
818 asObject(baseValue)->allocatePropertyStorage(oldSize, newSize);
819
820 return JSValue::encode(baseValue);
821}
822
823DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id)
824{
825 STUB_INIT_STACK_FRAME(stackFrame);
826
827 CallFrame* callFrame = stackFrame.callFrame;
828 Identifier& ident = stackFrame.args[1].identifier();
829
830 JSValue baseValue = stackFrame.args[0].jsValue();
831 PropertySlot slot(baseValue);
832 JSValue result = baseValue.get(callFrame, ident, slot);
833
834 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_second));
835
836 CHECK_FOR_EXCEPTION_AT_END();
837 return JSValue::encode(result);
838}
839
840DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check)
841{
842 STUB_INIT_STACK_FRAME(stackFrame);
843
844 CallFrame* callFrame = stackFrame.callFrame;
845 Identifier& ident = stackFrame.args[1].identifier();
846
847 JSValue baseValue = stackFrame.args[0].jsValue();
848 PropertySlot slot(baseValue);
849 JSValue result = baseValue.get(callFrame, ident, slot);
850
851 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_method_check_second));
852
853 CHECK_FOR_EXCEPTION_AT_END();
854 return JSValue::encode(result);
855}
856
857DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check_second)
858{
859 STUB_INIT_STACK_FRAME(stackFrame);
860
861 CallFrame* callFrame = stackFrame.callFrame;
862 Identifier& ident = stackFrame.args[1].identifier();
863
864 JSValue baseValue = stackFrame.args[0].jsValue();
865 PropertySlot slot(baseValue);
866 JSValue result = baseValue.get(callFrame, ident, slot);
867
868 CHECK_FOR_EXCEPTION();
869
870 // If we successfully got something, then the base from which it is being accessed must
871 // be an object. (Assertion to ensure asObject() call below is safe, which comes after
872 // an isCacheable() chceck.
873 ASSERT(!slot.isCacheable() || slot.slotBase().isObject());
874
875 // Check that:
876 // * We're dealing with a JSCell,
877 // * the property is cachable,
878 // * it's not a dictionary
879 // * there is a function cached.
880 Structure* structure;
881 JSCell* specific;
882 JSObject* slotBaseObject;
883 if (baseValue.isCell()
884 && slot.isCacheable()
885 && !(structure = asCell(baseValue)->structure())->isDictionary()
886 && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(callFrame, ident, specific)
887 && specific
888 ) {
889
890 JSFunction* callee = (JSFunction*)specific;
891
892 // Since we're accessing a prototype in a loop, it's a good bet that it
893 // should not be treated as a dictionary.
894 if (slotBaseObject->structure()->isDictionary())
895 slotBaseObject->setStructure(Structure::fromDictionaryTransition(slotBaseObject->structure()));
896
897 // The result fetched should always be the callee!
898 ASSERT(result == JSValue(callee));
899 MethodCallLinkInfo& methodCallLinkInfo = callFrame->codeBlock()->getMethodCallLinkInfo(STUB_RETURN_ADDRESS);
900
901 // Check to see if the function is on the object's prototype. Patch up the code to optimize.
902 if (slot.slotBase() == structure->prototypeForLookup(callFrame))
903 JIT::patchMethodCallProto(methodCallLinkInfo, callee, structure, slotBaseObject);
904 // Check to see if the function is on the object itself.
905 // Since we generate the method-check to check both the structure and a prototype-structure (since this
906 // is the common case) we have a problem - we need to patch the prototype structure check to do something
907 // useful. We could try to nop it out altogether, but that's a little messy, so lets do something simpler
908 // for now. For now it performs a check on a special object on the global object only used for this
909 // purpose. The object is in no way exposed, and as such the check will always pass.
910 else if (slot.slotBase() == baseValue)
911 JIT::patchMethodCallProto(methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject()->methodCallDummy());
912
913 // For now let any other case be cached as a normal get_by_id.
914 }
915
916 // Revert the get_by_id op back to being a regular get_by_id - allow it to cache like normal, if it needs to.
917 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id));
918
919 return JSValue::encode(result);
920}
921
922DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_second)
923{
924 STUB_INIT_STACK_FRAME(stackFrame);
925
926 CallFrame* callFrame = stackFrame.callFrame;
927 Identifier& ident = stackFrame.args[1].identifier();
928
929 JSValue baseValue = stackFrame.args[0].jsValue();
930 PropertySlot slot(baseValue);
931 JSValue result = baseValue.get(callFrame, ident, slot);
932
933 JITThunks::tryCacheGetByID(callFrame, callFrame->codeBlock(), STUB_RETURN_ADDRESS, baseValue, ident, slot);
934
935 CHECK_FOR_EXCEPTION_AT_END();
936 return JSValue::encode(result);
937}
938
939DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail)
940{
941 STUB_INIT_STACK_FRAME(stackFrame);
942
943 CallFrame* callFrame = stackFrame.callFrame;
944 Identifier& ident = stackFrame.args[1].identifier();
945
946 JSValue baseValue = stackFrame.args[0].jsValue();
947 PropertySlot slot(baseValue);
948 JSValue result = baseValue.get(callFrame, ident, slot);
949
950 CHECK_FOR_EXCEPTION();
951
952 if (baseValue.isCell()
953 && slot.isCacheable()
954 && !asCell(baseValue)->structure()->isDictionary()
955 && slot.slotBase() == baseValue) {
956
957 CodeBlock* codeBlock = callFrame->codeBlock();
958 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
959
960 ASSERT(slot.slotBase().isObject());
961
962 PolymorphicAccessStructureList* polymorphicStructureList;
963 int listIndex = 1;
964
965 if (stubInfo->opcodeID == op_get_by_id_self) {
966 ASSERT(!stubInfo->stubRoutine);
967 polymorphicStructureList = new PolymorphicAccessStructureList(CodeLocationLabel(), stubInfo->u.getByIdSelf.baseObjectStructure);
968 stubInfo->initGetByIdSelfList(polymorphicStructureList, 2);
969 } else {
970 polymorphicStructureList = stubInfo->u.getByIdSelfList.structureList;
971 listIndex = stubInfo->u.getByIdSelfList.listSize;
972 stubInfo->u.getByIdSelfList.listSize++;
973 }
974
975 JIT::compileGetByIdSelfList(callFrame->scopeChain()->globalData, codeBlock, stubInfo, polymorphicStructureList, listIndex, asCell(baseValue)->structure(), slot.cachedOffset());
976
977 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
978 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic));
979 } else {
980 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_generic));
981 }
982 return JSValue::encode(result);
983}
984
985static PolymorphicAccessStructureList* getPolymorphicAccessStructureListSlot(StructureStubInfo* stubInfo, int& listIndex)
986{
987 PolymorphicAccessStructureList* prototypeStructureList = 0;
988 listIndex = 1;
989
990 switch (stubInfo->opcodeID) {
991 case op_get_by_id_proto:
992 prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdProto.baseObjectStructure, stubInfo->u.getByIdProto.prototypeStructure);
993 stubInfo->stubRoutine = CodeLocationLabel();
994 stubInfo->initGetByIdProtoList(prototypeStructureList, 2);
995 break;
996 case op_get_by_id_chain:
997 prototypeStructureList = new PolymorphicAccessStructureList(stubInfo->stubRoutine, stubInfo->u.getByIdChain.baseObjectStructure, stubInfo->u.getByIdChain.chain);
998 stubInfo->stubRoutine = CodeLocationLabel();
999 stubInfo->initGetByIdProtoList(prototypeStructureList, 2);
1000 break;
1001 case op_get_by_id_proto_list:
1002 prototypeStructureList = stubInfo->u.getByIdProtoList.structureList;
1003 listIndex = stubInfo->u.getByIdProtoList.listSize;
1004 stubInfo->u.getByIdProtoList.listSize++;
1005 break;
1006 default:
1007 ASSERT_NOT_REACHED();
1008 }
1009
1010 ASSERT(listIndex < POLYMORPHIC_LIST_CACHE_SIZE);
1011 return prototypeStructureList;
1012}
1013
1014DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list)
1015{
1016 STUB_INIT_STACK_FRAME(stackFrame);
1017
1018 CallFrame* callFrame = stackFrame.callFrame;
1019
1020 JSValue baseValue = stackFrame.args[0].jsValue();
1021 PropertySlot slot(baseValue);
1022 JSValue result = baseValue.get(callFrame, stackFrame.args[1].identifier(), slot);
1023
1024 CHECK_FOR_EXCEPTION();
1025
1026 if (!baseValue.isCell() || !slot.isCacheable() || asCell(baseValue)->structure()->isDictionary()) {
1027 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
1028 return JSValue::encode(result);
1029 }
1030
1031 Structure* structure = asCell(baseValue)->structure();
1032 CodeBlock* codeBlock = callFrame->codeBlock();
1033 StructureStubInfo* stubInfo = &codeBlock->getStubInfo(STUB_RETURN_ADDRESS);
1034
1035 ASSERT(slot.slotBase().isObject());
1036 JSObject* slotBaseObject = asObject(slot.slotBase());
1037
1038 if (slot.slotBase() == baseValue)
1039 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
1040 else if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) {
1041 // Since we're accessing a prototype in a loop, it's a good bet that it
1042 // should not be treated as a dictionary.
1043 if (slotBaseObject->structure()->isDictionary())
1044 slotBaseObject->setStructure(Structure::fromDictionaryTransition(slotBaseObject->structure()));
1045
1046 int listIndex;
1047 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex);
1048
1049 JIT::compileGetByIdProtoList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, slotBaseObject->structure(), slot.cachedOffset());
1050
1051 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
1052 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full));
1053 } else if (size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot)) {
1054 StructureChain* protoChain = structure->prototypeChain(callFrame);
1055 if (!protoChain->isCacheable()) {
1056 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
1057 return JSValue::encode(result);
1058 }
1059
1060 int listIndex;
1061 PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex);
1062 JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, slot.cachedOffset());
1063
1064 if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1))
1065 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full));
1066 } else
1067 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail));
1068
1069 return JSValue::encode(result);
1070}
1071
1072DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list_full)
1073{
1074 STUB_INIT_STACK_FRAME(stackFrame);
1075
1076 JSValue baseValue = stackFrame.args[0].jsValue();
1077 PropertySlot slot(baseValue);
1078 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot);
1079
1080 CHECK_FOR_EXCEPTION_AT_END();
1081 return JSValue::encode(result);
1082}
1083
1084DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_fail)
1085{
1086 STUB_INIT_STACK_FRAME(stackFrame);
1087
1088 JSValue baseValue = stackFrame.args[0].jsValue();
1089 PropertySlot slot(baseValue);
1090 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot);
1091
1092 CHECK_FOR_EXCEPTION_AT_END();
1093 return JSValue::encode(result);
1094}
1095
1096DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_array_fail)
1097{
1098 STUB_INIT_STACK_FRAME(stackFrame);
1099
1100 JSValue baseValue = stackFrame.args[0].jsValue();
1101 PropertySlot slot(baseValue);
1102 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot);
1103
1104 CHECK_FOR_EXCEPTION_AT_END();
1105 return JSValue::encode(result);
1106}
1107
1108DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_string_fail)
1109{
1110 STUB_INIT_STACK_FRAME(stackFrame);
1111
1112 JSValue baseValue = stackFrame.args[0].jsValue();
1113 PropertySlot slot(baseValue);
1114 JSValue result = baseValue.get(stackFrame.callFrame, stackFrame.args[1].identifier(), slot);
1115
1116 CHECK_FOR_EXCEPTION_AT_END();
1117 return JSValue::encode(result);
1118}
1119
1120#endif
1121
1122DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof)
1123{
1124 STUB_INIT_STACK_FRAME(stackFrame);
1125
1126 CallFrame* callFrame = stackFrame.callFrame;
1127 JSValue value = stackFrame.args[0].jsValue();
1128 JSValue baseVal = stackFrame.args[1].jsValue();
1129 JSValue proto = stackFrame.args[2].jsValue();
1130
1131 // At least one of these checks must have failed to get to the slow case.
1132 ASSERT(!value.isCell() || !baseVal.isCell() || !proto.isCell()
1133 || !value.isObject() || !baseVal.isObject() || !proto.isObject()
1134 || (asObject(baseVal)->structure()->typeInfo().flags() & (ImplementsHasInstance | OverridesHasInstance)) != ImplementsHasInstance);
1135
1136
1137 // ECMA-262 15.3.5.3:
1138 // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function).
1139 TypeInfo typeInfo(UnspecifiedType, 0);
1140 if (!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()) {
1141 CallFrame* callFrame = stackFrame.callFrame;
1142 CodeBlock* codeBlock = callFrame->codeBlock();
1143 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
1144 stackFrame.globalData->exception = createInvalidParamError(callFrame, "instanceof", baseVal, vPCIndex, codeBlock);
1145 VM_THROW_EXCEPTION();
1146 }
1147 ASSERT(typeInfo.type() != UnspecifiedType);
1148
1149 if (!typeInfo.overridesHasInstance()) {
1150 if (!value.isObject())
1151 return JSValue::encode(jsBoolean(false));
1152
1153 if (!proto.isObject()) {
1154 throwError(callFrame, TypeError, "instanceof called on an object with an invalid prototype property.");
1155 VM_THROW_EXCEPTION();
1156 }
1157 }
1158
1159 JSValue result = jsBoolean(asObject(baseVal)->hasInstance(callFrame, value, proto));
1160 CHECK_FOR_EXCEPTION_AT_END();
1161
1162 return JSValue::encode(result);
1163}
1164
1165DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_id)
1166{
1167 STUB_INIT_STACK_FRAME(stackFrame);
1168
1169 CallFrame* callFrame = stackFrame.callFrame;
1170
1171 JSObject* baseObj = stackFrame.args[0].jsValue().toObject(callFrame);
1172
1173 JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, stackFrame.args[1].identifier()));
1174 CHECK_FOR_EXCEPTION_AT_END();
1175 return JSValue::encode(result);
1176}
1177
1178DEFINE_STUB_FUNCTION(EncodedJSValue, op_mul)
1179{
1180 STUB_INIT_STACK_FRAME(stackFrame);
1181
1182 JSValue src1 = stackFrame.args[0].jsValue();
1183 JSValue src2 = stackFrame.args[1].jsValue();
1184
1185 double left;
1186 double right;
1187 if (src1.getNumber(left) && src2.getNumber(right))
1188 return JSValue::encode(jsNumber(stackFrame.globalData, left * right));
1189
1190 CallFrame* callFrame = stackFrame.callFrame;
1191 JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) * src2.toNumber(callFrame));
1192 CHECK_FOR_EXCEPTION_AT_END();
1193 return JSValue::encode(result);
1194}
1195
1196DEFINE_STUB_FUNCTION(JSObject*, op_new_func)
1197{
1198 STUB_INIT_STACK_FRAME(stackFrame);
1199
1200 return stackFrame.args[0].funcDeclNode()->makeFunction(stackFrame.callFrame, stackFrame.callFrame->scopeChain());
1201}
1202
1203DEFINE_STUB_FUNCTION(void*, op_call_JSFunction)
1204{
1205 STUB_INIT_STACK_FRAME(stackFrame);
1206
1207#ifndef NDEBUG
1208 CallData callData;
1209 ASSERT(stackFrame.args[0].jsValue().getCallData(callData) == CallTypeJS);
1210#endif
1211
1212 JSFunction* function = asFunction(stackFrame.args[0].jsValue());
1213 ASSERT(!function->isHostFunction());
1214 FunctionBodyNode* body = function->body();
1215 ScopeChainNode* callDataScopeChain = function->scope().node();
1216 body->jitCode(callDataScopeChain);
1217
1218 return &(body->generatedBytecode());
1219}
1220
1221DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck)
1222{
1223 STUB_INIT_STACK_FRAME(stackFrame);
1224
1225 CallFrame* callFrame = stackFrame.callFrame;
1226 CodeBlock* newCodeBlock = stackFrame.args[3].codeBlock();
1227 ASSERT(newCodeBlock->codeType() != NativeCode);
1228 int argCount = stackFrame.args[2].int32();
1229
1230 ASSERT(argCount != newCodeBlock->m_numParameters);
1231
1232 CallFrame* oldCallFrame = callFrame->callerFrame();
1233
1234 if (argCount > newCodeBlock->m_numParameters) {
1235 size_t numParameters = newCodeBlock->m_numParameters;
1236 Register* r = callFrame->registers() + numParameters;
1237
1238 Register* argv = r - RegisterFile::CallFrameHeaderSize - numParameters - argCount;
1239 for (size_t i = 0; i < numParameters; ++i)
1240 argv[i + argCount] = argv[i];
1241
1242 callFrame = CallFrame::create(r);
1243 callFrame->setCallerFrame(oldCallFrame);
1244 } else {
1245 size_t omittedArgCount = newCodeBlock->m_numParameters - argCount;
1246 Register* r = callFrame->registers() + omittedArgCount;
1247 Register* newEnd = r + newCodeBlock->m_numCalleeRegisters;
1248 if (!stackFrame.registerFile->grow(newEnd)) {
1249 // Rewind to the previous call frame because op_call already optimistically
1250 // moved the call frame forward.
1251 stackFrame.callFrame = oldCallFrame;
1252 throwStackOverflowError(oldCallFrame, stackFrame.globalData, stackFrame.args[1].returnAddress(), STUB_RETURN_ADDRESS);
1253 RETURN_POINTER_PAIR(0, 0);
1254 }
1255
1256 Register* argv = r - RegisterFile::CallFrameHeaderSize - omittedArgCount;
1257 for (size_t i = 0; i < omittedArgCount; ++i)
1258 argv[i] = jsUndefined();
1259
1260 callFrame = CallFrame::create(r);
1261 callFrame->setCallerFrame(oldCallFrame);
1262 }
1263
1264 RETURN_POINTER_PAIR(newCodeBlock, callFrame);
1265}
1266
1267DEFINE_STUB_FUNCTION(void*, vm_dontLazyLinkCall)
1268{
1269 STUB_INIT_STACK_FRAME(stackFrame);
1270
1271 JSGlobalData* globalData = stackFrame.globalData;
1272 JSFunction* callee = asFunction(stackFrame.args[0].jsValue());
1273
1274 ctiPatchNearCallByReturnAddress(stackFrame.args[1].returnAddress(), globalData->jitStubs.ctiVirtualCallLink());
1275
1276 return callee->body()->generatedJITCode().addressForCall().executableAddress();
1277}
1278
1279DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall)
1280{
1281 STUB_INIT_STACK_FRAME(stackFrame);
1282
1283 JSFunction* callee = asFunction(stackFrame.args[0].jsValue());
1284 JITCode& jitCode = callee->body()->generatedJITCode();
1285
1286 CodeBlock* codeBlock = 0;
1287 if (!callee->isHostFunction())
1288 codeBlock = &callee->body()->bytecode(callee->scope().node());
1289 else
1290 codeBlock = &callee->body()->generatedBytecode();
1291
1292 CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(stackFrame.args[1].returnAddress());
1293 JIT::linkCall(callee, codeBlock, jitCode, callLinkInfo, stackFrame.args[2].int32(), stackFrame.globalData);
1294
1295 return jitCode.addressForCall().executableAddress();
1296}
1297
1298DEFINE_STUB_FUNCTION(JSObject*, op_push_activation)
1299{
1300 STUB_INIT_STACK_FRAME(stackFrame);
1301
1302 JSActivation* activation = new (stackFrame.globalData) JSActivation(stackFrame.callFrame, static_cast<FunctionBodyNode*>(stackFrame.callFrame->codeBlock()->ownerNode()));
1303 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->copy()->push(activation));
1304 return activation;
1305}
1306
1307DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_NotJSFunction)
1308{
1309 STUB_INIT_STACK_FRAME(stackFrame);
1310
1311 JSValue funcVal = stackFrame.args[0].jsValue();
1312
1313 CallData callData;
1314 CallType callType = funcVal.getCallData(callData);
1315
1316 ASSERT(callType != CallTypeJS);
1317
1318 if (callType == CallTypeHost) {
1319 int registerOffset = stackFrame.args[1].int32();
1320 int argCount = stackFrame.args[2].int32();
1321 CallFrame* previousCallFrame = stackFrame.callFrame;
1322 CallFrame* callFrame = CallFrame::create(previousCallFrame->registers() + registerOffset);
1323
1324 callFrame->init(0, static_cast<Instruction*>((STUB_RETURN_ADDRESS).value()), previousCallFrame->scopeChain(), previousCallFrame, 0, argCount, 0);
1325 stackFrame.callFrame = callFrame;
1326
1327 Register* argv = stackFrame.callFrame->registers() - RegisterFile::CallFrameHeaderSize - argCount;
1328 ArgList argList(argv + 1, argCount - 1);
1329
1330 JSValue returnValue;
1331 {
1332 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
1333
1334 // FIXME: All host methods should be calling toThisObject, but this is not presently the case.
1335 JSValue thisValue = argv[0].jsValue();
1336 if (thisValue == jsNull())
1337 thisValue = callFrame->globalThisValue();
1338
1339 returnValue = callData.native.function(callFrame, asObject(funcVal), thisValue, argList);
1340 }
1341 stackFrame.callFrame = previousCallFrame;
1342 CHECK_FOR_EXCEPTION();
1343
1344 return JSValue::encode(returnValue);
1345 }
1346
1347 ASSERT(callType == CallTypeNone);
1348
1349 CallFrame* callFrame = stackFrame.callFrame;
1350 CodeBlock* codeBlock = callFrame->codeBlock();
1351 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
1352 stackFrame.globalData->exception = createNotAFunctionError(stackFrame.callFrame, funcVal, vPCIndex, codeBlock);
1353 VM_THROW_EXCEPTION();
1354}
1355
1356DEFINE_STUB_FUNCTION(void, op_create_arguments)
1357{
1358 STUB_INIT_STACK_FRAME(stackFrame);
1359
1360 Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame);
1361 stackFrame.callFrame->setCalleeArguments(arguments);
1362 stackFrame.callFrame[RegisterFile::ArgumentsRegister] = arguments;
1363}
1364
1365DEFINE_STUB_FUNCTION(void, op_create_arguments_no_params)
1366{
1367 STUB_INIT_STACK_FRAME(stackFrame);
1368
1369 Arguments* arguments = new (stackFrame.globalData) Arguments(stackFrame.callFrame, Arguments::NoParameters);
1370 stackFrame.callFrame->setCalleeArguments(arguments);
1371 stackFrame.callFrame[RegisterFile::ArgumentsRegister] = arguments;
1372}
1373
1374DEFINE_STUB_FUNCTION(void, op_tear_off_activation)
1375{
1376 STUB_INIT_STACK_FRAME(stackFrame);
1377
1378 ASSERT(stackFrame.callFrame->codeBlock()->needsFullScopeChain());
1379 asActivation(stackFrame.args[0].jsValue())->copyRegisters(stackFrame.callFrame->optionalCalleeArguments());
1380}
1381
1382DEFINE_STUB_FUNCTION(void, op_tear_off_arguments)
1383{
1384 STUB_INIT_STACK_FRAME(stackFrame);
1385
1386 ASSERT(stackFrame.callFrame->codeBlock()->usesArguments() && !stackFrame.callFrame->codeBlock()->needsFullScopeChain());
1387 if (stackFrame.callFrame->optionalCalleeArguments())
1388 stackFrame.callFrame->optionalCalleeArguments()->copyRegisters();
1389}
1390
1391DEFINE_STUB_FUNCTION(void, op_profile_will_call)
1392{
1393 STUB_INIT_STACK_FRAME(stackFrame);
1394
1395 ASSERT(*stackFrame.enabledProfilerReference);
1396 (*stackFrame.enabledProfilerReference)->willExecute(stackFrame.callFrame, stackFrame.args[0].jsValue());
1397}
1398
1399DEFINE_STUB_FUNCTION(void, op_profile_did_call)
1400{
1401 STUB_INIT_STACK_FRAME(stackFrame);
1402
1403 ASSERT(*stackFrame.enabledProfilerReference);
1404 (*stackFrame.enabledProfilerReference)->didExecute(stackFrame.callFrame, stackFrame.args[0].jsValue());
1405}
1406
1407DEFINE_STUB_FUNCTION(void, op_ret_scopeChain)
1408{
1409 STUB_INIT_STACK_FRAME(stackFrame);
1410
1411 ASSERT(stackFrame.callFrame->codeBlock()->needsFullScopeChain());
1412 stackFrame.callFrame->scopeChain()->deref();
1413}
1414
1415DEFINE_STUB_FUNCTION(JSObject*, op_new_array)
1416{
1417 STUB_INIT_STACK_FRAME(stackFrame);
1418
1419 ArgList argList(&stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32());
1420 return constructArray(stackFrame.callFrame, argList);
1421}
1422
1423DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve)
1424{
1425 STUB_INIT_STACK_FRAME(stackFrame);
1426
1427 CallFrame* callFrame = stackFrame.callFrame;
1428 ScopeChainNode* scopeChain = callFrame->scopeChain();
1429
1430 ScopeChainIterator iter = scopeChain->begin();
1431 ScopeChainIterator end = scopeChain->end();
1432 ASSERT(iter != end);
1433
1434 Identifier& ident = stackFrame.args[0].identifier();
1435 do {
1436 JSObject* o = *iter;
1437 PropertySlot slot(o);
1438 if (o->getPropertySlot(callFrame, ident, slot)) {
1439 JSValue result = slot.getValue(callFrame, ident);
1440 CHECK_FOR_EXCEPTION_AT_END();
1441 return JSValue::encode(result);
1442 }
1443 } while (++iter != end);
1444
1445 CodeBlock* codeBlock = callFrame->codeBlock();
1446 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
1447 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock);
1448 VM_THROW_EXCEPTION();
1449}
1450
1451DEFINE_STUB_FUNCTION(JSObject*, op_construct_JSConstruct)
1452{
1453 STUB_INIT_STACK_FRAME(stackFrame);
1454
1455 JSFunction* constructor = asFunction(stackFrame.args[0].jsValue());
1456 if (constructor->isHostFunction()) {
1457 CallFrame* callFrame = stackFrame.callFrame;
1458 CodeBlock* codeBlock = callFrame->codeBlock();
1459 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
1460 stackFrame.globalData->exception = createNotAConstructorError(callFrame, constructor, vPCIndex, codeBlock);
1461 VM_THROW_EXCEPTION();
1462 }
1463
1464#ifndef NDEBUG
1465 ConstructData constructData;
1466 ASSERT(constructor->getConstructData(constructData) == ConstructTypeJS);
1467#endif
1468
1469 Structure* structure;
1470 if (stackFrame.args[3].jsValue().isObject())
1471 structure = asObject(stackFrame.args[3].jsValue())->inheritorID();
1472 else
1473 structure = constructor->scope().node()->globalObject()->emptyObjectStructure();
1474 return new (stackFrame.globalData) JSObject(structure);
1475}
1476
1477DEFINE_STUB_FUNCTION(EncodedJSValue, op_construct_NotJSConstruct)
1478{
1479 STUB_INIT_STACK_FRAME(stackFrame);
1480
1481 CallFrame* callFrame = stackFrame.callFrame;
1482
1483 JSValue constrVal = stackFrame.args[0].jsValue();
1484 int argCount = stackFrame.args[2].int32();
1485 int thisRegister = stackFrame.args[4].int32();
1486
1487 ConstructData constructData;
1488 ConstructType constructType = constrVal.getConstructData(constructData);
1489
1490 if (constructType == ConstructTypeHost) {
1491 ArgList argList(callFrame->registers() + thisRegister + 1, argCount - 1);
1492
1493 JSValue returnValue;
1494 {
1495 SamplingTool::HostCallRecord callRecord(CTI_SAMPLER);
1496 returnValue = constructData.native.function(callFrame, asObject(constrVal), argList);
1497 }
1498 CHECK_FOR_EXCEPTION();
1499
1500 return JSValue::encode(returnValue);
1501 }
1502
1503 ASSERT(constructType == ConstructTypeNone);
1504
1505 CodeBlock* codeBlock = callFrame->codeBlock();
1506 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
1507 stackFrame.globalData->exception = createNotAConstructorError(callFrame, constrVal, vPCIndex, codeBlock);
1508 VM_THROW_EXCEPTION();
1509}
1510
1511DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val)
1512{
1513 STUB_INIT_STACK_FRAME(stackFrame);
1514
1515 CallFrame* callFrame = stackFrame.callFrame;
1516 JSGlobalData* globalData = stackFrame.globalData;
1517
1518 JSValue baseValue = stackFrame.args[0].jsValue();
1519 JSValue subscript = stackFrame.args[1].jsValue();
1520
1521 JSValue result;
1522
1523 if (LIKELY(subscript.isUInt32Fast())) {
1524 uint32_t i = subscript.getUInt32Fast();
1525 if (isJSArray(globalData, baseValue)) {
1526 JSArray* jsArray = asArray(baseValue);
1527 if (jsArray->canGetIndex(i))
1528 result = jsArray->getIndex(i);
1529 else
1530 result = jsArray->JSArray::get(callFrame, i);
1531 } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) {
1532 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks.
1533 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_string));
1534 result = asString(baseValue)->getIndex(stackFrame.globalData, i);
1535 } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
1536 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks.
1537 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_byte_array));
1538 return JSValue::encode(asByteArray(baseValue)->getIndex(callFrame, i));
1539 } else
1540 result = baseValue.get(callFrame, i);
1541 } else {
1542 Identifier property(callFrame, subscript.toString(callFrame));
1543 result = baseValue.get(callFrame, property);
1544 }
1545
1546 CHECK_FOR_EXCEPTION_AT_END();
1547 return JSValue::encode(result);
1548}
1549
1550DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_string)
1551{
1552 STUB_INIT_STACK_FRAME(stackFrame);
1553
1554 CallFrame* callFrame = stackFrame.callFrame;
1555 JSGlobalData* globalData = stackFrame.globalData;
1556
1557 JSValue baseValue = stackFrame.args[0].jsValue();
1558 JSValue subscript = stackFrame.args[1].jsValue();
1559
1560 JSValue result;
1561
1562 if (LIKELY(subscript.isUInt32Fast())) {
1563 uint32_t i = subscript.getUInt32Fast();
1564 if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i))
1565 result = asString(baseValue)->getIndex(stackFrame.globalData, i);
1566 else {
1567 result = baseValue.get(callFrame, i);
1568 if (!isJSString(globalData, baseValue))
1569 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val));
1570 }
1571 } else {
1572 Identifier property(callFrame, subscript.toString(callFrame));
1573 result = baseValue.get(callFrame, property);
1574 }
1575
1576 CHECK_FOR_EXCEPTION_AT_END();
1577 return JSValue::encode(result);
1578}
1579
1580
1581DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_byte_array)
1582{
1583 STUB_INIT_STACK_FRAME(stackFrame);
1584
1585 CallFrame* callFrame = stackFrame.callFrame;
1586 JSGlobalData* globalData = stackFrame.globalData;
1587
1588 JSValue baseValue = stackFrame.args[0].jsValue();
1589 JSValue subscript = stackFrame.args[1].jsValue();
1590
1591 JSValue result;
1592
1593 if (LIKELY(subscript.isUInt32Fast())) {
1594 uint32_t i = subscript.getUInt32Fast();
1595 if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
1596 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks.
1597 return JSValue::encode(asByteArray(baseValue)->getIndex(callFrame, i));
1598 }
1599
1600 result = baseValue.get(callFrame, i);
1601 if (!isJSByteArray(globalData, baseValue))
1602 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val));
1603 } else {
1604 Identifier property(callFrame, subscript.toString(callFrame));
1605 result = baseValue.get(callFrame, property);
1606 }
1607
1608 CHECK_FOR_EXCEPTION_AT_END();
1609 return JSValue::encode(result);
1610}
1611
1612DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_func)
1613{
1614 STUB_INIT_STACK_FRAME(stackFrame);
1615
1616 CallFrame* callFrame = stackFrame.callFrame;
1617 ScopeChainNode* scopeChain = callFrame->scopeChain();
1618
1619 ScopeChainIterator iter = scopeChain->begin();
1620 ScopeChainIterator end = scopeChain->end();
1621
1622 // FIXME: add scopeDepthIsZero optimization
1623
1624 ASSERT(iter != end);
1625
1626 Identifier& ident = stackFrame.args[0].identifier();
1627 JSObject* base;
1628 do {
1629 base = *iter;
1630 PropertySlot slot(base);
1631 if (base->getPropertySlot(callFrame, ident, slot)) {
1632 // ECMA 11.2.3 says that if we hit an activation the this value should be null.
1633 // However, section 10.2.3 says that in the case where the value provided
1634 // by the caller is null, the global object should be used. It also says
1635 // that the section does not apply to internal functions, but for simplicity
1636 // of implementation we use the global object anyway here. This guarantees
1637 // that in host objects you always get a valid object for this.
1638 // We also handle wrapper substitution for the global object at the same time.
1639 JSObject* thisObj = base->toThisObject(callFrame);
1640 JSValue result = slot.getValue(callFrame, ident);
1641 CHECK_FOR_EXCEPTION_AT_END();
1642
1643 callFrame->registers()[stackFrame.args[1].int32()] = JSValue(thisObj);
1644 return JSValue::encode(result);
1645 }
1646 ++iter;
1647 } while (iter != end);
1648
1649 CodeBlock* codeBlock = callFrame->codeBlock();
1650 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
1651 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock);
1652 VM_THROW_EXCEPTION_AT_END();
1653 return JSValue::encode(JSValue());
1654}
1655
1656DEFINE_STUB_FUNCTION(EncodedJSValue, op_sub)
1657{
1658 STUB_INIT_STACK_FRAME(stackFrame);
1659
1660 JSValue src1 = stackFrame.args[0].jsValue();
1661 JSValue src2 = stackFrame.args[1].jsValue();
1662
1663 double left;
1664 double right;
1665 if (src1.getNumber(left) && src2.getNumber(right))
1666 return JSValue::encode(jsNumber(stackFrame.globalData, left - right));
1667
1668 CallFrame* callFrame = stackFrame.callFrame;
1669 JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) - src2.toNumber(callFrame));
1670 CHECK_FOR_EXCEPTION_AT_END();
1671 return JSValue::encode(result);
1672}
1673
1674DEFINE_STUB_FUNCTION(void, op_put_by_val)
1675{
1676 STUB_INIT_STACK_FRAME(stackFrame);
1677
1678 CallFrame* callFrame = stackFrame.callFrame;
1679 JSGlobalData* globalData = stackFrame.globalData;
1680
1681 JSValue baseValue = stackFrame.args[0].jsValue();
1682 JSValue subscript = stackFrame.args[1].jsValue();
1683 JSValue value = stackFrame.args[2].jsValue();
1684
1685 if (LIKELY(subscript.isUInt32Fast())) {
1686 uint32_t i = subscript.getUInt32Fast();
1687 if (isJSArray(globalData, baseValue)) {
1688 JSArray* jsArray = asArray(baseValue);
1689 if (jsArray->canSetIndex(i))
1690 jsArray->setIndex(i, value);
1691 else
1692 jsArray->JSArray::put(callFrame, i, value);
1693 } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
1694 JSByteArray* jsByteArray = asByteArray(baseValue);
1695 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val_byte_array));
1696 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks.
1697 if (value.isInt32Fast()) {
1698 jsByteArray->setIndex(i, value.getInt32Fast());
1699 return;
1700 } else {
1701 double dValue = 0;
1702 if (value.getNumber(dValue)) {
1703 jsByteArray->setIndex(i, dValue);
1704 return;
1705 }
1706 }
1707
1708 baseValue.put(callFrame, i, value);
1709 } else
1710 baseValue.put(callFrame, i, value);
1711 } else {
1712 Identifier property(callFrame, subscript.toString(callFrame));
1713 if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception.
1714 PutPropertySlot slot;
1715 baseValue.put(callFrame, property, value, slot);
1716 }
1717 }
1718
1719 CHECK_FOR_EXCEPTION_AT_END();
1720}
1721
1722DEFINE_STUB_FUNCTION(void, op_put_by_val_array)
1723{
1724 STUB_INIT_STACK_FRAME(stackFrame);
1725
1726 CallFrame* callFrame = stackFrame.callFrame;
1727 JSValue baseValue = stackFrame.args[0].jsValue();
1728 int i = stackFrame.args[1].int32();
1729 JSValue value = stackFrame.args[2].jsValue();
1730
1731 ASSERT(isJSArray(stackFrame.globalData, baseValue));
1732
1733 if (LIKELY(i >= 0))
1734 asArray(baseValue)->JSArray::put(callFrame, i, value);
1735 else {
1736 // This should work since we're re-boxing an immediate unboxed in JIT code.
1737 ASSERT(JSValue::makeInt32Fast(i));
1738 Identifier property(callFrame, JSValue::makeInt32Fast(i).toString(callFrame));
1739 // FIXME: can toString throw an exception here?
1740 if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception.
1741 PutPropertySlot slot;
1742 baseValue.put(callFrame, property, value, slot);
1743 }
1744 }
1745
1746 CHECK_FOR_EXCEPTION_AT_END();
1747}
1748
1749DEFINE_STUB_FUNCTION(void, op_put_by_val_byte_array)
1750{
1751 STUB_INIT_STACK_FRAME(stackFrame);
1752
1753 CallFrame* callFrame = stackFrame.callFrame;
1754 JSGlobalData* globalData = stackFrame.globalData;
1755
1756 JSValue baseValue = stackFrame.args[0].jsValue();
1757 JSValue subscript = stackFrame.args[1].jsValue();
1758 JSValue value = stackFrame.args[2].jsValue();
1759
1760 if (LIKELY(subscript.isUInt32Fast())) {
1761 uint32_t i = subscript.getUInt32Fast();
1762 if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) {
1763 JSByteArray* jsByteArray = asByteArray(baseValue);
1764
1765 // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks.
1766 if (value.isInt32Fast()) {
1767 jsByteArray->setIndex(i, value.getInt32Fast());
1768 return;
1769 } else {
1770 double dValue = 0;
1771 if (value.getNumber(dValue)) {
1772 jsByteArray->setIndex(i, dValue);
1773 return;
1774 }
1775 }
1776 }
1777
1778 if (!isJSByteArray(globalData, baseValue))
1779 ctiPatchCallByReturnAddress(STUB_RETURN_ADDRESS, FunctionPtr(cti_op_put_by_val));
1780 baseValue.put(callFrame, i, value);
1781 } else {
1782 Identifier property(callFrame, subscript.toString(callFrame));
1783 if (!stackFrame.globalData->exception) { // Don't put to an object if toString threw an exception.
1784 PutPropertySlot slot;
1785 baseValue.put(callFrame, property, value, slot);
1786 }
1787 }
1788
1789 CHECK_FOR_EXCEPTION_AT_END();
1790}
1791
1792DEFINE_STUB_FUNCTION(EncodedJSValue, op_lesseq)
1793{
1794 STUB_INIT_STACK_FRAME(stackFrame);
1795
1796 CallFrame* callFrame = stackFrame.callFrame;
1797 JSValue result = jsBoolean(jsLessEq(callFrame, stackFrame.args[0].jsValue(), stackFrame.args[1].jsValue()));
1798 CHECK_FOR_EXCEPTION_AT_END();
1799 return JSValue::encode(result);
1800}
1801
1802DEFINE_STUB_FUNCTION(int, op_loop_if_true)
1803{
1804 STUB_INIT_STACK_FRAME(stackFrame);
1805
1806 JSValue src1 = stackFrame.args[0].jsValue();
1807
1808 CallFrame* callFrame = stackFrame.callFrame;
1809
1810 bool result = src1.toBoolean(callFrame);
1811 CHECK_FOR_EXCEPTION_AT_END();
1812 return result;
1813}
1814
1815DEFINE_STUB_FUNCTION(int, op_load_varargs)
1816{
1817 STUB_INIT_STACK_FRAME(stackFrame);
1818 CallFrame* callFrame = stackFrame.callFrame;
1819 RegisterFile* registerFile = stackFrame.registerFile;
1820 int argsOffset = stackFrame.args[0].int32();
1821 JSValue arguments = callFrame->registers()[argsOffset].jsValue();
1822 uint32_t argCount = 0;
1823 if (!arguments) {
1824 int providedParams = callFrame->registers()[RegisterFile::ArgumentCount].i() - 1;
1825 argCount = providedParams;
1826 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
1827 Register* newEnd = callFrame->registers() + sizeDelta;
1828 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
1829 stackFrame.globalData->exception = createStackOverflowError(callFrame);
1830 VM_THROW_EXCEPTION();
1831 }
1832 int32_t expectedParams = asFunction(callFrame->registers()[RegisterFile::Callee].jsValue())->body()->parameterCount();
1833 int32_t inplaceArgs = min(providedParams, expectedParams);
1834
1835 Register* inplaceArgsDst = callFrame->registers() + argsOffset;
1836
1837 Register* inplaceArgsEnd = inplaceArgsDst + inplaceArgs;
1838 Register* inplaceArgsEnd2 = inplaceArgsDst + providedParams;
1839
1840 Register* inplaceArgsSrc = callFrame->registers() - RegisterFile::CallFrameHeaderSize - expectedParams;
1841 Register* inplaceArgsSrc2 = inplaceArgsSrc - providedParams - 1 + inplaceArgs;
1842
1843 // First step is to copy the "expected" parameters from their normal location relative to the callframe
1844 while (inplaceArgsDst < inplaceArgsEnd)
1845 *inplaceArgsDst++ = *inplaceArgsSrc++;
1846
1847 // Then we copy any additional arguments that may be further up the stack ('-1' to account for 'this')
1848 while (inplaceArgsDst < inplaceArgsEnd2)
1849 *inplaceArgsDst++ = *inplaceArgsSrc2++;
1850
1851 } else if (!arguments.isUndefinedOrNull()) {
1852 if (!arguments.isObject()) {
1853 CodeBlock* codeBlock = callFrame->codeBlock();
1854 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
1855 stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPCIndex, codeBlock);
1856 VM_THROW_EXCEPTION();
1857 }
1858 if (asObject(arguments)->classInfo() == &Arguments::info) {
1859 Arguments* argsObject = asArguments(arguments);
1860 argCount = argsObject->numProvidedArguments(callFrame);
1861 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
1862 Register* newEnd = callFrame->registers() + sizeDelta;
1863 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
1864 stackFrame.globalData->exception = createStackOverflowError(callFrame);
1865 VM_THROW_EXCEPTION();
1866 }
1867 argsObject->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
1868 } else if (isJSArray(&callFrame->globalData(), arguments)) {
1869 JSArray* array = asArray(arguments);
1870 argCount = array->length();
1871 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
1872 Register* newEnd = callFrame->registers() + sizeDelta;
1873 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
1874 stackFrame.globalData->exception = createStackOverflowError(callFrame);
1875 VM_THROW_EXCEPTION();
1876 }
1877 array->copyToRegisters(callFrame, callFrame->registers() + argsOffset, argCount);
1878 } else if (asObject(arguments)->inherits(&JSArray::info)) {
1879 JSObject* argObject = asObject(arguments);
1880 argCount = argObject->get(callFrame, callFrame->propertyNames().length).toUInt32(callFrame);
1881 int32_t sizeDelta = argsOffset + argCount + RegisterFile::CallFrameHeaderSize;
1882 Register* newEnd = callFrame->registers() + sizeDelta;
1883 if (!registerFile->grow(newEnd) || ((newEnd - callFrame->registers()) != sizeDelta)) {
1884 stackFrame.globalData->exception = createStackOverflowError(callFrame);
1885 VM_THROW_EXCEPTION();
1886 }
1887 Register* argsBuffer = callFrame->registers() + argsOffset;
1888 for (unsigned i = 0; i < argCount; ++i) {
1889 argsBuffer[i] = asObject(arguments)->get(callFrame, i);
1890 CHECK_FOR_EXCEPTION();
1891 }
1892 } else {
1893 CodeBlock* codeBlock = callFrame->codeBlock();
1894 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
1895 stackFrame.globalData->exception = createInvalidParamError(callFrame, "Function.prototype.apply", arguments, vPCIndex, codeBlock);
1896 VM_THROW_EXCEPTION();
1897 }
1898 }
1899
1900 return argCount + 1;
1901}
1902
1903DEFINE_STUB_FUNCTION(EncodedJSValue, op_negate)
1904{
1905 STUB_INIT_STACK_FRAME(stackFrame);
1906
1907 JSValue src = stackFrame.args[0].jsValue();
1908
1909 double v;
1910 if (src.getNumber(v))
1911 return JSValue::encode(jsNumber(stackFrame.globalData, -v));
1912
1913 CallFrame* callFrame = stackFrame.callFrame;
1914 JSValue result = jsNumber(stackFrame.globalData, -src.toNumber(callFrame));
1915 CHECK_FOR_EXCEPTION_AT_END();
1916 return JSValue::encode(result);
1917}
1918
1919DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_base)
1920{
1921 STUB_INIT_STACK_FRAME(stackFrame);
1922
1923 return JSValue::encode(JSC::resolveBase(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.callFrame->scopeChain()));
1924}
1925
1926DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_skip)
1927{
1928 STUB_INIT_STACK_FRAME(stackFrame);
1929
1930 CallFrame* callFrame = stackFrame.callFrame;
1931 ScopeChainNode* scopeChain = callFrame->scopeChain();
1932
1933 int skip = stackFrame.args[1].int32();
1934
1935 ScopeChainIterator iter = scopeChain->begin();
1936 ScopeChainIterator end = scopeChain->end();
1937 ASSERT(iter != end);
1938 while (skip--) {
1939 ++iter;
1940 ASSERT(iter != end);
1941 }
1942 Identifier& ident = stackFrame.args[0].identifier();
1943 do {
1944 JSObject* o = *iter;
1945 PropertySlot slot(o);
1946 if (o->getPropertySlot(callFrame, ident, slot)) {
1947 JSValue result = slot.getValue(callFrame, ident);
1948 CHECK_FOR_EXCEPTION_AT_END();
1949 return JSValue::encode(result);
1950 }
1951 } while (++iter != end);
1952
1953 CodeBlock* codeBlock = callFrame->codeBlock();
1954 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
1955 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock);
1956 VM_THROW_EXCEPTION();
1957}
1958
1959DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global)
1960{
1961 STUB_INIT_STACK_FRAME(stackFrame);
1962
1963 CallFrame* callFrame = stackFrame.callFrame;
1964 JSGlobalObject* globalObject = asGlobalObject(stackFrame.args[0].jsValue());
1965 Identifier& ident = stackFrame.args[1].identifier();
1966 unsigned globalResolveInfoIndex = stackFrame.args[2].int32();
1967 ASSERT(globalObject->isGlobalObject());
1968
1969 PropertySlot slot(globalObject);
1970 if (globalObject->getPropertySlot(callFrame, ident, slot)) {
1971 JSValue result = slot.getValue(callFrame, ident);
1972 if (slot.isCacheable() && !globalObject->structure()->isDictionary() && slot.slotBase() == globalObject) {
1973 GlobalResolveInfo& globalResolveInfo = callFrame->codeBlock()->globalResolveInfo(globalResolveInfoIndex);
1974 if (globalResolveInfo.structure)
1975 globalResolveInfo.structure->deref();
1976 globalObject->structure()->ref();
1977 globalResolveInfo.structure = globalObject->structure();
1978 globalResolveInfo.offset = slot.cachedOffset();
1979 return JSValue::encode(result);
1980 }
1981
1982 CHECK_FOR_EXCEPTION_AT_END();
1983 return JSValue::encode(result);
1984 }
1985
1986 unsigned vPCIndex = callFrame->codeBlock()->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
1987 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, callFrame->codeBlock());
1988 VM_THROW_EXCEPTION();
1989}
1990
1991DEFINE_STUB_FUNCTION(EncodedJSValue, op_div)
1992{
1993 STUB_INIT_STACK_FRAME(stackFrame);
1994
1995 JSValue src1 = stackFrame.args[0].jsValue();
1996 JSValue src2 = stackFrame.args[1].jsValue();
1997
1998 double left;
1999 double right;
2000 if (src1.getNumber(left) && src2.getNumber(right))
2001 return JSValue::encode(jsNumber(stackFrame.globalData, left / right));
2002
2003 CallFrame* callFrame = stackFrame.callFrame;
2004 JSValue result = jsNumber(stackFrame.globalData, src1.toNumber(callFrame) / src2.toNumber(callFrame));
2005 CHECK_FOR_EXCEPTION_AT_END();
2006 return JSValue::encode(result);
2007}
2008
2009DEFINE_STUB_FUNCTION(EncodedJSValue, op_pre_dec)
2010{
2011 STUB_INIT_STACK_FRAME(stackFrame);
2012
2013 JSValue v = stackFrame.args[0].jsValue();
2014
2015 CallFrame* callFrame = stackFrame.callFrame;
2016 JSValue result = jsNumber(stackFrame.globalData, v.toNumber(callFrame) - 1);
2017 CHECK_FOR_EXCEPTION_AT_END();
2018 return JSValue::encode(result);
2019}
2020
2021DEFINE_STUB_FUNCTION(int, op_jless)
2022{
2023 STUB_INIT_STACK_FRAME(stackFrame);
2024
2025 JSValue src1 = stackFrame.args[0].jsValue();
2026 JSValue src2 = stackFrame.args[1].jsValue();
2027 CallFrame* callFrame = stackFrame.callFrame;
2028
2029 bool result = jsLess(callFrame, src1, src2);
2030 CHECK_FOR_EXCEPTION_AT_END();
2031 return result;
2032}
2033
2034DEFINE_STUB_FUNCTION(int, op_jlesseq)
2035{
2036 STUB_INIT_STACK_FRAME(stackFrame);
2037
2038 JSValue src1 = stackFrame.args[0].jsValue();
2039 JSValue src2 = stackFrame.args[1].jsValue();
2040 CallFrame* callFrame = stackFrame.callFrame;
2041
2042 bool result = jsLessEq(callFrame, src1, src2);
2043 CHECK_FOR_EXCEPTION_AT_END();
2044 return result;
2045}
2046
2047DEFINE_STUB_FUNCTION(EncodedJSValue, op_not)
2048{
2049 STUB_INIT_STACK_FRAME(stackFrame);
2050
2051 JSValue src = stackFrame.args[0].jsValue();
2052
2053 CallFrame* callFrame = stackFrame.callFrame;
2054
2055 JSValue result = jsBoolean(!src.toBoolean(callFrame));
2056 CHECK_FOR_EXCEPTION_AT_END();
2057 return JSValue::encode(result);
2058}
2059
2060DEFINE_STUB_FUNCTION(int, op_jtrue)
2061{
2062 STUB_INIT_STACK_FRAME(stackFrame);
2063
2064 JSValue src1 = stackFrame.args[0].jsValue();
2065
2066 CallFrame* callFrame = stackFrame.callFrame;
2067
2068 bool result = src1.toBoolean(callFrame);
2069 CHECK_FOR_EXCEPTION_AT_END();
2070 return result;
2071}
2072
2073DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_inc)
2074{
2075 STUB_INIT_STACK_FRAME(stackFrame);
2076
2077 JSValue v = stackFrame.args[0].jsValue();
2078
2079 CallFrame* callFrame = stackFrame.callFrame;
2080
2081 JSValue number = v.toJSNumber(callFrame);
2082 CHECK_FOR_EXCEPTION_AT_END();
2083
2084 callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(stackFrame.globalData, number.uncheckedGetNumber() + 1);
2085 return JSValue::encode(number);
2086}
2087
2088DEFINE_STUB_FUNCTION(EncodedJSValue, op_eq)
2089{
2090 STUB_INIT_STACK_FRAME(stackFrame);
2091
2092 JSValue src1 = stackFrame.args[0].jsValue();
2093 JSValue src2 = stackFrame.args[1].jsValue();
2094
2095 CallFrame* callFrame = stackFrame.callFrame;
2096
2097 ASSERT(!JSValue::areBothInt32Fast(src1, src2));
2098 JSValue result = jsBoolean(JSValue::equalSlowCaseInline(callFrame, src1, src2));
2099 CHECK_FOR_EXCEPTION_AT_END();
2100 return JSValue::encode(result);
2101}
2102
2103DEFINE_STUB_FUNCTION(EncodedJSValue, op_lshift)
2104{
2105 STUB_INIT_STACK_FRAME(stackFrame);
2106
2107 JSValue val = stackFrame.args[0].jsValue();
2108 JSValue shift = stackFrame.args[1].jsValue();
2109
2110 int32_t left;
2111 uint32_t right;
2112 if (JSValue::areBothInt32Fast(val, shift))
2113 return JSValue::encode(jsNumber(stackFrame.globalData, val.getInt32Fast() << (shift.getInt32Fast() & 0x1f)));
2114 if (val.numberToInt32(left) && shift.numberToUInt32(right))
2115 return JSValue::encode(jsNumber(stackFrame.globalData, left << (right & 0x1f)));
2116
2117 CallFrame* callFrame = stackFrame.callFrame;
2118 JSValue result = jsNumber(stackFrame.globalData, (val.toInt32(callFrame)) << (shift.toUInt32(callFrame) & 0x1f));
2119 CHECK_FOR_EXCEPTION_AT_END();
2120 return JSValue::encode(result);
2121}
2122
2123DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitand)
2124{
2125 STUB_INIT_STACK_FRAME(stackFrame);
2126
2127 JSValue src1 = stackFrame.args[0].jsValue();
2128 JSValue src2 = stackFrame.args[1].jsValue();
2129
2130 int32_t left;
2131 int32_t right;
2132 if (src1.numberToInt32(left) && src2.numberToInt32(right))
2133 return JSValue::encode(jsNumber(stackFrame.globalData, left & right));
2134
2135 CallFrame* callFrame = stackFrame.callFrame;
2136 JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) & src2.toInt32(callFrame));
2137 CHECK_FOR_EXCEPTION_AT_END();
2138 return JSValue::encode(result);
2139}
2140
2141DEFINE_STUB_FUNCTION(EncodedJSValue, op_rshift)
2142{
2143 STUB_INIT_STACK_FRAME(stackFrame);
2144
2145 JSValue val = stackFrame.args[0].jsValue();
2146 JSValue shift = stackFrame.args[1].jsValue();
2147
2148 int32_t left;
2149 uint32_t right;
2150 if (JSFastMath::canDoFastRshift(val, shift))
2151 return JSValue::encode(JSFastMath::rightShiftImmediateNumbers(val, shift));
2152 if (val.numberToInt32(left) && shift.numberToUInt32(right))
2153 return JSValue::encode(jsNumber(stackFrame.globalData, left >> (right & 0x1f)));
2154
2155 CallFrame* callFrame = stackFrame.callFrame;
2156 JSValue result = jsNumber(stackFrame.globalData, (val.toInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
2157 CHECK_FOR_EXCEPTION_AT_END();
2158 return JSValue::encode(result);
2159}
2160
2161DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitnot)
2162{
2163 STUB_INIT_STACK_FRAME(stackFrame);
2164
2165 JSValue src = stackFrame.args[0].jsValue();
2166
2167 int value;
2168 if (src.numberToInt32(value))
2169 return JSValue::encode(jsNumber(stackFrame.globalData, ~value));
2170
2171 CallFrame* callFrame = stackFrame.callFrame;
2172 JSValue result = jsNumber(stackFrame.globalData, ~src.toInt32(callFrame));
2173 CHECK_FOR_EXCEPTION_AT_END();
2174 return JSValue::encode(result);
2175}
2176
2177DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base)
2178{
2179 STUB_INIT_STACK_FRAME(stackFrame);
2180
2181 CallFrame* callFrame = stackFrame.callFrame;
2182 ScopeChainNode* scopeChain = callFrame->scopeChain();
2183
2184 ScopeChainIterator iter = scopeChain->begin();
2185 ScopeChainIterator end = scopeChain->end();
2186
2187 // FIXME: add scopeDepthIsZero optimization
2188
2189 ASSERT(iter != end);
2190
2191 Identifier& ident = stackFrame.args[0].identifier();
2192 JSObject* base;
2193 do {
2194 base = *iter;
2195 PropertySlot slot(base);
2196 if (base->getPropertySlot(callFrame, ident, slot)) {
2197 JSValue result = slot.getValue(callFrame, ident);
2198 CHECK_FOR_EXCEPTION_AT_END();
2199
2200 callFrame->registers()[stackFrame.args[1].int32()] = JSValue(base);
2201 return JSValue::encode(result);
2202 }
2203 ++iter;
2204 } while (iter != end);
2205
2206 CodeBlock* codeBlock = callFrame->codeBlock();
2207 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
2208 stackFrame.globalData->exception = createUndefinedVariableError(callFrame, ident, vPCIndex, codeBlock);
2209 VM_THROW_EXCEPTION_AT_END();
2210 return JSValue::encode(JSValue());
2211}
2212
2213DEFINE_STUB_FUNCTION(JSObject*, op_new_func_exp)
2214{
2215 STUB_INIT_STACK_FRAME(stackFrame);
2216
2217 return stackFrame.args[0].funcExprNode()->makeFunction(stackFrame.callFrame, stackFrame.callFrame->scopeChain());
2218}
2219
2220DEFINE_STUB_FUNCTION(EncodedJSValue, op_mod)
2221{
2222 STUB_INIT_STACK_FRAME(stackFrame);
2223
2224 JSValue dividendValue = stackFrame.args[0].jsValue();
2225 JSValue divisorValue = stackFrame.args[1].jsValue();
2226
2227 CallFrame* callFrame = stackFrame.callFrame;
2228 double d = dividendValue.toNumber(callFrame);
2229 JSValue result = jsNumber(stackFrame.globalData, fmod(d, divisorValue.toNumber(callFrame)));
2230 CHECK_FOR_EXCEPTION_AT_END();
2231 return JSValue::encode(result);
2232}
2233
2234DEFINE_STUB_FUNCTION(EncodedJSValue, op_less)
2235{
2236 STUB_INIT_STACK_FRAME(stackFrame);
2237
2238 CallFrame* callFrame = stackFrame.callFrame;
2239 JSValue result = jsBoolean(jsLess(callFrame, stackFrame.args[0].jsValue(), stackFrame.args[1].jsValue()));
2240 CHECK_FOR_EXCEPTION_AT_END();
2241 return JSValue::encode(result);
2242}
2243
2244DEFINE_STUB_FUNCTION(EncodedJSValue, op_neq)
2245{
2246 STUB_INIT_STACK_FRAME(stackFrame);
2247
2248 JSValue src1 = stackFrame.args[0].jsValue();
2249 JSValue src2 = stackFrame.args[1].jsValue();
2250
2251 ASSERT(!JSValue::areBothInt32Fast(src1, src2));
2252
2253 CallFrame* callFrame = stackFrame.callFrame;
2254 JSValue result = jsBoolean(!JSValue::equalSlowCaseInline(callFrame, src1, src2));
2255 CHECK_FOR_EXCEPTION_AT_END();
2256 return JSValue::encode(result);
2257}
2258
2259DEFINE_STUB_FUNCTION(EncodedJSValue, op_post_dec)
2260{
2261 STUB_INIT_STACK_FRAME(stackFrame);
2262
2263 JSValue v = stackFrame.args[0].jsValue();
2264
2265 CallFrame* callFrame = stackFrame.callFrame;
2266
2267 JSValue number = v.toJSNumber(callFrame);
2268 CHECK_FOR_EXCEPTION_AT_END();
2269
2270 callFrame->registers()[stackFrame.args[1].int32()] = jsNumber(stackFrame.globalData, number.uncheckedGetNumber() - 1);
2271 return JSValue::encode(number);
2272}
2273
2274DEFINE_STUB_FUNCTION(EncodedJSValue, op_urshift)
2275{
2276 STUB_INIT_STACK_FRAME(stackFrame);
2277
2278 JSValue val = stackFrame.args[0].jsValue();
2279 JSValue shift = stackFrame.args[1].jsValue();
2280
2281 CallFrame* callFrame = stackFrame.callFrame;
2282
2283 if (JSFastMath::canDoFastUrshift(val, shift))
2284 return JSValue::encode(JSFastMath::rightShiftImmediateNumbers(val, shift));
2285 else {
2286 JSValue result = jsNumber(stackFrame.globalData, (val.toUInt32(callFrame)) >> (shift.toUInt32(callFrame) & 0x1f));
2287 CHECK_FOR_EXCEPTION_AT_END();
2288 return JSValue::encode(result);
2289 }
2290}
2291
2292DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitxor)
2293{
2294 STUB_INIT_STACK_FRAME(stackFrame);
2295
2296 JSValue src1 = stackFrame.args[0].jsValue();
2297 JSValue src2 = stackFrame.args[1].jsValue();
2298
2299 CallFrame* callFrame = stackFrame.callFrame;
2300
2301 JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) ^ src2.toInt32(callFrame));
2302 CHECK_FOR_EXCEPTION_AT_END();
2303 return JSValue::encode(result);
2304}
2305
2306DEFINE_STUB_FUNCTION(JSObject*, op_new_regexp)
2307{
2308 STUB_INIT_STACK_FRAME(stackFrame);
2309
2310 return new (stackFrame.globalData) RegExpObject(stackFrame.callFrame->lexicalGlobalObject()->regExpStructure(), stackFrame.args[0].regExp());
2311}
2312
2313DEFINE_STUB_FUNCTION(EncodedJSValue, op_bitor)
2314{
2315 STUB_INIT_STACK_FRAME(stackFrame);
2316
2317 JSValue src1 = stackFrame.args[0].jsValue();
2318 JSValue src2 = stackFrame.args[1].jsValue();
2319
2320 CallFrame* callFrame = stackFrame.callFrame;
2321
2322 JSValue result = jsNumber(stackFrame.globalData, src1.toInt32(callFrame) | src2.toInt32(callFrame));
2323 CHECK_FOR_EXCEPTION_AT_END();
2324 return JSValue::encode(result);
2325}
2326
2327DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_eval)
2328{
2329 STUB_INIT_STACK_FRAME(stackFrame);
2330
2331 CallFrame* callFrame = stackFrame.callFrame;
2332 RegisterFile* registerFile = stackFrame.registerFile;
2333
2334 Interpreter* interpreter = stackFrame.globalData->interpreter;
2335
2336 JSValue funcVal = stackFrame.args[0].jsValue();
2337 int registerOffset = stackFrame.args[1].int32();
2338 int argCount = stackFrame.args[2].int32();
2339
2340 Register* newCallFrame = callFrame->registers() + registerOffset;
2341 Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount;
2342 JSValue thisValue = argv[0].jsValue();
2343 JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject();
2344
2345 if (thisValue == globalObject && funcVal == globalObject->evalFunction()) {
2346 JSValue exceptionValue;
2347 JSValue result = interpreter->callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue);
2348 if (UNLIKELY(exceptionValue != JSValue())) {
2349 stackFrame.globalData->exception = exceptionValue;
2350 VM_THROW_EXCEPTION_AT_END();
2351 }
2352 return JSValue::encode(result);
2353 }
2354
2355 return JSValue::encode(JSValue());
2356}
2357
2358DEFINE_STUB_FUNCTION(EncodedJSValue, op_throw)
2359{
2360 STUB_INIT_STACK_FRAME(stackFrame);
2361
2362 CallFrame* callFrame = stackFrame.callFrame;
2363 CodeBlock* codeBlock = callFrame->codeBlock();
2364
2365 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
2366
2367 JSValue exceptionValue = stackFrame.args[0].jsValue();
2368 ASSERT(exceptionValue);
2369
2370 HandlerInfo* handler = stackFrame.globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex, true);
2371
2372 if (!handler) {
2373 *stackFrame.exception = exceptionValue;
2374 STUB_SET_RETURN_ADDRESS(reinterpret_cast<void*>(ctiOpThrowNotCaught));
2375 return JSValue::encode(jsNull());
2376 }
2377
2378 stackFrame.callFrame = callFrame;
2379 void* catchRoutine = handler->nativeCode.executableAddress();
2380 ASSERT(catchRoutine);
2381 STUB_SET_RETURN_ADDRESS(catchRoutine);
2382 return JSValue::encode(exceptionValue);
2383}
2384
2385DEFINE_STUB_FUNCTION(JSPropertyNameIterator*, op_get_pnames)
2386{
2387 STUB_INIT_STACK_FRAME(stackFrame);
2388
2389 return JSPropertyNameIterator::create(stackFrame.callFrame, stackFrame.args[0].jsValue());
2390}
2391
2392DEFINE_STUB_FUNCTION(EncodedJSValue, op_next_pname)
2393{
2394 STUB_INIT_STACK_FRAME(stackFrame);
2395
2396 JSPropertyNameIterator* it = stackFrame.args[0].propertyNameIterator();
2397 JSValue temp = it->next(stackFrame.callFrame);
2398 if (!temp)
2399 it->invalidate();
2400 return JSValue::encode(temp);
2401}
2402
2403DEFINE_STUB_FUNCTION(JSObject*, op_push_scope)
2404{
2405 STUB_INIT_STACK_FRAME(stackFrame);
2406
2407 JSObject* o = stackFrame.args[0].jsValue().toObject(stackFrame.callFrame);
2408 CHECK_FOR_EXCEPTION();
2409 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->push(o));
2410 return o;
2411}
2412
2413DEFINE_STUB_FUNCTION(void, op_pop_scope)
2414{
2415 STUB_INIT_STACK_FRAME(stackFrame);
2416
2417 stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->pop());
2418}
2419
2420DEFINE_STUB_FUNCTION(EncodedJSValue, op_typeof)
2421{
2422 STUB_INIT_STACK_FRAME(stackFrame);
2423
2424 return JSValue::encode(jsTypeStringForValue(stackFrame.callFrame, stackFrame.args[0].jsValue()));
2425}
2426
2427DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_undefined)
2428{
2429 STUB_INIT_STACK_FRAME(stackFrame);
2430
2431 JSValue v = stackFrame.args[0].jsValue();
2432 return JSValue::encode(jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined()));
2433}
2434
2435DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_boolean)
2436{
2437 STUB_INIT_STACK_FRAME(stackFrame);
2438
2439 return JSValue::encode(jsBoolean(stackFrame.args[0].jsValue().isBoolean()));
2440}
2441
2442DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_number)
2443{
2444 STUB_INIT_STACK_FRAME(stackFrame);
2445
2446 return JSValue::encode(jsBoolean(stackFrame.args[0].jsValue().isNumber()));
2447}
2448
2449DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_string)
2450{
2451 STUB_INIT_STACK_FRAME(stackFrame);
2452
2453 return JSValue::encode(jsBoolean(isJSString(stackFrame.globalData, stackFrame.args[0].jsValue())));
2454}
2455
2456DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_object)
2457{
2458 STUB_INIT_STACK_FRAME(stackFrame);
2459
2460 return JSValue::encode(jsBoolean(jsIsObjectType(stackFrame.args[0].jsValue())));
2461}
2462
2463DEFINE_STUB_FUNCTION(EncodedJSValue, op_is_function)
2464{
2465 STUB_INIT_STACK_FRAME(stackFrame);
2466
2467 return JSValue::encode(jsBoolean(jsIsFunctionType(stackFrame.args[0].jsValue())));
2468}
2469
2470DEFINE_STUB_FUNCTION(EncodedJSValue, op_stricteq)
2471{
2472 STUB_INIT_STACK_FRAME(stackFrame);
2473
2474 JSValue src1 = stackFrame.args[0].jsValue();
2475 JSValue src2 = stackFrame.args[1].jsValue();
2476
2477 return JSValue::encode(jsBoolean(JSValue::strictEqual(src1, src2)));
2478}
2479
2480DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_primitive)
2481{
2482 STUB_INIT_STACK_FRAME(stackFrame);
2483
2484 return JSValue::encode(stackFrame.args[0].jsValue().toPrimitive(stackFrame.callFrame));
2485}
2486
2487DEFINE_STUB_FUNCTION(EncodedJSValue, op_strcat)
2488{
2489 STUB_INIT_STACK_FRAME(stackFrame);
2490
2491 return JSValue::encode(concatenateStrings(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32()));
2492}
2493
2494DEFINE_STUB_FUNCTION(EncodedJSValue, op_nstricteq)
2495{
2496 STUB_INIT_STACK_FRAME(stackFrame);
2497
2498 JSValue src1 = stackFrame.args[0].jsValue();
2499 JSValue src2 = stackFrame.args[1].jsValue();
2500
2501 return JSValue::encode(jsBoolean(!JSValue::strictEqual(src1, src2)));
2502}
2503
2504DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_jsnumber)
2505{
2506 STUB_INIT_STACK_FRAME(stackFrame);
2507
2508 JSValue src = stackFrame.args[0].jsValue();
2509 CallFrame* callFrame = stackFrame.callFrame;
2510
2511 JSValue result = src.toJSNumber(callFrame);
2512 CHECK_FOR_EXCEPTION_AT_END();
2513 return JSValue::encode(result);
2514}
2515
2516DEFINE_STUB_FUNCTION(EncodedJSValue, op_in)
2517{
2518 STUB_INIT_STACK_FRAME(stackFrame);
2519
2520 CallFrame* callFrame = stackFrame.callFrame;
2521 JSValue baseVal = stackFrame.args[1].jsValue();
2522
2523 if (!baseVal.isObject()) {
2524 CallFrame* callFrame = stackFrame.callFrame;
2525 CodeBlock* codeBlock = callFrame->codeBlock();
2526 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, STUB_RETURN_ADDRESS);
2527 stackFrame.globalData->exception = createInvalidParamError(callFrame, "in", baseVal, vPCIndex, codeBlock);
2528 VM_THROW_EXCEPTION();
2529 }
2530
2531 JSValue propName = stackFrame.args[0].jsValue();
2532 JSObject* baseObj = asObject(baseVal);
2533
2534 uint32_t i;
2535 if (propName.getUInt32(i))
2536 return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, i)));
2537
2538 Identifier property(callFrame, propName.toString(callFrame));
2539 CHECK_FOR_EXCEPTION();
2540 return JSValue::encode(jsBoolean(baseObj->hasProperty(callFrame, property)));
2541}
2542
2543DEFINE_STUB_FUNCTION(JSObject*, op_push_new_scope)
2544{
2545 STUB_INIT_STACK_FRAME(stackFrame);
2546
2547 JSObject* scope = new (stackFrame.globalData) JSStaticScopeObject(stackFrame.callFrame, stackFrame.args[0].identifier(), stackFrame.args[1].jsValue(), DontDelete);
2548
2549 CallFrame* callFrame = stackFrame.callFrame;
2550 callFrame->setScopeChain(callFrame->scopeChain()->push(scope));
2551 return scope;
2552}
2553
2554DEFINE_STUB_FUNCTION(void, op_jmp_scopes)
2555{
2556 STUB_INIT_STACK_FRAME(stackFrame);
2557
2558 unsigned count = stackFrame.args[0].int32();
2559 CallFrame* callFrame = stackFrame.callFrame;
2560
2561 ScopeChainNode* tmp = callFrame->scopeChain();
2562 while (count--)
2563 tmp = tmp->pop();
2564 callFrame->setScopeChain(tmp);
2565}
2566
2567DEFINE_STUB_FUNCTION(void, op_put_by_index)
2568{
2569 STUB_INIT_STACK_FRAME(stackFrame);
2570
2571 CallFrame* callFrame = stackFrame.callFrame;
2572 unsigned property = stackFrame.args[1].int32();
2573
2574 stackFrame.args[0].jsValue().put(callFrame, property, stackFrame.args[2].jsValue());
2575}
2576
2577DEFINE_STUB_FUNCTION(void*, op_switch_imm)
2578{
2579 STUB_INIT_STACK_FRAME(stackFrame);
2580
2581 JSValue scrutinee = stackFrame.args[0].jsValue();
2582 unsigned tableIndex = stackFrame.args[1].int32();
2583 CallFrame* callFrame = stackFrame.callFrame;
2584 CodeBlock* codeBlock = callFrame->codeBlock();
2585
2586 if (scrutinee.isInt32Fast())
2587 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(scrutinee.getInt32Fast()).executableAddress();
2588 else {
2589 double value;
2590 int32_t intValue;
2591 if (scrutinee.getNumber(value) && ((intValue = static_cast<int32_t>(value)) == value))
2592 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiForValue(intValue).executableAddress();
2593 else
2594 return codeBlock->immediateSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
2595 }
2596}
2597
2598DEFINE_STUB_FUNCTION(void*, op_switch_char)
2599{
2600 STUB_INIT_STACK_FRAME(stackFrame);
2601
2602 JSValue scrutinee = stackFrame.args[0].jsValue();
2603 unsigned tableIndex = stackFrame.args[1].int32();
2604 CallFrame* callFrame = stackFrame.callFrame;
2605 CodeBlock* codeBlock = callFrame->codeBlock();
2606
2607 void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
2608
2609 if (scrutinee.isString()) {
2610 UString::Rep* value = asString(scrutinee)->value().rep();
2611 if (value->size() == 1)
2612 result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->data()[0]).executableAddress();
2613 }
2614
2615 return result;
2616}
2617
2618DEFINE_STUB_FUNCTION(void*, op_switch_string)
2619{
2620 STUB_INIT_STACK_FRAME(stackFrame);
2621
2622 JSValue scrutinee = stackFrame.args[0].jsValue();
2623 unsigned tableIndex = stackFrame.args[1].int32();
2624 CallFrame* callFrame = stackFrame.callFrame;
2625 CodeBlock* codeBlock = callFrame->codeBlock();
2626
2627 void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault.executableAddress();
2628
2629 if (scrutinee.isString()) {
2630 UString::Rep* value = asString(scrutinee)->value().rep();
2631 result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value).executableAddress();
2632 }
2633
2634 return result;
2635}
2636
2637DEFINE_STUB_FUNCTION(EncodedJSValue, op_del_by_val)
2638{
2639 STUB_INIT_STACK_FRAME(stackFrame);
2640
2641 CallFrame* callFrame = stackFrame.callFrame;
2642
2643 JSValue baseValue = stackFrame.args[0].jsValue();
2644 JSObject* baseObj = baseValue.toObject(callFrame); // may throw
2645
2646 JSValue subscript = stackFrame.args[1].jsValue();
2647 JSValue result;
2648 uint32_t i;
2649 if (subscript.getUInt32(i))
2650 result = jsBoolean(baseObj->deleteProperty(callFrame, i));
2651 else {
2652 CHECK_FOR_EXCEPTION();
2653 Identifier property(callFrame, subscript.toString(callFrame));
2654 CHECK_FOR_EXCEPTION();
2655 result = jsBoolean(baseObj->deleteProperty(callFrame, property));
2656 }
2657
2658 CHECK_FOR_EXCEPTION_AT_END();
2659 return JSValue::encode(result);
2660}
2661
2662DEFINE_STUB_FUNCTION(void, op_put_getter)
2663{
2664 STUB_INIT_STACK_FRAME(stackFrame);
2665
2666 CallFrame* callFrame = stackFrame.callFrame;
2667
2668 ASSERT(stackFrame.args[0].jsValue().isObject());
2669 JSObject* baseObj = asObject(stackFrame.args[0].jsValue());
2670 ASSERT(stackFrame.args[2].jsValue().isObject());
2671 baseObj->defineGetter(callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue()));
2672}
2673
2674DEFINE_STUB_FUNCTION(void, op_put_setter)
2675{
2676 STUB_INIT_STACK_FRAME(stackFrame);
2677
2678 CallFrame* callFrame = stackFrame.callFrame;
2679
2680 ASSERT(stackFrame.args[0].jsValue().isObject());
2681 JSObject* baseObj = asObject(stackFrame.args[0].jsValue());
2682 ASSERT(stackFrame.args[2].jsValue().isObject());
2683 baseObj->defineSetter(callFrame, stackFrame.args[1].identifier(), asObject(stackFrame.args[2].jsValue()));
2684}
2685
2686DEFINE_STUB_FUNCTION(JSObject*, op_new_error)
2687{
2688 STUB_INIT_STACK_FRAME(stackFrame);
2689
2690 CallFrame* callFrame = stackFrame.callFrame;
2691 CodeBlock* codeBlock = callFrame->codeBlock();
2692 unsigned type = stackFrame.args[0].int32();
2693 JSValue message = stackFrame.args[1].jsValue();
2694 unsigned bytecodeOffset = stackFrame.args[2].int32();
2695
2696 unsigned lineNumber = codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset);
2697 return Error::create(callFrame, static_cast<ErrorType>(type), message.toString(callFrame), lineNumber, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL());
2698}
2699
2700DEFINE_STUB_FUNCTION(void, op_debug)
2701{
2702 STUB_INIT_STACK_FRAME(stackFrame);
2703
2704 CallFrame* callFrame = stackFrame.callFrame;
2705
2706 int debugHookID = stackFrame.args[0].int32();
2707 int firstLine = stackFrame.args[1].int32();
2708 int lastLine = stackFrame.args[2].int32();
2709
2710 stackFrame.globalData->interpreter->debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine);
2711}
2712
2713DEFINE_STUB_FUNCTION(EncodedJSValue, vm_throw)
2714{
2715 STUB_INIT_STACK_FRAME(stackFrame);
2716
2717 CallFrame* callFrame = stackFrame.callFrame;
2718 CodeBlock* codeBlock = callFrame->codeBlock();
2719 JSGlobalData* globalData = stackFrame.globalData;
2720
2721 unsigned vPCIndex = codeBlock->getBytecodeIndex(callFrame, globalData->exceptionLocation);
2722
2723 JSValue exceptionValue = globalData->exception;
2724 ASSERT(exceptionValue);
2725 globalData->exception = JSValue();
2726
2727 HandlerInfo* handler = globalData->interpreter->throwException(callFrame, exceptionValue, vPCIndex, false);
2728
2729 if (!handler) {
2730 *stackFrame.exception = exceptionValue;
2731 return JSValue::encode(jsNull());
2732 }
2733
2734 stackFrame.callFrame = callFrame;
2735 void* catchRoutine = handler->nativeCode.executableAddress();
2736 ASSERT(catchRoutine);
2737 STUB_SET_RETURN_ADDRESS(catchRoutine);
2738 return JSValue::encode(exceptionValue);
2739}
2740
2741} // namespace JITStubs
2742
2743} // namespace JSC
2744
2745#endif // ENABLE(JIT)
Note: See TracBrowser for help on using the repository browser.