Changeset 36244 in webkit for trunk/JavaScriptCore/VM/Machine.cpp
- Timestamp:
- Sep 6, 2008, 10:44:58 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/VM/Machine.cpp
r36081 r36244 76 76 namespace KJS { 77 77 78 // Default number of ticks before a timeout check should be done.79 static const int initialTickCountThreshold = 255;80 81 78 // Preferred number of milliseconds between each timeout check 82 79 static const int preferredScriptCheckTimeInterval = 1000; … … 307 304 } 308 305 309 static void NEVER_INLINE resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock) 310 { 311 int dst = (vPC + 1)->u.operand; 312 int property = (vPC + 2)->u.operand; 313 306 ALWAYS_INLINE static JSValue* inlineResolveBase(ExecState* exec, Identifier& property, ScopeChainNode* scopeChain) 307 { 314 308 ScopeChainIterator iter = scopeChain->begin(); 315 309 ScopeChainIterator next = iter; … … 319 313 320 314 PropertySlot slot; 321 Identifier& ident = codeBlock->identifiers[property];322 315 JSObject* base; 323 316 while (true) { 324 317 base = *iter; 325 if (next == end || base->getPropertySlot(exec, ident, slot)) { 326 r[dst] = base; 327 return; 328 } 318 if (next == end || base->getPropertySlot(exec, property, slot)) 319 return base; 320 329 321 iter = next; 330 322 ++next; 331 323 } 324 325 ASSERT_NOT_REACHED(); 326 return 0; 327 } 328 329 NEVER_INLINE static void resolveBase(ExecState* exec, Instruction* vPC, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock) 330 { 331 int dst = (vPC + 1)->u.operand; 332 int property = (vPC + 2)->u.operand; 333 r[dst] = inlineResolveBase(exec, codeBlock->identifiers[property], scopeChain); 332 334 } 333 335 … … 466 468 (*it) = jsUndefined(); 467 469 468 469 470 for (size_t i = 0; i < newCodeBlock->constantRegisters.size(); ++i) 470 471 r[i] = newCodeBlock->constantRegisters[i]; … … 529 530 Machine::Machine() 530 531 : m_sampler(0) 532 #if ENABLE(CTI) 533 , m_ctiArrayLengthTrampoline(0) 534 , m_ctiStringLengthTrampoline(0) 535 , m_jitCodeBuffer(new JITCodeBuffer(1024 * 1024)) 536 #endif 531 537 , m_reentryDepth(0) 532 538 , m_timeoutTime(0) … … 548 554 m_jsStringVptr = jsString->vptr(); 549 555 static_cast<JSCell*>(jsString)->~JSCell(); 556 557 JSFunction* jsFunction = new (storage) JSFunction(StructureID::create(jsNull())); 558 m_jsFunctionVptr = jsFunction->vptr(); 559 static_cast<JSCell*>(jsFunction)->~JSCell(); 550 560 551 561 fastFree(storage); 562 } 563 564 Machine::~Machine() 565 { 566 #if ENABLE(CTI) 567 if (m_ctiArrayLengthTrampoline) 568 fastFree(m_ctiArrayLengthTrampoline); 569 if (m_ctiStringLengthTrampoline) 570 fastFree(m_ctiStringLengthTrampoline); 571 #endif 552 572 } 553 573 … … 627 647 #endif 628 648 629 #if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL)649 //#if !defined(NDEBUG) || ENABLE(SAMPLING_TOOL) 630 650 631 651 bool Machine::isOpcode(Opcode opcode) … … 640 660 } 641 661 642 #endif662 //#endif 643 663 644 664 NEVER_INLINE bool Machine::unwindCallFrame(ExecState* exec, JSValue* exceptionValue, const Instruction*& vPC, CodeBlock*& codeBlock, ScopeChainNode*& scopeChain, Register*& r) … … 686 706 { 687 707 // Set up the exception object 688 708 689 709 if (exceptionValue->isObject()) { 690 710 JSObject* exception = static_cast<JSObject*>(exceptionValue); … … 793 813 794 814 m_reentryDepth++; 815 #if ENABLE(CTI) 816 if (!codeBlock->ctiCode) 817 CTI::compile(this, exec, codeBlock); 818 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception); 819 #else 795 820 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception); 821 #endif 796 822 m_reentryDepth--; 797 823 … … 853 879 854 880 m_reentryDepth++; 881 #if ENABLE(CTI) 882 if (!newCodeBlock->ctiCode) 883 CTI::compile(this, exec, newCodeBlock); 884 JSValue* result = CTI::execute(newCodeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception); 885 #else 855 886 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, newCodeBlock, exception); 887 #endif 856 888 m_reentryDepth--; 857 889 … … 931 963 932 964 m_reentryDepth++; 965 #if ENABLE(CTI) 966 if (!codeBlock->ctiCode) 967 CTI::compile(this, exec, codeBlock); 968 JSValue* result = CTI::execute(codeBlock->ctiCode, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception); 969 #else 933 970 JSValue* result = privateExecute(Normal, &newExec, &m_registerFile, r, scopeChain, codeBlock, exception); 971 #endif 934 972 m_reentryDepth--; 935 973 … … 949 987 } 950 988 951 NEVER_INLINE void Machine::debug(ExecState* exec, const Instruction* vPC, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r) 952 { 953 int debugHookID = (++vPC)->u.operand; 954 int firstLine = (++vPC)->u.operand; 955 int lastLine = (++vPC)->u.operand; 956 989 NEVER_INLINE void Machine::debug(ExecState* exec, const CodeBlock* codeBlock, ScopeChainNode* scopeChain, Register* r, DebugHookID debugHookID, int firstLine, int lastLine) 990 { 957 991 Debugger* debugger = exec->dynamicGlobalObject()->debugger(); 958 992 if (!debugger) … … 961 995 DebuggerCallFrame debuggerCallFrame(exec, exec->dynamicGlobalObject(), codeBlock, scopeChain, r, 0); 962 996 963 switch((DebugHookID)debugHookID) { 964 case DidEnterCallFrame: { 965 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine); 966 return; 967 } 968 case WillLeaveCallFrame: { 969 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine); 970 return; 971 } 972 case WillExecuteStatement: { 973 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine); 974 return; 975 } 976 case WillExecuteProgram: { 977 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine); 978 return; 979 } 980 case DidExecuteProgram: { 981 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine); 982 return; 983 } 984 case DidReachBreakpoint: { 985 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine); 986 return; 987 } 997 switch (debugHookID) { 998 case DidEnterCallFrame: 999 debugger->callEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine); 1000 return; 1001 case WillLeaveCallFrame: 1002 debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine); 1003 return; 1004 case WillExecuteStatement: 1005 debugger->atStatement(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine); 1006 return; 1007 case WillExecuteProgram: 1008 debugger->willExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), firstLine); 1009 return; 1010 case DidExecuteProgram: 1011 debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine); 1012 return; 1013 case DidReachBreakpoint: 1014 debugger->didReachBreakpoint(debuggerCallFrame, codeBlock->ownerNode->sourceId(), lastLine); 1015 return; 988 1016 } 989 1017 } … … 1074 1102 } 1075 1103 1076 static int32_t offsetForStringSwitch(StringJumpTable& jumpTable, JSValue* scrutinee, int32_t defaultOffset) {1077 StringJumpTable::const_iterator end = jumpTable.end();1078 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep();1079 StringJumpTable::const_iterator loc = jumpTable.find(value);1080 if (loc == end)1081 return defaultOffset;1082 return loc->second;1083 }1084 1085 1104 static NEVER_INLINE ScopeChainNode* createExceptionScope(ExecState* exec, CodeBlock* codeBlock, const Instruction* vPC, Register* r, ScopeChainNode* scopeChain) 1086 1105 { … … 1236 1255 ASSERT(slot.slotBase()->isObject()); 1237 1256 1238 JSObject* slotBaseObject = static_cast<JSObject*>(slot.slotBase());1257 JSObject* baseObject = static_cast<JSObject*>(slot.slotBase()); 1239 1258 1240 1259 // Heavy access to a prototype is a good indication that it's not being 1241 1260 // used as a dictionary. 1242 if ( slotBaseObject->structureID()->isDictionary()) {1243 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition( slotBaseObject->structureID());1244 slotBaseObject->setStructureID(transition.release());1261 if (baseObject->structureID()->isDictionary()) { 1262 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(baseObject->structureID()); 1263 baseObject->setStructureID(transition.release()); 1245 1264 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0); 1246 1265 } 1247 1266 1248 1267 vPC[0] = getOpcode(op_get_by_id_proto); 1249 vPC[5] = slotBaseObject->structureID();1268 vPC[5] = baseObject->structureID(); 1250 1269 vPC[6] = slot.cachedOffset(); 1251 1270 … … 1259 1278 JSValue* v = o->structureID()->prototype(); 1260 1279 1261 // If we didn't find slotBase in baseValue's prototype chain, then baseValue1280 // If we didn't find base in baseValue's prototype chain, then baseValue 1262 1281 // must be a proxy for another object. 1263 1282 if (v->isNull()) { … … 1318 1337 } 1319 1338 1339 #if ENABLE(CTI) 1340 // Currently with CTI enabled we never interpret functions 1341 ASSERT_NOT_REACHED(); 1342 #endif 1343 1320 1344 JSValue* exceptionValue = 0; 1321 1345 Instruction* handlerVPC = 0; … … 1327 1351 1328 1352 #define VM_CHECK_EXCEPTION() \ 1329 1353 do { \ 1330 1354 if (UNLIKELY(exec->hadException())) { \ 1331 1355 exceptionValue = exec->exception(); \ … … 1344 1368 tickCount = m_ticksUntilNextTimeoutCheck; \ 1345 1369 } 1346 1370 1347 1371 #if HAVE(COMPUTED_GOTO) 1348 1372 #define NEXT_OPCODE MACHINE_SAMPLING_sample(codeBlock, vPC); goto *vPC->u.opcode … … 2485 2509 int base = (++vPC)->u.operand; 2486 2510 int property = (++vPC)->u.operand; 2487 2511 2488 2512 JSValue* baseValue = r[base].jsValue(exec); 2489 2513 JSValue* subscript = r[property].jsValue(exec); … … 2799 2823 vPC += defaultOffset; 2800 2824 else 2801 vPC += offsetForStringSwitch(codeBlock->stringSwitchJumpTables[tableIndex], scrutinee, defaultOffset);2825 vPC += codeBlock->stringSwitchJumpTables[tableIndex].offsetForValue(static_cast<JSString*>(scrutinee)->value().rep(), defaultOffset); 2802 2826 NEXT_OPCODE; 2803 2827 } … … 3381 3405 is only generated while the debugger is attached. 3382 3406 */ 3383 3384 debug(exec, vPC, codeBlock, scopeChain, r); 3385 3386 vPC += 4; 3407 int debugHookID = (++vPC)->u.operand; 3408 int firstLine = (++vPC)->u.operand; 3409 int lastLine = (++vPC)->u.operand; 3410 3411 debug(exec, codeBlock, scopeChain, r, static_cast<DebugHookID>(debugHookID), firstLine, lastLine); 3412 3413 ++vPC; 3387 3414 NEXT_OPCODE; 3388 3415 } … … 3406 3433 #undef BEGIN_OPCODE 3407 3434 #undef VM_CHECK_EXCEPTION 3435 #undef CHECK_FOR_TIMEOUT 3408 3436 } 3409 3437 … … 3499 3527 } 3500 3528 3529 #if ENABLE(CTI) 3530 3531 NEVER_INLINE static void doSetReturnAddressVMThrowTrampoline(void** returnAddress) 3532 { 3533 ctiSetReturnAddress(returnAddress, (void*)ctiVMThrowTrampoline); 3534 } 3535 3536 NEVER_INLINE void Machine::tryCTICachePutByID(ExecState* exec, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const PutPropertySlot& slot) 3537 { 3538 // The interpreter checks for recursion here; I do not believe this can occur in CTI. 3539 3540 if (JSImmediate::isImmediate(baseValue)) 3541 return; 3542 3543 // Uncacheable: give up. 3544 if (!slot.isCacheable()) { 3545 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic); 3546 return; 3547 } 3548 3549 // FIXME: Cache new property transitions, too. 3550 if (slot.type() == PutPropertySlot::NewProperty) { 3551 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic); 3552 return; 3553 } 3554 3555 JSCell* baseCell = static_cast<JSCell*>(baseValue); 3556 StructureID* structureID = baseCell->structureID(); 3557 3558 // FIXME: Remove this !structureID check once all objects have StructureIDs. 3559 if (!structureID) { 3560 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic); 3561 return; 3562 } 3563 3564 if (structureID->isDictionary()) { 3565 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic); 3566 return; 3567 } 3568 3569 // In the interpreter the last structure is trapped here; in CTI we use the 3570 // *_second method to achieve a similar (but not quite the same) effect. 3571 3572 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(returnAddress); 3573 Instruction* vPC = codeBlock->instructions.begin() + vPCIndex; 3574 3575 // Cache hit: Specialize instruction and ref StructureIDs. 3576 3577 // If baseCell != base, then baseCell must be a proxy for another object. 3578 if (baseCell != slot.base()) { 3579 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_put_by_id_generic); 3580 return; 3581 } 3582 vPC[0] = getOpcode(op_put_by_id_replace); 3583 vPC[4] = structureID; 3584 vPC[5] = slot.cachedOffset(); 3585 codeBlock->refStructureIDs(vPC); 3586 3587 ctiRepatchCallByReturnAddress(returnAddress, CTI::compilePutByIdReplace(this, exec, codeBlock, structureID, slot.cachedOffset())); 3588 } 3589 3590 void* Machine::getCTIArrayLengthTrampoline(ExecState* exec, CodeBlock* codeBlock) 3591 { 3592 if (!m_ctiArrayLengthTrampoline) 3593 m_ctiArrayLengthTrampoline = CTI::compileArrayLengthTrampoline(this, exec, codeBlock); 3594 3595 return m_ctiArrayLengthTrampoline; 3596 } 3597 3598 void* Machine::getCTIStringLengthTrampoline(ExecState* exec, CodeBlock* codeBlock) 3599 { 3600 if (!m_ctiStringLengthTrampoline) 3601 m_ctiStringLengthTrampoline = CTI::compileStringLengthTrampoline(this, exec, codeBlock); 3602 3603 return m_ctiStringLengthTrampoline; 3604 } 3605 3606 NEVER_INLINE void Machine::tryCTICacheGetByID(ExecState* exec, CodeBlock* codeBlock, void* returnAddress, JSValue* baseValue, const Identifier& propertyName, const PropertySlot& slot) 3607 { 3608 // The interpreter checks for recursion here; I do not believe this can occur in CTI. 3609 3610 if (isJSArray(baseValue) && propertyName == exec->propertyNames().length) { 3611 ctiRepatchCallByReturnAddress(returnAddress, getCTIArrayLengthTrampoline(exec, codeBlock)); 3612 return; 3613 } 3614 if (isJSString(baseValue) && propertyName == exec->propertyNames().length) { 3615 ctiRepatchCallByReturnAddress(returnAddress, getCTIStringLengthTrampoline(exec, codeBlock)); 3616 return; 3617 } 3618 3619 // Uncacheable: give up. 3620 if (!slot.isCacheable()) { 3621 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic); 3622 return; 3623 } 3624 3625 // FIXME: Cache property access for immediates. 3626 if (JSImmediate::isImmediate(baseValue)) { 3627 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic); 3628 return; 3629 } 3630 3631 JSCell* baseCell = static_cast<JSCell*>(baseValue); 3632 StructureID* structureID = baseCell->structureID(); 3633 3634 // FIXME: Remove this !structureID check once all JSCells have StructureIDs. 3635 if (!structureID) { 3636 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic); 3637 return; 3638 } 3639 3640 if (structureID->isDictionary()) { 3641 ctiRepatchCallByReturnAddress(returnAddress, (void*)cti_op_get_by_id_generic); 3642 return; 3643 } 3644 3645 // In the interpreter the last structure is trapped here; in CTI we use the 3646 // *_second method to achieve a similar (but not quite the same) effect. 3647 3648 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(returnAddress); 3649 Instruction* vPC = codeBlock->instructions.begin() + vPCIndex; 3650 3651 // Cache hit: Specialize instruction and ref StructureIDs. 3652 3653 if (slot.slotBase() == baseValue) { 3654 // set this up, so derefStructureIDs can do it's job. 3655 vPC[0] = getOpcode(op_get_by_id_self); 3656 vPC[4] = structureID; 3657 vPC[5] = slot.cachedOffset(); 3658 codeBlock->refStructureIDs(vPC); 3659 3660 ctiRepatchCallByReturnAddress(returnAddress, CTI::compileGetByIdSelf(this, exec, codeBlock, structureID, slot.cachedOffset())); 3661 return; 3662 } 3663 3664 if (slot.slotBase() == structureID->prototype()) { 3665 ASSERT(slot.slotBase()->isObject()); 3666 3667 JSObject* slotBaseObject = static_cast<JSObject*>(slot.slotBase()); 3668 3669 // Heavy access to a prototype is a good indication that it's not being 3670 // used as a dictionary. 3671 if (slotBaseObject->structureID()->isDictionary()) { 3672 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(slotBaseObject->structureID()); 3673 slotBaseObject->setStructureID(transition.release()); 3674 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0); 3675 } 3676 3677 vPC[0] = getOpcode(op_get_by_id_proto); 3678 vPC[4] = structureID; 3679 vPC[5] = slotBaseObject->structureID(); 3680 vPC[6] = slot.cachedOffset(); 3681 codeBlock->refStructureIDs(vPC); 3682 3683 ctiRepatchCallByReturnAddress(returnAddress, CTI::compileGetByIdProto(this, exec, codeBlock, structureID, slotBaseObject->structureID(), slot.cachedOffset())); 3684 return; 3685 } 3686 3687 size_t count = 0; 3688 JSObject* o = static_cast<JSObject*>(baseValue); 3689 while (slot.slotBase() != o) { 3690 JSValue* v = o->structureID()->prototype(); 3691 3692 // If we didn't find slotBase in baseValue's prototype chain, then baseValue 3693 // must be a proxy for another object. 3694 3695 if (v->isNull()) { 3696 vPC[0] = getOpcode(op_get_by_id_generic); 3697 return; 3698 } 3699 3700 o = static_cast<JSObject*>(v); 3701 3702 // Heavy access to a prototype is a good indication that it's not being 3703 // used as a dictionary. 3704 if (o->structureID()->isDictionary()) { 3705 RefPtr<StructureID> transition = StructureID::fromDictionaryTransition(o->structureID()); 3706 o->setStructureID(transition.release()); 3707 static_cast<JSObject*>(baseValue)->structureID()->setCachedPrototypeChain(0); 3708 } 3709 3710 ++count; 3711 } 3712 3713 StructureIDChain* chain = structureID->cachedPrototypeChain(); 3714 if (!chain) 3715 chain = cachePrototypeChain(structureID); 3716 3717 vPC[0] = getOpcode(op_get_by_id_chain); 3718 vPC[4] = structureID; 3719 vPC[5] = chain; 3720 vPC[6] = count; 3721 vPC[7] = slot.cachedOffset(); 3722 codeBlock->refStructureIDs(vPC); 3723 3724 ctiRepatchCallByReturnAddress(returnAddress, CTI::compileGetByIdChain(this, exec, codeBlock, structureID, chain, count, slot.cachedOffset())); 3725 } 3726 3727 3728 #define JSVALUE_VM_CHECK_EXCEPTION_ARG(exception) \ 3729 do { \ 3730 if (UNLIKELY(exception != 0)) { \ 3731 exec->setException(exception); \ 3732 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \ 3733 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \ 3734 return 0; \ 3735 } \ 3736 } while (0) 3737 #define VM_CHECK_EXCEPTION_v() \ 3738 do { \ 3739 if (UNLIKELY(exec->hadException())) { \ 3740 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \ 3741 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \ 3742 return; \ 3743 } \ 3744 } while (0) 3745 #define VM_CHECK_EXCEPTION(type) \ 3746 do { \ 3747 if (UNLIKELY(exec->hadException())) { \ 3748 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \ 3749 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \ 3750 return (type)0; \ 3751 } \ 3752 } while (0) 3753 #define VM_CHECK_EXCEPTION_AT_END() \ 3754 do { \ 3755 if (UNLIKELY(exec->hadException())) { \ 3756 /*printf("VM_CHECK_EXCEPTION_AT_END()\n");*/ \ 3757 exec->setCTIReturnAddress(CTI_RETURN_ADDRESS); \ 3758 doSetReturnAddressVMThrowTrampoline(&CTI_RETURN_ADDRESS); \ 3759 } \ 3760 } while (0) 3761 3762 void Machine::cti_op_end(CTI_ARGS) 3763 { 3764 ASSERT(ARG_scopeChain->refCount > 1); 3765 ARG_scopeChain->deref(); 3766 } 3767 3768 JSValue* Machine::cti_op_add(CTI_ARGS) 3769 { 3770 JSValue* src1 = ARG_src1; 3771 JSValue* src2 = ARG_src2; 3772 3773 ExecState* exec = ARG_exec; 3774 JSValue* result = jsAdd(exec, src1, src2); 3775 VM_CHECK_EXCEPTION_AT_END(); 3776 return result; 3777 } 3778 3779 JSValue* Machine::cti_op_pre_inc(CTI_ARGS) 3780 { 3781 JSValue* v = ARG_src1; 3782 3783 ExecState* exec = ARG_exec; 3784 JSValue* result = jsNumber(exec, v->toNumber(exec) + 1); 3785 VM_CHECK_EXCEPTION_AT_END(); 3786 return result; 3787 } 3788 3789 void Machine::cti_timeout_check(CTI_ARGS) 3790 { 3791 ExecState* exec = ARG_exec; 3792 3793 if (exec->machine()->checkTimeout(exec->dynamicGlobalObject())) 3794 exec->setException(createInterruptedExecutionException(exec)); 3795 3796 VM_CHECK_EXCEPTION_AT_END(); 3797 } 3798 3799 3800 int Machine::cti_op_loop_if_less(CTI_ARGS) 3801 { 3802 JSValue* src1 = ARG_src1; 3803 JSValue* src2 = ARG_src2; 3804 ExecState* exec = ARG_exec; 3805 3806 bool result = jsLess(exec, src1, src2); 3807 VM_CHECK_EXCEPTION_AT_END(); 3808 return result; 3809 } 3810 3811 JSValue* Machine::cti_op_new_object(CTI_ARGS) 3812 { 3813 return constructEmptyObject(ARG_exec);; 3814 } 3815 3816 void Machine::cti_op_put_by_id(CTI_ARGS) 3817 { 3818 ExecState* exec = ARG_exec; 3819 Identifier& ident = *ARG_id2; 3820 3821 PutPropertySlot slot; 3822 ARG_src1->put(exec, ident, ARG_src3, slot); 3823 3824 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_put_by_id_second); 3825 3826 VM_CHECK_EXCEPTION_AT_END(); 3827 } 3828 3829 void Machine::cti_op_put_by_id_second(CTI_ARGS) 3830 { 3831 ExecState* exec = ARG_exec; 3832 Identifier& ident = *ARG_id2; 3833 3834 JSValue* baseValue = ARG_src1; 3835 PutPropertySlot slot; 3836 baseValue->put(exec, ident, ARG_src3, slot); 3837 3838 exec->machine()->tryCTICachePutByID(exec, ARG_codeBlock, CTI_RETURN_ADDRESS, baseValue, slot); 3839 3840 VM_CHECK_EXCEPTION_AT_END(); 3841 } 3842 3843 void Machine::cti_op_put_by_id_generic(CTI_ARGS) 3844 { 3845 ExecState* exec = ARG_exec; 3846 Identifier& ident = *ARG_id2; 3847 3848 PutPropertySlot slot; 3849 ARG_src1->put(exec, ident, ARG_src3, slot); 3850 3851 VM_CHECK_EXCEPTION_AT_END(); 3852 } 3853 3854 void Machine::cti_op_put_by_id_fail(CTI_ARGS) 3855 { 3856 ExecState* exec = ARG_exec; 3857 Identifier& ident = *ARG_id2; 3858 3859 PutPropertySlot slot; 3860 ARG_src1->put(exec, ident, ARG_src3, slot); 3861 3862 // should probably uncachePutByID() ... this would mean doing a vPC lookup - might be worth just bleeding this until the end. 3863 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_put_by_id_generic); 3864 3865 VM_CHECK_EXCEPTION_AT_END(); 3866 } 3867 3868 JSValue* Machine::cti_op_get_by_id(CTI_ARGS) 3869 { 3870 ExecState* exec = ARG_exec; 3871 Identifier& ident = *ARG_id2; 3872 3873 JSValue* baseValue = ARG_src1; 3874 PropertySlot slot(baseValue); 3875 JSValue* result = baseValue->get(exec, ident, slot); 3876 3877 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_get_by_id_second); 3878 3879 VM_CHECK_EXCEPTION_AT_END(); 3880 return result; 3881 } 3882 3883 JSValue* Machine::cti_op_get_by_id_second(CTI_ARGS) 3884 { 3885 ExecState* exec = ARG_exec; 3886 Identifier& ident = *ARG_id2; 3887 3888 JSValue* baseValue = ARG_src1; 3889 PropertySlot slot(baseValue); 3890 JSValue* result = baseValue->get(exec, ident, slot); 3891 3892 exec->machine()->tryCTICacheGetByID(exec, ARG_codeBlock, CTI_RETURN_ADDRESS, baseValue, ident, slot); 3893 3894 VM_CHECK_EXCEPTION_AT_END(); 3895 return result; 3896 } 3897 3898 JSValue* Machine::cti_op_get_by_id_generic(CTI_ARGS) 3899 { 3900 ExecState* exec = ARG_exec; 3901 Identifier& ident = *ARG_id2; 3902 3903 JSValue* baseValue = ARG_src1; 3904 PropertySlot slot(baseValue); 3905 JSValue* result = baseValue->get(exec, ident, slot); 3906 3907 VM_CHECK_EXCEPTION_AT_END(); 3908 return result; 3909 } 3910 3911 JSValue* Machine::cti_op_get_by_id_fail(CTI_ARGS) 3912 { 3913 ExecState* exec = ARG_exec; 3914 Identifier& ident = *ARG_id2; 3915 3916 JSValue* baseValue = ARG_src1; 3917 PropertySlot slot(baseValue); 3918 JSValue* result = baseValue->get(exec, ident, slot); 3919 3920 // should probably uncacheGetByID() ... this would mean doing a vPC lookup - might be worth just bleeding this until the end. 3921 ctiRepatchCallByReturnAddress(CTI_RETURN_ADDRESS, (void*)cti_op_get_by_id_generic); 3922 3923 VM_CHECK_EXCEPTION_AT_END(); 3924 return result; 3925 } 3926 3927 JSValue* Machine::cti_op_instanceof(CTI_ARGS) 3928 { 3929 ExecState* exec = ARG_exec; 3930 JSValue* baseVal = ARG_src2; 3931 3932 if (!baseVal->isObject()) { 3933 CodeBlock* codeBlock = ARG_codeBlock; 3934 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS)); 3935 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS); 3936 exec->setException(createInvalidParamError(exec, "instanceof", baseVal, codeBlock->instructions.begin() + vPCIndex, codeBlock)); 3937 VM_CHECK_EXCEPTION(JSValue*); 3938 } 3939 3940 JSObject* baseObj = static_cast<JSObject*>(baseVal); 3941 JSValue* result = jsBoolean(baseObj->implementsHasInstance() ? baseObj->hasInstance(exec, ARG_src1) : false); 3942 VM_CHECK_EXCEPTION_AT_END(); 3943 return result; 3944 } 3945 3946 JSValue* Machine::cti_op_del_by_id(CTI_ARGS) 3947 { 3948 ExecState* exec = ARG_exec; 3949 Identifier& ident = *ARG_id2; 3950 3951 JSObject* baseObj = ARG_src1->toObject(exec); 3952 3953 JSValue* result = jsBoolean(baseObj->deleteProperty(exec, ident)); 3954 VM_CHECK_EXCEPTION_AT_END(); 3955 return result; 3956 } 3957 3958 JSValue* Machine::cti_op_mul(CTI_ARGS) 3959 { 3960 ExecState* exec = ARG_exec; 3961 JSValue* src1 = ARG_src1; 3962 JSValue* src2 = ARG_src2; 3963 3964 double left; 3965 double right; 3966 if (fastIsNumber(src1, left) && fastIsNumber(src2, right)) 3967 return jsNumber(exec, left * right); 3968 else { 3969 JSValue* result = jsNumber(exec, src1->toNumber(exec) * src2->toNumber(exec)); 3970 VM_CHECK_EXCEPTION_AT_END(); 3971 return result; 3972 } 3973 } 3974 3975 JSValue* Machine::cti_op_new_func(CTI_ARGS) 3976 { 3977 return ARG_func1->makeFunction(ARG_exec, ARG_scopeChain); 3978 } 3979 3980 void* Machine::cti_op_call_JSFunction(CTI_ARGS) 3981 { 3982 ExecState* exec = ARG_exec; 3983 RegisterFile* registerFile = ARG_registerFile; 3984 Register* r = ARG_r; 3985 CodeBlock* codeBlock = ARG_codeBlock; 3986 ScopeChainNode* scopeChain = ARG_scopeChain; 3987 3988 Machine* machine = exec->machine(); 3989 JSValue* exceptionValue = 0; 3990 Register* registerBase = registerFile->base(); 3991 3992 JSValue* funcVal = ARG_src1; 3993 JSValue* thisValue = ARG_src2; 3994 int firstArg = ARG_int3; 3995 int argCount = ARG_int4; 3996 3997 CallData callData; 3998 #ifndef NDEBUG 3999 CallType callType = 4000 #endif 4001 funcVal->getCallData(callData); 4002 4003 ASSERT(callType == CallTypeJS); 4004 4005 if (*ARG_profilerReference) 4006 (*ARG_profilerReference)->willExecute(exec, static_cast<JSObject*>(funcVal)); 4007 4008 ScopeChainNode* callDataScopeChain = callData.js.scopeChain; 4009 FunctionBodyNode* functionBodyNode = callData.js.functionBody; 4010 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain); 4011 4012 r[firstArg] = thisValue; 4013 4014 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize; 4015 machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, 0, funcVal); 4016 exec->m_callFrame = callFrame; 4017 4018 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue); 4019 JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue); 4020 4021 codeBlock = newCodeBlock; 4022 machine->setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r)); 4023 4024 if (!codeBlock->ctiCode) 4025 CTI::compile(machine, exec, codeBlock); 4026 4027 ARG_setScopeChain(scopeChain); 4028 ARG_setCodeBlock(codeBlock); 4029 ARG_setR(r); 4030 return codeBlock->ctiCode; 4031 } 4032 4033 JSValue* Machine::cti_op_call_NotJSFunction(CTI_ARGS) 4034 { 4035 ExecState* exec = ARG_exec; 4036 Register* r = ARG_r; 4037 4038 JSValue* funcVal = ARG_src1; 4039 JSValue* thisValue = ARG_src2; 4040 int firstArg = ARG_int3; 4041 int argCount = ARG_int4; 4042 4043 CallData callData; 4044 CallType callType = funcVal->getCallData(callData); 4045 4046 ASSERT(callType != CallTypeJS); 4047 4048 if (callType == CallTypeHost) { 4049 CodeBlock* codeBlock = ARG_codeBlock; 4050 ScopeChainNode* scopeChain = ARG_scopeChain; 4051 Machine* machine = exec->machine(); 4052 4053 Register* oldCallFrame = exec->m_callFrame; 4054 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize; 4055 machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, 0, funcVal); 4056 exec->m_callFrame = callFrame; 4057 4058 if (*ARG_profilerReference) 4059 (*ARG_profilerReference)->willExecute(exec, static_cast<JSObject*>(funcVal)); 4060 4061 ArgList argList(r + firstArg + 1, argCount - 1); 4062 4063 CTI_MACHINE_SAMPLING_callingHostFunction(); 4064 4065 JSValue* returnValue = callData.native.function(exec, static_cast<JSObject*>(funcVal), thisValue, argList); 4066 exec->m_callFrame = oldCallFrame; 4067 VM_CHECK_EXCEPTION(JSValue*); 4068 4069 if (*ARG_profilerReference) 4070 (*ARG_profilerReference)->didExecute(exec, static_cast<JSObject*>(funcVal)); 4071 4072 return returnValue; 4073 4074 } 4075 4076 ASSERT(callType == CallTypeNone); 4077 4078 exec->setException(createNotAFunctionError(exec, funcVal, ARG_instr5, ARG_codeBlock)); 4079 VM_CHECK_EXCEPTION_AT_END(); 4080 return 0; 4081 } 4082 4083 JSValue* Machine::cti_op_ret(CTI_ARGS) 4084 { 4085 ExecState* exec = ARG_exec; 4086 Register* r = ARG_r; 4087 CodeBlock* codeBlock = ARG_codeBlock; 4088 ScopeChainNode* scopeChain = ARG_scopeChain; 4089 4090 Machine* machine = exec->machine(); 4091 4092 Register* callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize; 4093 if (JSActivation* activation = static_cast<JSActivation*>(callFrame[RegisterFile::OptionalCalleeActivation].jsValue(exec))) { 4094 ASSERT(!codeBlock->needsFullScopeChain || scopeChain->object == activation); 4095 ASSERT(activation->isActivationObject()); 4096 activation->copyRegisters(); 4097 } 4098 4099 if (*ARG_profilerReference) 4100 (*ARG_profilerReference)->didExecute(exec, static_cast<JSObject*>(callFrame[RegisterFile::Callee].jsValue(exec))); 4101 4102 if (codeBlock->needsFullScopeChain) 4103 scopeChain->deref(); 4104 4105 JSValue* returnValue = ARG_src1; 4106 if (callFrame[RegisterFile::CalledAsConstructor].i() && !returnValue->isObject()) { 4107 JSValue* thisObject = callFrame[RegisterFile::CallFrameHeaderSize].jsValue(exec); 4108 returnValue = thisObject; 4109 } 4110 4111 codeBlock = callFrame[RegisterFile::CallerCodeBlock].codeBlock(); 4112 if (codeBlock) { 4113 machine->setScopeChain(exec, scopeChain, callFrame[RegisterFile::CallerScopeChain].scopeChain()); 4114 r = callFrame[RegisterFile::CallerRegisters].r(); 4115 exec->m_callFrame = r - codeBlock->numLocals - RegisterFile::CallFrameHeaderSize; 4116 } 4117 4118 ARG_setScopeChain(scopeChain); 4119 ARG_setCodeBlock(codeBlock); 4120 ARG_setR(r); 4121 4122 return returnValue; 4123 } 4124 4125 JSValue* Machine::cti_op_new_array(CTI_ARGS) 4126 { 4127 ArgList argsList(ARG_registers1, ARG_int2); 4128 return constructArray(ARG_exec, argsList); 4129 } 4130 4131 JSValue* Machine::cti_op_resolve(CTI_ARGS) 4132 { 4133 ExecState* exec = ARG_exec; 4134 ScopeChainNode* scopeChain = ARG_scopeChain; 4135 4136 ScopeChainIterator iter = scopeChain->begin(); 4137 ScopeChainIterator end = scopeChain->end(); 4138 ASSERT(iter != end); 4139 4140 Identifier& ident = *ARG_id1; 4141 do { 4142 JSObject* o = *iter; 4143 PropertySlot slot(o); 4144 if (o->getPropertySlot(exec, ident, slot)) { 4145 JSValue* result = slot.getValue(exec, ident); 4146 VM_CHECK_EXCEPTION_AT_END(); 4147 return result; 4148 } 4149 } while (++iter != end); 4150 4151 CodeBlock* codeBlock = ARG_codeBlock; 4152 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS)); 4153 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS); 4154 exec->setException(createUndefinedVariableError(exec, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock)); 4155 4156 VM_CHECK_EXCEPTION_AT_END(); 4157 return 0; 4158 } 4159 4160 void* Machine::cti_op_construct_JSConstruct(CTI_ARGS) 4161 { 4162 ExecState* exec = ARG_exec; 4163 RegisterFile* registerFile = ARG_registerFile; 4164 Register* r = ARG_r; 4165 CodeBlock* codeBlock = ARG_codeBlock; 4166 ScopeChainNode* scopeChain = ARG_scopeChain; 4167 4168 Machine* machine = exec->machine(); 4169 JSValue* exceptionValue = 0; 4170 Register* registerBase = registerFile->base(); 4171 4172 JSValue* constrVal = ARG_src1; 4173 int firstArg = ARG_int2; 4174 int argCount = ARG_int3; 4175 4176 ConstructData constructData; 4177 #ifndef NDEBUG 4178 ConstructType constructType = 4179 #endif 4180 constrVal->getConstructData(constructData); 4181 4182 // Removing this line of code causes a measurable regression on squirrelfish. 4183 JSObject* constructor = static_cast<JSObject*>(constrVal); 4184 4185 ASSERT(constructType == ConstructTypeJS); 4186 4187 if (*ARG_profilerReference) 4188 (*ARG_profilerReference)->willExecute(exec, constructor); 4189 4190 JSObject* prototype; 4191 JSValue* p = constructor->get(exec, exec->propertyNames().prototype); 4192 if (p->isObject()) 4193 prototype = static_cast<JSObject*>(p); 4194 else 4195 prototype = scopeChain->globalObject()->objectPrototype(); 4196 JSObject* newObject = new (exec) JSObject(prototype); 4197 4198 ScopeChainNode* callDataScopeChain = constructData.js.scopeChain; 4199 FunctionBodyNode* functionBodyNode = constructData.js.functionBody; 4200 CodeBlock* newCodeBlock = &functionBodyNode->byteCode(callDataScopeChain); 4201 4202 r[firstArg] = newObject; // "this" value 4203 4204 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize; 4205 machine->initializeCallFrame(callFrame, codeBlock, ARG_instr4, scopeChain, r, 0/*dst*/, firstArg, argCount, 1, constructor); 4206 exec->m_callFrame = callFrame; 4207 4208 r = slideRegisterWindowForCall(exec, newCodeBlock, registerFile, registerBase, r, firstArg, argCount, exceptionValue); 4209 JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue); 4210 4211 codeBlock = newCodeBlock; 4212 machine->setScopeChain(exec, scopeChain, scopeChainForCall(exec, functionBodyNode, codeBlock, callDataScopeChain, r)); 4213 4214 if (!codeBlock->ctiCode) 4215 CTI::compile(machine, exec, codeBlock); 4216 4217 ARG_setScopeChain(scopeChain); 4218 ARG_setCodeBlock(codeBlock); 4219 ARG_setR(r); 4220 return codeBlock->ctiCode; 4221 } 4222 4223 JSValue* Machine::cti_op_construct_NotJSConstruct(CTI_ARGS) 4224 { 4225 ExecState* exec = ARG_exec; 4226 Register* r = ARG_r; 4227 4228 JSValue* constrVal = ARG_src1; 4229 int firstArg = ARG_int2; 4230 int argCount = ARG_int3; 4231 4232 ConstructData constructData; 4233 ConstructType constructType = constrVal->getConstructData(constructData); 4234 4235 // Removing this line of code causes a measurable regression on squirrelfish. 4236 JSObject* constructor = static_cast<JSObject*>(constrVal); 4237 4238 ASSERT(constructType != ConstructTypeJS); 4239 4240 if (constructType == ConstructTypeHost) { 4241 CodeBlock* codeBlock = ARG_codeBlock; 4242 ScopeChainNode* scopeChain = ARG_scopeChain; 4243 Machine* machine = exec->machine(); 4244 4245 Register* oldCallFrame = exec->m_callFrame; 4246 Register* callFrame = r + firstArg - RegisterFile::CallFrameHeaderSize; 4247 machine->initializeCallFrame(callFrame, codeBlock, ARG_instr5, scopeChain, r, 0/*dst*/, firstArg, argCount, 1, constrVal); 4248 exec->m_callFrame = callFrame; 4249 4250 if (*ARG_profilerReference) 4251 (*ARG_profilerReference)->willExecute(exec, constructor); 4252 4253 ArgList argList(r + firstArg + 1, argCount - 1); 4254 4255 CTI_MACHINE_SAMPLING_callingHostFunction(); 4256 4257 JSValue* returnValue = constructData.native.function(exec, constructor, argList); 4258 exec->m_callFrame = oldCallFrame; 4259 VM_CHECK_EXCEPTION(JSValue*); 4260 4261 if (*ARG_profilerReference) 4262 (*ARG_profilerReference)->didExecute(exec, constructor); 4263 4264 return returnValue; 4265 } 4266 4267 ASSERT(constructType == ConstructTypeNone); 4268 4269 exec->setException(createNotAConstructorError(exec, constrVal, ARG_instr4, ARG_codeBlock)); 4270 VM_CHECK_EXCEPTION_AT_END(); 4271 return 0; 4272 } 4273 4274 JSValue* Machine::cti_op_get_by_val(CTI_ARGS) 4275 { 4276 ExecState* exec = ARG_exec; 4277 Machine* machine = exec->machine(); 4278 4279 JSValue* baseValue = ARG_src1; 4280 JSValue* subscript = ARG_src2; 4281 4282 JSValue* result; 4283 unsigned i; 4284 4285 bool isUInt32 = JSImmediate::getUInt32(subscript, i); 4286 if (LIKELY(isUInt32)) { 4287 if (machine->isJSArray(baseValue)) { 4288 JSArray* jsArray = static_cast<JSArray*>(baseValue); 4289 if (jsArray->canGetIndex(i)) 4290 result = jsArray->getIndex(i); 4291 else 4292 result = jsArray->JSArray::get(exec, i); 4293 } else if (machine->isJSString(baseValue) && static_cast<JSString*>(baseValue)->canGetIndex(i)) 4294 result = static_cast<JSString*>(baseValue)->getIndex(exec, i); 4295 else 4296 result = baseValue->get(exec, i); 4297 } else { 4298 Identifier property(exec, subscript->toString(exec)); 4299 result = baseValue->get(exec, property); 4300 } 4301 4302 VM_CHECK_EXCEPTION_AT_END(); 4303 return result; 4304 } 4305 4306 JSValue* Machine::cti_op_resolve_func(CTI_ARGS) 4307 { 4308 ExecState* exec = ARG_exec; 4309 ScopeChainNode* scopeChain = ARG_scopeChain; 4310 4311 ScopeChainIterator iter = scopeChain->begin(); 4312 ScopeChainIterator end = scopeChain->end(); 4313 4314 // FIXME: add scopeDepthIsZero optimization 4315 4316 ASSERT(iter != end); 4317 4318 Identifier& ident = *ARG_id1; 4319 JSObject* base; 4320 do { 4321 base = *iter; 4322 PropertySlot slot(base); 4323 if (base->getPropertySlot(exec, ident, slot)) { 4324 // ECMA 11.2.3 says that if we hit an activation the this value should be null. 4325 // However, section 10.2.3 says that in the case where the value provided 4326 // by the caller is null, the global object should be used. It also says 4327 // that the section does not apply to internal functions, but for simplicity 4328 // of implementation we use the global object anyway here. This guarantees 4329 // that in host objects you always get a valid object for this. 4330 // We also handle wrapper substitution for the global object at the same time. 4331 JSObject* thisObj = base->toThisObject(exec); 4332 JSValue* result = slot.getValue(exec, ident); 4333 VM_CHECK_EXCEPTION_AT_END(); 4334 4335 ARG_set2ndResult(result); 4336 return thisObj; 4337 } 4338 ++iter; 4339 } while (iter != end); 4340 4341 CodeBlock* codeBlock = ARG_codeBlock; 4342 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS)); 4343 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS); 4344 exec->setException(createUndefinedVariableError(exec, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock)); 4345 4346 VM_CHECK_EXCEPTION_AT_END(); 4347 return 0; 4348 } 4349 4350 JSValue* Machine::cti_op_sub(CTI_ARGS) 4351 { 4352 JSValue* src1 = ARG_src1; 4353 JSValue* src2 = ARG_src2; 4354 4355 double left; 4356 double right; 4357 if (fastIsNumber(src1, left) && fastIsNumber(src2, right)) 4358 return jsNumber(ARG_exec, left - right); 4359 else { 4360 ExecState* exec = ARG_exec; 4361 JSValue* result = jsNumber(exec, src1->toNumber(exec) - src2->toNumber(exec)); 4362 VM_CHECK_EXCEPTION_AT_END(); 4363 return result; 4364 } 4365 } 4366 4367 void Machine::cti_op_put_by_val(CTI_ARGS) 4368 { 4369 ExecState* exec = ARG_exec; 4370 Machine* machine = exec->machine(); 4371 4372 JSValue* baseValue = ARG_src1; 4373 JSValue* subscript = ARG_src2; 4374 JSValue* value = ARG_src3; 4375 4376 unsigned i; 4377 4378 bool isUInt32 = JSImmediate::getUInt32(subscript, i); 4379 if (LIKELY(isUInt32)) { 4380 if (machine->isJSArray(baseValue)) { 4381 JSArray* jsArray = static_cast<JSArray*>(baseValue); 4382 if (jsArray->canSetIndex(i)) 4383 jsArray->setIndex(i, value); 4384 else 4385 jsArray->JSArray::put(exec, i, value); 4386 } else 4387 baseValue->put(exec, i, value); 4388 } else { 4389 Identifier property(exec, subscript->toString(exec)); 4390 if (!exec->hadException()) { // Don't put to an object if toString threw an exception. 4391 PutPropertySlot slot; 4392 baseValue->put(exec, property, value, slot); 4393 } 4394 } 4395 4396 VM_CHECK_EXCEPTION_AT_END(); 4397 } 4398 4399 JSValue* Machine::cti_op_lesseq(CTI_ARGS) 4400 { 4401 ExecState* exec = ARG_exec; 4402 JSValue* result = jsBoolean(jsLessEq(exec, ARG_src1, ARG_src2)); 4403 VM_CHECK_EXCEPTION_AT_END(); 4404 return result; 4405 } 4406 4407 int Machine::cti_op_loop_if_true(CTI_ARGS) 4408 { 4409 JSValue* src1 = ARG_src1; 4410 4411 ExecState* exec = ARG_exec; 4412 4413 bool result = src1->toBoolean(exec); 4414 VM_CHECK_EXCEPTION_AT_END(); 4415 return result; 4416 } 4417 4418 JSValue* Machine::cti_op_negate(CTI_ARGS) 4419 { 4420 JSValue* src = ARG_src1; 4421 4422 ExecState* exec = ARG_exec; 4423 4424 double v; 4425 if (fastIsNumber(src, v)) 4426 return jsNumber(exec, -v); 4427 else { 4428 JSValue* result = jsNumber(exec, -src->toNumber(exec)); 4429 VM_CHECK_EXCEPTION_AT_END(); 4430 return result; 4431 } 4432 } 4433 4434 JSValue* Machine::cti_op_resolve_base(CTI_ARGS) 4435 { 4436 return inlineResolveBase(ARG_exec, *ARG_id1, ARG_scopeChain); 4437 } 4438 4439 JSValue* Machine::cti_op_resolve_skip(CTI_ARGS) 4440 { 4441 ExecState* exec = ARG_exec; 4442 ScopeChainNode* scopeChain = ARG_scopeChain; 4443 4444 int skip = ARG_int2; 4445 4446 ScopeChainIterator iter = scopeChain->begin(); 4447 ScopeChainIterator end = scopeChain->end(); 4448 ASSERT(iter != end); 4449 while (skip--) { 4450 ++iter; 4451 ASSERT(iter != end); 4452 } 4453 Identifier& ident = *ARG_id1; 4454 do { 4455 JSObject* o = *iter; 4456 PropertySlot slot(o); 4457 if (o->getPropertySlot(exec, ident, slot)) { 4458 JSValue* result = slot.getValue(exec, ident); 4459 VM_CHECK_EXCEPTION_AT_END(); 4460 return result; 4461 } 4462 } while (++iter != end); 4463 4464 CodeBlock* codeBlock = ARG_codeBlock; 4465 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS)); 4466 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS); 4467 exec->setException(createUndefinedVariableError(exec, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock)); 4468 4469 VM_CHECK_EXCEPTION_AT_END(); 4470 return 0; 4471 } 4472 4473 JSValue* Machine::cti_op_div(CTI_ARGS) 4474 { 4475 ExecState* exec = ARG_exec; 4476 JSValue* src1 = ARG_src1; 4477 JSValue* src2 = ARG_src2; 4478 4479 double left; 4480 double right; 4481 if (fastIsNumber(src1, left) && fastIsNumber(src2, right)) 4482 return jsNumber(exec, left / right); 4483 else { 4484 JSValue* result = jsNumber(exec, src1->toNumber(exec) / src2->toNumber(exec)); 4485 VM_CHECK_EXCEPTION_AT_END(); 4486 return result; 4487 } 4488 } 4489 4490 JSValue* Machine::cti_op_pre_dec(CTI_ARGS) 4491 { 4492 JSValue* v = ARG_src1; 4493 4494 ExecState* exec = ARG_exec; 4495 JSValue* result = jsNumber(exec, v->toNumber(exec) - 1); 4496 VM_CHECK_EXCEPTION_AT_END(); 4497 return result; 4498 } 4499 4500 int Machine::cti_op_jless(CTI_ARGS) 4501 { 4502 JSValue* src1 = ARG_src1; 4503 JSValue* src2 = ARG_src2; 4504 ExecState* exec = ARG_exec; 4505 4506 bool result = jsLess(exec, src1, src2); 4507 VM_CHECK_EXCEPTION_AT_END(); 4508 return result; 4509 } 4510 4511 JSValue* Machine::cti_op_not(CTI_ARGS) 4512 { 4513 JSValue* src = ARG_src1; 4514 4515 ExecState* exec = ARG_exec; 4516 4517 JSValue* result = jsBoolean(!src->toBoolean(exec)); 4518 VM_CHECK_EXCEPTION_AT_END(); 4519 return result; 4520 } 4521 4522 int SFX_CALL Machine::cti_op_jtrue(CTI_ARGS) 4523 { 4524 JSValue* src1 = ARG_src1; 4525 4526 ExecState* exec = ARG_exec; 4527 4528 bool result = src1->toBoolean(exec); 4529 VM_CHECK_EXCEPTION_AT_END(); 4530 return result; 4531 } 4532 4533 JSValue* Machine::cti_op_post_inc(CTI_ARGS) 4534 { 4535 JSValue* v = ARG_src1; 4536 4537 ExecState* exec = ARG_exec; 4538 4539 JSValue* number = v->toJSNumber(exec); 4540 VM_CHECK_EXCEPTION(JSValue*); 4541 ARG_set2ndResult(jsNumber(exec, number->uncheckedGetNumber() + 1)); 4542 return number; 4543 } 4544 4545 JSValue* Machine::cti_op_eq(CTI_ARGS) 4546 { 4547 JSValue* src1 = ARG_src1; 4548 JSValue* src2 = ARG_src2; 4549 4550 if (JSImmediate::areBothImmediateNumbers(src1, src2)) 4551 return jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2)); 4552 else { 4553 ExecState* exec = ARG_exec; 4554 JSValue* result = jsBoolean(equal(exec, src1, src2)); 4555 VM_CHECK_EXCEPTION_AT_END(); 4556 return result; 4557 } 4558 } 4559 4560 JSValue* Machine::cti_op_lshift(CTI_ARGS) 4561 { 4562 JSValue* val = ARG_src1; 4563 JSValue* shift = ARG_src2; 4564 4565 ExecState* exec = ARG_exec; 4566 4567 int32_t left; 4568 uint32_t right; 4569 if (JSImmediate::areBothImmediateNumbers(val, shift)) 4570 return jsNumber(exec, JSImmediate::getTruncatedInt32(val) << (JSImmediate::getTruncatedUInt32(shift) & 0x1f)); 4571 else if (fastToInt32(val, left) && fastToUInt32(shift, right)) 4572 return jsNumber(exec, left << (right & 0x1f)); 4573 else { 4574 JSValue* result = jsNumber(exec, (val->toInt32(exec)) << (shift->toUInt32(exec) & 0x1f)); 4575 VM_CHECK_EXCEPTION_AT_END(); 4576 return result; 4577 } 4578 } 4579 4580 JSValue* Machine::cti_op_bitand(CTI_ARGS) 4581 { 4582 JSValue* src1 = ARG_src1; 4583 JSValue* src2 = ARG_src2; 4584 4585 ExecState* exec = ARG_exec; 4586 4587 int32_t left; 4588 int32_t right; 4589 if (fastToInt32(src1, left) && fastToInt32(src2, right)) 4590 return jsNumber(exec, left & right); 4591 else { 4592 JSValue* result = jsNumber(exec, src1->toInt32(exec) & src2->toInt32(exec)); 4593 VM_CHECK_EXCEPTION_AT_END(); 4594 return result; 4595 } 4596 } 4597 4598 JSValue* Machine::cti_op_rshift(CTI_ARGS) 4599 { 4600 JSValue* val = ARG_src1; 4601 JSValue* shift = ARG_src2; 4602 4603 ExecState* exec = ARG_exec; 4604 4605 int32_t left; 4606 uint32_t right; 4607 if (JSImmediate::areBothImmediateNumbers(val, shift)) 4608 return JSImmediate::rightShiftImmediateNumbers(val, shift); 4609 else if (fastToInt32(val, left) && fastToUInt32(shift, right)) 4610 return jsNumber(exec, left >> (right & 0x1f)); 4611 else { 4612 JSValue* result = jsNumber(exec, (val->toInt32(exec)) >> (shift->toUInt32(exec) & 0x1f)); 4613 VM_CHECK_EXCEPTION_AT_END(); 4614 return result; 4615 } 4616 } 4617 4618 JSValue* Machine::cti_op_bitnot(CTI_ARGS) 4619 { 4620 JSValue* src = ARG_src1; 4621 4622 ExecState* exec = ARG_exec; 4623 4624 int value; 4625 if (fastToInt32(src, value)) 4626 return jsNumber(exec, ~value); 4627 4628 JSValue* result = jsNumber(exec, ~src->toInt32(exec)); 4629 VM_CHECK_EXCEPTION_AT_END(); 4630 return result; 4631 } 4632 4633 JSValue* Machine::cti_op_resolve_with_base(CTI_ARGS) 4634 { 4635 ExecState* exec = ARG_exec; 4636 ScopeChainNode* scopeChain = ARG_scopeChain; 4637 4638 ScopeChainIterator iter = scopeChain->begin(); 4639 ScopeChainIterator end = scopeChain->end(); 4640 4641 // FIXME: add scopeDepthIsZero optimization 4642 4643 ASSERT(iter != end); 4644 4645 Identifier& ident = *ARG_id1; 4646 JSObject* base; 4647 do { 4648 base = *iter; 4649 PropertySlot slot(base); 4650 if (base->getPropertySlot(exec, ident, slot)) { 4651 JSValue* result = slot.getValue(exec, ident); 4652 VM_CHECK_EXCEPTION_AT_END(); 4653 ARG_set2ndResult(result); 4654 return base; 4655 } 4656 ++iter; 4657 } while (iter != end); 4658 4659 CodeBlock* codeBlock = ARG_codeBlock; 4660 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS)); 4661 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS); 4662 exec->setException(createUndefinedVariableError(exec, ident, codeBlock->instructions.begin() + vPCIndex, codeBlock)); 4663 4664 VM_CHECK_EXCEPTION_AT_END(); 4665 return 0; 4666 } 4667 4668 JSValue* Machine::cti_op_new_func_exp(CTI_ARGS) 4669 { 4670 return ARG_funcexp1->makeFunction(ARG_exec, ARG_scopeChain); 4671 } 4672 4673 JSValue* Machine::cti_op_mod(CTI_ARGS) 4674 { 4675 JSValue* dividendValue = ARG_src1; 4676 JSValue* divisorValue = ARG_src2; 4677 4678 ExecState* exec = ARG_exec; 4679 double d = dividendValue->toNumber(exec); 4680 JSValue* result = jsNumber(exec, fmod(d, divisorValue->toNumber(exec))); 4681 VM_CHECK_EXCEPTION_AT_END(); 4682 return result; 4683 } 4684 4685 JSValue* Machine::cti_op_less(CTI_ARGS) 4686 { 4687 ExecState* exec = ARG_exec; 4688 JSValue* result = jsBoolean(jsLess(exec, ARG_src1, ARG_src2)); 4689 VM_CHECK_EXCEPTION_AT_END(); 4690 return result; 4691 } 4692 4693 JSValue* Machine::cti_op_neq(CTI_ARGS) 4694 { 4695 JSValue* src1 = ARG_src1; 4696 JSValue* src2 = ARG_src2; 4697 4698 if (JSImmediate::areBothImmediateNumbers(src1, src2)) 4699 return jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2)); 4700 else { 4701 ExecState* exec = ARG_exec; 4702 JSValue* result = jsBoolean(!equal(exec, src1, src2)); 4703 VM_CHECK_EXCEPTION_AT_END(); 4704 return result; 4705 } 4706 } 4707 4708 JSValue* Machine::cti_op_post_dec(CTI_ARGS) 4709 { 4710 JSValue* v = ARG_src1; 4711 4712 ExecState* exec = ARG_exec; 4713 4714 JSValue* number = v->toJSNumber(exec); 4715 VM_CHECK_EXCEPTION(JSValue*); 4716 4717 ARG_set2ndResult(jsNumber(exec, number->uncheckedGetNumber() - 1)); 4718 return number; 4719 } 4720 4721 JSValue* Machine::cti_op_urshift(CTI_ARGS) 4722 { 4723 JSValue* val = ARG_src1; 4724 JSValue* shift = ARG_src2; 4725 4726 ExecState* exec = ARG_exec; 4727 4728 if (JSImmediate::areBothImmediateNumbers(val, shift) && !JSImmediate::isNegative(val)) 4729 return JSImmediate::rightShiftImmediateNumbers(val, shift); 4730 else { 4731 JSValue* result = jsNumber(exec, (val->toUInt32(exec)) >> (shift->toUInt32(exec) & 0x1f)); 4732 VM_CHECK_EXCEPTION_AT_END(); 4733 return result; 4734 } 4735 } 4736 4737 JSValue* Machine::cti_op_bitxor(CTI_ARGS) 4738 { 4739 JSValue* src1 = ARG_src1; 4740 JSValue* src2 = ARG_src2; 4741 4742 ExecState* exec = ARG_exec; 4743 4744 JSValue* result = jsNumber(exec, src1->toInt32(exec) ^ src2->toInt32(exec)); 4745 VM_CHECK_EXCEPTION_AT_END(); 4746 return result; 4747 } 4748 4749 JSValue* Machine::cti_op_new_regexp(CTI_ARGS) 4750 { 4751 return new (ARG_exec) RegExpObject(ARG_scopeChain->globalObject()->regExpPrototype(), ARG_regexp1); 4752 } 4753 4754 JSValue* Machine::cti_op_bitor(CTI_ARGS) 4755 { 4756 JSValue* src1 = ARG_src1; 4757 JSValue* src2 = ARG_src2; 4758 4759 ExecState* exec = ARG_exec; 4760 4761 JSValue* result = jsNumber(exec, src1->toInt32(exec) | src2->toInt32(exec)); 4762 VM_CHECK_EXCEPTION_AT_END(); 4763 return result; 4764 } 4765 4766 JSValue* Machine::cti_op_call_eval(CTI_ARGS) 4767 { 4768 ExecState* exec = ARG_exec; 4769 RegisterFile* registerFile = ARG_registerFile; 4770 Register* r = ARG_r; 4771 CodeBlock* codeBlock = ARG_codeBlock; 4772 ScopeChainNode* scopeChain = ARG_scopeChain; 4773 4774 Machine* machine = exec->machine(); 4775 JSValue* exceptionValue = 0; 4776 4777 JSValue* funcVal = ARG_src1; 4778 JSValue* baseVal = ARG_src2; 4779 int firstArg = ARG_int3; 4780 int argCount = ARG_int4; 4781 4782 if (baseVal == scopeChain->globalObject() && funcVal == scopeChain->globalObject()->evalFunction()) { 4783 JSObject* thisObject = static_cast<JSObject*>(r[codeBlock->thisRegister].jsValue(exec)); 4784 JSValue* result = machine->callEval(exec, thisObject, scopeChain, registerFile, r, firstArg, argCount, exceptionValue); 4785 JSVALUE_VM_CHECK_EXCEPTION_ARG(exceptionValue); 4786 return result; 4787 } 4788 4789 return JSImmediate::impossibleValue(); 4790 } 4791 4792 void* Machine::cti_op_throw(CTI_ARGS) 4793 { 4794 ExecState* exec = ARG_exec; 4795 CodeBlock* codeBlock = ARG_codeBlock; 4796 ScopeChainNode* scopeChain = ARG_scopeChain; 4797 Register* r = ARG_r; 4798 4799 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS)); 4800 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS); 4801 4802 JSValue* exceptionValue = ARG_src1; 4803 Instruction* handlerVPC = ARG_exec->machine()->throwException(exec, exceptionValue, codeBlock->instructions.begin() + vPCIndex, codeBlock, scopeChain, r, true); 4804 4805 if (handlerVPC) { 4806 exec->setException(exceptionValue); 4807 ARG_setScopeChain(scopeChain); 4808 ARG_setCodeBlock(codeBlock); 4809 ARG_setR(r); 4810 4811 void* catchRoutine = codeBlock->nativeExceptionCodeForHandlerVPC(handlerVPC); 4812 ASSERT(catchRoutine); 4813 ctiSetReturnAddress(&CTI_RETURN_ADDRESS, catchRoutine); 4814 return catchRoutine; 4815 } else { 4816 exec->clearException(); 4817 *ARG_exception = exceptionValue; 4818 return JSImmediate::nullImmediate(); 4819 } 4820 } 4821 4822 JSPropertyNameIterator* Machine::cti_op_get_pnames(CTI_ARGS) 4823 { 4824 return JSPropertyNameIterator::create(ARG_exec, ARG_src1); 4825 } 4826 4827 JSValue* Machine::cti_op_next_pname(CTI_ARGS) 4828 { 4829 JSPropertyNameIterator* it = ARG_pni1; 4830 JSValue* temp = it->next(ARG_exec); 4831 if (!temp) 4832 it->invalidate(); 4833 return temp; 4834 } 4835 4836 void Machine::cti_op_push_scope(CTI_ARGS) 4837 { 4838 ExecState* exec = ARG_exec; 4839 4840 JSValue* v = ARG_src1; 4841 JSObject* o = v->toObject(exec); 4842 VM_CHECK_EXCEPTION_v(); 4843 4844 ScopeChainNode* newScopeChain = ARG_scopeChain->push(o); 4845 ARG_setScopeChain(newScopeChain); 4846 exec->m_scopeChain = newScopeChain; 4847 } 4848 4849 void Machine::cti_op_pop_scope(CTI_ARGS) 4850 { 4851 ExecState* exec = ARG_exec; 4852 4853 ScopeChainNode* newScopeChain = ARG_scopeChain->pop(); 4854 ARG_setScopeChain(newScopeChain); 4855 exec->m_scopeChain = newScopeChain; 4856 } 4857 4858 JSValue* Machine::cti_op_typeof(CTI_ARGS) 4859 { 4860 return jsTypeStringForValue(ARG_exec, ARG_src1); 4861 } 4862 4863 JSValue* Machine::cti_op_stricteq(CTI_ARGS) 4864 { 4865 JSValue* src1 = ARG_src1; 4866 JSValue* src2 = ARG_src2; 4867 4868 if (JSImmediate::areBothImmediateNumbers(src1, src2)) 4869 return jsBoolean(reinterpret_cast<intptr_t>(src1) == reinterpret_cast<intptr_t>(src2)); 4870 else { 4871 ExecState* exec = ARG_exec; 4872 JSValue* result = jsBoolean(strictEqual(src1, src2)); 4873 VM_CHECK_EXCEPTION_AT_END(); 4874 return result; 4875 } 4876 } 4877 4878 JSValue* Machine::cti_op_nstricteq(CTI_ARGS) 4879 { 4880 JSValue* src1 = ARG_src1; 4881 JSValue* src2 = ARG_src2; 4882 4883 if (JSImmediate::areBothImmediateNumbers(src1, src2)) 4884 return jsBoolean(reinterpret_cast<intptr_t>(src1) != reinterpret_cast<intptr_t>(src2)); 4885 else { 4886 ExecState* exec = ARG_exec; 4887 JSValue* result = jsBoolean(!strictEqual(src1, src2)); 4888 VM_CHECK_EXCEPTION_AT_END(); 4889 return result; 4890 } 4891 } 4892 4893 JSValue* Machine::cti_op_to_jsnumber(CTI_ARGS) 4894 { 4895 JSValue* src = ARG_src1; 4896 ExecState* exec = ARG_exec; 4897 4898 JSValue* result = src->toJSNumber(exec); 4899 VM_CHECK_EXCEPTION_AT_END(); 4900 return result; 4901 } 4902 4903 JSValue* Machine::cti_op_in(CTI_ARGS) 4904 { 4905 ExecState* exec = ARG_exec; 4906 JSValue* baseVal = ARG_src2; 4907 4908 if (!baseVal->isObject()) { 4909 CodeBlock* codeBlock = ARG_codeBlock; 4910 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(CTI_RETURN_ADDRESS)); 4911 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(CTI_RETURN_ADDRESS); 4912 exec->setException(createInvalidParamError(exec, "in", baseVal, codeBlock->instructions.begin() + vPCIndex, codeBlock)); 4913 VM_CHECK_EXCEPTION(JSValue*); 4914 } 4915 4916 JSValue* propName = ARG_src1; 4917 JSObject* baseObj = static_cast<JSObject*>(baseVal); 4918 4919 uint32_t i; 4920 if (propName->getUInt32(i)) 4921 return jsBoolean(baseObj->hasProperty(exec, i)); 4922 4923 Identifier property(exec, propName->toString(exec)); 4924 VM_CHECK_EXCEPTION(JSValue*); 4925 return jsBoolean(baseObj->hasProperty(exec, property)); 4926 } 4927 4928 JSValue* Machine::cti_op_push_new_scope(CTI_ARGS) 4929 { 4930 ExecState* exec = ARG_exec; 4931 JSObject* scope = new (exec) JSStaticScopeObject(exec, *ARG_id1, ARG_src2, DontDelete); 4932 4933 ScopeChainNode* newScopeChain = ARG_scopeChain->push(scope); 4934 ARG_setScopeChain(newScopeChain); 4935 exec->m_scopeChain = newScopeChain; 4936 4937 return scope; 4938 } 4939 4940 void Machine::cti_op_jmp_scopes(CTI_ARGS) 4941 { 4942 ExecState* exec = ARG_exec; 4943 unsigned count = ARG_int1; 4944 4945 ScopeChainNode* tmp = ARG_scopeChain; 4946 while (count--) 4947 tmp = tmp->pop(); 4948 4949 ARG_setScopeChain(tmp); 4950 exec->m_scopeChain = tmp; 4951 } 4952 4953 void Machine::cti_op_put_by_index(CTI_ARGS) 4954 { 4955 ExecState* exec = ARG_exec; 4956 unsigned property = ARG_int2; 4957 4958 ARG_src1->put(exec, property, ARG_src3); 4959 } 4960 4961 void* Machine::cti_op_switch_imm(CTI_ARGS) 4962 { 4963 JSValue* scrutinee = ARG_src1; 4964 unsigned tableIndex = ARG_int2; 4965 4966 CodeBlock* codeBlock = ARG_codeBlock; 4967 4968 if (JSImmediate::isNumber(scrutinee)) { 4969 int32_t value = JSImmediate::getTruncatedInt32(scrutinee); 4970 return codeBlock->immediateSwitchJumpTables[tableIndex].ctiForValue(value); 4971 } 4972 4973 return codeBlock->immediateSwitchJumpTables[tableIndex].ctiDefault; 4974 } 4975 4976 void* Machine::cti_op_switch_char(CTI_ARGS) 4977 { 4978 JSValue* scrutinee = ARG_src1; 4979 unsigned tableIndex = ARG_int2; 4980 4981 CodeBlock* codeBlock = ARG_codeBlock; 4982 4983 void* result = codeBlock->characterSwitchJumpTables[tableIndex].ctiDefault; 4984 4985 if (scrutinee->isString()) { 4986 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep(); 4987 if (value->size() == 1) 4988 result = codeBlock->characterSwitchJumpTables[tableIndex].ctiForValue(value->data()[0]); 4989 } 4990 4991 return result; 4992 } 4993 4994 void* Machine::cti_op_switch_string(CTI_ARGS) 4995 { 4996 JSValue* scrutinee = ARG_src1; 4997 unsigned tableIndex = ARG_int2; 4998 4999 CodeBlock* codeBlock = ARG_codeBlock; 5000 5001 void* result = codeBlock->stringSwitchJumpTables[tableIndex].ctiDefault; 5002 5003 if (scrutinee->isString()) { 5004 UString::Rep* value = static_cast<JSString*>(scrutinee)->value().rep(); 5005 result = codeBlock->stringSwitchJumpTables[tableIndex].ctiForValue(value); 5006 } 5007 5008 return result; 5009 } 5010 5011 JSValue* Machine::cti_op_del_by_val(CTI_ARGS) 5012 { 5013 ExecState* exec = ARG_exec; 5014 5015 JSValue* baseValue = ARG_src1; 5016 JSObject* baseObj = baseValue->toObject(exec); // may throw 5017 5018 JSValue* subscript = ARG_src2; 5019 JSValue* result; 5020 uint32_t i; 5021 if (subscript->getUInt32(i)) 5022 result = jsBoolean(baseObj->deleteProperty(exec, i)); 5023 else { 5024 VM_CHECK_EXCEPTION(JSValue*); 5025 Identifier property(exec, subscript->toString(exec)); 5026 VM_CHECK_EXCEPTION(JSValue*); 5027 result = jsBoolean(baseObj->deleteProperty(exec, property)); 5028 } 5029 5030 VM_CHECK_EXCEPTION_AT_END(); 5031 return result; 5032 } 5033 5034 void Machine::cti_op_put_getter(CTI_ARGS) 5035 { 5036 ExecState* exec = ARG_exec; 5037 5038 ASSERT(ARG_src1->isObject()); 5039 JSObject* baseObj = static_cast<JSObject*>(ARG_src1); 5040 Identifier& ident = *ARG_id2; 5041 ASSERT(ARG_src3->isObject()); 5042 baseObj->defineGetter(exec, ident, static_cast<JSObject*>(ARG_src3)); 5043 } 5044 5045 void Machine::cti_op_put_setter(CTI_ARGS) 5046 { 5047 ExecState* exec = ARG_exec; 5048 5049 ASSERT(ARG_src1->isObject()); 5050 JSObject* baseObj = static_cast<JSObject*>(ARG_src1); 5051 Identifier& ident = *ARG_id2; 5052 ASSERT(ARG_src3->isObject()); 5053 baseObj->defineSetter(exec, ident, static_cast<JSObject*>(ARG_src3)); 5054 } 5055 5056 JSValue* Machine::cti_op_new_error(CTI_ARGS) 5057 { 5058 ExecState* exec = ARG_exec; 5059 CodeBlock* codeBlock = ARG_codeBlock; 5060 unsigned type = ARG_int1; 5061 JSValue* message = ARG_src2; 5062 unsigned lineNumber = ARG_int3; 5063 5064 return Error::create(exec, static_cast<ErrorType>(type), message->toString(exec), lineNumber, codeBlock->ownerNode->sourceId(), codeBlock->ownerNode->sourceURL()); 5065 } 5066 5067 void Machine::cti_op_debug(CTI_ARGS) 5068 { 5069 ExecState* exec = ARG_exec; 5070 CodeBlock* codeBlock = ARG_codeBlock; 5071 ScopeChainNode* scopeChain = ARG_scopeChain; 5072 Register* r = ARG_r; 5073 5074 int debugHookID = ARG_int1; 5075 int firstLine = ARG_int2; 5076 int lastLine = ARG_int3; 5077 5078 exec->machine()->debug(exec, codeBlock, scopeChain, r, static_cast<DebugHookID>(debugHookID), firstLine, lastLine); 5079 } 5080 5081 JSValue* Machine::cti_op_eq_null(CTI_ARGS) 5082 { 5083 JSValue* src = ARG_src1; 5084 if (src->isUndefinedOrNull()) 5085 return jsBoolean(true); 5086 5087 return jsBoolean(!JSImmediate::isImmediate(src) && static_cast<JSCell*>(src)->masqueradeAsUndefined()); 5088 } 5089 5090 JSValue* Machine::cti_op_neq_null(CTI_ARGS) 5091 { 5092 JSValue* src = ARG_src1; 5093 if (src->isUndefinedOrNull()) 5094 return jsBoolean(false); 5095 5096 return jsBoolean(JSImmediate::isImmediate(src) || !static_cast<JSCell*>(src)->masqueradeAsUndefined()); 5097 } 5098 5099 void* Machine::cti_vm_throw(CTI_ARGS) 5100 { 5101 ExecState* exec = ARG_exec; 5102 CodeBlock* codeBlock = ARG_codeBlock; 5103 ScopeChainNode* scopeChain = ARG_scopeChain; 5104 Register* r = ARG_r; 5105 5106 ASSERT(codeBlock->ctiReturnAddressVPCMap.contains(exec->ctiReturnAddress())); 5107 unsigned vPCIndex = codeBlock->ctiReturnAddressVPCMap.get(exec->ctiReturnAddress()); 5108 5109 ASSERT(exec->hadException()); 5110 5111 JSValue* exceptionValue = exec->exception(); 5112 5113 Instruction* handlerVPC = ARG_exec->machine()->throwException(exec, exceptionValue, codeBlock->instructions.begin() + vPCIndex, codeBlock, scopeChain, r, false); 5114 5115 if (handlerVPC) { 5116 exec->setException(exceptionValue); 5117 ARG_setScopeChain(scopeChain); 5118 ARG_setCodeBlock(codeBlock); 5119 ARG_setR(r); 5120 5121 void* catchRoutine = codeBlock->nativeExceptionCodeForHandlerVPC(handlerVPC); 5122 ASSERT(catchRoutine); 5123 ctiSetReturnAddress(&CTI_RETURN_ADDRESS, catchRoutine); 5124 return catchRoutine; 5125 } else { 5126 exec->clearException(); 5127 *ARG_exception = exceptionValue; 5128 return JSImmediate::nullImmediate(); 5129 } 5130 } 5131 5132 #undef VM_CHECK_EXCEPTION 5133 #undef VM_CHECK_EXCEPTION_v 5134 #undef VM_CHECK_EXCEPTION_AT_END 5135 5136 #endif // ENABLE(CTI) 5137 3501 5138 } // namespace KJS
Note:
See TracChangeset
for help on using the changeset viewer.