Changeset 34842 in webkit for trunk/JavaScriptCore/VM/Machine.cpp
- Timestamp:
- Jun 27, 2008, 9:02:03 PM (17 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/VM/Machine.cpp
r34838 r34842 50 50 #include "RegExpObject.h" 51 51 52 #if HAVE(SYS_TIME_H) 53 #include <sys/time.h> 54 #endif 55 56 #if PLATFORM(WIN_OS) 57 #include <windows.h> 58 #endif 59 60 #if PLATFORM(QT) 61 #include <QDateTime> 62 #endif 63 52 64 using namespace std; 53 65 54 66 namespace KJS { 67 68 // Default number of ticks before a timeout check should be done. 69 static const int initialTickCountThreshold = 255; 70 71 // Preferred number of milliseconds between each timeout check 72 static const int preferredScriptCheckTimeInterval = 1000; 55 73 56 74 #if HAVE(COMPUTED_GOTO) … … 453 471 Machine::Machine() 454 472 : m_reentryDepth(0) 473 , m_timeoutTime(0) 474 , m_timeAtLastCheckTimeout(0) 475 , m_timeExecuting(0) 476 , m_timeoutCheckCount(0) 477 , m_ticksUntilNextTimeoutCheck(initialTickCountThreshold) 455 478 { 456 479 privateExecute(InitializeAndReturn); … … 592 615 exception->put(exec, Identifier(exec, "sourceURL"), jsOwnedString(exec, codeBlock->ownerNode->sourceURL())); 593 616 } 617 618 if (exception->isWatchdogException()) { 619 while (unwindCallFrame(exec, exceptionValue, registerBase, vPC, codeBlock, k, scopeChain, r)) { 620 // Don't need handler checks or anything, we just want to unroll all the JS callframes possible. 621 } 622 return 0; 623 } 594 624 } 595 625 … … 848 878 } 849 879 880 void Machine::resetTimeoutCheck() 881 { 882 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold; 883 m_timeAtLastCheckTimeout = 0; 884 m_timeExecuting = 0; 885 } 886 887 // Returns the current time in milliseconds 888 // It doesn't matter what "current time" is here, just as long as 889 // it's possible to measure the time difference correctly. 890 // In an ideal world this would be in DateMath or some such, but unfortunately 891 // that's a regression. 892 static inline unsigned getCurrentTime() 893 { 894 #if HAVE(SYS_TIME_H) 895 struct timeval tv; 896 gettimeofday(&tv, 0); 897 return tv.tv_sec * 1000 + tv.tv_usec / 1000; 898 #elif PLATFORM(QT) 899 QDateTime t = QDateTime::currentDateTime(); 900 return t.toTime_t() * 1000 + t.time().msec(); 901 #elif PLATFORM(WIN_OS) 902 return timeGetTime(); 903 #else 904 #error Platform does not have getCurrentTime function 905 #endif 906 } 907 908 // We have to return a JSValue here, gcc seems to produce worse code if 909 // we attempt to return a bool 910 ALWAYS_INLINE JSValue* Machine::checkTimeout(JSGlobalObject* globalObject) 911 { 912 unsigned currentTime = getCurrentTime(); 913 914 if (!m_timeAtLastCheckTimeout) { 915 // Suspicious amount of looping in a script -- start timing it 916 m_timeAtLastCheckTimeout = currentTime; 917 return 0; 918 } 919 920 unsigned timeDiff = currentTime - m_timeAtLastCheckTimeout; 921 922 if (timeDiff == 0) 923 timeDiff = 1; 924 925 m_timeExecuting += timeDiff; 926 m_timeAtLastCheckTimeout = currentTime; 927 928 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in 929 // preferredScriptCheckTimeInterval 930 m_ticksUntilNextTimeoutCheck = static_cast<unsigned>((static_cast<float>(preferredScriptCheckTimeInterval) / timeDiff) * m_ticksUntilNextTimeoutCheck); 931 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the 932 // preferred script check time interval. 933 if (m_ticksUntilNextTimeoutCheck == 0) 934 m_ticksUntilNextTimeoutCheck = initialTickCountThreshold; 935 936 if (m_timeoutTime && m_timeExecuting > m_timeoutTime) { 937 if (globalObject->shouldInterruptScript()) 938 return jsNull(); // Appeasing GCC, all we need is a non-null js value. 939 940 resetTimeoutCheck(); 941 } 942 943 return 0; 944 } 945 850 946 JSValue* Machine::privateExecute(ExecutionFlag flag, ExecState* exec, RegisterFile* registerFile, Register* r, ScopeChainNode* scopeChain, CodeBlock* codeBlock, JSValue** exception) 851 947 { … … 875 971 JSValue** k = codeBlock->jsValues.data(); 876 972 Profiler** enabledProfilerReference = Profiler::enabledProfilerReference(); 877 973 unsigned tickCount = m_ticksUntilNextTimeoutCheck + 1; 974 878 975 #define VM_CHECK_EXCEPTION() \ 879 976 do { \ … … 888 985 #endif 889 986 987 #define CHECK_FOR_TIMEOUT() \ 988 if (!--tickCount) { \ 989 if ((exceptionValue = checkTimeout(exec->dynamicGlobalObject()))) \ 990 goto vm_throw; \ 991 tickCount = m_ticksUntilNextTimeoutCheck; \ 992 } 993 890 994 #if HAVE(COMPUTED_GOTO) 891 995 #define NEXT_OPCODE goto *vPC->u.opcode … … 1844 1948 NEXT_OPCODE; 1845 1949 } 1846 BEGIN_OPCODE(op_ jmp) {1847 /* jmp target(offset)1848 1950 BEGIN_OPCODE(op_loop) { 1951 /* loop target(offset) 1952 1849 1953 Jumps unconditionally to offset target from the current 1850 1954 instruction. 1851 */ 1955 1956 Additionally this loop instruction may terminate JS execution is 1957 the JS timeout is reached. 1958 */ 1852 1959 #if DUMP_OPCODE_STATS 1853 1960 OpcodeStats::resetLastInstruction(); 1854 1961 #endif 1855 1962 int target = (++vPC)->u.operand; 1856 1963 CHECK_FOR_TIMEOUT(); 1857 1964 vPC += target; 1965 NEXT_OPCODE; 1966 } 1967 BEGIN_OPCODE(op_jmp) { 1968 /* jmp target(offset) 1969 1970 Jumps unconditionally to offset target from the current 1971 instruction. 1972 */ 1973 #if DUMP_OPCODE_STATS 1974 OpcodeStats::resetLastInstruction(); 1975 #endif 1976 int target = (++vPC)->u.operand; 1977 1978 vPC += target; 1979 NEXT_OPCODE; 1980 } 1981 BEGIN_OPCODE(op_loop_if_true) { 1982 /* loop_if_true cond(r) target(offset) 1983 1984 Jumps to offset target from the current instruction, if and 1985 only if register cond converts to boolean as true. 1986 1987 Additionally this loop instruction may terminate JS execution is 1988 the JS timeout is reached. 1989 */ 1990 int cond = (++vPC)->u.operand; 1991 int target = (++vPC)->u.operand; 1992 if (r[cond].u.jsValue->toBoolean(exec)) { 1993 vPC += target; 1994 CHECK_FOR_TIMEOUT(); 1995 NEXT_OPCODE; 1996 } 1997 1998 ++vPC; 1858 1999 NEXT_OPCODE; 1859 2000 } … … 1887 2028 } 1888 2029 2030 ++vPC; 2031 NEXT_OPCODE; 2032 } 2033 BEGIN_OPCODE(op_loop_if_less) { 2034 /* loop_if_less src1(r) src2(r) target(offset) 2035 2036 Checks whether register src1 is less than register src2, as 2037 with the ECMAScript '<' operator, and then jumps to offset 2038 target from the current instruction, if and only if the 2039 result of the comparison is true. 2040 2041 Additionally this loop instruction may terminate JS execution is 2042 the JS timeout is reached. 2043 */ 2044 JSValue* src1 = r[(++vPC)->u.operand].u.jsValue; 2045 JSValue* src2 = r[(++vPC)->u.operand].u.jsValue; 2046 int target = (++vPC)->u.operand; 2047 2048 bool result = jsLess(exec, src1, src2); 2049 VM_CHECK_EXCEPTION(); 2050 2051 if (result) { 2052 vPC += target; 2053 CHECK_FOR_TIMEOUT(); 2054 NEXT_OPCODE; 2055 } 2056 1889 2057 ++vPC; 1890 2058 NEXT_OPCODE; … … 2285 2453 JSPropertyNameIterator* it = r[iter].u.jsPropertyNameIterator; 2286 2454 if (JSValue* temp = it->next(exec)) { 2455 CHECK_FOR_TIMEOUT(); 2287 2456 r[dst].u.jsValue = temp; 2288 2457 vPC += target; … … 2476 2645 vm_throw: { 2477 2646 exec->clearException(); 2647 if (!tickCount) { 2648 // The exceptionValue is a lie! (GCC produces bad code for reasons I 2649 // cannot fathom if we don't assign to the exceptionValue before branching) 2650 exceptionValue = createInterruptedExecutionException(exec); 2651 } 2478 2652 handlerVPC = throwException(exec, exceptionValue, ®isterBase, vPC, codeBlock, k, scopeChain, r); 2479 2653 if (!handlerVPC) {
Note:
See TracChangeset
for help on using the changeset viewer.