summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/runtime
diff options
context:
space:
mode:
authorFeng Qian <>2009-04-10 18:11:29 -0700
committerThe Android Open Source Project <initial-contribution@android.com>2009-04-10 18:11:29 -0700
commit8f72e70a9fd78eec56623b3a62e68f16b7b27e28 (patch)
tree181bf9a400c30a1bf34ea6d72560e8d00111d549 /JavaScriptCore/runtime
parent7ed56f225e0ade046e1c2178977f72b2d896f196 (diff)
downloadexternal_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')
-rw-r--r--JavaScriptCore/runtime/Arguments.cpp7
-rw-r--r--JavaScriptCore/runtime/ArrayPrototype.cpp23
-rw-r--r--JavaScriptCore/runtime/Collector.cpp3
-rw-r--r--JavaScriptCore/runtime/Completion.cpp2
-rw-r--r--JavaScriptCore/runtime/DateMath.cpp8
-rw-r--r--JavaScriptCore/runtime/DatePrototype.cpp25
-rw-r--r--JavaScriptCore/runtime/ExceptionHelpers.cpp2
-rw-r--r--JavaScriptCore/runtime/FunctionConstructor.cpp9
-rw-r--r--JavaScriptCore/runtime/FunctionPrototype.cpp64
-rw-r--r--JavaScriptCore/runtime/JSArray.h2
-rw-r--r--JavaScriptCore/runtime/JSByteArray.h11
-rw-r--r--JavaScriptCore/runtime/JSCell.h4
-rw-r--r--JavaScriptCore/runtime/JSFunction.h3
-rw-r--r--JavaScriptCore/runtime/JSGlobalData.cpp67
-rw-r--r--JavaScriptCore/runtime/JSGlobalData.h83
-rw-r--r--JavaScriptCore/runtime/JSGlobalObject.cpp19
-rw-r--r--JavaScriptCore/runtime/JSGlobalObject.h4
-rw-r--r--JavaScriptCore/runtime/JSImmediate.cpp8
-rw-r--r--JavaScriptCore/runtime/JSString.h4
-rw-r--r--JavaScriptCore/runtime/NumberConstructor.cpp10
-rw-r--r--JavaScriptCore/runtime/Operations.cpp66
-rw-r--r--JavaScriptCore/runtime/Operations.h153
-rw-r--r--JavaScriptCore/runtime/RegExp.cpp1
-rw-r--r--JavaScriptCore/runtime/Structure.cpp6
-rw-r--r--JavaScriptCore/runtime/TimeoutChecker.cpp154
-rw-r--r--JavaScriptCore/runtime/TimeoutChecker.h73
-rw-r--r--JavaScriptCore/runtime/UString.cpp2
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", &gtm);
+ strftime(timeZoneName, sizeof(timeZoneName), "%Z", &gtm);
- 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))