diff options
author | Feng Qian <> | 2009-04-10 18:11:29 -0700 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-04-10 18:11:29 -0700 |
commit | 8f72e70a9fd78eec56623b3a62e68f16b7b27e28 (patch) | |
tree | 181bf9a400c30a1bf34ea6d72560e8d00111d549 /JavaScriptCore/runtime | |
parent | 7ed56f225e0ade046e1c2178977f72b2d896f196 (diff) | |
download | external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.zip external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.tar.gz external_webkit-8f72e70a9fd78eec56623b3a62e68f16b7b27e28.tar.bz2 |
AI 145796: Land the WebKit merge @r42026.
Automated import of CL 145796
Diffstat (limited to 'JavaScriptCore/runtime')
27 files changed, 672 insertions, 141 deletions
diff --git a/JavaScriptCore/runtime/Arguments.cpp b/JavaScriptCore/runtime/Arguments.cpp index b0429a9..ea4b4f0 100644 --- a/JavaScriptCore/runtime/Arguments.cpp +++ b/JavaScriptCore/runtime/Arguments.cpp @@ -71,6 +71,13 @@ void Arguments::mark() void Arguments::fillArgList(ExecState* exec, ArgList& args) { + if (UNLIKELY(d->overrodeLength)) { + unsigned length = get(exec, exec->propertyNames().length).toUInt32(exec); + for (unsigned i = 0; i < length; i++) + args.append(get(exec, i)); + return; + } + if (LIKELY(!d->deletedArguments)) { if (LIKELY(!d->numParameters)) { args.initialize(d->extraArguments, d->numArguments); diff --git a/JavaScriptCore/runtime/ArrayPrototype.cpp b/JavaScriptCore/runtime/ArrayPrototype.cpp index 4cd229a..654386b 100644 --- a/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -26,6 +26,7 @@ #include "CodeBlock.h" #include "Interpreter.h" +#include "JIT.h" #include "ObjectPrototype.h" #include "Lookup.h" #include "Operations.h" @@ -67,8 +68,16 @@ static inline bool isNumericCompareFunction(CallType callType, const CallData& c { if (callType != CallTypeJS) return false; - - return callData.js.functionBody->bytecode(callData.js.scopeChain).isNumericCompareFunction(); + + CodeBlock& codeBlock = callData.js.functionBody->bytecode(callData.js.scopeChain); +#if ENABLE(JIT) + // If the JIT is enabled then we need to preserve the invariant that every + // function with a CodeBlock also has JIT code. + if (!codeBlock.jitCode()) + JIT::compile(callData.js.scopeChain->globalData, &codeBlock); +#endif + + return codeBlock.isNumericCompareFunction(); } // ------------------------------ ArrayPrototype ---------------------------- @@ -278,10 +287,10 @@ JSValuePtr arrayProtoFuncConcat(ExecState* exec, JSObject*, JSValuePtr thisValue ArgList::const_iterator end = args.end(); while (1) { if (curArg.isObject(&JSArray::info)) { - JSArray* curArray = asArray(curArg); - unsigned length = curArray->length(); + unsigned length = curArg.get(exec, exec->propertyNames().length).toUInt32(exec); + JSObject* curObject = curArg.toObject(exec); for (unsigned k = 0; k < length; ++k) { - if (JSValuePtr v = getProperty(exec, curArray, k)) + if (JSValuePtr v = getProperty(exec, curObject, k)) arr->put(exec, n, v); n++; } @@ -300,7 +309,7 @@ JSValuePtr arrayProtoFuncConcat(ExecState* exec, JSObject*, JSValuePtr thisValue JSValuePtr arrayProtoFuncPop(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList&) { - if (exec->interpreter()->isJSArray(thisValue)) + if (isJSArray(&exec->globalData(), thisValue)) return asArray(thisValue)->pop(); JSObject* thisObj = thisValue.toThisObject(exec); @@ -319,7 +328,7 @@ JSValuePtr arrayProtoFuncPop(ExecState* exec, JSObject*, JSValuePtr thisValue, c JSValuePtr arrayProtoFuncPush(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args) { - if (exec->interpreter()->isJSArray(thisValue) && args.size() == 1) { + if (isJSArray(&exec->globalData(), thisValue) && args.size() == 1) { JSArray* array = asArray(thisValue); array->push(exec, args.begin()->jsValue(exec)); return jsNumber(exec, array->length()); diff --git a/JavaScriptCore/runtime/Collector.cpp b/JavaScriptCore/runtime/Collector.cpp index 13e7f51..a4fea7d 100644 --- a/JavaScriptCore/runtime/Collector.cpp +++ b/JavaScriptCore/runtime/Collector.cpp @@ -349,6 +349,9 @@ collect: // didn't find a block, and GC didn't reclaim anything, need to allocate a new block size_t numBlocks = heap.numBlocks; if (usedBlocks == numBlocks) { + static const size_t maxNumBlocks = ULONG_MAX / sizeof(CollectorBlock*) / GROWTH_FACTOR; + if (numBlocks > maxNumBlocks) + CRASH(); numBlocks = max(MIN_ARRAY_SIZE, numBlocks * GROWTH_FACTOR); heap.numBlocks = numBlocks; heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, numBlocks * sizeof(CollectorBlock*))); diff --git a/JavaScriptCore/runtime/Completion.cpp b/JavaScriptCore/runtime/Completion.cpp index 0231a15..5655fa5 100644 --- a/JavaScriptCore/runtime/Completion.cpp +++ b/JavaScriptCore/runtime/Completion.cpp @@ -68,7 +68,7 @@ Completion evaluate(ExecState* exec, ScopeChain& scopeChain, const SourceCode& s if (exception) { if (exception.isObject() && asObject(exception)->isWatchdogException()) - return Completion(Interrupted, result); + return Completion(Interrupted, exception); return Completion(Throw, exception); } return Completion(Normal, result); diff --git a/JavaScriptCore/runtime/DateMath.cpp b/JavaScriptCore/runtime/DateMath.cpp index b452963..356d7a1 100644 --- a/JavaScriptCore/runtime/DateMath.cpp +++ b/JavaScriptCore/runtime/DateMath.cpp @@ -919,14 +919,14 @@ UString formatTime(const GregorianDateTime &t, bool utc) snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.hour, t.minute, t.second); } else { int offset = abs(gmtoffset(t)); - char tzname[70]; + char timeZoneName[70]; struct tm gtm = t; - strftime(tzname, sizeof(tzname), "%Z", >m); + strftime(timeZoneName, sizeof(timeZoneName), "%Z", >m); - if (tzname[0]) { + if (timeZoneName[0]) { snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d (%s)", t.hour, t.minute, t.second, - gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, tzname); + gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, timeZoneName); } else { snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d", t.hour, t.minute, t.second, diff --git a/JavaScriptCore/runtime/DatePrototype.cpp b/JavaScriptCore/runtime/DatePrototype.cpp index b325070..fad1d55 100644 --- a/JavaScriptCore/runtime/DatePrototype.cpp +++ b/JavaScriptCore/runtime/DatePrototype.cpp @@ -27,6 +27,11 @@ #include "ObjectPrototype.h" #include "DateInstance.h" #include <float.h> + +#if !PLATFORM(MAC) && HAVE(LANGINFO_H) +#include <langinfo.h> +#endif + #include <limits.h> #include <locale.h> #include <math.h> @@ -181,7 +186,11 @@ static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMil static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format) { +#if HAVE(LANGINFO_H) + static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT }; +#else static const char* const formatStrings[] = { "%#c", "%#x", "%X" }; +#endif // Offset year if needed struct tm localTM = gdt; @@ -190,10 +199,26 @@ static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, L if (yearNeedsOffset) localTM.tm_year = equivalentYearForDST(year) - 1900; +#if HAVE(LANGINFO_H) + // We do not allow strftime to generate dates with 2-digits years, + // both to avoid ambiguity, and a crash in strncpy, for years that + // need offset. + char* formatString = strdup(nl_langinfo(formats[format])); + char* yPos = strchr(formatString, 'y'); + if (yPos) + *yPos = 'Y'; +#endif + // Do the formatting const int bufsize = 128; char timebuffer[bufsize]; + +#if HAVE(LANGINFO_H) + size_t ret = strftime(timebuffer, bufsize, formatString, &localTM); + free(formatString); +#else size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM); +#endif if (ret == 0) return jsEmptyString(exec); diff --git a/JavaScriptCore/runtime/ExceptionHelpers.cpp b/JavaScriptCore/runtime/ExceptionHelpers.cpp index d1b5aac..30f1503 100644 --- a/JavaScriptCore/runtime/ExceptionHelpers.cpp +++ b/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -47,6 +47,8 @@ public: } virtual bool isWatchdogException() const { return true; } + + virtual UString toString(ExecState*) const { return "JavaScript execution exceeded timeout."; } }; JSValuePtr createInterruptedExecutionException(JSGlobalData* globalData) diff --git a/JavaScriptCore/runtime/FunctionConstructor.cpp b/JavaScriptCore/runtime/FunctionConstructor.cpp index d58334a..ff77b9d 100644 --- a/JavaScriptCore/runtime/FunctionConstructor.cpp +++ b/JavaScriptCore/runtime/FunctionConstructor.cpp @@ -93,16 +93,19 @@ FunctionBodyNode* extractFunctionBody(ProgramNode* program) // ECMA 15.3.2 The Function Constructor JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber) { + // Functions need to have a space following the opening { due to for web compatibility + // see https://bugs.webkit.org/show_bug.cgi?id=24350 + // We also need \n before the closing } to handle // comments at the end of the last line UString program; if (args.isEmpty()) - program = "(function(){})"; + program = "(function() { \n})"; else if (args.size() == 1) - program = "(function(){" + args.at(exec, 0).toString(exec) + "})"; + program = "(function() { " + args.at(exec, 0).toString(exec) + "\n})"; else { program = "(function(" + args.at(exec, 0).toString(exec); for (size_t i = 1; i < args.size() - 1; i++) program += "," + args.at(exec, i).toString(exec); - program += "){" + args.at(exec, args.size() - 1).toString(exec) + "})"; + program += ") { " + args.at(exec, args.size() - 1).toString(exec) + "\n})"; } int errLine; diff --git a/JavaScriptCore/runtime/FunctionPrototype.cpp b/JavaScriptCore/runtime/FunctionPrototype.cpp index 7be2685..01fc57c 100644 --- a/JavaScriptCore/runtime/FunctionPrototype.cpp +++ b/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -26,6 +26,7 @@ #include "JSFunction.h" #include "JSString.h" #include "Interpreter.h" +#include "Lexer.h" #include "PrototypeFunction.h" namespace JSC { @@ -63,11 +64,29 @@ CallType FunctionPrototype::getCallData(CallData& callData) // Functions +// Compatibility hack for the Optimost JavaScript library. (See <rdar://problem/6595040>.) +static inline void insertSemicolonIfNeeded(UString& functionBody) +{ + ASSERT(functionBody[0] == '{'); + ASSERT(functionBody[functionBody.size() - 1] == '}'); + + for (size_t i = functionBody.size() - 2; i > 0; --i) { + UChar ch = functionBody[i]; + if (!Lexer::isWhiteSpace(ch) && !Lexer::isLineTerminator(ch)) { + if (ch != ';' && ch != '}') + functionBody = functionBody.substr(0, i + 1) + ";" + functionBody.substr(i + 1, functionBody.size() - (i + 1)); + return; + } + } +} + JSValuePtr functionProtoFuncToString(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList&) { if (thisValue.isObject(&JSFunction::info)) { JSFunction* function = asFunction(thisValue); - return jsString(exec, "function " + function->name(&exec->globalData()) + "(" + function->body()->paramString() + ") " + function->body()->toSourceString()); + UString functionBody = function->body()->toSourceString(); + insertSemicolonIfNeeded(functionBody); + return jsString(exec, "function " + function->name(&exec->globalData()) + "(" + function->body()->paramString() + ") " + functionBody); } if (thisValue.isObject(&InternalFunction::info)) { @@ -85,32 +104,25 @@ JSValuePtr functionProtoFuncApply(ExecState* exec, JSObject*, JSValuePtr thisVal if (callType == CallTypeNone) return throwError(exec, TypeError); - JSValuePtr thisArg = args.at(exec, 0); - JSValuePtr argArray = args.at(exec, 1); - - JSValuePtr applyThis; - if (thisArg.isUndefinedOrNull()) - applyThis = exec->globalThisValue(); - else - applyThis = thisArg.toObject(exec); + JSValuePtr array = args.at(exec, 1); ArgList applyArgs; - if (!argArray.isUndefinedOrNull()) { - if (!argArray.isObject()) + if (!array.isUndefinedOrNull()) { + if (!array.isObject()) return throwError(exec, TypeError); - if (asObject(argArray)->classInfo() == &Arguments::info) - asArguments(argArray)->fillArgList(exec, applyArgs); - else if (exec->interpreter()->isJSArray(argArray)) - asArray(argArray)->fillArgList(exec, applyArgs); - else if (asObject(argArray)->inherits(&JSArray::info)) { - unsigned length = asArray(argArray)->get(exec, exec->propertyNames().length).toUInt32(exec); + if (asObject(array)->classInfo() == &Arguments::info) + asArguments(array)->fillArgList(exec, applyArgs); + else if (isJSArray(&exec->globalData(), array)) + asArray(array)->fillArgList(exec, applyArgs); + else if (asObject(array)->inherits(&JSArray::info)) { + unsigned length = asArray(array)->get(exec, exec->propertyNames().length).toUInt32(exec); for (unsigned i = 0; i < length; ++i) - applyArgs.append(asArray(argArray)->get(exec, i)); + applyArgs.append(asArray(array)->get(exec, i)); } else return throwError(exec, TypeError); } - return call(exec, thisValue, callType, callData, applyThis, applyArgs); + return call(exec, thisValue, callType, callData, args.at(exec, 0), applyArgs); } JSValuePtr functionProtoFuncCall(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args) @@ -120,17 +132,9 @@ JSValuePtr functionProtoFuncCall(ExecState* exec, JSObject*, JSValuePtr thisValu if (callType == CallTypeNone) return throwError(exec, TypeError); - JSValuePtr thisArg = args.at(exec, 0); - - JSObject* callThis; - if (thisArg.isUndefinedOrNull()) - callThis = exec->globalThisValue(); - else - callThis = thisArg.toObject(exec); - - ArgList argsTail; - args.getSlice(1, argsTail); - return call(exec, thisValue, callType, callData, callThis, argsTail); + ArgList callArgs; + args.getSlice(1, callArgs); + return call(exec, thisValue, callType, callData, args.at(exec, 0), callArgs); } } // namespace JSC diff --git a/JavaScriptCore/runtime/JSArray.h b/JavaScriptCore/runtime/JSArray.h index 7eecf33..f873f13 100644 --- a/JavaScriptCore/runtime/JSArray.h +++ b/JavaScriptCore/runtime/JSArray.h @@ -122,6 +122,8 @@ namespace JSC { return static_cast<JSArray*>(asObject(value)); } + inline bool isJSArray(JSGlobalData* globalData, JSValuePtr v) { return v.isCell() && v.asCell()->vptr() == globalData->jsArrayVPtr; } + } // namespace JSC #endif // JSArray_h diff --git a/JavaScriptCore/runtime/JSByteArray.h b/JavaScriptCore/runtime/JSByteArray.h index 19c8f0e..eb8e0ac 100644 --- a/JavaScriptCore/runtime/JSByteArray.h +++ b/JavaScriptCore/runtime/JSByteArray.h @@ -33,7 +33,7 @@ namespace JSC { class JSByteArray : public JSObject { - friend class Interpreter; + friend class VPtrSet; public: bool canAccessIndex(unsigned i) { return i < m_storage->length(); } JSValuePtr getIndex(ExecState* exec, unsigned i) @@ -88,6 +88,8 @@ namespace JSC { size_t length() const { return m_storage->length(); } + WTF::ByteArray* storage() const { return m_storage.get(); } + private: enum VPtrStealingHackType { VPtrStealingHack }; JSByteArray(VPtrStealingHackType) @@ -105,6 +107,9 @@ namespace JSC { { return static_cast<JSByteArray*>(asCell(value)); } -} -#endif + inline bool isJSByteArray(JSGlobalData* globalData, JSValuePtr v) { return v.isCell() && v.asCell()->vptr() == globalData->jsByteArrayVPtr; } + +} // namespace JSC + +#endif // JSByteArray_h diff --git a/JavaScriptCore/runtime/JSCell.h b/JavaScriptCore/runtime/JSCell.h index 43d81a5..1973c54 100644 --- a/JavaScriptCore/runtime/JSCell.h +++ b/JavaScriptCore/runtime/JSCell.h @@ -32,15 +32,15 @@ namespace JSC { class JSCell : Noncopyable { - friend class JIT; friend class GetterSetter; friend class Heap; + friend class JIT; friend class JSNumberCell; friend class JSObject; friend class JSPropertyNameIterator; friend class JSString; friend class JSValuePtr; - friend class Interpreter; + friend class VPtrSet; private: explicit JSCell(Structure*); diff --git a/JavaScriptCore/runtime/JSFunction.h b/JavaScriptCore/runtime/JSFunction.h index 6a43737..87ca2a2 100644 --- a/JavaScriptCore/runtime/JSFunction.h +++ b/JavaScriptCore/runtime/JSFunction.h @@ -39,7 +39,8 @@ namespace JSC { class JSFunction : public InternalFunction { friend class JIT; - friend class Interpreter; + friend class JITStubs; + friend class VPtrSet; typedef InternalFunction Base; diff --git a/JavaScriptCore/runtime/JSGlobalData.cpp b/JavaScriptCore/runtime/JSGlobalData.cpp index 10b584d..3a2f7c0 100644 --- a/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/JavaScriptCore/runtime/JSGlobalData.cpp @@ -35,6 +35,8 @@ #include "FunctionConstructor.h" #include "Interpreter.h" #include "JSActivation.h" +#include "JSArray.h" +#include "JSByteArray.h" #include "JSClassRef.h" #include "JSLock.h" #include "JSNotAnObject.h" @@ -64,10 +66,42 @@ extern const HashTable regExpTable; extern const HashTable regExpConstructorTable; extern const HashTable stringTable; -JSGlobalData::JSGlobalData(bool isShared) - : initializingLazyNumericCompareFunction(false) - , interpreter(new Interpreter) - , exception(noValue()) +struct VPtrSet { + VPtrSet(); + + void* jsArrayVPtr; + void* jsByteArrayVPtr; + void* jsStringVPtr; + void* jsFunctionVPtr; +}; + +VPtrSet::VPtrSet() +{ + // Bizarrely, calling fastMalloc here is faster than allocating space on the stack. + void* storage = fastMalloc(sizeof(CollectorBlock)); + + JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull())); + jsArrayVPtr = jsArray->vptr(); + jsArray->~JSCell(); + + JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack); + jsByteArrayVPtr = jsByteArray->vptr(); + jsByteArray->~JSCell(); + + JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack); + jsStringVPtr = jsString->vptr(); + jsString->~JSCell(); + + JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull())); + jsFunctionVPtr = jsFunction->vptr(); + jsFunction->~JSCell(); + + fastFree(storage); +} + +JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet) + : isSharedInstance(isShared) + , clientData(0) , arrayTable(new HashTable(JSC::arrayTable)) , dateTable(new HashTable(JSC::dateTable)) , mathTable(new HashTable(JSC::mathTable)) @@ -84,24 +118,31 @@ JSGlobalData::JSGlobalData(bool isShared) #if !USE(ALTERNATE_JSIMMEDIATE) , numberStructure(JSNumberCell::createStructure(jsNull())) #endif + , jsArrayVPtr(vptrSet.jsArrayVPtr) + , jsByteArrayVPtr(vptrSet.jsByteArrayVPtr) + , jsStringVPtr(vptrSet.jsStringVPtr) + , jsFunctionVPtr(vptrSet.jsFunctionVPtr) , identifierTable(createIdentifierTable()) , propertyNames(new CommonIdentifiers(this)) , emptyList(new ArgList) - , newParserObjects(0) - , parserObjectExtraRefCounts(0) , lexer(new Lexer(this)) , parser(new Parser) + , interpreter(new Interpreter) +#if ENABLE(JIT) + , jitStubs(this) +#endif + , heap(this) + , exception(noValue()) + , initializingLazyNumericCompareFunction(false) + , newParserObjects(0) + , parserObjectExtraRefCounts(0) , head(0) , dynamicGlobalObject(0) - , isSharedInstance(isShared) - , clientData(0) , scopeNodeBeingReparsed(0) - , heap(this) { #if PLATFORM(MAC) startProfilerServerIfNeeded(); #endif - interpreter->initialize(this); } JSGlobalData::~JSGlobalData() @@ -145,9 +186,9 @@ JSGlobalData::~JSGlobalData() delete clientData; } -PassRefPtr<JSGlobalData> JSGlobalData::create() +PassRefPtr<JSGlobalData> JSGlobalData::create(bool isShared) { - return adoptRef(new JSGlobalData); + return adoptRef(new JSGlobalData(isShared, VPtrSet())); } PassRefPtr<JSGlobalData> JSGlobalData::createLeaked() @@ -171,7 +212,7 @@ JSGlobalData& JSGlobalData::sharedInstance() { JSGlobalData*& instance = sharedInstanceInternal(); if (!instance) { - instance = new JSGlobalData(true); + instance = create(true).releaseRef(); #if ENABLE(JSC_MULTIPLE_THREADS) instance->makeUsableFromMultipleThreads(); #endif diff --git a/JavaScriptCore/runtime/JSGlobalData.h b/JavaScriptCore/runtime/JSGlobalData.h index 4223191..1936f1f 100644 --- a/JavaScriptCore/runtime/JSGlobalData.h +++ b/JavaScriptCore/runtime/JSGlobalData.h @@ -29,13 +29,15 @@ #ifndef JSGlobalData_h #define JSGlobalData_h -#include <wtf/Forward.h> -#include <wtf/HashMap.h> -#include <wtf/RefCounted.h> #include "Collector.h" #include "ExecutableAllocator.h" -#include "SmallStrings.h" +#include "JITStubs.h" #include "JSValue.h" +#include "SmallStrings.h" +#include "TimeoutChecker.h" +#include <wtf/Forward.h> +#include <wtf/HashMap.h> +#include <wtf/RefCounted.h> struct OpaqueJSClass; struct OpaqueJSClassContextData; @@ -57,13 +59,18 @@ namespace JSC { class Structure; class UString; struct HashTable; + struct VPtrSet; class JSGlobalData : public RefCounted<JSGlobalData> { public: + struct ClientData { + virtual ~ClientData() = 0; + }; + static bool sharedInstanceExists(); static JSGlobalData& sharedInstance(); - static PassRefPtr<JSGlobalData> create(); + static PassRefPtr<JSGlobalData> create(bool isShared = false); static PassRefPtr<JSGlobalData> createLeaked(); ~JSGlobalData(); @@ -72,16 +79,8 @@ namespace JSC { void makeUsableFromMultipleThreads() { heap.makeUsableFromMultipleThreads(); } #endif - const Vector<Instruction>& numericCompareFunction(ExecState*); - Vector<Instruction> lazyNumericCompareFunction; - bool initializingLazyNumericCompareFunction; - - Interpreter* interpreter; - - JSValuePtr exception; -#if ENABLE(JIT) - void* exceptionLocation; -#endif + bool isSharedInstance; + ClientData* clientData; const HashTable* arrayTable; const HashTable* dateTable; @@ -101,48 +100,54 @@ namespace JSC { RefPtr<Structure> numberStructure; #endif + void* jsArrayVPtr; + void* jsByteArrayVPtr; + void* jsStringVPtr; + void* jsFunctionVPtr; + IdentifierTable* identifierTable; CommonIdentifiers* propertyNames; const ArgList* emptyList; // Lists are supposed to be allocated on the stack to have their elements properly marked, which is not the case here - but this list has nothing to mark. - SmallStrings smallStrings; - - HashMap<OpaqueJSClass*, OpaqueJSClassContextData*> opaqueJSClassData; - HashSet<ParserRefCounted*>* newParserObjects; - HashCountedSet<ParserRefCounted*>* parserObjectExtraRefCounts; +#if ENABLE(ASSEMBLER) + ExecutableAllocator executableAllocator; +#endif Lexer* lexer; Parser* parser; + Interpreter* interpreter; +#if ENABLE(JIT) + JITStubs jitStubs; +#endif + TimeoutChecker timeoutChecker; + Heap heap; - JSGlobalObject* head; - JSGlobalObject* dynamicGlobalObject; + JSValuePtr exception; +#if ENABLE(JIT) + void* exceptionLocation; +#endif - bool isSharedInstance; + const Vector<Instruction>& numericCompareFunction(ExecState*); + Vector<Instruction> lazyNumericCompareFunction; + bool initializingLazyNumericCompareFunction; - struct ClientData { - virtual ~ClientData() = 0; - }; + HashMap<OpaqueJSClass*, OpaqueJSClassContextData*> opaqueJSClassData; - ClientData* clientData; + HashSet<ParserRefCounted*>* newParserObjects; + HashCountedSet<ParserRefCounted*>* parserObjectExtraRefCounts; + + JSGlobalObject* head; + JSGlobalObject* dynamicGlobalObject; HashSet<JSObject*> arrayVisitedElements; ScopeNode* scopeNodeBeingReparsed; - Heap heap; -#if ENABLE(ASSEMBLER) - PassRefPtr<ExecutablePool> poolForSize(size_t n) { return m_executableAllocator.poolForSize(n); } -#endif private: - JSGlobalData(bool isShared = false); -#if ENABLE(ASSEMBLER) - ExecutableAllocator m_executableAllocator; -#endif - + JSGlobalData(bool isShared, const VPtrSet&); static JSGlobalData*& sharedInstanceInternal(); }; +} // namespace JSC -} - -#endif +#endif // JSGlobalData_h diff --git a/JavaScriptCore/runtime/JSGlobalObject.cpp b/JavaScriptCore/runtime/JSGlobalObject.cpp index eb2b349..d6ad295 100644 --- a/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -341,22 +341,11 @@ void JSGlobalObject::reset(JSValuePtr prototype) void JSGlobalObject::resetPrototype(JSValuePtr prototype) { setPrototype(prototype); - lastInPrototypeChain(this)->setPrototype(d()->objectPrototype); -} - -void JSGlobalObject::setTimeoutTime(unsigned timeoutTime) -{ - globalData()->interpreter->setTimeoutTime(timeoutTime); -} -void JSGlobalObject::startTimeoutCheck() -{ - globalData()->interpreter->startTimeoutCheck(); -} - -void JSGlobalObject::stopTimeoutCheck() -{ - globalData()->interpreter->stopTimeoutCheck(); + JSObject* oldLastInPrototypeChain = lastInPrototypeChain(this); + JSObject* objectPrototype = d()->objectPrototype; + if (oldLastInPrototypeChain != objectPrototype) + oldLastInPrototypeChain->setPrototype(objectPrototype); } void JSGlobalObject::mark() diff --git a/JavaScriptCore/runtime/JSGlobalObject.h b/JavaScriptCore/runtime/JSGlobalObject.h index 4a10f64..da8b7bf 100644 --- a/JavaScriptCore/runtime/JSGlobalObject.h +++ b/JavaScriptCore/runtime/JSGlobalObject.h @@ -214,10 +214,6 @@ namespace JSC { void setProfileGroup(unsigned value) { d()->profileGroup = value; } unsigned profileGroup() const { return d()->profileGroup; } - void setTimeoutTime(unsigned timeoutTime); - void startTimeoutCheck(); - void stopTimeoutCheck(); - Debugger* debugger() const { return d()->debugger; } void setDebugger(Debugger* debugger) { d()->debugger = debugger; } diff --git a/JavaScriptCore/runtime/JSImmediate.cpp b/JavaScriptCore/runtime/JSImmediate.cpp index c6cca80..a407ec3 100644 --- a/JavaScriptCore/runtime/JSImmediate.cpp +++ b/JavaScriptCore/runtime/JSImmediate.cpp @@ -39,12 +39,8 @@ JSObject* JSImmediate::toThisObject(JSValuePtr v, ExecState* exec) return constructNumber(exec, v); if (isBoolean(v)) return constructBooleanFromImmediateBoolean(exec, v); - if (v.isNull()) - return exec->globalThisValue(); - - JSNotAnObjectErrorStub* exception = createNotAnObjectErrorStub(exec, v.isNull()); - exec->setException(exception); - return new (exec) JSNotAnObject(exec, exception); + ASSERT(v.isUndefinedOrNull()); + return exec->globalThisValue(); } JSObject* JSImmediate::toObject(JSValuePtr v, ExecState* exec) diff --git a/JavaScriptCore/runtime/JSString.h b/JavaScriptCore/runtime/JSString.h index e4baa73..7398d50 100644 --- a/JavaScriptCore/runtime/JSString.h +++ b/JavaScriptCore/runtime/JSString.h @@ -60,7 +60,7 @@ namespace JSC { class JSString : public JSCell { friend class JIT; - friend class Interpreter; + friend class VPtrSet; public: JSString(JSGlobalData* globalData, const UString& value) @@ -202,6 +202,8 @@ namespace JSC { return false; } + inline bool isJSString(JSGlobalData* globalData, JSValuePtr v) { return v.isCell() && v.asCell()->vptr() == globalData->jsStringVPtr; } + // --- JSValue inlines ---------------------------- inline JSString* JSValuePtr::toThisJSString(ExecState* exec) diff --git a/JavaScriptCore/runtime/NumberConstructor.cpp b/JavaScriptCore/runtime/NumberConstructor.cpp index caa4a70..8bd424d 100644 --- a/JavaScriptCore/runtime/NumberConstructor.cpp +++ b/JavaScriptCore/runtime/NumberConstructor.cpp @@ -68,27 +68,27 @@ bool NumberConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& pr return getStaticValueSlot<NumberConstructor, InternalFunction>(exec, ExecState::numberTable(exec), this, propertyName, slot); } -JSValuePtr numberConstructorNaNValue(ExecState* exec, const Identifier&, const PropertySlot&) +static JSValuePtr numberConstructorNaNValue(ExecState* exec, const Identifier&, const PropertySlot&) { return jsNaN(exec); } -JSValuePtr numberConstructorNegInfinity(ExecState* exec, const Identifier&, const PropertySlot&) +static JSValuePtr numberConstructorNegInfinity(ExecState* exec, const Identifier&, const PropertySlot&) { return jsNumber(exec, -Inf); } -JSValuePtr numberConstructorPosInfinity(ExecState* exec, const Identifier&, const PropertySlot&) +static JSValuePtr numberConstructorPosInfinity(ExecState* exec, const Identifier&, const PropertySlot&) { return jsNumber(exec, Inf); } -JSValuePtr numberConstructorMaxValue(ExecState* exec, const Identifier&, const PropertySlot&) +static JSValuePtr numberConstructorMaxValue(ExecState* exec, const Identifier&, const PropertySlot&) { return jsNumber(exec, 1.7976931348623157E+308); } -JSValuePtr numberConstructorMinValue(ExecState* exec, const Identifier&, const PropertySlot&) +static JSValuePtr numberConstructorMinValue(ExecState* exec, const Identifier&, const PropertySlot&) { return jsNumber(exec, 5E-324); } diff --git a/JavaScriptCore/runtime/Operations.cpp b/JavaScriptCore/runtime/Operations.cpp index 550d3f6..fe516fe 100644 --- a/JavaScriptCore/runtime/Operations.cpp +++ b/JavaScriptCore/runtime/Operations.cpp @@ -52,4 +52,70 @@ NEVER_INLINE JSValuePtr throwOutOfMemoryError(ExecState* exec) return error; } +NEVER_INLINE JSValuePtr jsAddSlowCase(CallFrame* callFrame, JSValuePtr v1, JSValuePtr v2) +{ + // exception for the Date exception in defaultValue() + JSValuePtr p1 = v1.toPrimitive(callFrame); + JSValuePtr p2 = v2.toPrimitive(callFrame); + + if (p1.isString() || p2.isString()) { + RefPtr<UString::Rep> value = concatenate(p1.toString(callFrame).rep(), p2.toString(callFrame).rep()); + if (!value) + return throwOutOfMemoryError(callFrame); + return jsString(callFrame, value.release()); + } + + return jsNumber(callFrame, p1.toNumber(callFrame) + p2.toNumber(callFrame)); +} + +JSValuePtr jsTypeStringForValue(CallFrame* callFrame, JSValuePtr v) +{ + if (v.isUndefined()) + return jsNontrivialString(callFrame, "undefined"); + if (v.isBoolean()) + return jsNontrivialString(callFrame, "boolean"); + if (v.isNumber()) + return jsNontrivialString(callFrame, "number"); + if (v.isString()) + return jsNontrivialString(callFrame, "string"); + if (v.isObject()) { + // Return "undefined" for objects that should be treated + // as null when doing comparisons. + if (asObject(v)->structure()->typeInfo().masqueradesAsUndefined()) + return jsNontrivialString(callFrame, "undefined"); + CallData callData; + if (asObject(v)->getCallData(callData) != CallTypeNone) + return jsNontrivialString(callFrame, "function"); + } + return jsNontrivialString(callFrame, "object"); +} + +bool jsIsObjectType(JSValuePtr v) +{ + if (!v.isCell()) + return v.isNull(); + + JSType type = asCell(v)->structure()->typeInfo().type(); + if (type == NumberType || type == StringType) + return false; + if (type == ObjectType) { + if (asObject(v)->structure()->typeInfo().masqueradesAsUndefined()) + return false; + CallData callData; + if (asObject(v)->getCallData(callData) != CallTypeNone) + return false; + } + return true; +} + +bool jsIsFunctionType(JSValuePtr v) +{ + if (v.isObject()) { + CallData callData; + if (asObject(v)->getCallData(callData) != CallTypeNone) + return true; + } + return false; +} + } // namespace JSC diff --git a/JavaScriptCore/runtime/Operations.h b/JavaScriptCore/runtime/Operations.h index c6a7e7a..85dee99 100644 --- a/JavaScriptCore/runtime/Operations.h +++ b/JavaScriptCore/runtime/Operations.h @@ -22,12 +22,19 @@ #ifndef Operations_h #define Operations_h +#include "Interpreter.h" #include "JSImmediate.h" #include "JSNumberCell.h" #include "JSString.h" namespace JSC { + NEVER_INLINE JSValuePtr throwOutOfMemoryError(ExecState*); + NEVER_INLINE JSValuePtr jsAddSlowCase(CallFrame*, JSValuePtr, JSValuePtr); + JSValuePtr jsTypeStringForValue(CallFrame*, JSValuePtr); + bool jsIsObjectType(JSValuePtr); + bool jsIsFunctionType(JSValuePtr); + // ECMA 11.9.3 inline bool JSValuePtr::equal(ExecState* exec, JSValuePtr v1, JSValuePtr v2) { @@ -129,7 +136,147 @@ namespace JSC { return v1 == v2; } - JSValuePtr throwOutOfMemoryError(ExecState*); + inline bool jsLess(CallFrame* callFrame, JSValuePtr v1, JSValuePtr v2) + { + if (JSValuePtr::areBothInt32Fast(v1, v2)) + return v1.getInt32Fast() < v2.getInt32Fast(); + + double n1; + double n2; + if (v1.getNumber(n1) && v2.getNumber(n2)) + return n1 < n2; + + JSGlobalData* globalData = &callFrame->globalData(); + if (isJSString(globalData, v1) && isJSString(globalData, v2)) + return asString(v1)->value() < asString(v2)->value(); + + JSValuePtr p1; + JSValuePtr p2; + bool wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1); + bool wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2); + + if (wasNotString1 | wasNotString2) + return n1 < n2; + + return asString(p1)->value() < asString(p2)->value(); + } + + inline bool jsLessEq(CallFrame* callFrame, JSValuePtr v1, JSValuePtr v2) + { + if (JSValuePtr::areBothInt32Fast(v1, v2)) + return v1.getInt32Fast() <= v2.getInt32Fast(); + + double n1; + double n2; + if (v1.getNumber(n1) && v2.getNumber(n2)) + return n1 <= n2; + + JSGlobalData* globalData = &callFrame->globalData(); + if (isJSString(globalData, v1) && isJSString(globalData, v2)) + return !(asString(v2)->value() < asString(v1)->value()); + + JSValuePtr p1; + JSValuePtr p2; + bool wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1); + bool wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2); + + if (wasNotString1 | wasNotString2) + return n1 <= n2; + + return !(asString(p2)->value() < asString(p1)->value()); + } + + // Fast-path choices here are based on frequency data from SunSpider: + // <times> Add case: <t1> <t2> + // --------------------------- + // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values) + // 247412 Add case: 5 5 + // 20900 Add case: 5 6 + // 13962 Add case: 5 3 + // 4000 Add case: 3 5 + + ALWAYS_INLINE JSValuePtr jsAdd(CallFrame* callFrame, JSValuePtr v1, JSValuePtr v2) + { + double left; + double right = 0.0; + + bool rightIsNumber = v2.getNumber(right); + if (rightIsNumber && v1.getNumber(left)) + return jsNumber(callFrame, left + right); + + bool leftIsString = v1.isString(); + if (leftIsString && v2.isString()) { + RefPtr<UString::Rep> value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep()); + if (!value) + return throwOutOfMemoryError(callFrame); + return jsString(callFrame, value.release()); + } + + if (rightIsNumber & leftIsString) { + RefPtr<UString::Rep> value = v2.isInt32Fast() ? + concatenate(asString(v1)->value().rep(), v2.getInt32Fast()) : + concatenate(asString(v1)->value().rep(), right); + + if (!value) + return throwOutOfMemoryError(callFrame); + return jsString(callFrame, value.release()); + } + + // All other cases are pretty uncommon + return jsAddSlowCase(callFrame, v1, v2); + } + + inline size_t countPrototypeChainEntriesAndCheckForProxies(CallFrame* callFrame, JSValuePtr baseValue, const PropertySlot& slot) + { + JSCell* cell = asCell(baseValue); + size_t count = 0; + + while (slot.slotBase() != cell) { + JSValuePtr v = cell->structure()->prototypeForLookup(callFrame); + + // If we didn't find slotBase in baseValue's prototype chain, then baseValue + // must be a proxy for another object. + + if (v.isNull()) + return 0; + + cell = asCell(v); + + // Since we're accessing a prototype in a loop, it's a good bet that it + // should not be treated as a dictionary. + if (cell->structure()->isDictionary()) + asObject(cell)->setStructure(Structure::fromDictionaryTransition(cell->structure())); + + ++count; + } + + ASSERT(count); + return count; + } + + ALWAYS_INLINE JSValuePtr resolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain) + { + ScopeChainIterator iter = scopeChain->begin(); + ScopeChainIterator next = iter; + ++next; + ScopeChainIterator end = scopeChain->end(); + ASSERT(iter != end); + + PropertySlot slot; + JSObject* base; + while (true) { + base = *iter; + if (next == end || base->getPropertySlot(callFrame, property, slot)) + return base; + + iter = next; + ++next; + } + + ASSERT_NOT_REACHED(); + return noValue(); + } + +} // namespace JSC -} -#endif +#endif // Operations_h diff --git a/JavaScriptCore/runtime/RegExp.cpp b/JavaScriptCore/runtime/RegExp.cpp index b8251d2..5d05f11 100644 --- a/JavaScriptCore/runtime/RegExp.cpp +++ b/JavaScriptCore/runtime/RegExp.cpp @@ -123,6 +123,7 @@ int RegExp::match(const UString& s, int startOffset, OwnArrayPtr<int>* ovector) if (m_wrecFunction) { int offsetVectorSize = (m_numSubpatterns + 1) * 2; int* offsetVector = new int [offsetVectorSize]; + ASSERT(offsetVector); for (int j = 0; j < offsetVectorSize; ++j) offsetVector[j] = -1; diff --git a/JavaScriptCore/runtime/Structure.cpp b/JavaScriptCore/runtime/Structure.cpp index 86ee76c..f702221 100644 --- a/JavaScriptCore/runtime/Structure.cpp +++ b/JavaScriptCore/runtime/Structure.cpp @@ -65,15 +65,15 @@ static const unsigned newTableSize = 16; static WTF::RefCountedLeakCounter structureCounter("Structure"); #if ENABLE(JSC_MULTIPLE_THREADS) -static Mutex ignoreSetMutex; +static Mutex& ignoreSetMutex = *(new Mutex); #endif static bool shouldIgnoreLeaks; -static HashSet<Structure*> ignoreSet; +static HashSet<Structure*>& ignoreSet = *(new HashSet<Structure*>); #endif #if DUMP_STRUCTURE_ID_STATISTICS -static HashSet<Structure*> liveStructureSet; +static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>); #endif void Structure::dumpStatistics() diff --git a/JavaScriptCore/runtime/TimeoutChecker.cpp b/JavaScriptCore/runtime/TimeoutChecker.cpp new file mode 100644 index 0000000..30ba6e9 --- /dev/null +++ b/JavaScriptCore/runtime/TimeoutChecker.cpp @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "TimeoutChecker.h" + +#include "CallFrame.h" +#include "JSGlobalObject.h" + +#if PLATFORM(DARWIN) +#include <mach/mach.h> +#endif + +#if HAVE(SYS_TIME_H) +#include <sys/time.h> +#endif + +#if PLATFORM(WIN_OS) +#include <windows.h> +#endif + +#if PLATFORM(QT) +#include <QDateTime> +#endif + +using namespace std; + +namespace JSC { + +// Number of ticks before the first timeout check is done. +static const int ticksUntilFirstCheck = 1024; + +// Number of milliseconds between each timeout check. +static const int intervalBetweenChecks = 1000; + +// Returns the time the current thread has spent executing, in milliseconds. +static inline unsigned getCPUTime() +{ +#if PLATFORM(DARWIN) + mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT; + thread_basic_info_data_t info; + + // Get thread information + mach_port_t threadPort = mach_thread_self(); + thread_info(threadPort, THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount); + mach_port_deallocate(mach_task_self(), threadPort); + + unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000; + time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000; + + return time; +#elif HAVE(SYS_TIME_H) + // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag. + struct timeval tv; + gettimeofday(&tv, 0); + return tv.tv_sec * 1000 + tv.tv_usec / 1000; +#elif PLATFORM(QT) + QDateTime t = QDateTime::currentDateTime(); + return t.toTime_t() * 1000 + t.time().msec(); +#elif PLATFORM(WIN_OS) + union { + FILETIME fileTime; + unsigned long long fileTimeAsLong; + } userTime, kernelTime; + + // GetThreadTimes won't accept NULL arguments so we pass these even though + // they're not used. + FILETIME creationTime, exitTime; + + GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime); + + return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000; +#else +#error Platform does not have getCurrentTime function +#endif +} + +TimeoutChecker::TimeoutChecker() + : m_timeoutInterval(0) + , m_startCount(0) +{ + reset(); +} + +void TimeoutChecker::reset() +{ + m_ticksUntilNextCheck = ticksUntilFirstCheck; + m_timeAtLastCheck = 0; + m_timeExecuting = 0; +} + +bool TimeoutChecker::didTimeOut(ExecState* exec) +{ + unsigned currentTime = getCPUTime(); + + if (!m_timeAtLastCheck) { + // Suspicious amount of looping in a script -- start timing it + m_timeAtLastCheck = currentTime; + return false; + } + + unsigned timeDiff = currentTime - m_timeAtLastCheck; + + if (timeDiff == 0) + timeDiff = 1; + + m_timeExecuting += timeDiff; + m_timeAtLastCheck = currentTime; + + // Adjust the tick threshold so we get the next checkTimeout call in the + // interval specified in intervalBetweenChecks. + m_ticksUntilNextCheck = static_cast<unsigned>((static_cast<float>(intervalBetweenChecks) / timeDiff) * m_ticksUntilNextCheck); + // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the + // preferred script check time interval. + if (m_ticksUntilNextCheck == 0) + m_ticksUntilNextCheck = ticksUntilFirstCheck; + + if (m_timeoutInterval && m_timeExecuting > m_timeoutInterval) { + if (exec->dynamicGlobalObject()->shouldInterruptScript()) + return true; + + reset(); + } + + return false; +} + +} // namespace JSC diff --git a/JavaScriptCore/runtime/TimeoutChecker.h b/JavaScriptCore/runtime/TimeoutChecker.h new file mode 100644 index 0000000..7bfa6d0 --- /dev/null +++ b/JavaScriptCore/runtime/TimeoutChecker.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef TimeoutChecker_h +#define TimeoutChecker_h + +#include <wtf/Assertions.h> + +namespace JSC { + + class ExecState; + + class TimeoutChecker { + public: + TimeoutChecker(); + + void setTimeoutInterval(unsigned timeoutInterval) { m_timeoutInterval = timeoutInterval; } + + unsigned ticksUntilNextCheck() { return m_ticksUntilNextCheck; } + + void start() + { + if (!m_startCount) + reset(); + ++m_startCount; + } + + void stop() + { + ASSERT(m_startCount); + --m_startCount; + } + + void reset(); + + bool didTimeOut(ExecState*); + + private: + unsigned m_timeoutInterval; + unsigned m_timeAtLastCheck; + unsigned m_timeExecuting; + unsigned m_startCount; + unsigned m_ticksUntilNextCheck; + }; + +} // namespace JSC + +#endif // TimeoutChecker_h diff --git a/JavaScriptCore/runtime/UString.cpp b/JavaScriptCore/runtime/UString.cpp index 8cb12cf..024d6a1 100644 --- a/JavaScriptCore/runtime/UString.cpp +++ b/JavaScriptCore/runtime/UString.cpp @@ -93,7 +93,7 @@ static inline void copyChars(UChar* destination, const UChar* source, unsigned n memcpy(destination, source, numCharacters * sizeof(UChar)); } -COMPILE_ASSERT(sizeof(UChar) == 2, uchar_is_2_bytes) +COMPILE_ASSERT(sizeof(UChar) == 2, uchar_is_2_bytes); CString::CString(const char* c) : m_length(strlen(c)) |