Changeset 34842 in webkit for trunk/JavaScriptCore
- Timestamp:
- Jun 27, 2008, 9:02:03 PM (17 years ago)
- Location:
- trunk/JavaScriptCore
- Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/JavaScriptCore/ChangeLog
r34840 r34842 1 2008-06-27 Oliver Hunt <[email protected]> 2 3 Reviewed by Sam. 4 5 Bug 18626: SQUIRRELFISH: support the "slow script" dialog <https://bugs.webkit.org/show_bug.cgi?id=18626> 6 <rdar://problem/5973931> Slow script dialog needs to be reimplemented for squirrelfish 7 8 Adds support for the slow script dialog in squirrelfish. This requires the addition 9 of three new op codes, op_loop, op_loop_if_true, and op_loop_if_less which have the 10 same behaviour as their simple jump equivalents but have an additional time out check. 11 12 Additional assertions were added to other jump instructions to prevent accidentally 13 creating loops with jump types that do not support time out checks. 14 15 Sunspider does not report a regression, however this appears very sensitive to code 16 layout and hardware, so i would expect up to a 1% regression on other systems. 17 18 Part of this required moving the old timeout logic from JSGlobalObject and into Machine 19 which is the cause of a number of the larger diff blocks. 20 21 * JavaScriptCore.exp: 22 * VM/CodeBlock.cpp: 23 (KJS::CodeBlock::dump): 24 * VM/CodeGenerator.cpp: 25 (KJS::CodeGenerator::emitJumpIfTrue): 26 (KJS::CodeGenerator::emitJumpScopes): 27 * VM/ExceptionHelpers.cpp: 28 (KJS::InterruptedExecutionError::isWatchdogException): 29 (KJS::createInterruptedExecutionException): 30 * VM/ExceptionHelpers.h: 31 * VM/LabelID.h: 32 * VM/Machine.cpp: 33 (KJS::Machine::Machine): 34 (KJS::Machine::throwException): 35 (KJS::Machine::resetTimeoutCheck): 36 (KJS::getCurrentTime): 37 (KJS::Machine::checkTimeout): 38 (KJS::Machine::privateExecute): 39 * VM/Machine.h: 40 (KJS::Machine::setTimeoutTime): 41 (KJS::Machine::startTimeoutCheck): 42 (KJS::Machine::stopTimeoutCheck): 43 (KJS::Machine::initTimeout): 44 * VM/Opcode.cpp: 45 (KJS::): 46 * VM/Opcode.h: 47 * kjs/JSGlobalObject.cpp: 48 (KJS::JSGlobalObject::init): 49 (KJS::JSGlobalObject::setTimeoutTime): 50 (KJS::JSGlobalObject::startTimeoutCheck): 51 * kjs/JSGlobalObject.h: 52 * kjs/JSObject.h: 53 * kjs/interpreter.cpp: 54 (KJS::Interpreter::evaluate): 55 1 56 2008-06-27 Jan Michael Alonzo <[email protected]> 2 57 -
trunk/JavaScriptCore/JavaScriptCore.exp
r34838 r34842 116 116 __ZN3KJS14JSGlobalObject12defineGetterEPNS_9ExecStateERKNS_10IdentifierEPNS_8JSObjectE 117 117 __ZN3KJS14JSGlobalObject12defineSetterEPNS_9ExecStateERKNS_10IdentifierEPNS_8JSObjectE 118 __ZN3KJS14JSGlobalObject14setTimeoutTimeEj 118 119 __ZN3KJS14JSGlobalObject16stopTimeoutCheckEv 119 120 __ZN3KJS14JSGlobalObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierEPNS_7JSValueEj -
trunk/JavaScriptCore/VM/CodeBlock.cpp
r34684 r34842 463 463 break; 464 464 } 465 case op_loop: { 466 int offset = (++it)->u.operand; 467 printf("[%4d] loop\t\t %d(->%d)\n", location, offset, jumpTarget(begin, it, offset)); 468 break; 469 } 465 470 case op_jtrue: { 466 471 printConditionalJump(begin, it, location, "jtrue"); 467 472 break; 468 473 } 474 case op_loop_if_true: { 475 printConditionalJump(begin, it, location, "loop_if_true"); 476 break; 477 } 469 478 case op_jfalse: { 470 479 printConditionalJump(begin, it, location, "jfalse"); … … 476 485 int offset = (++it)->u.operand; 477 486 printf("[%4d] jless\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset)); 487 break; 488 } 489 case op_loop_if_less: { 490 int r0 = (++it)->u.operand; 491 int r1 = (++it)->u.operand; 492 int offset = (++it)->u.operand; 493 printf("[%4d] loop_if_less %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, jumpTarget(begin, it, offset)); 478 494 break; 479 495 } -
trunk/JavaScriptCore/VM/CodeGenerator.cpp
r34838 r34842 438 438 PassRefPtr<LabelID> CodeGenerator::emitJump(LabelID* target) 439 439 { 440 emitOpcode( op_jmp);440 emitOpcode(target->isForwardLabel() ? op_jmp : op_loop); 441 441 instructions().append(target->offsetFrom(instructions().size())); 442 442 return target; … … 454 454 if (cond->index() == dstIndex && !cond->refCount()) { 455 455 rewindBinaryOp(); 456 emitOpcode( op_jless);456 emitOpcode(target->isForwardLabel() ? op_jless : op_loop_if_less); 457 457 instructions().append(src1Index); 458 458 instructions().append(src2Index); … … 462 462 } 463 463 464 emitOpcode( op_jtrue);464 emitOpcode(target->isForwardLabel() ? op_jtrue : op_loop_if_true); 465 465 instructions().append(cond->index()); 466 466 instructions().append(target->offsetFrom(instructions().size())); … … 470 470 PassRefPtr<LabelID> CodeGenerator::emitJumpIfFalse(RegisterID* cond, LabelID* target) 471 471 { 472 ASSERT(target->isForwardLabel()); 472 473 emitOpcode(op_jfalse); 473 474 instructions().append(cond->index()); … … 1044 1045 { 1045 1046 ASSERT(scopeDepth() - targetScopeDepth >= 0); 1047 ASSERT(target->isForwardLabel()); 1046 1048 1047 1049 size_t scopeDelta = scopeDepth() - targetScopeDepth; -
trunk/JavaScriptCore/VM/ExceptionHelpers.cpp
r34581 r34842 44 44 newString.append(string.substr(position + 2)); 45 45 string = newString; 46 } 47 48 class InterruptedExecutionError : public JSObject { 49 public: 50 virtual bool isWatchdogException() const { return true; } 51 }; 52 53 JSValue* createInterruptedExecutionException(ExecState* exec) 54 { 55 return new (exec) InterruptedExecutionError; 46 56 } 47 57 -
trunk/JavaScriptCore/VM/ExceptionHelpers.h
r34581 r34842 36 36 class Node; 37 37 38 JSValue* createInterruptedExecutionException(ExecState* exec); 38 39 JSValue* createStackOverflowError(ExecState*); 39 40 JSValue* createUndefinedVariableError(ExecState*, const Identifier&); -
trunk/JavaScriptCore/VM/LabelID.h
r34781 r34842 99 99 } 100 100 101 bool isForwardLabel() const { return m_location == invalidLocation; } 102 101 103 private: 102 104 typedef Vector<int, 8> JumpVector; -
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) { -
trunk/JavaScriptCore/VM/Machine.h
r34838 r34842 43 43 class Instruction; 44 44 class JSFunction; 45 class JSGlobalObject; 45 46 class ProgramNode; 46 47 class Register; … … 97 98 98 99 void getFunctionAndArguments(Register** registerBase, Register* callFrame, JSFunction*&, Register*& argv, int& argc); 100 void setTimeoutTime(unsigned timeoutTime) { m_timeoutTime = timeoutTime; } 101 102 void startTimeoutCheck() 103 { 104 if (!m_timeoutCheckCount) 105 resetTimeoutCheck(); 106 107 ++m_timeoutCheckCount; 108 } 109 110 void stopTimeoutCheck() 111 { 112 --m_timeoutCheckCount; 113 } 99 114 115 inline void initTimeout() 116 { 117 resetTimeoutCheck(); 118 m_timeoutTime = 0; 119 m_timeoutCheckCount = 0; 120 } 100 121 void mark(Heap* heap) { m_registerFile.mark(heap); } 101 122 … … 119 140 void dumpRegisters(const CodeBlock*, RegisterFile*, const Register*); 120 141 142 JSValue* checkTimeout(JSGlobalObject*); 143 void resetTimeoutCheck(); 144 121 145 int m_reentryDepth; 146 unsigned m_timeoutTime; 147 unsigned m_timeAtLastCheckTimeout; 148 unsigned m_timeExecuting; 149 unsigned m_timeoutCheckCount; 150 unsigned m_ticksUntilNextTimeoutCheck; 151 122 152 RegisterFile m_registerFile; 123 153 -
trunk/JavaScriptCore/VM/Opcode.cpp
r34527 r34842 106 106 "jless ", 107 107 "jmp_scopes ", 108 "loop ", 109 "loop_if_true", 110 "loop_if_less", 108 111 109 112 "new_func ", -
trunk/JavaScriptCore/VM/Opcode.h
r34781 r34842 98 98 macro(op_jless) \ 99 99 macro(op_jmp_scopes) \ 100 macro(op_loop) \ 101 macro(op_loop_if_true) \ 102 macro(op_loop_if_less) \ 100 103 \ 101 104 macro(op_new_func) \ -
trunk/JavaScriptCore/kjs/JSGlobalObject.cpp
r34839 r34842 46 46 #include "string_object.h" 47 47 48 #if HAVE(SYS_TIME_H)49 #include <sys/time.h>50 #endif51 52 #if PLATFORM(WIN_OS)53 #include <windows.h>54 #endif55 56 #if PLATFORM(QT)57 #include <QDateTime>58 #endif59 60 48 namespace KJS { 61 49 … … 70 58 if (v && !v->marked()) 71 59 v->mark(); 72 }73 74 // Returns the current time in milliseconds75 // It doesn't matter what "current time" is here, just as long as76 // it's possible to measure the time difference correctly.77 static inline unsigned getCurrentTime()78 {79 #if HAVE(SYS_TIME_H)80 struct timeval tv;81 gettimeofday(&tv, 0);82 return tv.tv_sec * 1000 + tv.tv_usec / 1000;83 #elif PLATFORM(QT)84 QDateTime t = QDateTime::currentDateTime();85 return t.toTime_t() * 1000 + t.time().msec();86 #elif PLATFORM(WIN_OS)87 return timeGetTime();88 #else89 #error Platform does not have getCurrentTime function90 #endif91 60 } 92 61 … … 132 101 headObject = d()->next = d()->prev = this; 133 102 134 resetTimeoutCheck();135 d()->timeoutTime = 0;136 d()->timeoutCheckCount = 0;137 138 103 d()->recursion = 0; 139 104 d()->debugger = 0; 140 105 globalData()->machine->initTimeout(); 106 141 107 d()->globalExec.set(new ExecState(this, thisValue, d()->globalScopeChain.node())); 142 108 … … 347 313 } 348 314 315 void JSGlobalObject::setTimeoutTime(unsigned timeoutTime) 316 { 317 globalData()->machine->setTimeoutTime(timeoutTime); 318 } 319 349 320 void JSGlobalObject::startTimeoutCheck() 350 321 { 351 if (!d()->timeoutCheckCount) 352 resetTimeoutCheck(); 353 354 ++d()->timeoutCheckCount; 322 globalData()->machine->startTimeoutCheck(); 355 323 } 356 324 357 325 void JSGlobalObject::stopTimeoutCheck() 358 326 { 359 --d()->timeoutCheckCount; 360 } 361 362 void JSGlobalObject::resetTimeoutCheck() 363 { 364 d()->tickCount = 0; 365 d()->ticksUntilNextTimeoutCheck = initialTickCountThreshold; 366 d()->timeAtLastCheckTimeout = 0; 367 d()->timeExecuting = 0; 368 } 369 370 bool JSGlobalObject::checkTimeout() 371 { 372 d()->tickCount = 0; 373 374 unsigned currentTime = getCurrentTime(); 375 376 if (!d()->timeAtLastCheckTimeout) { 377 // Suspicious amount of looping in a script -- start timing it 378 d()->timeAtLastCheckTimeout = currentTime; 379 return false; 380 } 381 382 unsigned timeDiff = currentTime - d()->timeAtLastCheckTimeout; 383 384 if (timeDiff == 0) 385 timeDiff = 1; 386 387 d()->timeExecuting += timeDiff; 388 d()->timeAtLastCheckTimeout = currentTime; 389 390 // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in 391 // preferredScriptCheckTimeInterval 392 d()->ticksUntilNextTimeoutCheck = (unsigned)((float)preferredScriptCheckTimeInterval / timeDiff) * d()->ticksUntilNextTimeoutCheck; 393 394 // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the 395 // preferred script check time interval. 396 if (d()->ticksUntilNextTimeoutCheck == 0) 397 d()->ticksUntilNextTimeoutCheck = initialTickCountThreshold; 398 399 if (d()->timeoutTime && d()->timeExecuting > d()->timeoutTime) { 400 if (shouldInterruptScript()) 401 return true; 402 403 resetTimeoutCheck(); 404 } 405 406 return false; 327 globalData()->machine->stopTimeoutCheck(); 407 328 } 408 329 -
trunk/JavaScriptCore/kjs/JSGlobalObject.h
r34838 r34842 90 90 int recursion; 91 91 92 unsigned timeoutTime;93 unsigned timeAtLastCheckTimeout;94 unsigned timeExecuting;95 unsigned timeoutCheckCount;96 unsigned tickCount;97 unsigned ticksUntilNextTimeoutCheck;98 99 92 RegExpConstructor* regExpConstructor; 100 93 ErrorConstructor* errorConstructor; … … 203 196 unsigned pageGroupIdentifier() const { return d()->pageGroupIdentifier; } 204 197 205 void setTimeoutTime(unsigned timeoutTime) { d()->timeoutTime = timeoutTime; }198 void setTimeoutTime(unsigned timeoutTime); 206 199 void startTimeoutCheck(); 207 200 void stopTimeoutCheck(); 208 bool timedOut();209 201 210 202 Debugger* debugger() const { return d()->debugger; } … … 263 255 void addStaticGlobals(GlobalPropertyInfo*, int count); 264 256 265 private:266 bool checkTimeout();267 void resetTimeoutCheck();268 257 }; 269 258 … … 299 288 } 300 289 301 inline bool JSGlobalObject::timedOut()302 {303 d()->tickCount++;304 305 if (d()->tickCount != d()->ticksUntilNextTimeoutCheck)306 return false;307 308 return checkTimeout();309 }310 311 290 inline JSGlobalObject* ScopeChainNode::globalObject() const 312 291 { -
trunk/JavaScriptCore/kjs/JSObject.h
r34821 r34842 379 379 virtual bool isVariableObject() const { return false; } 380 380 381 virtual bool isWatchdogException() const { return false; } 382 381 383 protected: 382 384 PropertyMap _prop; -
trunk/JavaScriptCore/kjs/interpreter.cpp
r34838 r34842 82 82 JSValue* result = exec->machine()->execute(programNode.get(), exec, scopeChain.node(), thisObj, &exception); 83 83 84 return exception ? Completion(Throw, exception) : Completion(Normal, result); 84 if (exception) { 85 if (exception->isObject() && static_cast<JSObject*>(exception)->isWatchdogException()) 86 return Completion(Interrupted, result); 87 return Completion(Throw, exception); 88 } 89 return Completion(Normal, result); 85 90 } 86 91
Note:
See TracChangeset
for help on using the changeset viewer.