summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime')
-rw-r--r--Source/JavaScriptCore/runtime/Arguments.cpp31
-rw-r--r--Source/JavaScriptCore/runtime/Arguments.h2
-rw-r--r--Source/JavaScriptCore/runtime/ArrayPrototype.cpp116
-rw-r--r--Source/JavaScriptCore/runtime/ClassInfo.h3
-rw-r--r--Source/JavaScriptCore/runtime/CommonIdentifiers.h3
-rw-r--r--Source/JavaScriptCore/runtime/CommonSlowPaths.h2
-rw-r--r--Source/JavaScriptCore/runtime/DateConstructor.cpp6
-rw-r--r--Source/JavaScriptCore/runtime/Error.cpp37
-rw-r--r--Source/JavaScriptCore/runtime/Error.h5
-rw-r--r--Source/JavaScriptCore/runtime/Executable.cpp8
-rw-r--r--Source/JavaScriptCore/runtime/Executable.h13
-rw-r--r--Source/JavaScriptCore/runtime/FunctionPrototype.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/GCActivityCallback.cpp10
-rw-r--r--Source/JavaScriptCore/runtime/GCActivityCallback.h16
-rw-r--r--Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp62
-rw-r--r--Source/JavaScriptCore/runtime/Identifier.cpp10
-rw-r--r--Source/JavaScriptCore/runtime/Identifier.h10
-rw-r--r--Source/JavaScriptCore/runtime/InitializeThreading.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/Intrinsic.h2
-rw-r--r--Source/JavaScriptCore/runtime/JSActivation.cpp15
-rw-r--r--Source/JavaScriptCore/runtime/JSActivation.h19
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.cpp79
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.h36
-rw-r--r--Source/JavaScriptCore/runtime/JSBoundFunction.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/JSByteArray.cpp120
-rw-r--r--Source/JavaScriptCore/runtime/JSByteArray.h133
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.h20
-rw-r--r--Source/JavaScriptCore/runtime/JSDateMath.cpp13
-rw-r--r--Source/JavaScriptCore/runtime/JSDateMath.h27
-rw-r--r--Source/JavaScriptCore/runtime/JSFunction.cpp106
-rw-r--r--Source/JavaScriptCore/runtime/JSFunction.h11
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.cpp124
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.h29
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.cpp5
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.h6
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp41
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalThis.cpp7
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalThis.h5
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp20
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.h53
-rw-r--r--Source/JavaScriptCore/runtime/JSPropertyNameIterator.h2
-rw-r--r--Source/JavaScriptCore/runtime/JSString.cpp35
-rw-r--r--Source/JavaScriptCore/runtime/JSString.h298
-rw-r--r--Source/JavaScriptCore/runtime/JSStringJoiner.cpp126
-rw-r--r--Source/JavaScriptCore/runtime/JSStringJoiner.h78
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.cpp18
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.h4
-rw-r--r--Source/JavaScriptCore/runtime/LiteralParser.cpp12
-rw-r--r--Source/JavaScriptCore/runtime/Lookup.cpp10
-rw-r--r--Source/JavaScriptCore/runtime/MatchResult.h71
-rw-r--r--Source/JavaScriptCore/runtime/NumberPrototype.cpp87
-rw-r--r--Source/JavaScriptCore/runtime/NumericStrings.h8
-rw-r--r--Source/JavaScriptCore/runtime/ObjectPrototype.cpp12
-rw-r--r--Source/JavaScriptCore/runtime/Operations.cpp15
-rw-r--r--Source/JavaScriptCore/runtime/Operations.h8
-rw-r--r--Source/JavaScriptCore/runtime/Options.cpp6
-rw-r--r--Source/JavaScriptCore/runtime/Options.h1
-rw-r--r--Source/JavaScriptCore/runtime/PropertyNameArray.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/RegExp.cpp169
-rw-r--r--Source/JavaScriptCore/runtime/RegExp.h22
-rw-r--r--Source/JavaScriptCore/runtime/RegExpCache.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/RegExpCachedResult.cpp62
-rw-r--r--Source/JavaScriptCore/runtime/RegExpCachedResult.h86
-rw-r--r--Source/JavaScriptCore/runtime/RegExpConstructor.cpp138
-rw-r--r--Source/JavaScriptCore/runtime/RegExpConstructor.h106
-rw-r--r--Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp105
-rw-r--r--Source/JavaScriptCore/runtime/RegExpMatchesArray.h88
-rw-r--r--Source/JavaScriptCore/runtime/RegExpObject.cpp44
-rw-r--r--Source/JavaScriptCore/runtime/RegExpObject.h6
-rw-r--r--Source/JavaScriptCore/runtime/RegExpPrototype.cpp4
-rw-r--r--Source/JavaScriptCore/runtime/SmallStrings.cpp35
-rw-r--r--Source/JavaScriptCore/runtime/SmallStrings.h29
-rw-r--r--Source/JavaScriptCore/runtime/StringPrototype.cpp283
-rw-r--r--Source/JavaScriptCore/runtime/StringRecursionChecker.h2
-rw-r--r--Source/JavaScriptCore/runtime/Structure.cpp17
-rw-r--r--Source/JavaScriptCore/runtime/Structure.h14
-rw-r--r--Source/JavaScriptCore/runtime/StructureTransitionTable.h35
-rw-r--r--Source/JavaScriptCore/runtime/TimeoutChecker.cpp2
-rw-r--r--Source/JavaScriptCore/runtime/UString.h6
-rw-r--r--Source/JavaScriptCore/runtime/WeakGCMap.h74
81 files changed, 1916 insertions, 1421 deletions
diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp
index 7a53ec1a4..9a3d7257b 100644
--- a/Source/JavaScriptCore/runtime/Arguments.cpp
+++ b/Source/JavaScriptCore/runtime/Arguments.cpp
@@ -306,6 +306,10 @@ bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, const Ident
bool isArrayIndex;
unsigned i = propertyName.toArrayIndex(isArrayIndex);
if (isArrayIndex && i < thisObject->d->numArguments) {
+ // If the property is not yet present on the object, and is not yet marked as deleted, then add it now.
+ PropertySlot slot;
+ if ((!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i]) && !JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot))
+ object->putDirect(exec->globalData(), propertyName, thisObject->argument(i).get(), 0);
if (!Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow))
return false;
@@ -331,35 +335,16 @@ bool Arguments::defineOwnProperty(JSObject* object, ExecState* exec, const Ident
thisObject->d->deletedArguments[i] = true;
}
}
-
return true;
}
if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
+ thisObject->putDirect(exec->globalData(), propertyName, jsNumber(thisObject->d->numArguments), DontEnum);
thisObject->d->overrodeLength = true;
- if (!descriptor.isAccessorDescriptor()) {
- if (!descriptor.value())
- descriptor.setValue(jsNumber(thisObject->d->numArguments));
- if (!descriptor.configurablePresent())
- descriptor.setConfigurable(true);
- }
- if (!descriptor.configurablePresent())
- descriptor.setConfigurable(true);
- }
-
- if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) {
+ } else if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) {
+ thisObject->putDirect(exec->globalData(), propertyName, thisObject->d->callee.get(), DontEnum);
thisObject->d->overrodeCallee = true;
- if (!descriptor.isAccessorDescriptor()) {
- if (!descriptor.value())
- descriptor.setValue(thisObject->d->callee.get());
- if (!descriptor.configurablePresent())
- descriptor.setConfigurable(true);
- }
- if (!descriptor.configurablePresent())
- descriptor.setConfigurable(true);
- }
-
- if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
+ } else if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
thisObject->createStrictModeCallerIfNecessary(exec);
return Base::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h
index 8e7af1844..a1f36de56 100644
--- a/Source/JavaScriptCore/runtime/Arguments.h
+++ b/Source/JavaScriptCore/runtime/Arguments.h
@@ -158,7 +158,7 @@ namespace JSC {
Base::finishCreation(callFrame->globalData());
ASSERT(inherits(&s_info));
- JSFunction* callee = asFunction(callFrame->callee());
+ JSFunction* callee = jsCast<JSFunction*>(callFrame->callee());
d->numArguments = callFrame->argumentCount();
d->registers = reinterpret_cast<WriteBarrier<Unknown>*>(callFrame->registers());
d->callee.set(callFrame->globalData(), this, callee);
diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
index 2f000fc74..6df58b773 100644
--- a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
@@ -29,6 +29,7 @@
#include "Interpreter.h"
#include "JIT.h"
#include "JSStringBuilder.h"
+#include "JSStringJoiner.h"
#include "Lookup.h"
#include "ObjectPrototype.h"
#include "Operations.h"
@@ -254,9 +255,27 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec)
{
JSValue thisValue = exec->hostThisValue();
- bool isRealArray = isJSArray(thisValue);
- if (!isRealArray && !thisValue.inherits(&JSArray::s_info))
- return throwVMTypeError(exec);
+ // 1. Let array be the result of calling ToObject on the this value.
+ JSObject* thisObject = thisValue.toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // 2. Let func be the result of calling the [[Get]] internal method of array with argument "join".
+ JSValue function = JSValue(thisObject).get(exec, exec->propertyNames().join);
+
+ // 3. If IsCallable(func) is false, then let func be the standard built-in method Object.prototype.toString (15.2.4.2).
+ if (!function.isCell())
+ return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]"));
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ if (callType == CallTypeNone)
+ return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]"));
+
+ // 4. Return the result of calling the [[Call]] internal method of func providing array as the this value and an empty arguments list.
+ if (!isJSArray(thisObject) || callType != CallTypeHost || callData.native.function != arrayProtoFuncJoin)
+ return JSValue::encode(call(exec, function, callType, callData, thisObject, exec->emptyList()));
+
+ ASSERT(isJSArray(thisValue));
JSArray* thisObj = asArray(thisValue);
unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
@@ -273,7 +292,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec)
for (unsigned k = 0; k < length; k++) {
JSValue element;
- if (isRealArray && thisObj->canGetIndex(k))
+ if (thisObj->canGetIndex(k))
element = thisObj->getIndex(k);
else
element = thisObj->get(exec, k);
@@ -281,7 +300,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec)
if (element.isUndefinedOrNull())
continue;
- UString str = element.toString(exec)->value(exec);
+ UString str = element.toUString(exec);
strBuffer[k] = str.impl();
totalSize += str.length();
allStrings8Bit = allStrings8Bit && str.is8Bit();
@@ -343,11 +362,9 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec)
if (JSValue earlyReturnValue = checker.earlyReturnValue())
return JSValue::encode(earlyReturnValue);
- JSStringBuilder strBuffer;
+ UString separator(",");
+ JSStringJoiner stringJoiner(separator, length);
for (unsigned k = 0; k < length; k++) {
- if (k >= 1)
- strBuffer.append(',');
-
JSValue element = thisObj->get(exec, k);
if (exec->hadException())
return JSValue::encode(jsUndefined());
@@ -360,16 +377,16 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec)
CallData callData;
CallType callType = getCallData(conversionFunction, callData);
if (callType != CallTypeNone)
- str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toString(exec)->value(exec);
+ str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toUString(exec);
else
- str = element.toString(exec)->value(exec);
+ str = element.toUString(exec);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- strBuffer.append(str);
+ stringJoiner.append(str);
}
}
- return JSValue::encode(strBuffer.build(exec));
+ return JSValue::encode(stringJoiner.build(exec));
}
EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
@@ -383,60 +400,39 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
if (JSValue earlyReturnValue = checker.earlyReturnValue())
return JSValue::encode(earlyReturnValue);
- JSStringBuilder strBuffer;
-
UString separator;
if (!exec->argument(0).isUndefined())
- separator = exec->argument(0).toString(exec)->value(exec);
+ separator = exec->argument(0).toUString(exec);
+ if (separator.isNull())
+ separator = UString(",");
+
+ JSStringJoiner stringJoiner(separator, length);
unsigned k = 0;
if (isJSArray(thisObj)) {
JSArray* array = asArray(thisObj);
- if (length) {
- if (!array->canGetIndex(k))
- goto skipFirstLoop;
+ for (; k < length; k++) {
+ if (!array->canGetIndex(k))
+ break;
+
JSValue element = array->getIndex(k);
if (!element.isUndefinedOrNull())
- strBuffer.append(element.toString(exec)->value(exec));
- k++;
- }
-
- if (separator.isNull()) {
- for (; k < length; k++) {
- if (!array->canGetIndex(k))
- break;
- strBuffer.append(',');
- JSValue element = array->getIndex(k);
- if (!element.isUndefinedOrNull())
- strBuffer.append(element.toString(exec)->value(exec));
- }
- } else {
- for (; k < length; k++) {
- if (!array->canGetIndex(k))
- break;
- strBuffer.append(separator);
- JSValue element = array->getIndex(k);
- if (!element.isUndefinedOrNull())
- strBuffer.append(element.toString(exec)->value(exec));
- }
- }
- }
- skipFirstLoop:
- for (; k < length; k++) {
- if (k >= 1) {
- if (separator.isNull())
- strBuffer.append(',');
+ stringJoiner.append(element.toUStringInline(exec));
else
- strBuffer.append(separator);
+ stringJoiner.append(UString());
}
+ }
+ for (; k < length; k++) {
JSValue element = thisObj->get(exec, k);
if (!element.isUndefinedOrNull())
- strBuffer.append(element.toString(exec)->value(exec));
+ stringJoiner.append(element.toUStringInline(exec));
+ else
+ stringJoiner.append(UString());
}
- return JSValue::encode(strBuffer.build(exec));
+ return JSValue::encode(stringJoiner.build(exec));
}
EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec)
@@ -524,7 +520,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
thisObj->methodTable()->putByIndex(thisObj, exec, length + n, exec->argument(n), true);
else {
PutPropertySlot slot;
- Identifier propertyName(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toString(exec)->value(exec));
+ Identifier propertyName(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toUString(exec));
thisObj->methodTable()->put(thisObj, exec, propertyName, exec->argument(n), slot);
}
if (exec->hadException())
@@ -665,7 +661,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
l.append(minObj);
compareResult = call(exec, function, callType, callData, jsUndefined(), l).toNumber(exec);
} else
- compareResult = (jObj.toString(exec)->value(exec) < minObj.toString(exec)->value(exec)) ? -1 : 1;
+ compareResult = (jObj.toUStringInline(exec) < minObj.toUStringInline(exec)) ? -1 : 1;
if (compareResult < 0) {
themin = j;
@@ -788,7 +784,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec)
unsigned filterIndex = 0;
unsigned k = 0;
if (callType == CallTypeJS && isJSArray(thisObj)) {
- JSFunction* f = asFunction(function);
+ JSFunction* f = jsCast<JSFunction*>(function);
JSArray* array = asArray(thisObj);
CachedCall cachedCall(exec, f, 3);
for (; k < length && !exec->hadException(); ++k) {
@@ -846,7 +842,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec)
JSArray* resultArray = constructEmptyArray(exec, length);
unsigned k = 0;
if (callType == CallTypeJS && isJSArray(thisObj)) {
- JSFunction* f = asFunction(function);
+ JSFunction* f = jsCast<JSFunction*>(function);
JSArray* array = asArray(thisObj);
CachedCall cachedCall(exec, f, 3);
for (; k < length && !exec->hadException(); ++k) {
@@ -909,7 +905,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec)
unsigned k = 0;
if (callType == CallTypeJS && isJSArray(thisObj)) {
- JSFunction* f = asFunction(function);
+ JSFunction* f = jsCast<JSFunction*>(function);
JSArray* array = asArray(thisObj);
CachedCall cachedCall(exec, f, 3);
for (; k < length && !exec->hadException(); ++k) {
@@ -965,7 +961,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec)
unsigned k = 0;
if (callType == CallTypeJS && isJSArray(thisObj)) {
- JSFunction* f = asFunction(function);
+ JSFunction* f = jsCast<JSFunction*>(function);
JSArray* array = asArray(thisObj);
CachedCall cachedCall(exec, f, 3);
for (; k < length && !exec->hadException(); ++k) {
@@ -1017,7 +1013,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec)
unsigned k = 0;
if (callType == CallTypeJS && isJSArray(thisObj)) {
- JSFunction* f = asFunction(function);
+ JSFunction* f = jsCast<JSFunction*>(function);
JSArray* array = asArray(thisObj);
CachedCall cachedCall(exec, f, 3);
for (; k < length && !exec->hadException(); ++k) {
@@ -1096,7 +1092,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec)
}
if (callType == CallTypeJS && array) {
- CachedCall cachedCall(exec, asFunction(function), 4);
+ CachedCall cachedCall(exec, jsCast<JSFunction*>(function), 4);
for (; i < length && !exec->hadException(); ++i) {
cachedCall.setThis(jsUndefined());
cachedCall.setArgument(0, rv);
@@ -1173,7 +1169,7 @@ EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec)
}
if (callType == CallTypeJS && array) {
- CachedCall cachedCall(exec, asFunction(function), 4);
+ CachedCall cachedCall(exec, jsCast<JSFunction*>(function), 4);
for (; i < length && !exec->hadException(); ++i) {
unsigned idx = length - i - 1;
cachedCall.setThis(jsUndefined());
diff --git a/Source/JavaScriptCore/runtime/ClassInfo.h b/Source/JavaScriptCore/runtime/ClassInfo.h
index 214258cc6..eb4a6f9cd 100644
--- a/Source/JavaScriptCore/runtime/ClassInfo.h
+++ b/Source/JavaScriptCore/runtime/ClassInfo.h
@@ -131,7 +131,6 @@ struct MemberCheck##member { \
&ClassName::defineOwnProperty, \
&ClassName::getOwnPropertyDescriptor, \
}, \
- sizeof(ClassName), \
ClassName::TypedArrayStorageType
struct ClassInfo {
@@ -180,8 +179,6 @@ struct MemberCheck##member { \
MethodTable methodTable;
- size_t cellSize;
-
TypedArrayType typedArrayStorageType;
};
diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.h b/Source/JavaScriptCore/runtime/CommonIdentifiers.h
index 0d9580197..e15335ef0 100644
--- a/Source/JavaScriptCore/runtime/CommonIdentifiers.h
+++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.h
@@ -73,10 +73,11 @@
macro(valueOf) \
macro(writable) \
macro(displayName) \
- macro(undefined)
+ macro(join)
#define JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(macro) \
macro(null) \
+ macro(undefined) \
macro(true) \
macro(false) \
macro(break) \
diff --git a/Source/JavaScriptCore/runtime/CommonSlowPaths.h b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
index 345af2ebe..c41ced7ee 100644
--- a/Source/JavaScriptCore/runtime/CommonSlowPaths.h
+++ b/Source/JavaScriptCore/runtime/CommonSlowPaths.h
@@ -44,7 +44,7 @@ namespace CommonSlowPaths {
ALWAYS_INLINE ExecState* arityCheckFor(ExecState* exec, RegisterFile* registerFile, CodeSpecializationKind kind)
{
- JSFunction* callee = asFunction(exec->callee());
+ JSFunction* callee = jsCast<JSFunction*>(exec->callee());
ASSERT(!callee->isHostFunction());
CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecodeFor(kind);
int argumentCountIncludingThis = exec->argumentCountIncludingThis();
diff --git a/Source/JavaScriptCore/runtime/DateConstructor.cpp b/Source/JavaScriptCore/runtime/DateConstructor.cpp
index 365172294..66f0baea5 100644
--- a/Source/JavaScriptCore/runtime/DateConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/DateConstructor.cpp
@@ -166,10 +166,8 @@ ConstructType DateConstructor::getConstructData(JSCell*, ConstructData& construc
// ECMA 15.9.2
static EncodedJSValue JSC_HOST_CALL callDate(ExecState* exec)
{
- time_t localTime = time(0);
- tm localTM;
- getLocalTime(&localTime, &localTM);
- GregorianDateTime ts(exec, localTM);
+ GregorianDateTime ts;
+ msToGregorianDateTime(exec, currentTimeMS(), false, ts);
DateConversionBuffer date;
DateConversionBuffer time;
formatDate(ts, date);
diff --git a/Source/JavaScriptCore/runtime/Error.cpp b/Source/JavaScriptCore/runtime/Error.cpp
index 5266c1ebe..bae07448b 100644
--- a/Source/JavaScriptCore/runtime/Error.cpp
+++ b/Source/JavaScriptCore/runtime/Error.cpp
@@ -79,6 +79,11 @@ JSObject* createTypeError(JSGlobalObject* globalObject, const UString& message)
return ErrorInstance::create(globalObject->globalData(), globalObject->typeErrorConstructor()->errorStructure(), message);
}
+JSObject* createNotEnoughArgumentsError(JSGlobalObject* globalObject)
+{
+ return createTypeError(globalObject, "Not enough arguments");
+}
+
JSObject* createURIError(JSGlobalObject* globalObject, const UString& message)
{
ASSERT(!message.isEmpty());
@@ -115,42 +120,31 @@ JSObject* createTypeError(ExecState* exec, const UString& message)
return createTypeError(exec->lexicalGlobalObject(), message);
}
+JSObject* createNotEnoughArgumentsError(ExecState* exec)
+{
+ return createNotEnoughArgumentsError(exec->lexicalGlobalObject());
+}
+
JSObject* createURIError(ExecState* exec, const UString& message)
{
return createURIError(exec->lexicalGlobalObject(), message);
}
-JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source, const Vector<StackFrame>& stackTrace)
+JSObject* addErrorInfo(CallFrame* callFrame, JSObject* error, int line, const SourceCode& source)
{
+ JSGlobalData* globalData = &callFrame->globalData();
const UString& sourceURL = source.provider()->url();
if (line != -1)
error->putDirect(*globalData, Identifier(globalData, linePropertyName), jsNumber(line), ReadOnly | DontDelete);
if (!sourceURL.isNull())
error->putDirect(*globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete);
- if (!stackTrace.isEmpty()) {
- JSGlobalObject* globalObject = 0;
- if (isTerminatedExecutionException(error) || isInterruptedExecutionException(error))
- globalObject = globalData->dynamicGlobalObject;
- else
- globalObject = error->globalObject();
- StringBuilder builder;
- for (unsigned i = 0; i < stackTrace.size(); i++) {
- builder.append(String(stackTrace[i].toString(globalObject->globalExec()).impl()));
- if (i != stackTrace.size() - 1)
- builder.append('\n');
- }
-
- error->putDirect(*globalData, globalData->propertyNames->stack, jsString(globalData, UString(builder.toString().impl())), ReadOnly | DontDelete);
- }
+
+ globalData->interpreter->addStackTraceIfNecessary(callFrame, error);
return error;
}
-JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source, const Vector<StackFrame>& stackTrace)
-{
- return addErrorInfo(&exec->globalData(), error, line, source, stackTrace);
-}
bool hasErrorInfo(ExecState* exec, JSObject* error)
{
@@ -160,12 +154,15 @@ bool hasErrorInfo(ExecState* exec, JSObject* error)
JSValue throwError(ExecState* exec, JSValue error)
{
+ if (error.isObject())
+ return throwError(exec, asObject(error));
exec->globalData().exception = error;
return error;
}
JSObject* throwError(ExecState* exec, JSObject* error)
{
+ Interpreter::addStackTraceIfNecessary(exec, error);
exec->globalData().exception = error;
return error;
}
diff --git a/Source/JavaScriptCore/runtime/Error.h b/Source/JavaScriptCore/runtime/Error.h
index 59b39495f..79617655e 100644
--- a/Source/JavaScriptCore/runtime/Error.h
+++ b/Source/JavaScriptCore/runtime/Error.h
@@ -45,6 +45,7 @@ namespace JSC {
JSObject* createReferenceError(JSGlobalObject*, const UString&);
JSObject* createSyntaxError(JSGlobalObject*, const UString&);
JSObject* createTypeError(JSGlobalObject*, const UString&);
+ JSObject* createNotEnoughArgumentsError(JSGlobalObject*);
JSObject* createURIError(JSGlobalObject*, const UString&);
// ExecState wrappers.
JS_EXPORT_PRIVATE JSObject* createError(ExecState*, const UString&);
@@ -53,13 +54,13 @@ namespace JSC {
JS_EXPORT_PRIVATE JSObject* createReferenceError(ExecState*, const UString&);
JS_EXPORT_PRIVATE JSObject* createSyntaxError(ExecState*, const UString&);
JS_EXPORT_PRIVATE JSObject* createTypeError(ExecState*, const UString&);
+ JS_EXPORT_PRIVATE JSObject* createNotEnoughArgumentsError(ExecState*);
JSObject* createURIError(ExecState*, const UString&);
// Methods to add
bool hasErrorInfo(ExecState*, JSObject* error);
- JSObject* addErrorInfo(JSGlobalData*, JSObject* error, int line, const SourceCode&, const Vector<StackFrame>&);
// ExecState wrappers.
- JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&, const Vector<StackFrame>&);
+ JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&);
// Methods to throw Errors.
JS_EXPORT_PRIVATE JSValue throwError(ExecState*, JSValue);
diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp
index ea40447e4..934533c46 100644
--- a/Source/JavaScriptCore/runtime/Executable.cpp
+++ b/Source/JavaScriptCore/runtime/Executable.cpp
@@ -146,6 +146,8 @@ FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, const Identifie
, m_name(name)
, m_inferredName(inferredName.isNull() ? globalData.propertyNames->emptyIdentifier : inferredName)
, m_symbolTable(0)
+ , m_next(0)
+ , m_prev(0)
{
}
@@ -157,6 +159,8 @@ FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name,
, m_name(name)
, m_inferredName(inferredName.isNull() ? exec->globalData().propertyNames->emptyIdentifier : inferredName)
, m_symbolTable(0)
+ , m_next(0)
+ , m_prev(0)
{
}
@@ -654,7 +658,9 @@ void FunctionExecutable::discardCode()
void FunctionExecutable::finalize(JSCell* cell)
{
- jsCast<FunctionExecutable*>(cell)->clearCode();
+ FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
+ Heap::heap(executable)->removeFunctionExecutable(executable);
+ executable->clearCode();
}
inline void FunctionExecutable::clearCode()
diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h
index 08b39fcf0..3b979ba82 100644
--- a/Source/JavaScriptCore/runtime/Executable.h
+++ b/Source/JavaScriptCore/runtime/Executable.h
@@ -463,9 +463,10 @@ namespace JSC {
OwnPtr<ProgramCodeBlock> m_programCodeBlock;
};
- class FunctionExecutable : public ScriptExecutable {
+ class FunctionExecutable : public ScriptExecutable, public DoublyLinkedListNode<FunctionExecutable> {
friend class JIT;
friend class LLIntOffsetsExtractor;
+ friend class WTF::DoublyLinkedListNode<FunctionExecutable>;
public:
typedef ScriptExecutable Base;
@@ -473,6 +474,7 @@ namespace JSC {
{
FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext);
executable->finishCreation(exec->globalData(), name, firstLine, lastLine);
+ exec->globalData().heap.addFunctionExecutable(executable);
exec->globalData().heap.addFinalizer(executable, &finalize);
return executable;
}
@@ -481,6 +483,7 @@ namespace JSC {
{
FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, inferredName, source, forceUsesArguments, parameters, isInStrictContext);
executable->finishCreation(globalData, name, firstLine, lastLine);
+ globalData.heap.addFunctionExecutable(executable);
globalData.heap.addFinalizer(executable, &finalize);
return executable;
}
@@ -567,7 +570,7 @@ namespace JSC {
{
ASSERT(exec->callee());
ASSERT(exec->callee()->inherits(&JSFunction::s_info));
- ASSERT(asFunction(exec->callee())->jsExecutable() == this);
+ ASSERT(jsCast<JSFunction*>(exec->callee())->jsExecutable() == this);
if (kind == CodeForCall)
return compileForCall(exec, scopeChainNode);
@@ -579,7 +582,7 @@ namespace JSC {
{
ASSERT(exec->callee());
ASSERT(exec->callee()->inherits(&JSFunction::s_info));
- ASSERT(asFunction(exec->callee())->jsExecutable() == this);
+ ASSERT(jsCast<JSFunction*>(exec->callee())->jsExecutable() == this);
if (kind == CodeForCall)
return compileOptimizedForCall(exec, scopeChainNode);
@@ -688,6 +691,8 @@ namespace JSC {
Identifier m_inferredName;
WriteBarrier<JSString> m_nameValue;
SharedSymbolTable* m_symbolTable;
+ FunctionExecutable* m_next;
+ FunctionExecutable* m_prev;
};
inline FunctionExecutable* JSFunction::jsExecutable() const
@@ -716,7 +721,7 @@ namespace JSC {
inline bool isHostFunction(JSValue value, NativeFunction nativeFunction)
{
- JSFunction* function = static_cast<JSFunction*>(getJSFunction(value));
+ JSFunction* function = jsCast<JSFunction*>(getJSFunction(value));
if (!function || !function->isHostFunction())
return false;
return function->nativeFunction() == nativeFunction;
diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
index 266ddc241..d341b847b 100644
--- a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
@@ -102,7 +102,7 @@ EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec)
{
JSValue thisValue = exec->hostThisValue();
if (thisValue.inherits(&JSFunction::s_info)) {
- JSFunction* function = asFunction(thisValue);
+ JSFunction* function = jsCast<JSFunction*>(thisValue);
if (function->isHostFunction())
return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}"));
FunctionExecutable* executable = function->jsExecutable();
diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp
index 308d245a9..6ec538f72 100644
--- a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp
+++ b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp
@@ -42,7 +42,11 @@ DefaultGCActivityCallback::~DefaultGCActivityCallback()
{
}
-void DefaultGCActivityCallback::operator()()
+void DefaultGCActivityCallback::didAllocate(size_t)
+{
+}
+
+void DefaultGCActivityCallback::willCollect()
{
}
@@ -50,5 +54,9 @@ void DefaultGCActivityCallback::synchronize()
{
}
+void DefaultGCActivityCallback::cancel()
+{
+}
+
}
diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.h b/Source/JavaScriptCore/runtime/GCActivityCallback.h
index f40ebee5b..1a18a8b45 100644
--- a/Source/JavaScriptCore/runtime/GCActivityCallback.h
+++ b/Source/JavaScriptCore/runtime/GCActivityCallback.h
@@ -42,9 +42,11 @@ class Heap;
class GCActivityCallback {
public:
- virtual ~GCActivityCallback() {}
- virtual void operator()() {}
- virtual void synchronize() {}
+ virtual ~GCActivityCallback() { }
+ virtual void didAllocate(size_t) { }
+ virtual void willCollect() { }
+ virtual void synchronize() { }
+ virtual void cancel() { }
protected:
GCActivityCallback() {}
@@ -57,10 +59,12 @@ public:
static PassOwnPtr<DefaultGCActivityCallback> create(Heap*);
DefaultGCActivityCallback(Heap*);
- ~DefaultGCActivityCallback();
+ virtual ~DefaultGCActivityCallback();
- void operator()();
- void synchronize();
+ virtual void didAllocate(size_t);
+ virtual void willCollect();
+ virtual void synchronize();
+ virtual void cancel();
#if USE(CF)
protected:
diff --git a/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp b/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp
index 7f45f0746..8b690a480 100644
--- a/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp
+++ b/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp
@@ -45,21 +45,34 @@
namespace JSC {
struct DefaultGCActivityCallbackPlatformData {
- static void trigger(CFRunLoopTimerRef, void *info);
+ static void timerDidFire(CFRunLoopTimerRef, void *info);
RetainPtr<CFRunLoopTimerRef> timer;
RetainPtr<CFRunLoopRef> runLoop;
CFRunLoopTimerContext context;
+ double delay;
};
+const double gcTimeSlicePerMB = 0.01; // Percentage of CPU time we will spend to reclaim 1 MB
+const double maxGCTimeSlice = 0.05; // The maximum amount of CPU time we want to use for opportunistic timer-triggered collections.
+const double timerSlop = 2.0; // Fudge factor to avoid performance cost of resetting timer.
+const double pagingTimeOut = 0.1; // Time in seconds to allow opportunistic timer to iterate over all blocks to see if the Heap is paged out.
const CFTimeInterval decade = 60 * 60 * 24 * 365 * 10;
+const CFTimeInterval hour = 60 * 60;
-void DefaultGCActivityCallbackPlatformData::trigger(CFRunLoopTimerRef timer, void *info)
+void DefaultGCActivityCallbackPlatformData::timerDidFire(CFRunLoopTimerRef, void *info)
{
Heap* heap = static_cast<Heap*>(info);
APIEntryShim shim(heap->globalData());
+#if !PLATFORM(IOS)
+ double startTime = WTF::monotonicallyIncreasingTime();
+ if (heap->isPagedOut(startTime + pagingTimeOut)) {
+ heap->activityCallback()->cancel();
+ heap->increaseLastGCLength(pagingTimeOut);
+ return;
+ }
+#endif
heap->collectAllGarbage();
- CFRunLoopTimerSetNextFireDate(timer, CFAbsoluteTimeGetCurrent() + decade);
}
DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap)
@@ -76,9 +89,6 @@ DefaultGCActivityCallback::~DefaultGCActivityCallback()
{
CFRunLoopRemoveTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes);
CFRunLoopTimerInvalidate(d->timer.get());
- d->context.info = 0;
- d->runLoop = 0;
- d->timer = 0;
}
void DefaultGCActivityCallback::commonConstructor(Heap* heap, CFRunLoopRef runLoop)
@@ -88,14 +98,41 @@ void DefaultGCActivityCallback::commonConstructor(Heap* heap, CFRunLoopRef runLo
memset(&d->context, 0, sizeof(CFRunLoopTimerContext));
d->context.info = heap;
d->runLoop = runLoop;
- d->timer.adoptCF(CFRunLoopTimerCreate(0, decade, decade, 0, 0, DefaultGCActivityCallbackPlatformData::trigger, &d->context));
+ d->timer.adoptCF(CFRunLoopTimerCreate(0, decade, decade, 0, 0, DefaultGCActivityCallbackPlatformData::timerDidFire, &d->context));
+ d->delay = decade;
CFRunLoopAddTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes);
}
-void DefaultGCActivityCallback::operator()()
+static void scheduleTimer(DefaultGCActivityCallbackPlatformData* d, double newDelay)
+{
+ if (newDelay * timerSlop > d->delay)
+ return;
+ double delta = d->delay - newDelay;
+ d->delay = newDelay;
+ CFRunLoopTimerSetNextFireDate(d->timer.get(), CFRunLoopTimerGetNextFireDate(d->timer.get()) - delta);
+}
+
+static void cancelTimer(DefaultGCActivityCallbackPlatformData* d)
{
- CFTimeInterval triggerInterval = static_cast<Heap*>(d->context.info)->lastGCLength() * 100.0;
- CFRunLoopTimerSetNextFireDate(d->timer.get(), CFAbsoluteTimeGetCurrent() + triggerInterval);
+ d->delay = decade;
+ CFRunLoopTimerSetNextFireDate(d->timer.get(), CFAbsoluteTimeGetCurrent() + decade);
+}
+
+void DefaultGCActivityCallback::didAllocate(size_t bytes)
+{
+ // The first byte allocated in an allocation cycle will report 0 bytes to didAllocate.
+ // We pretend it's one byte so that we don't ignore this allocation entirely.
+ if (!bytes)
+ bytes = 1;
+ Heap* heap = static_cast<Heap*>(d->context.info);
+ double gcTimeSlice = std::min((static_cast<double>(bytes) / MB) * gcTimeSlicePerMB, maxGCTimeSlice);
+ double newDelay = heap->lastGCLength() / gcTimeSlice;
+ scheduleTimer(d.get(), newDelay);
+}
+
+void DefaultGCActivityCallback::willCollect()
+{
+ cancelTimer(d.get());
}
void DefaultGCActivityCallback::synchronize()
@@ -107,4 +144,9 @@ void DefaultGCActivityCallback::synchronize()
CFRunLoopAddTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes);
}
+void DefaultGCActivityCallback::cancel()
+{
+ cancelTimer(d.get());
+}
+
}
diff --git a/Source/JavaScriptCore/runtime/Identifier.cpp b/Source/JavaScriptCore/runtime/Identifier.cpp
index fbc5787ce..182bcc462 100644
--- a/Source/JavaScriptCore/runtime/Identifier.cpp
+++ b/Source/JavaScriptCore/runtime/Identifier.cpp
@@ -110,11 +110,11 @@ PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const char* c)
if (iter != literalIdentifierTable.end())
return iter->second;
- pair<HashSet<StringImpl*>::iterator, bool> addResult = identifierTable.add<const LChar*, IdentifierCStringTranslator>(reinterpret_cast<const LChar*>(c));
+ HashSet<StringImpl*>::AddResult addResult = identifierTable.add<const LChar*, IdentifierCStringTranslator>(reinterpret_cast<const LChar*>(c));
// If the string is newly-translated, then we need to adopt it.
// The boolean in the pair tells us if that is so.
- RefPtr<StringImpl> addedString = addResult.second ? adoptRef(*addResult.first) : *addResult.first;
+ RefPtr<StringImpl> addedString = addResult.isNewEntry ? adoptRef(*addResult.iterator) : *addResult.iterator;
literalIdentifierTable.add(c, addedString.get());
@@ -138,11 +138,11 @@ PassRefPtr<StringImpl> Identifier::add8(JSGlobalData* globalData, const UChar* s
if (!length)
return StringImpl::empty();
CharBuffer<UChar> buf = {s, length};
- pair<HashSet<StringImpl*>::iterator, bool> addResult = globalData->identifierTable->add<CharBuffer<UChar>, IdentifierLCharFromUCharTranslator >(buf);
+ HashSet<StringImpl*>::AddResult addResult = globalData->identifierTable->add<CharBuffer<UChar>, IdentifierLCharFromUCharTranslator >(buf);
// If the string is newly-translated, then we need to adopt it.
// The boolean in the pair tells us if that is so.
- return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
+ return addResult.isNewEntry ? adoptRef(*addResult.iterator) : *addResult.iterator;
}
template <typename CharType>
@@ -210,7 +210,7 @@ PassRefPtr<StringImpl> Identifier::addSlowCase(JSGlobalData* globalData, StringI
return r;
}
- return *globalData->identifierTable->add(r).first;
+ return *globalData->identifierTable->add(r).iterator;
}
PassRefPtr<StringImpl> Identifier::addSlowCase(ExecState* exec, StringImpl* r)
diff --git a/Source/JavaScriptCore/runtime/Identifier.h b/Source/JavaScriptCore/runtime/Identifier.h
index b9e5a1854..14960876b 100644
--- a/Source/JavaScriptCore/runtime/Identifier.h
+++ b/Source/JavaScriptCore/runtime/Identifier.h
@@ -178,11 +178,11 @@ namespace JSC {
if (!length)
return StringImpl::empty();
CharBuffer<T> buf = {s, length};
- pair<HashSet<StringImpl*>::iterator, bool> addResult = globalData->identifierTable->add<CharBuffer<T>, IdentifierCharBufferTranslator<T> >(buf);
+ HashSet<StringImpl*>::AddResult addResult = globalData->identifierTable->add<CharBuffer<T>, IdentifierCharBufferTranslator<T> >(buf);
// If the string is newly-translated, then we need to adopt it.
// The boolean in the pair tells us if that is so.
- return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
+ return addResult.isNewEntry ? adoptRef(*addResult.iterator) : *addResult.iterator;
}
inline bool operator==(const Identifier& a, const Identifier& b)
@@ -246,10 +246,10 @@ namespace JSC {
typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, IdentifierMapIndexHashTraits> IdentifierMap;
template<typename U, typename V>
- std::pair<HashSet<StringImpl*>::iterator, bool> IdentifierTable::add(U value)
+ HashSet<StringImpl*>::AddResult IdentifierTable::add(U value)
{
- std::pair<HashSet<StringImpl*>::iterator, bool> result = m_table.add<U, V>(value);
- (*result.first)->setIsIdentifier(true);
+ HashSet<StringImpl*>::AddResult result = m_table.add<U, V>(value);
+ (*result.iterator)->setIsIdentifier(true);
return result;
}
diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.cpp b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
index b6fd6ce1f..4c0e123a4 100644
--- a/Source/JavaScriptCore/runtime/InitializeThreading.cpp
+++ b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
@@ -57,7 +57,7 @@ static void initializeThreadingOnce()
#if ENABLE(WRITE_BARRIER_PROFILING)
WriteBarrierCounters::initialize();
#endif
-#if ENABLE(JIT) && ENABLE(ASSEMBLER)
+#if ENABLE(ASSEMBLER)
ExecutableAllocator::initializeAllocator();
#endif
RegisterFile::initializeThreading();
diff --git a/Source/JavaScriptCore/runtime/Intrinsic.h b/Source/JavaScriptCore/runtime/Intrinsic.h
index 5cc00685f..73244e7c7 100644
--- a/Source/JavaScriptCore/runtime/Intrinsic.h
+++ b/Source/JavaScriptCore/runtime/Intrinsic.h
@@ -45,6 +45,8 @@ enum Intrinsic {
RoundIntrinsic,
ExpIntrinsic,
LogIntrinsic,
+ RegExpExecIntrinsic,
+ RegExpTestIntrinsic,
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp
index 3e05738eb..a10361007 100644
--- a/Source/JavaScriptCore/runtime/JSActivation.cpp
+++ b/Source/JavaScriptCore/runtime/JSActivation.cpp
@@ -45,6 +45,7 @@ JSActivation::JSActivation(CallFrame* callFrame, FunctionExecutable* functionExe
: Base(callFrame->globalData(), callFrame->globalData().activationStructure.get(), functionExecutable->symbolTable(), callFrame->registers())
, m_numCapturedArgs(max(callFrame->argumentCount(), functionExecutable->parameterCount()))
, m_numCapturedVars(functionExecutable->capturedVariableCount())
+ , m_isTornOff(false)
, m_requiresDynamicChecks(functionExecutable->usesEval() && !functionExecutable->isStrictMode())
, m_argumentsRegister(functionExecutable->generatedBytecode().argumentsRegister())
{
@@ -78,11 +79,15 @@ void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor)
WriteBarrier<Unknown>* registerArray = thisObject->m_registerArray.get();
if (!registerArray)
return;
-
+
visitor.appendValues(registerArray, thisObject->m_numCapturedArgs);
- // Skip 'this' and call frame.
- visitor.appendValues(registerArray + CallFrame::offsetFor(thisObject->m_numCapturedArgs + 1), thisObject->m_numCapturedVars);
+ // Skip 'this' and call frame, except for callee and scope chain.
+ int offset = CallFrame::offsetFor(thisObject->m_numCapturedArgs + 1);
+ visitor.append(registerArray + offset + RegisterFile::ScopeChain);
+ visitor.append(registerArray + offset + RegisterFile::Callee);
+
+ visitor.appendValues(registerArray + offset, thisObject->m_numCapturedVars);
}
inline bool JSActivation::symbolTableGet(const Identifier& propertyName, PropertySlot& slot)
@@ -90,7 +95,7 @@ inline bool JSActivation::symbolTableGet(const Identifier& propertyName, Propert
SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
if (entry.isNull())
return false;
- if (entry.getIndex() >= m_numCapturedVars)
+ if (m_isTornOff && entry.getIndex() >= m_numCapturedVars)
return false;
slot.setValue(registerAt(entry.getIndex()).get());
@@ -110,7 +115,7 @@ inline bool JSActivation::symbolTablePut(ExecState* exec, const Identifier& prop
throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
return true;
}
- if (entry.getIndex() >= m_numCapturedVars)
+ if (m_isTornOff && entry.getIndex() >= m_numCapturedVars)
return false;
registerAt(entry.getIndex()).set(globalData, this, value);
diff --git a/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h
index 80c8aa8d0..fd1b2fd7f 100644
--- a/Source/JavaScriptCore/runtime/JSActivation.h
+++ b/Source/JavaScriptCore/runtime/JSActivation.h
@@ -92,7 +92,8 @@ namespace JSC {
NEVER_INLINE PropertySlot::GetValueFunc getArgumentsGetter();
int m_numCapturedArgs;
- int m_numCapturedVars : 31;
+ int m_numCapturedVars : 30;
+ bool m_isTornOff : 1;
bool m_requiresDynamicChecks : 1;
int m_argumentsRegister;
};
@@ -102,7 +103,7 @@ namespace JSC {
inline JSActivation* asActivation(JSValue value)
{
ASSERT(asObject(value)->inherits(&JSActivation::s_info));
- return static_cast<JSActivation*>(asObject(value));
+ return jsCast<JSActivation*>(asObject(value));
}
ALWAYS_INLINE JSActivation* Register::activation() const
@@ -127,19 +128,13 @@ namespace JSC {
OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[registerArraySize]);
WriteBarrier<Unknown>* registers = registerArray.get() + registerOffset;
- // Copy all arguments that can be captured by name or by the arguments object.
- for (int i = 0; i < m_numCapturedArgs; ++i) {
- int index = CallFrame::argumentOffset(i);
- registers[index].set(globalData, this, m_registers[index].get());
- }
-
- // Skip 'this' and call frame.
-
- // Copy all captured vars.
- for (int i = 0; i < m_numCapturedVars; ++i)
+ int from = CallFrame::argumentOffset(m_numCapturedArgs - 1);
+ int to = m_numCapturedVars;
+ for (int i = from; i < to; ++i)
registers[i].set(globalData, this, m_registers[i].get());
setRegisters(registers, registerArray.release());
+ m_isTornOff = true;
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp
index 4244bc31c..aa1b8b7d9 100644
--- a/Source/JavaScriptCore/runtime/JSArray.cpp
+++ b/Source/JavaScriptCore/runtime/JSArray.cpp
@@ -125,15 +125,6 @@ inline void JSArray::checkConsistency(ConsistencyCheckType)
#endif
-JSArray::JSArray(JSGlobalData& globalData, Structure* structure)
- : JSNonFinalObject(globalData, structure)
- , m_indexBias(0)
- , m_storage(0)
- , m_sparseValueMap(0)
- , m_subclassData(0)
-{
-}
-
void JSArray::finishCreation(JSGlobalData& globalData, unsigned initialLength)
{
Base::finishCreation(globalData);
@@ -176,11 +167,12 @@ JSArray* JSArray::tryFinishCreationUninitialized(JSGlobalData& globalData, unsig
m_storage = static_cast<ArrayStorage*>(newStorage);
m_storage->m_allocBase = m_storage;
- m_storage->m_length = 0;
+ m_storage->m_length = initialLength;
m_vectorLength = initialVectorLength;
m_storage->m_numValuesInVector = initialLength;
#if CHECK_ARRAY_CONSISTENCY
+ m_storage->m_initializationIndex = 0;
m_storage->m_inCompactInitialization = true;
#endif
@@ -195,10 +187,12 @@ void JSArray::finalize(JSCell* cell)
thisObject->deallocateSparseMap();
}
-inline std::pair<SparseArrayValueMap::iterator, bool> SparseArrayValueMap::add(JSArray* array, unsigned i)
+inline SparseArrayValueMap::AddResult SparseArrayValueMap::add(JSArray* array, unsigned i)
{
SparseArrayEntry entry;
- std::pair<iterator, bool> result = m_map.add(i, entry);
+ entry.setWithoutWriteBarrier(jsUndefined());
+
+ AddResult result = m_map.add(i, entry);
size_t capacity = m_map.capacity();
if (capacity != m_reportedCapacity) {
Heap::heap(array)->reportExtraMemoryCost((capacity - m_reportedCapacity) * (sizeof(unsigned) + sizeof(WriteBarrier<Unknown>)));
@@ -209,14 +203,14 @@ inline std::pair<SparseArrayValueMap::iterator, bool> SparseArrayValueMap::add(J
inline void SparseArrayValueMap::put(ExecState* exec, JSArray* array, unsigned i, JSValue value, bool shouldThrow)
{
- std::pair<SparseArrayValueMap::iterator, bool> result = add(array, i);
- SparseArrayEntry& entry = result.first->second;
+ AddResult result = add(array, i);
+ SparseArrayEntry& entry = result.iterator->second;
// To save a separate find & add, we first always add to the sparse map.
// In the uncommon case that this is a new property, and the array is not
// extensible, this is not the right thing to have done - so remove again.
- if (result.second && !array->isExtensible()) {
- remove(result.first);
+ if (result.isNewEntry && !array->isExtensible()) {
+ remove(result.iterator);
if (shouldThrow)
throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
return;
@@ -252,14 +246,14 @@ inline void SparseArrayValueMap::put(ExecState* exec, JSArray* array, unsigned i
inline bool SparseArrayValueMap::putDirect(ExecState* exec, JSArray* array, unsigned i, JSValue value, bool shouldThrow)
{
- std::pair<SparseArrayValueMap::iterator, bool> result = add(array, i);
- SparseArrayEntry& entry = result.first->second;
+ AddResult result = add(array, i);
+ SparseArrayEntry& entry = result.iterator->second;
// To save a separate find & add, we first always add to the sparse map.
// In the uncommon case that this is a new property, and the array is not
// extensible, this is not the right thing to have done - so remove again.
- if (result.second && !array->isExtensible()) {
- remove(result.first);
+ if (result.isNewEntry && !array->isExtensible()) {
+ remove(result.iterator);
return reject(exec, shouldThrow, "Attempting to define property on object that is not extensible.");
}
@@ -355,7 +349,7 @@ void JSArray::enterDictionaryMode(JSGlobalData& globalData)
// This will always be a new entry in the map, so no need to check we can write,
// and attributes are default so no need to set them.
if (value)
- map->add(this, i).first->second.set(globalData, this, value);
+ map->add(this, i).iterator->second.set(globalData, this, value);
}
void* newRawStorage = 0;
@@ -430,15 +424,15 @@ bool JSArray::defineOwnNumericProperty(ExecState* exec, unsigned index, Property
ASSERT(map);
// 1. Let current be the result of calling the [[GetOwnProperty]] internal method of O with property name P.
- std::pair<SparseArrayValueMap::iterator, bool> result = map->add(this, index);
- SparseArrayEntry* entryInMap = &result.first->second;
+ SparseArrayValueMap::AddResult result = map->add(this, index);
+ SparseArrayEntry* entryInMap = &result.iterator->second;
// 2. Let extensible be the value of the [[Extensible]] internal property of O.
// 3. If current is undefined and extensible is false, then Reject.
// 4. If current is undefined and extensible is true, then
- if (result.second) {
+ if (result.isNewEntry) {
if (!isExtensible()) {
- map->remove(result.first);
+ map->remove(result.iterator);
return reject(exec, throwException, "Attempting to define property on object that is not extensible.");
}
@@ -543,7 +537,7 @@ void JSArray::setLengthWritable(ExecState* exec, bool writable)
// Defined in ES5.1 15.4.5.1
bool JSArray::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException)
{
- JSArray* array = static_cast<JSArray*>(object);
+ JSArray* array = jsCast<JSArray*>(object);
// 3. If P is "length", then
if (propertyName == exec->propertyNames().length) {
@@ -1388,7 +1382,7 @@ void JSArray::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitor.copyAndAppend(reinterpret_cast<void**>(&baseStorage), storageSize(thisObject->m_vectorLength + thisObject->m_indexBias), storage->m_vector->slot(), thisObject->m_vectorLength);
if (baseStorage != thisObject->m_storage->m_allocBase) {
- thisObject->m_storage = reinterpret_cast<ArrayStorage*>(static_cast<char*>(baseStorage) + sizeof(JSValue) * thisObject->m_indexBias);
+ thisObject->m_storage = reinterpret_cast_ptr<ArrayStorage*>(static_cast<char*>(baseStorage) + sizeof(JSValue) * thisObject->m_indexBias);
thisObject->m_storage->m_allocBase = baseStorage;
ASSERT(thisObject->m_storage->m_allocBase);
}
@@ -1473,17 +1467,19 @@ void JSArray::sort(ExecState* exec)
Heap::heap(this)->pushTempSortVector(&values);
+ bool isSortingPrimitiveValues = true;
for (size_t i = 0; i < lengthNotIncludingUndefined; i++) {
JSValue value = m_storage->m_vector[i].get();
ASSERT(!value.isUndefined());
values[i].first = value;
+ isSortingPrimitiveValues = isSortingPrimitiveValues && value.isPrimitive();
}
// FIXME: The following loop continues to call toString on subsequent values even after
// a toString call raises an exception.
for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
- values[i].second = values[i].first.toString(exec)->value(exec);
+ values[i].second = values[i].first.toUStringInline(exec);
if (exec->hadException()) {
Heap::heap(this)->popTempSortVector(&values);
@@ -1494,7 +1490,10 @@ void JSArray::sort(ExecState* exec)
// than O(N log N).
#if HAVE(MERGESORT)
- mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
+ if (isSortingPrimitiveValues)
+ qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
+ else
+ mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
#else
// FIXME: The qsort library function is likely to not be a stable sort.
// ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort.
@@ -1622,7 +1621,7 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType,
tree.abstractor().m_nodes.grow(nodeCount);
if (callType == CallTypeJS)
- tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, asFunction(compareFunction), 2));
+ tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, jsCast<JSFunction*>(compareFunction), 2));
if (!tree.abstractor().m_nodes.begin()) {
throwOutOfMemoryError(exec);
@@ -1802,16 +1801,6 @@ unsigned JSArray::compactForSorting(JSGlobalData& globalData)
return numDefined;
}
-void* JSArray::subclassData() const
-{
- return m_subclassData;
-}
-
-void JSArray::setSubclassData(void* d)
-{
- m_subclassData = d;
-}
-
#if CHECK_ARRAY_CONSISTENCY
void JSArray::checkConsistency(ConsistencyCheckType type)
@@ -1826,7 +1815,7 @@ void JSArray::checkConsistency(ConsistencyCheckType type)
unsigned numValuesInVector = 0;
for (unsigned i = 0; i < m_vectorLength; ++i) {
- if (JSValue value = storage->m_vector[i]) {
+ if (JSValue value = storage->m_vector[i].get()) {
ASSERT(i < storage->m_length);
if (type != DestructorConsistencyCheck)
value.isUndefined(); // Likely to crash if the object was deallocated.
@@ -1840,15 +1829,15 @@ void JSArray::checkConsistency(ConsistencyCheckType type)
ASSERT(numValuesInVector <= storage->m_length);
if (m_sparseValueMap) {
- SparseArrayValueMap::iterator end = m_sparseValueMap->end();
- for (SparseArrayValueMap::iterator it = m_sparseValueMap->begin(); it != end; ++it) {
+ SparseArrayValueMap::const_iterator end = m_sparseValueMap->end();
+ for (SparseArrayValueMap::const_iterator it = m_sparseValueMap->begin(); it != end; ++it) {
unsigned index = it->first;
ASSERT(index < storage->m_length);
- ASSERT(index >= storage->m_vectorLength);
+ ASSERT(index >= m_vectorLength);
ASSERT(index <= MAX_ARRAY_INDEX);
ASSERT(it->second);
if (type != DestructorConsistencyCheck)
- it->second.isUndefined(); // Likely to crash if the object was deallocated.
+ it->second.getNonSparseMode().isUndefined(); // Likely to crash if the object was deallocated.
}
}
}
diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h
index ad98d6619..17c7f3ed7 100644
--- a/Source/JavaScriptCore/runtime/JSArray.h
+++ b/Source/JavaScriptCore/runtime/JSArray.h
@@ -55,6 +55,7 @@ namespace JSC {
public:
typedef Map::iterator iterator;
typedef Map::const_iterator const_iterator;
+ typedef Map::AddResult AddResult;
SparseArrayValueMap()
: m_flags(Normal)
@@ -87,7 +88,7 @@ namespace JSC {
// These methods may mutate the contents of the map
void put(ExecState*, JSArray*, unsigned, JSValue, bool shouldThrow);
bool putDirect(ExecState*, JSArray*, unsigned, JSValue, bool shouldThrow);
- std::pair<iterator, bool> add(JSArray*, unsigned);
+ AddResult add(JSArray*, unsigned);
iterator find(unsigned i) { return m_map.find(i); }
// This should ASSERT the remove is valid (check the result of the find).
void remove(iterator it) { m_map.remove(it); }
@@ -118,7 +119,9 @@ namespace JSC {
unsigned m_numValuesInVector;
void* m_allocBase; // Pointer to base address returned by malloc(). Keeping this pointer does eliminate false positives from the leak detector.
#if CHECK_ARRAY_CONSISTENCY
- uintptr_t m_inCompactInitialization; // Needs to be a uintptr_t for alignment purposes.
+ // Needs to be a uintptr_t for alignment purposes.
+ uintptr_t m_initializationIndex;
+ uintptr_t m_inCompactInitialization;
#else
uintptr_t m_padding;
#endif
@@ -136,7 +139,13 @@ namespace JSC {
friend class JIT;
protected:
- JS_EXPORT_PRIVATE explicit JSArray(JSGlobalData&, Structure*);
+ explicit JSArray(JSGlobalData& globalData, Structure* structure)
+ : JSNonFinalObject(globalData, structure)
+ , m_indexBias(0)
+ , m_storage(0)
+ , m_sparseValueMap(0)
+ {
+ }
JS_EXPORT_PRIVATE void finishCreation(JSGlobalData&, unsigned initialLength = 0);
JS_EXPORT_PRIVATE JSArray* tryFinishCreationUninitialized(JSGlobalData&, unsigned initialLength);
@@ -218,24 +227,25 @@ namespace JSC {
ArrayStorage *storage = m_storage;
#if CHECK_ARRAY_CONSISTENCY
ASSERT(storage->m_inCompactInitialization);
-#endif
// Check that we are initializing the next index in sequence.
- ASSERT_UNUSED(i, i == storage->m_length);
+ ASSERT(i == storage->m_initializationIndex);
// tryCreateUninitialized set m_numValuesInVector to the initialLength,
// check we do not try to initialize more than this number of properties.
- ASSERT(storage->m_length < storage->m_numValuesInVector);
- // It is improtant that we increment length here, so that all newly added
- // values in the array still get marked during the initialization phase.
- storage->m_vector[storage->m_length++].set(globalData, this, v);
+ ASSERT(storage->m_initializationIndex < storage->m_numValuesInVector);
+ storage->m_initializationIndex++;
+#endif
+ ASSERT(i < storage->m_length);
+ ASSERT(i < storage->m_numValuesInVector);
+ storage->m_vector[i].set(globalData, this, v);
}
inline void completeInitialization(unsigned newLength)
{
// Check that we have initialized as meny properties as we think we have.
ASSERT_UNUSED(newLength, newLength == m_storage->m_length);
- // Check that the number of propreties initialized matches the initialLength.
- ASSERT(m_storage->m_length == m_storage->m_numValuesInVector);
#if CHECK_ARRAY_CONSISTENCY
+ // Check that the number of propreties initialized matches the initialLength.
+ ASSERT(m_storage->m_initializationIndex == m_storage->m_numValuesInVector);
ASSERT(m_storage->m_inCompactInitialization);
m_storage->m_inCompactInitialization = false;
#endif
@@ -313,10 +323,8 @@ namespace JSC {
// FIXME: Maybe SparseArrayValueMap should be put into its own JSCell?
SparseArrayValueMap* m_sparseValueMap;
- void* m_subclassData; // A JSArray subclass can use this to fill the vector lazily.
static ptrdiff_t sparseValueMapOffset() { return OBJECT_OFFSETOF(JSArray, m_sparseValueMap); }
- static ptrdiff_t subclassDataOffset() { return OBJECT_OFFSETOF(JSArray, m_subclassData); }
static ptrdiff_t indexBiasOffset() { return OBJECT_OFFSETOF(JSArray, m_indexBias); }
};
@@ -338,7 +346,7 @@ namespace JSC {
inline JSArray* asArray(JSCell* cell)
{
ASSERT(cell->inherits(&JSArray::s_info));
- return static_cast<JSArray*>(cell);
+ return jsCast<JSArray*>(cell);
}
inline JSArray* asArray(JSValue value)
diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
index 8ebf8c638..5fee47c24 100644
--- a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
@@ -38,7 +38,7 @@ const ClassInfo JSBoundFunction::s_info = { "Function", &Base::s_info, 0, 0, CRE
EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState* exec)
{
- JSBoundFunction* boundFunction = static_cast<JSBoundFunction*>(exec->callee());
+ JSBoundFunction* boundFunction = jsCast<JSBoundFunction*>(exec->callee());
ASSERT(isJSArray(boundFunction->boundArgs())); // Currently this is true!
JSArray* boundArgs = asArray(boundFunction->boundArgs());
@@ -58,7 +58,7 @@ EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState* exec)
EncodedJSValue JSC_HOST_CALL boundFunctionConstruct(ExecState* exec)
{
- JSBoundFunction* boundFunction = static_cast<JSBoundFunction*>(exec->callee());
+ JSBoundFunction* boundFunction = jsCast<JSBoundFunction*>(exec->callee());
ASSERT(isJSArray(boundFunction->boundArgs())); // Currently this is true!
JSArray* boundArgs = asArray(boundFunction->boundArgs());
diff --git a/Source/JavaScriptCore/runtime/JSByteArray.cpp b/Source/JavaScriptCore/runtime/JSByteArray.cpp
deleted file mode 100644
index 39ea4d0b9..000000000
--- a/Source/JavaScriptCore/runtime/JSByteArray.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
- * 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 "JSByteArray.h"
-
-#include "JSGlobalObject.h"
-#include "PropertyNameArray.h"
-
-using namespace WTF;
-
-namespace JSC {
-
-const ClassInfo JSByteArray::s_info = { "Uint8ClampedArray", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSByteArray) };
-
-JSByteArray::JSByteArray(ExecState* exec, Structure* structure, ByteArray* storage)
- : JSNonFinalObject(exec->globalData(), structure)
- , m_storage(storage)
-{
-}
-
-JSByteArray::~JSByteArray()
-{
- ASSERT(jsCast<JSByteArray*>(this));
-}
-
-void JSByteArray::destroy(JSCell* cell)
-{
- jsCast<JSByteArray*>(cell)->JSByteArray::~JSByteArray();
-}
-
-Structure* JSByteArray::createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const JSC::ClassInfo* classInfo)
-{
- return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), classInfo);
-}
-
-bool JSByteArray::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
-{
- JSByteArray* thisObject = jsCast<JSByteArray*>(cell);
- bool ok;
- unsigned index = propertyName.toUInt32(ok);
- if (ok && thisObject->canAccessIndex(index)) {
- slot.setValue(thisObject->getIndex(exec, index));
- return true;
- }
- return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
-}
-
-bool JSByteArray::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
-{
- JSByteArray* thisObject = jsCast<JSByteArray*>(object);
- bool ok;
- unsigned index = propertyName.toUInt32(ok);
- if (ok && thisObject->canAccessIndex(index)) {
- descriptor.setDescriptor(thisObject->getIndex(exec, index), DontDelete);
- return true;
- }
- return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
-}
-
-bool JSByteArray::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot)
-{
- JSByteArray* thisObject = jsCast<JSByteArray*>(cell);
- if (thisObject->canAccessIndex(propertyName)) {
- slot.setValue(thisObject->getIndex(exec, propertyName));
- return true;
- }
- return JSObject::getOwnPropertySlot(thisObject, exec, Identifier::from(exec, propertyName), slot);
-}
-
-void JSByteArray::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
-{
- JSByteArray* thisObject = jsCast<JSByteArray*>(cell);
- bool ok;
- unsigned index = propertyName.toUInt32(ok);
- if (ok) {
- thisObject->setIndex(exec, index, value);
- return;
- }
- JSObject::put(thisObject, exec, propertyName, value, slot);
-}
-
-void JSByteArray::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value, bool)
-{
- jsCast<JSByteArray*>(cell)->setIndex(exec, propertyName, value);
-}
-
-void JSByteArray::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
-{
- JSByteArray* thisObject = jsCast<JSByteArray*>(object);
- unsigned length = thisObject->m_storage->length();
- for (unsigned i = 0; i < length; ++i)
- propertyNames.add(Identifier::from(exec, i));
- JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
-}
-
-}
-
diff --git a/Source/JavaScriptCore/runtime/JSByteArray.h b/Source/JavaScriptCore/runtime/JSByteArray.h
deleted file mode 100644
index 06181d901..000000000
--- a/Source/JavaScriptCore/runtime/JSByteArray.h
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
- * 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 JSByteArray_h
-#define JSByteArray_h
-
-#include "JSObject.h"
-
-#include <wtf/ByteArray.h>
-
-namespace JSC {
-
- class JSByteArray : public JSNonFinalObject {
- friend class JSGlobalData;
- public:
- typedef JSNonFinalObject Base;
-
- bool canAccessIndex(unsigned i) { return i < m_storage->length(); }
- JSValue getIndex(ExecState*, unsigned i)
- {
- ASSERT(canAccessIndex(i));
- return jsNumber(m_storage->data()[i]);
- }
-
- void setIndex(unsigned i, int value)
- {
- ASSERT(canAccessIndex(i));
- if (value & ~0xFF) {
- if (value < 0)
- value = 0;
- else
- value = 255;
- }
- m_storage->data()[i] = static_cast<unsigned char>(value);
- }
-
- void setIndex(unsigned i, double value)
- {
- ASSERT(canAccessIndex(i));
- if (!(value > 0)) // Clamp NaN to 0
- value = 0;
- else if (value > 255)
- value = 255;
- m_storage->data()[i] = static_cast<unsigned char>(value + 0.5);
- }
-
- void setIndex(ExecState* exec, unsigned i, JSValue value)
- {
- double byteValue = value.toNumber(exec);
- if (exec->hadException())
- return;
- if (canAccessIndex(i))
- setIndex(i, byteValue);
- }
-
- private:
- JS_EXPORT_PRIVATE JSByteArray(ExecState*, Structure*, ByteArray* storage);
-
- public:
- static JSByteArray* create(ExecState* exec, Structure* structure, ByteArray* storage)
- {
- JSByteArray* array = new (NotNull, allocateCell<JSByteArray>(*exec->heap())) JSByteArray(exec, structure, storage);
- array->finishCreation(exec);
- return array;
- }
-
- JS_EXPORT_PRIVATE static Structure* createStructure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const JSC::ClassInfo* = &s_info);
-
- JS_EXPORT_PRIVATE static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&);
- JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);
- JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
- JS_EXPORT_PRIVATE static void put(JSC::JSCell*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&);
- JS_EXPORT_PRIVATE static void putByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::JSValue, bool shouldThrow);
-
- JS_EXPORT_PRIVATE static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, EnumerationMode);
-
- static JS_EXPORTDATA const ClassInfo s_info;
-
- size_t length() const { return m_storage->length(); }
-
- WTF::ByteArray* storage() const { return m_storage.get(); }
-
- ~JSByteArray();
- JS_EXPORT_PRIVATE static void destroy(JSCell*);
-
- static size_t offsetOfStorage() { return OBJECT_OFFSETOF(JSByteArray, m_storage); }
-
- protected:
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags;
-
- void finishCreation(ExecState* exec)
- {
- Base::finishCreation(exec->globalData());
- putDirect(exec->globalData(), exec->globalData().propertyNames->length, jsNumber(m_storage->length()), ReadOnly | DontDelete);
- }
-
- private:
- RefPtr<WTF::ByteArray> m_storage;
- };
-
- JSByteArray* asByteArray(JSValue value);
- inline JSByteArray* asByteArray(JSValue value)
- {
- return static_cast<JSByteArray*>(value.asCell());
- }
-
- inline bool isJSByteArray(JSValue v) { return v.isCell() && v.asCell()->classInfo() == &JSByteArray::s_info; }
-
-} // namespace JSC
-
-#endif // JSByteArray_h
diff --git a/Source/JavaScriptCore/runtime/JSCell.cpp b/Source/JavaScriptCore/runtime/JSCell.cpp
index f08d0260a..7f9ba88a2 100644
--- a/Source/JavaScriptCore/runtime/JSCell.cpp
+++ b/Source/JavaScriptCore/runtime/JSCell.cpp
@@ -159,7 +159,7 @@ JSObject* JSCell::toObject(ExecState* exec, JSGlobalObject* globalObject) const
if (isString())
return static_cast<const JSString*>(this)->toObject(exec, globalObject);
ASSERT(isObject());
- return static_cast<JSObject*>(const_cast<JSCell*>(this));
+ return jsCast<JSObject*>(const_cast<JSCell*>(this));
}
void slowValidateCell(JSCell* cell)
diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h
index 2ef359b76..431e67145 100644
--- a/Source/JavaScriptCore/runtime/JSCell.h
+++ b/Source/JavaScriptCore/runtime/JSCell.h
@@ -178,7 +178,7 @@ namespace JSC {
{
#if ENABLE(GC_VALIDATION)
ASSERT(globalData.isInitializingObject());
- globalData.setInitializingObject(false);
+ globalData.setInitializingObjectClass(0);
#else
UNUSED_PARAM(globalData);
#endif
@@ -328,9 +328,8 @@ namespace JSC {
void* allocateCell(Heap& heap)
{
#if ENABLE(GC_VALIDATION)
- ASSERT(sizeof(T) == T::s_info.cellSize);
ASSERT(!heap.globalData()->isInitializingObject());
- heap.globalData()->setInitializingObject(true);
+ heap.globalData()->setInitializingObjectClass(&T::s_info);
#endif
JSCell* result = 0;
if (NeedsDestructor<T>::value)
@@ -351,16 +350,29 @@ namespace JSC {
template<typename To, typename From>
inline To jsCast(From* from)
{
- ASSERT(from->inherits(&WTF::RemovePointer<To>::Type::s_info));
+ ASSERT(!from || from->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info));
return static_cast<To>(from);
}
+ template<typename To>
+ inline To jsCast(JSValue from)
+ {
+ ASSERT(from.isCell() && from.asCell()->JSCell::inherits(&WTF::RemovePointer<To>::Type::s_info));
+ return static_cast<To>(from.asCell());
+ }
+
template<typename To, typename From>
inline To jsDynamicCast(From* from)
{
return from->inherits(&WTF::RemovePointer<To>::Type::s_info) ? static_cast<To>(from) : 0;
}
+ template<typename To>
+ inline To jsDynamicCast(JSValue from)
+ {
+ return from.isCell() && from.asCell()->inherits(&WTF::RemovePointer<To>::Type::s_info) ? static_cast<To>(from.asCell()) : 0;
+ }
+
} // namespace JSC
#endif // JSCell_h
diff --git a/Source/JavaScriptCore/runtime/JSDateMath.cpp b/Source/JavaScriptCore/runtime/JSDateMath.cpp
index 882f86fa0..dbe748835 100644
--- a/Source/JavaScriptCore/runtime/JSDateMath.cpp
+++ b/Source/JavaScriptCore/runtime/JSDateMath.cpp
@@ -72,12 +72,8 @@
#include "config.h"
#include "JSDateMath.h"
-#include "CurrentTime.h"
#include "JSObject.h"
-#include "MathExtras.h"
#include "ScopeChain.h"
-#include "StdLibExtras.h"
-#include "StringExtras.h"
#include <algorithm>
#include <limits.h>
@@ -86,17 +82,16 @@
#include <time.h>
#include <wtf/ASCIICType.h>
#include <wtf/Assertions.h>
+#include <wtf/CurrentTime.h>
+#include <wtf/MathExtras.h>
+#include <wtf/StdLibExtras.h>
+#include <wtf/StringExtras.h>
#include <wtf/text/StringBuilder.h>
#if HAVE(ERRNO_H)
#include <errno.h>
#endif
-#if OS(WINCE)
-extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t);
-extern "C" struct tm * localtime(const time_t *timer);
-#endif
-
#if HAVE(SYS_TIME_H)
#include <sys/time.h>
#endif
diff --git a/Source/JavaScriptCore/runtime/JSDateMath.h b/Source/JavaScriptCore/runtime/JSDateMath.h
index ba6d647dd..f77cf1e75 100644
--- a/Source/JavaScriptCore/runtime/JSDateMath.h
+++ b/Source/JavaScriptCore/runtime/JSDateMath.h
@@ -74,33 +74,6 @@ public:
{
}
- GregorianDateTime(ExecState* exec, const tm& inTm)
- : second(inTm.tm_sec)
- , minute(inTm.tm_min)
- , hour(inTm.tm_hour)
- , weekDay(inTm.tm_wday)
- , monthDay(inTm.tm_mday)
- , yearDay(inTm.tm_yday)
- , month(inTm.tm_mon)
- , year(inTm.tm_year)
- , isDST(inTm.tm_isdst)
- {
- UNUSED_PARAM(exec);
-#if HAVE(TM_GMTOFF)
- utcOffset = static_cast<int>(inTm.tm_gmtoff);
-#else
- utcOffset = static_cast<int>(getUTCOffset(exec) / WTF::msPerSecond + (isDST ? WTF::secondsPerHour : 0));
-#endif
-
-#if HAVE(TM_ZONE)
- int inZoneSize = strlen(inTm.tm_zone) + 1;
- timeZone = adoptArrayPtr(new char[inZoneSize]);
- strncpy(timeZone.get(), inTm.tm_zone, inZoneSize);
-#else
- timeZone = nullptr;
-#endif
- }
-
operator tm() const
{
tm ret;
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
index fa798f41a..243946ba9 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.cpp
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -59,22 +59,25 @@ bool JSFunction::isHostFunctionNonInline() const
return isHostFunction();
}
-JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, int length, const Identifier& name, NativeFunction nativeFunction, NativeFunction nativeConstructor)
+JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, int length, const Identifier& name, NativeFunction nativeFunction, Intrinsic intrinsic, NativeFunction nativeConstructor)
{
- NativeExecutable* executable = exec->globalData().getHostFunction(nativeFunction, nativeConstructor);
+ NativeExecutable* executable;
+#if !ENABLE(JIT)
+ UNUSED_PARAM(intrinsic);
+#else
+ if (intrinsic != NoIntrinsic && exec->globalData().canUseJIT()) {
+ ASSERT(nativeConstructor == callHostFunctionAsConstructor);
+ executable = exec->globalData().getHostFunction(nativeFunction, intrinsic);
+ } else
+#endif
+ executable = exec->globalData().getHostFunction(nativeFunction, nativeConstructor);
+
JSFunction* function = new (NotNull, allocateCell<JSFunction>(*exec->heap())) JSFunction(exec, globalObject, globalObject->functionStructure());
// Can't do this during initialization because getHostFunction might do a GC allocation.
function->finishCreation(exec, executable, length, name);
return function;
}
-JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, int length, const Identifier& name, NativeExecutable* nativeExecutable)
-{
- JSFunction* function = new (NotNull, allocateCell<JSFunction>(*exec->heap())) JSFunction(exec, globalObject, globalObject->functionStructure());
- function->finishCreation(exec, nativeExecutable, length, name);
- return function;
-}
-
JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
: Base(exec->globalData(), structure)
, m_executable()
@@ -172,21 +175,21 @@ CallType JSFunction::getCallData(JSCell* cell, CallData& callData)
JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, const Identifier&)
{
- JSFunction* thisObj = asFunction(slotBase);
+ JSFunction* thisObj = jsCast<JSFunction*>(slotBase);
ASSERT(!thisObj->isHostFunction());
return exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObj);
}
JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, const Identifier&)
{
- JSFunction* thisObj = asFunction(slotBase);
+ JSFunction* thisObj = jsCast<JSFunction*>(slotBase);
ASSERT(!thisObj->isHostFunction());
JSValue caller = exec->interpreter()->retrieveCallerFromVMCode(exec, thisObj);
// See ES5.1 15.3.5.4 - Function.caller may not be used to retrieve a strict caller.
if (!caller.isObject() || !asObject(caller)->inherits(&JSFunction::s_info))
return caller;
- JSFunction* function = asFunction(caller);
+ JSFunction* function = jsCast<JSFunction*>(caller);
if (function->isHostFunction() || !function->jsExecutable()->isStrictMode())
return caller;
return throwTypeError(exec, "Function.caller used to retrieve strict caller");
@@ -194,7 +197,7 @@ JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, const Identi
JSValue JSFunction::lengthGetter(ExecState*, JSValue slotBase, const Identifier&)
{
- JSFunction* thisObj = asFunction(slotBase);
+ JSFunction* thisObj = jsCast<JSFunction*>(slotBase);
ASSERT(!thisObj->isHostFunction());
return jsNumber(thisObj->jsExecutable()->parameterCount());
}
@@ -369,46 +372,55 @@ bool JSFunction::defineOwnProperty(JSObject* object, ExecState* exec, const Iden
// following the rules set out in ECMA-262 8.12.9.
PropertySlot slot;
thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
- } else if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length || propertyName == exec->propertyNames().caller) {
- if (!object->isExtensible()) {
- if (throwException)
- throwError(exec, createTypeError(exec, "Attempting to define property on object that is not extensible."));
- return false;
- }
- if (descriptor.configurablePresent() && descriptor.configurable()) {
- if (throwException)
- throwError(exec, createTypeError(exec, "Attempting to configurable attribute of unconfigurable property."));
- return false;
- }
- if (descriptor.enumerablePresent() && descriptor.enumerable()) {
- if (throwException)
- throwError(exec, createTypeError(exec, "Attempting to change enumerable attribute of unconfigurable property."));
- return false;
- }
- if (descriptor.isAccessorDescriptor()) {
- if (throwException)
- throwError(exec, createTypeError(exec, "Attempting to change access mechanism for an unconfigurable property."));
- return false;
+ return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
+ }
+
+ bool valueCheck;
+ if (propertyName == exec->propertyNames().arguments) {
+ if (thisObject->jsExecutable()->isStrictMode()) {
+ if (!Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor))
+ thisObject->putDirectAccessor(exec->globalData(), propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
+ return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
}
- if (descriptor.writablePresent() && descriptor.writable()) {
- if (throwException)
- throwError(exec, createTypeError(exec, "Attempting to change writable attribute of unconfigurable property."));
- return false;
+ valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject));
+ } else if (propertyName == exec->propertyNames().caller) {
+ if (thisObject->jsExecutable()->isStrictMode()) {
+ if (!Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor))
+ thisObject->putDirectAccessor(exec->globalData(), propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Accessor);
+ return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
}
- if (!descriptor.value())
- return true;
- if (propertyName == exec->propertyNames().arguments && sameValue(exec, descriptor.value(), exec->interpreter()->retrieveArgumentsFromVMCode(exec, thisObject)))
- return true;
- if (propertyName == exec->propertyNames().length && sameValue(exec, descriptor.value(), jsNumber(thisObject->jsExecutable()->parameterCount())))
- return true;
- if (propertyName == exec->propertyNames().caller && sameValue(exec, descriptor.value(), exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject)))
- return true;
+ valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), exec->interpreter()->retrieveCallerFromVMCode(exec, thisObject));
+ } else if (propertyName == exec->propertyNames().length)
+ valueCheck = !descriptor.value() || sameValue(exec, descriptor.value(), jsNumber(thisObject->jsExecutable()->parameterCount()));
+ else
+ return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
+
+ if (descriptor.configurablePresent() && descriptor.configurable()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to configurable attribute of unconfigurable property."));
+ return false;
+ }
+ if (descriptor.enumerablePresent() && descriptor.enumerable()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change enumerable attribute of unconfigurable property."));
+ return false;
+ }
+ if (descriptor.isAccessorDescriptor()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change access mechanism for an unconfigurable property."));
+ return false;
+ }
+ if (descriptor.writablePresent() && descriptor.writable()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change writable attribute of unconfigurable property."));
+ return false;
+ }
+ if (!valueCheck) {
if (throwException)
throwError(exec, createTypeError(exec, "Attempting to change value of a readonly property."));
return false;
}
-
- return Base::defineOwnProperty(object, exec, propertyName, descriptor, throwException);
+ return true;
}
// ECMA 13.2.2 [[Construct]]
diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h
index 288181060..5553115bf 100644
--- a/Source/JavaScriptCore/runtime/JSFunction.h
+++ b/Source/JavaScriptCore/runtime/JSFunction.h
@@ -24,6 +24,7 @@
#ifndef JSFunction_h
#define JSFunction_h
+#include "InternalFunction.h"
#include "JSObject.h"
namespace JSC {
@@ -54,8 +55,7 @@ namespace JSC {
public:
typedef JSNonFinalObject Base;
- JS_EXPORT_PRIVATE static JSFunction* create(ExecState*, JSGlobalObject*, int length, const Identifier& name, NativeFunction nativeFunction, NativeFunction nativeConstructor = callHostFunctionAsConstructor);
- static JSFunction* create(ExecState*, JSGlobalObject*, int length, const Identifier& name, NativeExecutable* nativeExecutable);
+ JS_EXPORT_PRIVATE static JSFunction* create(ExecState*, JSGlobalObject*, int length, const Identifier& name, NativeFunction nativeFunction, Intrinsic = NoIntrinsic, NativeFunction nativeConstructor = callHostFunctionAsConstructor);
static JSFunction* create(ExecState* exec, FunctionExecutable* executable, ScopeChainNode* scopeChain)
{
@@ -154,12 +154,9 @@ namespace JSC {
WriteBarrier<ScopeChainNode> m_scopeChain;
};
- JSFunction* asFunction(JSValue);
-
- inline JSFunction* asFunction(JSValue value)
+ inline bool JSValue::isFunction() const
{
- ASSERT(asObject(value)->inherits(&JSFunction::s_info));
- return static_cast<JSFunction*>(asObject(value));
+ return isCell() && (asCell()->inherits(&JSFunction::s_info) || asCell()->inherits(&InternalFunction::s_info));
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
index f138e75fb..b08c7dfa2 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -40,7 +40,6 @@
#include "JSActivation.h"
#include "JSAPIValueWrapper.h"
#include "JSArray.h"
-#include "JSByteArray.h"
#include "JSClassRef.h"
#include "JSFunction.h"
#include "JSLock.h"
@@ -62,33 +61,12 @@
#include "RegExp.h"
#endif
-#if PLATFORM(MAC)
+#if USE(CF)
#include <CoreFoundation/CoreFoundation.h>
#endif
using namespace WTF;
-namespace {
-
-using namespace JSC;
-
-class Recompiler : public MarkedBlock::VoidFunctor {
-public:
- void operator()(JSCell*);
-};
-
-inline void Recompiler::operator()(JSCell* cell)
-{
- if (!cell->inherits(&JSFunction::s_info))
- return;
- JSFunction* function = asFunction(cell);
- if (!function->executable() || function->executable()->isHostFunction())
- return;
- function->jsExecutable()->discardCode();
-}
-
-} // namespace
-
namespace JSC {
extern const HashTable arrayConstructorTable;
@@ -110,8 +88,34 @@ extern const HashTable regExpPrototypeTable;
extern const HashTable stringTable;
extern const HashTable stringConstructorTable;
+#if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
+static bool enableAssembler(ExecutableAllocator& executableAllocator)
+{
+ if (!executableAllocator.isValid() || !Options::useJIT)
+ return false;
+
+#if USE(CF)
+ CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman);
+ CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication);
+ if (canUseJIT) {
+ return kCFBooleanTrue == canUseJIT;
+ CFRelease(canUseJIT);
+ }
+ CFRelease(canUseJITKey);
+#endif
+
+#if USE(CF) || OS(UNIX)
+ char* canUseJITString = getenv("JavaScriptCoreUseJIT");
+ return !canUseJITString || atoi(canUseJITString);
+#else
+ return true;
+#endif
+}
+#endif
+
JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType, HeapSize heapSize)
- : globalDataType(globalDataType)
+ : heap(this, heapSize)
+ , globalDataType(globalDataType)
, clientData(0)
, topCallFrame(CallFrame::noCaller())
, arrayConstructorTable(fastNew<HashTable>(JSC::arrayConstructorTable))
@@ -141,7 +145,6 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread
, parserArena(adoptPtr(new ParserArena))
, keywords(adoptPtr(new Keywords(this)))
, interpreter(0)
- , heap(this, heapSize)
, jsArrayClassInfo(&JSArray::s_info)
, jsFinalObjectClassInfo(&JSFinalObject::s_info)
#if ENABLE(DFG_JIT)
@@ -160,8 +163,11 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread
#if CPU(X86) && ENABLE(JIT)
, m_timeoutCount(512)
#endif
+#if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
+ , m_canUseAssembler(enableAssembler(executableAllocator))
+#endif
#if ENABLE(GC_VALIDATION)
- , m_isInitializingObject(false)
+ , m_initializingObjectClass(0)
#endif
, m_inDefineOwnProperty(false)
{
@@ -193,33 +199,7 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread
wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
-#if ENABLE(JIT) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
-#if USE(CF)
- CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman);
- CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication);
- if (canUseJIT) {
- m_canUseJIT = kCFBooleanTrue == canUseJIT;
- CFRelease(canUseJIT);
- } else {
- char* canUseJITString = getenv("JavaScriptCoreUseJIT");
- m_canUseJIT = !canUseJITString || atoi(canUseJITString);
- }
- CFRelease(canUseJITKey);
-#elif OS(UNIX)
- char* canUseJITString = getenv("JavaScriptCoreUseJIT");
- m_canUseJIT = !canUseJITString || atoi(canUseJITString);
-#else
- m_canUseJIT = true;
-#endif
-#endif
#if ENABLE(JIT)
-#if ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT)
- if (m_canUseJIT)
- m_canUseJIT = executableAllocator.isValid();
-
- if (!Options::useJIT)
- m_canUseJIT = false;
-#endif
jitStubs = adoptPtr(new JITThunks(this));
#endif
@@ -232,38 +212,13 @@ JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType thread
llintData.performAssertions(*this);
}
-void JSGlobalData::clearBuiltinStructures()
-{
- structureStructure.clear();
- debuggerActivationStructure.clear();
- activationStructure.clear();
- interruptedExecutionErrorStructure.clear();
- terminatedExecutionErrorStructure.clear();
- staticScopeStructure.clear();
- strictEvalActivationStructure.clear();
- stringStructure.clear();
- notAnObjectStructure.clear();
- propertyNameIteratorStructure.clear();
- getterSetterStructure.clear();
- apiWrapperStructure.clear();
- scopeChainNodeStructure.clear();
- executableStructure.clear();
- nativeExecutableStructure.clear();
- evalExecutableStructure.clear();
- programExecutableStructure.clear();
- functionExecutableStructure.clear();
- regExpStructure.clear();
- structureChainStructure.clear();
-}
-
JSGlobalData::~JSGlobalData()
{
- // By the time this is destroyed, heap.destroy() must already have been called.
+ heap.lastChanceToFinalize();
delete interpreter;
#ifndef NDEBUG
- // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance.
- interpreter = 0;
+ interpreter = reinterpret_cast<Interpreter*>(0xbbadbeef);
#endif
arrayPrototypeTable->deleteTable();
@@ -443,15 +398,6 @@ void JSGlobalData::dumpSampleData(ExecState* exec)
#endif
}
-void JSGlobalData::recompileAllJSFunctions()
-{
- // If JavaScript is running, it's not safe to recompile, since we'll end
- // up throwing away code that is live on the stack.
- ASSERT(!dynamicGlobalObject);
-
- heap.objectSpace().forEachCell<Recompiler>();
-}
-
struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor {
HashSet<FunctionExecutable*> currentlyExecutingFunctions;
void operator()(JSCell* cell)
@@ -478,7 +424,7 @@ void JSGlobalData::releaseExecutableMemory()
if (cell->inherits(&ScriptExecutable::s_info))
executable = static_cast<ScriptExecutable*>(*ptr);
else if (cell->inherits(&JSFunction::s_info)) {
- JSFunction* function = asFunction(*ptr);
+ JSFunction* function = jsCast<JSFunction*>(*ptr);
if (function->isHostFunction())
continue;
executable = function->jsExecutable();
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h
index acbcee816..177d80298 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalData.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.h
@@ -152,6 +152,8 @@ namespace JSC {
void makeUsableFromMultipleThreads() { heap.machineThreads().makeUsableFromMultipleThreads(); }
+ Heap heap; // The heap is our first data member to ensure that it's destructed after all the objects that reference it.
+
GlobalDataType globalDataType;
ClientData* clientData;
CallFrame* topCallFrame;
@@ -234,7 +236,15 @@ namespace JSC {
#elif !ENABLE(CLASSIC_INTERPRETER) && !ENABLE(LLINT)
bool canUseJIT() { return true; } // jit only
#else
- bool canUseJIT() { return m_canUseJIT; }
+ bool canUseJIT() { return m_canUseAssembler; }
+#endif
+
+#if !ENABLE(YARR_JIT)
+ bool canUseRegExpJIT() { return false; } // interpreter only
+#elif !ENABLE(CLASSIC_INTERPRETER) && !ENABLE(LLINT)
+ bool canUseRegExpJIT() { return true; } // jit only
+#else
+ bool canUseRegExpJIT() { return m_canUseAssembler; }
#endif
OwnPtr<ParserArena> parserArena;
@@ -252,7 +262,6 @@ namespace JSC {
TimeoutChecker timeoutChecker;
Terminator terminator;
- Heap heap;
JSValue exception;
@@ -324,20 +333,18 @@ namespace JSC {
JS_EXPORT_PRIVATE void startSampling();
JS_EXPORT_PRIVATE void stopSampling();
JS_EXPORT_PRIVATE void dumpSampleData(ExecState* exec);
- void recompileAllJSFunctions();
RegExpCache* regExpCache() { return m_regExpCache; }
#if ENABLE(REGEXP_TRACING)
void addRegExpToTrace(PassRefPtr<RegExp> regExp);
#endif
JS_EXPORT_PRIVATE void dumpRegExpTrace();
- JS_EXPORT_PRIVATE void clearBuiltinStructures();
bool isCollectorBusy() { return heap.isBusy(); }
JS_EXPORT_PRIVATE void releaseExecutableMemory();
#if ENABLE(GC_VALIDATION)
bool isInitializingObject() const;
- void setInitializingObject(bool);
+ void setInitializingObjectClass(const ClassInfo*);
#endif
#if CPU(X86) && ENABLE(JIT)
@@ -369,11 +376,11 @@ namespace JSC {
JSGlobalData(GlobalDataType, ThreadStackType, HeapSize);
static JSGlobalData*& sharedInstanceInternal();
void createNativeThunk();
-#if ENABLE(JIT) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
- bool m_canUseJIT;
+#if ENABLE(ASSEMBLER) && (ENABLE(CLASSIC_INTERPRETER) || ENABLE(LLINT))
+ bool m_canUseAssembler;
#endif
#if ENABLE(GC_VALIDATION)
- bool m_isInitializingObject;
+ const ClassInfo* m_initializingObjectClass;
#endif
bool m_inDefineOwnProperty;
@@ -391,12 +398,12 @@ namespace JSC {
#if ENABLE(GC_VALIDATION)
inline bool JSGlobalData::isInitializingObject() const
{
- return m_isInitializingObject;
+ return !!m_initializingObjectClass;
}
- inline void JSGlobalData::setInitializingObject(bool initializingObject)
+ inline void JSGlobalData::setInitializingObjectClass(const ClassInfo* initializingObjectClass)
{
- m_isInitializingObject = initializingObject;
+ m_initializingObjectClass = initializingObjectClass;
}
#endif
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
index 8d3975848..0f74a8061 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
@@ -133,8 +133,7 @@ void JSGlobalObject::init(JSObject* thisValue)
structure()->disableSpecificFunctionTracking();
- m_globalData = Heap::heap(this)->globalData();
- m_globalScopeChain.set(*m_globalData, this, ScopeChainNode::create(0, this, m_globalData.get(), this, thisValue));
+ m_globalScopeChain.set(globalData(), this, ScopeChainNode::create(0, this, &globalData(), this, thisValue));
JSGlobalObject::globalExec()->init(0, 0, m_globalScopeChain.get(), CallFrame::noCaller(), 0, 0);
@@ -460,7 +459,7 @@ DynamicGlobalObjectScope::DynamicGlobalObjectScope(JSGlobalData& globalData, JSG
if (!m_dynamicGlobalObjectSlot) {
#if ENABLE(ASSEMBLER)
if (ExecutableAllocator::underMemoryPressure())
- globalData.recompileAllJSFunctions();
+ globalData.heap.discardAllCompiledCode();
#endif
m_dynamicGlobalObjectSlot = dynamicGlobalObject;
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h
index cbc436e1a..d9fc81dc4 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObject.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h
@@ -86,8 +86,6 @@ namespace JSC {
protected:
- RefPtr<JSGlobalData> m_globalData;
-
size_t m_registerArraySize;
Register m_globalCallFrame[RegisterFile::CallFrameHeaderSize];
@@ -302,7 +300,7 @@ namespace JSC {
void resetPrototype(JSGlobalData&, JSValue prototype);
- JSGlobalData& globalData() const { return *m_globalData.get(); }
+ JSGlobalData& globalData() const { return *Heap::heap(this)->globalData(); }
static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
{
@@ -358,7 +356,7 @@ namespace JSC {
inline JSGlobalObject* asGlobalObject(JSValue value)
{
ASSERT(asObject(value)->isGlobalObject());
- return static_cast<JSGlobalObject*>(asObject(value));
+ return jsCast<JSGlobalObject*>(asObject(value));
}
inline void JSGlobalObject::setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count)
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
index 75789e602..e8017b904 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
@@ -1,7 +1,7 @@
/*
* Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
- * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
* Copyright (C) 2007 Maks Orlovich
*
@@ -295,17 +295,20 @@ static double parseInt(const UString& s, const CharType* data, int radix)
number += digit;
++p;
}
- if (number >= mantissaOverflowLowerBound) {
- if (radix == 10)
- number = WTF::strtod<WTF::AllowTrailingJunk>(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), 0);
- else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
- number = parseIntOverflow(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), p - firstDigitPosition, radix);
- }
// 12. If Z is empty, return NaN.
if (!sawDigit)
return std::numeric_limits<double>::quiet_NaN();
+ // Alternate code path for certain large numbers.
+ if (number >= mantissaOverflowLowerBound) {
+ if (radix == 10) {
+ size_t parsedLength;
+ number = parseDouble(s.characters() + firstDigitPosition, p - firstDigitPosition, parsedLength);
+ } else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
+ number = parseIntOverflow(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), p - firstDigitPosition, radix);
+ }
+
// 15. Return sign x number.
return sign * number;
}
@@ -361,20 +364,10 @@ static double jsStrDecimalLiteral(const CharType*& data, const CharType* end)
{
ASSERT(data < end);
- // Copy the sting into a null-terminated byte buffer, and call strtod.
- Vector<char, 32> byteBuffer;
- for (const CharType* characters = data; characters < end; ++characters) {
- CharType character = *characters;
- byteBuffer.append(isASCII(character) ? static_cast<char>(character) : 0);
- }
- byteBuffer.append(0);
- char* endOfNumber;
- double number = WTF::strtod<WTF::AllowTrailingJunk>(byteBuffer.data(), &endOfNumber);
-
- // Check if strtod found a number; if so return it.
- ptrdiff_t consumed = endOfNumber - byteBuffer.data();
- if (consumed) {
- data += consumed;
+ size_t parsedLength;
+ double number = parseDouble(data, end - data, parsedLength);
+ if (parsedLength) {
+ data += parsedLength;
return number;
}
@@ -505,7 +498,7 @@ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
{
JSObject* thisObject = exec->hostThisValue().toThisObject(exec);
JSObject* unwrappedObject = thisObject->unwrappedObject();
- if (!unwrappedObject->isGlobalObject() || static_cast<JSGlobalObject*>(unwrappedObject)->evalFunction() != exec->callee())
+ if (!unwrappedObject->isGlobalObject() || jsCast<JSGlobalObject*>(unwrappedObject)->evalFunction() != exec->callee())
return throwVMError(exec, createEvalError(exec, "The \"this\" value passed to eval must be the global object from which eval originated"));
JSValue x = exec->argument(0);
@@ -525,11 +518,11 @@ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
}
EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false);
- JSObject* error = eval->compile(exec, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain());
+ JSObject* error = eval->compile(exec, jsCast<JSGlobalObject*>(unwrappedObject)->globalScopeChain());
if (error)
return throwVMError(exec, error);
- return JSValue::encode(exec->interpreter()->execute(eval, exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain()));
+ return JSValue::encode(exec->interpreter()->execute(eval, exec, thisObject, jsCast<JSGlobalObject*>(unwrappedObject)->globalScopeChain()));
}
EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec)
diff --git a/Source/JavaScriptCore/runtime/JSGlobalThis.cpp b/Source/JavaScriptCore/runtime/JSGlobalThis.cpp
index 8b2a7a1ef..abd31ac14 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalThis.cpp
+++ b/Source/JavaScriptCore/runtime/JSGlobalThis.cpp
@@ -48,9 +48,12 @@ void JSGlobalThis::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitor.append(&thisObject->m_unwrappedObject);
}
-JSGlobalObject* JSGlobalThis::unwrappedObject()
+void JSGlobalThis::setUnwrappedObject(JSGlobalData& globalData, JSGlobalObject* globalObject)
{
- return m_unwrappedObject.get();
+ ASSERT_ARG(globalObject, globalObject);
+ m_unwrappedObject.set(globalData, this, globalObject);
+ setPrototype(globalData, globalObject->prototype());
+ resetInheritorID();
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGlobalThis.h b/Source/JavaScriptCore/runtime/JSGlobalThis.h
index fa5c2eb34..0ca99414a 100644
--- a/Source/JavaScriptCore/runtime/JSGlobalThis.h
+++ b/Source/JavaScriptCore/runtime/JSGlobalThis.h
@@ -48,7 +48,7 @@ public:
static JS_EXPORTDATA const JSC::ClassInfo s_info;
- JSGlobalObject* unwrappedObject();
+ JSGlobalObject* unwrappedObject() const { return m_unwrappedObject.get(); }
protected:
JSGlobalThis(JSGlobalData& globalData, Structure* structure)
@@ -65,6 +65,9 @@ protected:
JS_EXPORT_PRIVATE static void visitChildren(JSCell*, SlotVisitor&);
+ JS_EXPORT_PRIVATE void setUnwrappedObject(JSGlobalData&, JSGlobalObject*);
+
+private:
WriteBarrier<JSGlobalObject> m_unwrappedObject;
};
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
index 1bdb90ff6..500f3891a 100644
--- a/Source/JavaScriptCore/runtime/JSObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -203,7 +203,7 @@ bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prot
{
JSValue checkFor = this;
if (this->isGlobalObject())
- checkFor = static_cast<JSGlobalObject*>(this)->globalExec()->thisValue();
+ checkFor = jsCast<JSGlobalObject*>(this)->globalExec()->thisValue();
JSValue nextPrototype = prototype;
while (nextPrototype && nextPrototype.isObject()) {
@@ -217,7 +217,7 @@ bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prot
bool JSObject::allowsAccessFrom(ExecState* exec)
{
- JSGlobalObject* globalObject = isGlobalThis() ? static_cast<JSGlobalThis*>(this)->unwrappedObject() : this->globalObject();
+ JSGlobalObject* globalObject = isGlobalThis() ? jsCast<JSGlobalThis*>(this)->unwrappedObject() : this->globalObject();
return globalObject->globalObjectMethodTable()->allowsAccessFrom(globalObject, exec);
}
@@ -445,13 +445,13 @@ JSString* JSObject::toString(ExecState* exec) const
JSObject* JSObject::toThisObject(JSCell* cell, ExecState*)
{
- return static_cast<JSObject*>(cell);
+ return jsCast<JSObject*>(cell);
}
JSObject* JSObject::unwrappedObject()
{
if (isGlobalThis())
- return static_cast<JSGlobalThis*>(this)->unwrappedObject();
+ return jsCast<JSGlobalThis*>(this)->unwrappedObject();
return this;
}
@@ -541,12 +541,18 @@ NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, WriteBarr
Structure* JSObject::createInheritorID(JSGlobalData& globalData)
{
- m_inheritorID.set(globalData, this, createEmptyObjectStructure(globalData, structure()->globalObject(), this));
+ JSGlobalObject* globalObject;
+ if (isGlobalThis())
+ globalObject = static_cast<JSGlobalThis*>(this)->unwrappedObject();
+ else
+ globalObject = structure()->globalObject();
+ ASSERT(globalObject);
+ m_inheritorID.set(globalData, this, createEmptyObjectStructure(globalData, globalObject, this));
ASSERT(m_inheritorID->isEmpty());
return m_inheritorID.get();
}
-void JSObject::allocatePropertyStorage(JSGlobalData& globalData, size_t oldSize, size_t newSize)
+PropertyStorage JSObject::growPropertyStorage(JSGlobalData& globalData, size_t oldSize, size_t newSize)
{
ASSERT(newSize > oldSize);
@@ -574,7 +580,7 @@ void JSObject::allocatePropertyStorage(JSGlobalData& globalData, size_t oldSize,
}
ASSERT(newPropertyStorage);
- m_propertyStorage.set(globalData, this, newPropertyStorage);
+ return newPropertyStorage;
}
bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
index 3f3d281cf..d95860d62 100644
--- a/Source/JavaScriptCore/runtime/JSObject.h
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -212,8 +212,9 @@ namespace JSC {
bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
void reifyStaticFunctionsForDelete(ExecState* exec);
- JS_EXPORT_PRIVATE void allocatePropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize);
+ JS_EXPORT_PRIVATE PropertyStorage growPropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize);
bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage.get()) == static_cast<const void*>(this + 1); }
+ void setPropertyStorage(JSGlobalData&, PropertyStorage, Structure*);
void* addressOfPropertyStorage()
{
@@ -263,6 +264,11 @@ namespace JSC {
// To instantiate objects you likely want JSFinalObject, below.
// To create derived types you likely want JSNonFinalObject, below.
JSObject(JSGlobalData&, Structure*, PropertyStorage inlineStorage);
+
+ void resetInheritorID()
+ {
+ m_inheritorID.clear();
+ }
private:
friend class LLIntOffsetsExtractor;
@@ -447,6 +453,14 @@ inline bool JSObject::isGlobalThis() const
return structure()->typeInfo().type() == GlobalThisType;
}
+inline void JSObject::setPropertyStorage(JSGlobalData& globalData, PropertyStorage storage, Structure* structure)
+{
+ ASSERT(storage);
+ ASSERT(structure);
+ setStructure(globalData, structure);
+ m_propertyStorage.set(globalData, this, storage);
+}
+
inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
{
return JSFinalObject::create(exec, structure);
@@ -474,7 +488,7 @@ inline Structure* createEmptyObjectStructure(JSGlobalData& globalData, JSGlobalO
inline JSObject* asObject(JSCell* cell)
{
ASSERT(cell->isObject());
- return static_cast<JSObject*>(cell);
+ return jsCast<JSObject*>(cell);
}
inline JSObject* asObject(JSValue value)
@@ -658,10 +672,11 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi
if ((mode == PutModePut) && !isExtensible())
return false;
- size_t currentCapacity = structure()->propertyStorageCapacity();
+ PropertyStorage newStorage = propertyStorage();
+ if (structure()->shouldGrowPropertyStorage())
+ newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction);
- if (currentCapacity != structure()->propertyStorageCapacity())
- allocatePropertyStorage(globalData, currentCapacity, structure()->propertyStorageCapacity());
+ setPropertyStorage(globalData, newStorage, structure());
ASSERT(offset < structure()->propertyStorageCapacity());
putDirectOffset(globalData, offset, value);
@@ -673,12 +688,13 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi
size_t offset;
size_t currentCapacity = structure()->propertyStorageCapacity();
- if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) {
+ if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) {
+ PropertyStorage newStorage = propertyStorage();
if (currentCapacity != structure->propertyStorageCapacity())
- allocatePropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity());
+ newStorage = growPropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity());
ASSERT(offset < structure->propertyStorageCapacity());
- setStructure(globalData, structure);
+ setPropertyStorage(globalData, newStorage, structure);
putDirectOffset(globalData, offset, value);
// This is a new property; transitions with specific values are not currently cachable,
// so leave the slot in an uncachable state.
@@ -722,13 +738,14 @@ inline bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi
if ((mode == PutModePut) && !isExtensible())
return false;
- Structure* structure = Structure::addPropertyTransition(globalData, this->structure(), propertyName, attributes, specificFunction, offset);
+ PropertyStorage newStorage = propertyStorage();
+ if (structure()->shouldGrowPropertyStorage())
+ newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
- if (currentCapacity != structure->propertyStorageCapacity())
- allocatePropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity());
+ Structure* structure = Structure::addPropertyTransition(globalData, this->structure(), propertyName, attributes, specificFunction, offset);
ASSERT(offset < structure->propertyStorageCapacity());
- setStructure(globalData, structure);
+ setPropertyStorage(globalData, newStorage, structure);
putDirectOffset(globalData, offset, value);
// This is a new property; transitions with specific values are not currently cachable,
// so leave the slot in an uncachable state.
@@ -762,18 +779,20 @@ inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& prop
inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
{
ASSERT(!value.isGetterSetter() && !(attributes & Accessor));
- size_t currentCapacity = structure()->propertyStorageCapacity();
+ PropertyStorage newStorage = propertyStorage();
+ if (structure()->shouldGrowPropertyStorage())
+ newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), structure()->suggestedNewPropertyStorageSize());
size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getJSFunction(value));
- if (currentCapacity != structure()->propertyStorageCapacity())
- allocatePropertyStorage(globalData, currentCapacity, structure()->propertyStorageCapacity());
+ setPropertyStorage(globalData, newStorage, structure());
putDirectOffset(globalData, offset, value);
}
inline void JSObject::transitionTo(JSGlobalData& globalData, Structure* newStructure)
{
+ PropertyStorage newStorage = propertyStorage();
if (structure()->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
- allocatePropertyStorage(globalData, structure()->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
- setStructure(globalData, newStructure);
+ newStorage = growPropertyStorage(globalData, structure()->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
+ setPropertyStorage(globalData, newStorage, newStructure);
}
inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
index 7530d7532..5b65e59f2 100644
--- a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
+++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
@@ -121,7 +121,7 @@ namespace JSC {
ALWAYS_INLINE JSPropertyNameIterator* Register::propertyNameIterator() const
{
- return static_cast<JSPropertyNameIterator*>(jsValue().asCell());
+ return jsCast<JSPropertyNameIterator*>(jsValue().asCell());
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp
index e84ce3620..904cc4d3e 100644
--- a/Source/JavaScriptCore/runtime/JSString.cpp
+++ b/Source/JavaScriptCore/runtime/JSString.cpp
@@ -36,9 +36,9 @@ static const unsigned substringFromRopeCutoff = 4;
const ClassInfo JSString::s_info = { "string", 0, 0, 0, CREATE_METHOD_TABLE(JSString) };
-void JSString::RopeBuilder::expand()
+void JSRopeString::RopeBuilder::expand()
{
- ASSERT(m_index == JSString::s_maxInternalRopeLength);
+ ASSERT(m_index == JSRopeString::s_maxInternalRopeLength);
JSString* jsString = m_jsString;
m_jsString = jsStringBuilder(&m_globalData);
m_index = 0;
@@ -55,11 +55,18 @@ void JSString::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
JSString* thisObject = jsCast<JSString*>(cell);
Base::visitChildren(thisObject, visitor);
- for (size_t i = 0; i < s_maxInternalRopeLength && thisObject->m_fibers[i]; ++i)
- visitor.append(&thisObject->m_fibers[i]);
+
+ if (thisObject->isRope())
+ static_cast<JSRopeString*>(thisObject)->visitFibers(visitor);
+}
+
+void JSRopeString::visitFibers(SlotVisitor& visitor)
+{
+ for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i)
+ visitor.append(&m_fibers[i]);
}
-void JSString::resolveRope(ExecState* exec) const
+void JSRopeString::resolveRope(ExecState* exec) const
{
ASSERT(isRope());
@@ -128,7 +135,7 @@ void JSString::resolveRope(ExecState* exec) const
// Vector before performing any concatenation, but by working backwards we likely
// only fill the queue with the number of substrings at any given level in a
// rope-of-ropes.)
-void JSString::resolveRopeSlowCase8(LChar* buffer) const
+void JSRopeString::resolveRopeSlowCase8(LChar* buffer) const
{
LChar* position = buffer + m_length; // We will be working backwards over the rope.
Vector<JSString*, 32> workQueue; // Putting strings into a Vector is only OK because there are no GC points in this method.
@@ -144,8 +151,9 @@ void JSString::resolveRopeSlowCase8(LChar* buffer) const
workQueue.removeLast();
if (currentFiber->isRope()) {
- for (size_t i = 0; i < s_maxInternalRopeLength && currentFiber->m_fibers[i]; ++i)
- workQueue.append(currentFiber->m_fibers[i].get());
+ JSRopeString* currentFiberAsRope = static_cast<JSRopeString*>(currentFiber);
+ for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->m_fibers[i]; ++i)
+ workQueue.append(currentFiberAsRope->m_fibers[i].get());
continue;
}
@@ -159,7 +167,7 @@ void JSString::resolveRopeSlowCase8(LChar* buffer) const
ASSERT(!isRope());
}
-void JSString::resolveRopeSlowCase(UChar* buffer) const
+void JSRopeString::resolveRopeSlowCase(UChar* buffer) const
{
UChar* position = buffer + m_length; // We will be working backwards over the rope.
Vector<JSString*, 32> workQueue; // These strings are kept alive by the parent rope, so using a Vector is OK.
@@ -172,8 +180,9 @@ void JSString::resolveRopeSlowCase(UChar* buffer) const
workQueue.removeLast();
if (currentFiber->isRope()) {
- for (size_t i = 0; i < s_maxInternalRopeLength && currentFiber->m_fibers[i]; ++i)
- workQueue.append(currentFiber->m_fibers[i].get());
+ JSRopeString* currentFiberAsRope = static_cast<JSRopeString*>(currentFiber);
+ for (size_t i = 0; i < s_maxInternalRopeLength && currentFiberAsRope->m_fibers[i]; ++i)
+ workQueue.append(currentFiberAsRope->m_fibers[i].get());
continue;
}
@@ -187,7 +196,7 @@ void JSString::resolveRopeSlowCase(UChar* buffer) const
ASSERT(!isRope());
}
-void JSString::outOfMemory(ExecState* exec) const
+void JSRopeString::outOfMemory(ExecState* exec) const
{
for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i)
m_fibers[i].clear();
@@ -197,7 +206,7 @@ void JSString::outOfMemory(ExecState* exec) const
throwOutOfMemoryError(exec);
}
-JSString* JSString::getIndexSlowCase(ExecState* exec, unsigned i)
+JSString* JSRopeString::getIndexSlowCase(ExecState* exec, unsigned i)
{
ASSERT(isRope());
resolveRope(exec);
diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h
index 32a32788a..10ec799e5 100644
--- a/Source/JavaScriptCore/runtime/JSString.h
+++ b/Source/JavaScriptCore/runtime/JSString.h
@@ -32,6 +32,7 @@
namespace JSC {
class JSString;
+ class JSRopeString;
class LLIntOffsetsExtractor;
JSString* jsEmptyString(JSGlobalData*);
@@ -58,55 +59,20 @@ namespace JSC {
JSString* jsOwnedString(JSGlobalData*, const UString&);
JSString* jsOwnedString(ExecState*, const UString&);
- JSString* jsStringBuilder(JSGlobalData*);
+ JSRopeString* jsStringBuilder(JSGlobalData*);
class JSString : public JSCell {
public:
friend class JIT;
friend class JSGlobalData;
friend class SpecializedThunkJIT;
+ friend class JSRopeString;
friend struct ThunkHelpers;
- friend JSString* jsStringBuilder(JSGlobalData*);
typedef JSCell Base;
static void destroy(JSCell*);
- class RopeBuilder {
- public:
- RopeBuilder(JSGlobalData& globalData)
- : m_globalData(globalData)
- , m_jsString(jsStringBuilder(&globalData))
- , m_index(0)
- {
- }
-
- void append(JSString* jsString)
- {
- if (m_index == JSString::s_maxInternalRopeLength)
- expand();
- m_jsString->m_fibers[m_index++].set(m_globalData, m_jsString, jsString);
- m_jsString->m_length += jsString->m_length;
- m_jsString->m_is8Bit = m_jsString->m_is8Bit && jsString->m_is8Bit;
- }
-
- JSString* release()
- {
- JSString* tmp = m_jsString;
- m_jsString = 0;
- return tmp;
- }
-
- unsigned length() { return m_jsString->m_length; }
-
- private:
- void expand();
-
- JSGlobalData& m_globalData;
- JSString* m_jsString;
- size_t m_index;
- };
-
private:
JSString(JSGlobalData& globalData, PassRefPtr<StringImpl> value)
: JSCell(globalData, globalData.stringStructure.get())
@@ -119,13 +85,6 @@ namespace JSC {
{
}
- void finishCreation(JSGlobalData& globalData)
- {
- Base::finishCreation(globalData);
- m_length = 0;
- m_is8Bit = true;
- }
-
void finishCreation(JSGlobalData& globalData, size_t length)
{
ASSERT(!m_value.isNull());
@@ -143,32 +102,14 @@ namespace JSC {
Heap::heap(this)->reportExtraMemoryCost(cost);
}
- void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2)
- {
- Base::finishCreation(globalData);
- m_length = s1->length() + s2->length();
- m_is8Bit = (s1->is8Bit() && s2->is8Bit());
- m_fibers[0].set(globalData, this, s1);
- m_fibers[1].set(globalData, this, s2);
- }
-
- void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3)
+ protected:
+ void finishCreation(JSGlobalData& globalData)
{
Base::finishCreation(globalData);
- m_length = s1->length() + s2->length() + s3->length();
- m_is8Bit = (s1->is8Bit() && s2->is8Bit() && s3->is8Bit());
- m_fibers[0].set(globalData, this, s1);
- m_fibers[1].set(globalData, this, s2);
- m_fibers[2].set(globalData, this, s3);
- }
-
- static JSString* createNull(JSGlobalData& globalData)
- {
- JSString* newString = new (NotNull, allocateCell<JSString>(globalData.heap)) JSString(globalData);
- newString->finishCreation(globalData);
- return newString;
+ m_length = 0;
+ m_is8Bit = true;
}
-
+
public:
static JSString* create(JSGlobalData& globalData, PassRefPtr<StringImpl> value)
{
@@ -179,18 +120,6 @@ namespace JSC {
newString->finishCreation(globalData, length, cost);
return newString;
}
- static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2)
- {
- JSString* newString = new (NotNull, allocateCell<JSString>(globalData.heap)) JSString(globalData);
- newString->finishCreation(globalData, s1, s2);
- return newString;
- }
- static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3)
- {
- JSString* newString = new (NotNull, allocateCell<JSString>(globalData.heap)) JSString(globalData);
- newString->finishCreation(globalData, s1, s2, s3);
- return newString;
- }
static JSString* createHasOtherOwner(JSGlobalData& globalData, PassRefPtr<StringImpl> value)
{
ASSERT(value);
@@ -200,18 +129,8 @@ namespace JSC {
return newString;
}
- const UString& value(ExecState* exec) const
- {
- if (isRope())
- resolveRope(exec);
- return m_value;
- }
- const UString& tryGetValue() const
- {
- if (isRope())
- resolveRope(0);
- return m_value;
- }
+ const UString& value(ExecState*) const;
+ const UString& tryGetValue() const;
unsigned length() { return m_length; }
JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
@@ -226,7 +145,6 @@ namespace JSC {
bool canGetIndex(unsigned i) { return i < m_length; }
JSString* getIndex(ExecState*, unsigned);
- JSString* getIndexSlowCase(ExecState*, unsigned);
static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
{
@@ -240,44 +158,145 @@ namespace JSC {
static void visitChildren(JSCell*, SlotVisitor&);
+ protected:
+ bool isRope() const { return m_value.isNull(); }
+ bool is8Bit() const { return m_is8Bit; }
+
+ // A string is represented either by a UString or a rope of fibers.
+ bool m_is8Bit : 1;
+ unsigned m_length;
+ mutable UString m_value;
+
private:
friend class LLIntOffsetsExtractor;
- JS_EXPORT_PRIVATE void resolveRope(ExecState*) const;
- void resolveRopeSlowCase8(LChar*) const;
- void resolveRopeSlowCase(UChar*) const;
- void outOfMemory(ExecState*) const;
-
static JSObject* toThisObject(JSCell*, ExecState*);
// Actually getPropertySlot, not getOwnPropertySlot (see JSCell).
static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
- static const unsigned s_maxInternalRopeLength = 3;
-
- // A string is represented either by a UString or a rope of fibers.
- bool m_is8Bit : 1;
- unsigned m_length;
- mutable UString m_value;
- mutable FixedArray<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers;
-
- bool isRope() const { return m_value.isNull(); }
- bool is8Bit() const { return m_is8Bit; }
UString& string() { ASSERT(!isRope()); return m_value; }
friend JSValue jsString(ExecState*, JSString*, JSString*);
- friend JSValue jsString(ExecState*, Register*, unsigned count);
- friend JSValue jsStringFromArguments(ExecState*, JSValue thisValue);
friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length);
};
+ class JSRopeString : public JSString {
+ friend class JSString;
+
+ friend JSRopeString* jsStringBuilder(JSGlobalData*);
+
+ class RopeBuilder {
+ public:
+ RopeBuilder(JSGlobalData& globalData)
+ : m_globalData(globalData)
+ , m_jsString(jsStringBuilder(&globalData))
+ , m_index(0)
+ {
+ }
+
+ void append(JSString* jsString)
+ {
+ if (m_index == JSRopeString::s_maxInternalRopeLength)
+ expand();
+ m_jsString->m_fibers[m_index++].set(m_globalData, m_jsString, jsString);
+ m_jsString->m_length += jsString->m_length;
+ m_jsString->m_is8Bit = m_jsString->m_is8Bit && jsString->m_is8Bit;
+ }
+
+ JSRopeString* release()
+ {
+ JSRopeString* tmp = m_jsString;
+ m_jsString = 0;
+ return tmp;
+ }
+
+ unsigned length() { return m_jsString->m_length; }
+
+ private:
+ void expand();
+
+ JSGlobalData& m_globalData;
+ JSRopeString* m_jsString;
+ size_t m_index;
+ };
+
+ private:
+ JSRopeString(JSGlobalData& globalData)
+ : JSString(globalData)
+ {
+ }
+
+ void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2)
+ {
+ Base::finishCreation(globalData);
+ m_length = s1->length() + s2->length();
+ m_is8Bit = (s1->is8Bit() && s2->is8Bit());
+ m_fibers[0].set(globalData, this, s1);
+ m_fibers[1].set(globalData, this, s2);
+ }
+
+ void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3)
+ {
+ Base::finishCreation(globalData);
+ m_length = s1->length() + s2->length() + s3->length();
+ m_is8Bit = (s1->is8Bit() && s2->is8Bit() && s3->is8Bit());
+ m_fibers[0].set(globalData, this, s1);
+ m_fibers[1].set(globalData, this, s2);
+ m_fibers[2].set(globalData, this, s3);
+ }
+
+ void finishCreation(JSGlobalData& globalData)
+ {
+ JSString::finishCreation(globalData);
+ }
+
+ static JSRopeString* createNull(JSGlobalData& globalData)
+ {
+ JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(globalData.heap)) JSRopeString(globalData);
+ newString->finishCreation(globalData);
+ return newString;
+ }
+
+ public:
+ static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2)
+ {
+ JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(globalData.heap)) JSRopeString(globalData);
+ newString->finishCreation(globalData, s1, s2);
+ return newString;
+ }
+ static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3)
+ {
+ JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(globalData.heap)) JSRopeString(globalData);
+ newString->finishCreation(globalData, s1, s2, s3);
+ return newString;
+ }
+
+ void visitFibers(SlotVisitor&);
+
+ private:
+ friend JSValue jsString(ExecState*, Register*, unsigned);
+ friend JSValue jsStringFromArguments(ExecState*, JSValue);
+
+ JS_EXPORT_PRIVATE void resolveRope(ExecState*) const;
+ void resolveRopeSlowCase8(LChar*) const;
+ void resolveRopeSlowCase(UChar*) const;
+ void outOfMemory(ExecState*) const;
+
+ JSString* getIndexSlowCase(ExecState*, unsigned);
+
+ static const unsigned s_maxInternalRopeLength = 3;
+
+ mutable FixedArray<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers;
+ };
+
JSString* asString(JSValue);
inline JSString* asString(JSValue value)
{
ASSERT(value.asCell()->isString());
- return static_cast<JSString*>(value.asCell());
+ return jsCast<JSString*>(value.asCell());
}
inline JSString* jsEmptyString(JSGlobalData* globalData)
@@ -285,14 +304,14 @@ namespace JSC {
return globalData->smallStrings.emptyString(globalData);
}
- inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c)
+ ALWAYS_INLINE JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c)
{
if (c <= maxSingleCharacterString)
return globalData->smallStrings.singleCharacterString(globalData, c);
return JSString::create(*globalData, UString(&c, 1).impl());
}
- inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset)
+ ALWAYS_INLINE JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset)
{
JSGlobalData* globalData = &exec->globalData();
ASSERT(offset < static_cast<unsigned>(s.length()));
@@ -316,11 +335,25 @@ namespace JSC {
return JSString::create(*globalData, s.impl());
}
+ inline const UString& JSString::value(ExecState* exec) const
+ {
+ if (isRope())
+ static_cast<const JSRopeString*>(this)->resolveRope(exec);
+ return m_value;
+ }
+
+ inline const UString& JSString::tryGetValue() const
+ {
+ if (isRope())
+ static_cast<const JSRopeString*>(this)->resolveRope(0);
+ return m_value;
+ }
+
inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
{
ASSERT(canGetIndex(i));
if (isRope())
- return getIndexSlowCase(exec, i);
+ return static_cast<JSRopeString*>(this)->getIndexSlowCase(exec, i);
ASSERT(i < m_value.length());
return jsSingleCharacterSubstring(exec, m_value, i);
}
@@ -392,9 +425,9 @@ namespace JSC {
return JSString::createHasOtherOwner(*globalData, s.impl());
}
- inline JSString* jsStringBuilder(JSGlobalData* globalData)
+ inline JSRopeString* jsStringBuilder(JSGlobalData* globalData)
{
- return JSString::createNull(*globalData);
+ return JSRopeString::createNull(*globalData);
}
inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); }
@@ -458,10 +491,43 @@ namespace JSC {
inline JSString* JSValue::toString(ExecState* exec) const
{
if (isString())
- return static_cast<JSString*>(asCell());
+ return jsCast<JSString*>(asCell());
return toStringSlowCase(exec);
}
+ inline UString JSValue::toUString(ExecState* exec) const
+ {
+ if (isString())
+ return static_cast<JSString*>(asCell())->value(exec);
+ return toUStringSlowCase(exec);
+ }
+
+ ALWAYS_INLINE UString inlineJSValueNotStringtoUString(const JSValue& value, ExecState* exec)
+ {
+ JSGlobalData& globalData = exec->globalData();
+ if (value.isInt32())
+ return globalData.numericStrings.add(value.asInt32());
+ if (value.isDouble())
+ return globalData.numericStrings.add(value.asDouble());
+ if (value.isTrue())
+ return globalData.propertyNames->trueKeyword.ustring();
+ if (value.isFalse())
+ return globalData.propertyNames->falseKeyword.ustring();
+ if (value.isNull())
+ return globalData.propertyNames->nullKeyword.ustring();
+ if (value.isUndefined())
+ return globalData.propertyNames->undefinedKeyword.ustring();
+ return value.toString(exec)->value(exec);
+ }
+
+ ALWAYS_INLINE UString JSValue::toUStringInline(ExecState* exec) const
+ {
+ if (isString())
+ return static_cast<JSString*>(asCell())->value(exec);
+
+ return inlineJSValueNotStringtoUString(*this, exec);
+ }
+
} // namespace JSC
#endif // JSString_h
diff --git a/Source/JavaScriptCore/runtime/JSStringJoiner.cpp b/Source/JavaScriptCore/runtime/JSStringJoiner.cpp
new file mode 100644
index 000000000..ea260243b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSStringJoiner.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2012 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
+ * 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 "JSStringJoiner.h"
+
+#include "ExceptionHelpers.h"
+#include "JSString.h"
+#include "ScopeChain.h"
+#include <wtf/text/StringImpl.h>
+
+
+namespace JSC {
+
+// The destination is 16bits, at least one string is 16 bits.
+static inline void appendStringToData(UChar*& data, const UString& string)
+{
+ if (string.isNull())
+ return;
+
+ unsigned length = string.length();
+ const StringImpl* stringImpl = string.impl();
+
+ if (stringImpl->is8Bit()) {
+ for (unsigned i = 0; i < length; ++i) {
+ *data = stringImpl->characters8()[i];
+ ++data;
+ }
+ } else {
+ for (unsigned i = 0; i < length; ++i) {
+ *data = stringImpl->characters16()[i];
+ ++data;
+ }
+ }
+}
+
+// If the destination is 8bits, we know every string has to be 8bit.
+static inline void appendStringToData(LChar*& data, const UString& string)
+{
+ if (string.isNull())
+ return;
+ ASSERT(string.is8Bit());
+
+ unsigned length = string.length();
+ const StringImpl* stringImpl = string.impl();
+
+ for (unsigned i = 0; i < length; ++i) {
+ *data = stringImpl->characters8()[i];
+ ++data;
+ }
+}
+
+template<typename CharacterType>
+static inline PassRefPtr<StringImpl> joinStrings(const Vector<UString>& strings, const UString& separator, unsigned outputLength)
+{
+ ASSERT(outputLength);
+
+ CharacterType* data;
+ RefPtr<StringImpl> outputStringImpl = StringImpl::tryCreateUninitialized(outputLength, data);
+ if (!outputStringImpl)
+ return PassRefPtr<StringImpl>();
+
+ const UString firstString = strings.first();
+ appendStringToData(data, firstString);
+
+ for (size_t i = 1; i < strings.size(); ++i) {
+ appendStringToData(data, separator);
+ appendStringToData(data, strings[i]);
+ }
+
+ ASSERT(data == (outputStringImpl->getCharacters<CharacterType>() + outputStringImpl->length()));
+ return outputStringImpl.release();
+}
+
+JSValue JSStringJoiner::build(ExecState* exec)
+{
+ if (!m_isValid)
+ return throwOutOfMemoryError(exec);
+
+ if (!m_strings.size())
+ return jsEmptyString(exec);
+
+ size_t separatorLength = m_separator.length();
+ // FIXME: add special cases of joinStrings() for (separatorLength == 0) and (separatorLength == 1).
+ ASSERT(m_strings.size() > 0);
+ size_t totalSeparactorsLength = separatorLength * (m_strings.size() - 1);
+ size_t outputStringSize = totalSeparactorsLength + m_cumulatedStringsLength;
+
+ if (!outputStringSize)
+ return jsEmptyString(exec);
+
+ RefPtr<StringImpl> outputStringImpl;
+ if (m_is8Bits)
+ outputStringImpl = joinStrings<LChar>(m_strings, m_separator, outputStringSize);
+ else
+ outputStringImpl = joinStrings<UChar>(m_strings, m_separator, outputStringSize);
+
+ if (!outputStringImpl)
+ return throwOutOfMemoryError(exec);
+
+ return JSString::create(exec->globalData(), outputStringImpl.release());
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/JSStringJoiner.h b/Source/JavaScriptCore/runtime/JSStringJoiner.h
new file mode 100644
index 000000000..49f846c1f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSStringJoiner.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2012 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
+ * 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 JSStringJoiner_h
+#define JSStringJoiner_h
+
+#include "JSValue.h"
+#include "UString.h"
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+class ExecState;
+
+
+class JSStringJoiner {
+public:
+ JSStringJoiner(const UString& separator, size_t stringCount);
+
+ void append(const UString&);
+ JSValue build(ExecState*);
+
+private:
+ UString m_separator;
+ Vector<UString> m_strings;
+
+ unsigned m_cumulatedStringsLength;
+ bool m_isValid;
+ bool m_is8Bits;
+};
+
+inline JSStringJoiner::JSStringJoiner(const UString& separator, size_t stringCount)
+ : m_separator(separator)
+ , m_cumulatedStringsLength(0)
+ , m_isValid(true)
+ , m_is8Bits(m_separator.is8Bit())
+{
+ ASSERT(!m_separator.isNull());
+ m_isValid = m_strings.tryReserveCapacity(stringCount);
+}
+
+inline void JSStringJoiner::append(const UString& str)
+{
+ if (!m_isValid)
+ return;
+
+ m_strings.uncheckedAppend(str);
+ if (!str.isNull()) {
+ m_cumulatedStringsLength += str.length();
+ m_is8Bits = m_is8Bits && str.is8Bit();
+ }
+}
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp
index 36697c60c..088f214b9 100644
--- a/Source/JavaScriptCore/runtime/JSValue.cpp
+++ b/Source/JavaScriptCore/runtime/JSValue.cpp
@@ -260,19 +260,20 @@ bool JSValue::isValidCallee()
JSString* JSValue::toStringSlowCase(ExecState* exec) const
{
+ JSGlobalData& globalData = exec->globalData();
ASSERT(!isString());
if (isInt32())
- return jsString(&exec->globalData(), exec->globalData().numericStrings.add(asInt32()));
+ return jsString(&globalData, globalData.numericStrings.add(asInt32()));
if (isDouble())
- return jsString(&exec->globalData(), exec->globalData().numericStrings.add(asDouble()));
+ return jsString(&globalData, globalData.numericStrings.add(asDouble()));
if (isTrue())
- return jsNontrivialString(exec, exec->propertyNames().trueKeyword.ustring());
+ return globalData.smallStrings.trueString(&globalData);
if (isFalse())
- return jsNontrivialString(exec, exec->propertyNames().falseKeyword.ustring());
+ return globalData.smallStrings.falseString(&globalData);
if (isNull())
- return jsNontrivialString(exec, exec->propertyNames().nullKeyword.ustring());
+ return globalData.smallStrings.nullString(&globalData);
if (isUndefined())
- return jsNontrivialString(exec, exec->propertyNames().undefined.ustring());
+ return globalData.smallStrings.undefinedString(&globalData);
ASSERT(isCell());
JSValue value = asCell()->toPrimitive(exec, PreferString);
@@ -282,4 +283,9 @@ JSString* JSValue::toStringSlowCase(ExecState* exec) const
return value.toString(exec);
}
+UString JSValue::toUStringSlowCase(ExecState* exec) const
+{
+ return inlineJSValueNotStringtoUString(*this, exec);
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSValue.h
index a6f359360..7facb9353 100644
--- a/Source/JavaScriptCore/runtime/JSValue.h
+++ b/Source/JavaScriptCore/runtime/JSValue.h
@@ -173,6 +173,7 @@ namespace JSC {
// Querying the type.
bool isEmpty() const;
+ bool isFunction() const;
bool isUndefined() const;
bool isNull() const;
bool isUndefinedOrNull() const;
@@ -202,6 +203,8 @@ namespace JSC {
// been set in the ExecState already.
double toNumber(ExecState*) const;
JSString* toString(ExecState*) const;
+ UString toUString(ExecState*) const;
+ UString toUStringInline(ExecState*) const;
JSObject* toObject(ExecState*) const;
JSObject* toObject(ExecState*, JSGlobalObject*) const;
@@ -250,6 +253,7 @@ namespace JSC {
inline const JSValue asValue() const { return *this; }
JS_EXPORT_PRIVATE double toNumberSlowCase(ExecState*) const;
JS_EXPORT_PRIVATE JSString* toStringSlowCase(ExecState*) const;
+ JS_EXPORT_PRIVATE UString toUStringSlowCase(ExecState*) const;
JS_EXPORT_PRIVATE JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const;
JS_EXPORT_PRIVATE JSObject* toThisObjectSlowCase(ExecState*) const;
diff --git a/Source/JavaScriptCore/runtime/LiteralParser.cpp b/Source/JavaScriptCore/runtime/LiteralParser.cpp
index 3bde3ff08..e1f85cefe 100644
--- a/Source/JavaScriptCore/runtime/LiteralParser.cpp
+++ b/Source/JavaScriptCore/runtime/LiteralParser.cpp
@@ -529,16 +529,8 @@ TokenType LiteralParser<CharType>::Lexer::lexNumber(LiteralParserToken<CharType>
token.type = TokNumber;
token.end = m_ptr;
- Vector<char, 64> buffer(token.end - token.start + 1);
- int i;
- for (i = 0; i < token.end - token.start; i++) {
- ASSERT(static_cast<char>(token.start[i]) == token.start[i]);
- buffer[i] = static_cast<char>(token.start[i]);
- }
- buffer[i] = 0;
- char* end;
- token.numberToken = WTF::strtod<WTF::AllowTrailingJunk>(buffer.data(), &end);
- ASSERT(buffer.data() + (token.end - token.start) == end);
+ size_t parsedLength;
+ token.numberToken = parseDouble(token.start, token.end - token.start, parsedLength);
return TokNumber;
}
diff --git a/Source/JavaScriptCore/runtime/Lookup.cpp b/Source/JavaScriptCore/runtime/Lookup.cpp
index 55c048fa3..b935eb260 100644
--- a/Source/JavaScriptCore/runtime/Lookup.cpp
+++ b/Source/JavaScriptCore/runtime/Lookup.cpp
@@ -76,15 +76,7 @@ bool setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject*
if (thisObj->staticFunctionsReified())
return false;
- JSFunction* function;
- JSGlobalObject* globalObject = thisObj->globalObject();
-#if ENABLE(JIT)
- if (exec->globalData().canUseJIT() && entry->intrinsic() != NoIntrinsic)
- function = JSFunction::create(exec, globalObject, entry->functionLength(), propertyName, exec->globalData().getHostFunction(entry->function(), entry->intrinsic()));
- else
-#endif
- function = JSFunction::create(exec, globalObject, entry->functionLength(), propertyName, entry->function());
-
+ JSFunction* function = JSFunction::create(exec, thisObj->globalObject(), entry->functionLength(), propertyName, entry->function(), entry->intrinsic());
thisObj->putDirect(exec->globalData(), propertyName, function, entry->attributes());
location = thisObj->getDirectLocation(exec->globalData(), propertyName);
}
diff --git a/Source/JavaScriptCore/runtime/MatchResult.h b/Source/JavaScriptCore/runtime/MatchResult.h
new file mode 100644
index 000000000..d87c8516b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/MatchResult.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2012 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
+ * 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 MatchResult_h
+#define MatchResult_h
+
+typedef uint64_t EncodedMatchResult;
+
+struct MatchResult {
+ ALWAYS_INLINE MatchResult(size_t start, size_t end)
+ : start(start)
+ , end(end)
+ {
+ }
+
+ explicit ALWAYS_INLINE MatchResult(EncodedMatchResult encoded)
+ {
+ union u {
+ uint64_t encoded;
+ struct s {
+ size_t start;
+ size_t end;
+ } split;
+ } value;
+ value.encoded = encoded;
+ start = value.split.start;
+ end = value.split.end;
+ }
+
+ ALWAYS_INLINE static MatchResult failed()
+ {
+ return MatchResult(WTF::notFound, 0);
+ }
+
+ ALWAYS_INLINE operator bool()
+ {
+ return start != WTF::notFound;
+ }
+
+ ALWAYS_INLINE bool empty()
+ {
+ return start == end;
+ }
+
+ size_t start;
+ size_t end;
+};
+
+#endif
diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.cpp b/Source/JavaScriptCore/runtime/NumberPrototype.cpp
index 8f8c3c00f..060a80107 100644
--- a/Source/JavaScriptCore/runtime/NumberPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/NumberPrototype.cpp
@@ -148,7 +148,7 @@ static ALWAYS_INLINE bool getIntegerArgumentInRange(ExecState* exec, int low, in
typedef char RadixBuffer[2180];
// Mapping from integers 0..35 to digit identifying this value, for radix 2..36.
-static const char* const radixDigits = "0123456789abcdefghijklmnopqrstuvwxyz";
+static const char radixDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
static char* toStringWithRadix(RadixBuffer& buffer, double number, unsigned radix)
{
@@ -339,6 +339,31 @@ static char* toStringWithRadix(RadixBuffer& buffer, double number, unsigned radi
return startOfResultString;
}
+static UString toUStringWithRadix(int32_t number, unsigned radix)
+{
+ LChar buf[1 + 32]; // Worst case is radix == 2, which gives us 32 digits + sign.
+ LChar* end = buf + WTF_ARRAY_LENGTH(buf);
+ LChar* p = end;
+
+ bool negative = false;
+ uint32_t positiveNumber = number;
+ if (number < 0) {
+ negative = true;
+ positiveNumber = -number;
+ }
+
+ while (positiveNumber) {
+ uint32_t index = positiveNumber % radix;
+ ASSERT(index < sizeof(radixDigits));
+ *--p = static_cast<LChar>(radixDigits[index]);
+ positiveNumber /= radix;
+ }
+ if (negative)
+ *--p = '-';
+
+ return UString(p, static_cast<unsigned>(end - p));
+}
+
// toExponential converts a number to a string, always formatting as an expoential.
// This method takes an optional argument specifying a number of *decimal places*
// to round the significand to (or, put another way, this method optionally rounds
@@ -431,41 +456,63 @@ EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec)
return JSValue::encode(jsString(exec, UString(numberToFixedPrecisionString(x, significantFigures, buffer))));
}
-EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
+static inline int32_t extractRadixFromArgs(ExecState* exec)
{
- double x;
- if (!toThisNumber(exec->hostThisValue(), x))
- return throwVMTypeError(exec);
-
JSValue radixValue = exec->argument(0);
- int radix;
+ int32_t radix;
if (radixValue.isInt32())
radix = radixValue.asInt32();
else if (radixValue.isUndefined())
radix = 10;
else
- radix = static_cast<int>(radixValue.toInteger(exec)); // nan -> 0
+ radix = static_cast<int32_t>(radixValue.toInteger(exec)); // nan -> 0
- if (radix == 10)
- return JSValue::encode(jsNumber(x).toString(exec));
+ return radix;
+}
- // Fast path for number to character conversion.
- if (radix == 36) {
- unsigned c = static_cast<unsigned>(x);
- if (c == x && c < 36) {
- JSGlobalData* globalData = &exec->globalData();
- return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, radixDigits[c]));
- }
+static inline EncodedJSValue integerValueToString(ExecState* exec, int32_t radix, int32_t value)
+{
+ // A negative value casted to unsigned would be bigger than 36 (the max radix).
+ if (static_cast<unsigned>(value) < static_cast<unsigned>(radix)) {
+ ASSERT(value <= 36);
+ ASSERT(value >= 0);
+ JSGlobalData* globalData = &exec->globalData();
+ return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, radixDigits[value]));
}
+ if (radix == 10) {
+ JSGlobalData* globalData = &exec->globalData();
+ return JSValue::encode(jsString(globalData, globalData->numericStrings.add(value)));
+ }
+
+ return JSValue::encode(jsString(exec, toUStringWithRadix(value, radix)));
+
+}
+
+EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
+{
+ double doubleValue;
+ if (!toThisNumber(exec->hostThisValue(), doubleValue))
+ return throwVMTypeError(exec);
+
+ int32_t radix = extractRadixFromArgs(exec);
if (radix < 2 || radix > 36)
return throwVMError(exec, createRangeError(exec, "toString() radix argument must be between 2 and 36"));
- if (!isfinite(x))
- return JSValue::encode(jsString(exec, UString::number(x)));
+ int32_t integerValue = static_cast<int32_t>(doubleValue);
+ if (integerValue == doubleValue)
+ return integerValueToString(exec, radix, integerValue);
+
+ if (radix == 10) {
+ JSGlobalData* globalData = &exec->globalData();
+ return JSValue::encode(jsString(globalData, globalData->numericStrings.add(doubleValue)));
+ }
+
+ if (!isfinite(doubleValue))
+ return JSValue::encode(jsString(exec, UString::number(doubleValue)));
RadixBuffer s;
- return JSValue::encode(jsString(exec, toStringWithRadix(s, x, radix)));
+ return JSValue::encode(jsString(exec, toStringWithRadix(s, doubleValue, radix)));
}
EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec)
diff --git a/Source/JavaScriptCore/runtime/NumericStrings.h b/Source/JavaScriptCore/runtime/NumericStrings.h
index d65f14265..7fa20c44d 100644
--- a/Source/JavaScriptCore/runtime/NumericStrings.h
+++ b/Source/JavaScriptCore/runtime/NumericStrings.h
@@ -34,7 +34,7 @@ namespace JSC {
class NumericStrings {
public:
- UString add(double d)
+ ALWAYS_INLINE UString add(double d)
{
CacheEntry<double>& entry = lookup(d);
if (d == entry.key && !entry.value.isNull())
@@ -44,7 +44,7 @@ namespace JSC {
return entry.value;
}
- UString add(int i)
+ ALWAYS_INLINE UString add(int i)
{
if (static_cast<unsigned>(i) < cacheSize)
return lookupSmallString(static_cast<unsigned>(i));
@@ -56,7 +56,7 @@ namespace JSC {
return entry.value;
}
- UString add(unsigned i)
+ ALWAYS_INLINE UString add(unsigned i)
{
if (i < cacheSize)
return lookupSmallString(static_cast<unsigned>(i));
@@ -79,7 +79,7 @@ namespace JSC {
CacheEntry<double>& lookup(double d) { return doubleCache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; }
CacheEntry<int>& lookup(int i) { return intCache[WTF::IntHash<int>::hash(i) & (cacheSize - 1)]; }
CacheEntry<unsigned>& lookup(unsigned i) { return unsignedCache[WTF::IntHash<unsigned>::hash(i) & (cacheSize - 1)]; }
- const UString& lookupSmallString(unsigned i)
+ ALWAYS_INLINE const UString& lookupSmallString(unsigned i)
{
ASSERT(i < cacheSize);
if (smallIntCache[i].isNull())
diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
index 6ad312c7c..e980ac590 100644
--- a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
@@ -255,7 +255,17 @@ EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec)
if (thisValue.isUndefinedOrNull())
return JSValue::encode(jsNontrivialString(exec, thisValue.isUndefined() ? "[object Undefined]" : "[object Null]"));
JSObject* thisObject = thisValue.toObject(exec);
- return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]"));
+
+ JSString* result = thisObject->structure()->objectToStringValue();
+ if (!result) {
+ RefPtr<StringImpl> newString = WTF::tryMakeString("[object ", thisObject->methodTable()->className(thisObject), "]");
+ if (!newString)
+ return JSValue::encode(throwOutOfMemoryError(exec));
+
+ result = jsNontrivialString(exec, newString.release());
+ thisObject->structure()->setObjectToStringValue(exec->globalData(), thisObject, result);
+ }
+ return JSValue::encode(result);
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Operations.cpp b/Source/JavaScriptCore/runtime/Operations.cpp
index 459feb466..4cb9de505 100644
--- a/Source/JavaScriptCore/runtime/Operations.cpp
+++ b/Source/JavaScriptCore/runtime/Operations.cpp
@@ -58,25 +58,26 @@ NEVER_INLINE JSValue jsAddSlowCase(CallFrame* callFrame, JSValue v1, JSValue v2)
JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v)
{
+ JSGlobalData& globalData = callFrame->globalData();
if (v.isUndefined())
- return jsNontrivialString(callFrame, "undefined");
+ return globalData.smallStrings.undefinedString(&globalData);
if (v.isBoolean())
- return jsNontrivialString(callFrame, "boolean");
+ return globalData.smallStrings.booleanString(&globalData);
if (v.isNumber())
- return jsNontrivialString(callFrame, "number");
+ return globalData.smallStrings.numberString(&globalData);
if (v.isString())
- return jsNontrivialString(callFrame, "string");
+ return globalData.smallStrings.stringString(&globalData);
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");
+ return globalData.smallStrings.undefinedString(&globalData);
CallData callData;
JSObject* object = asObject(v);
if (object->methodTable()->getCallData(object, callData) != CallTypeNone)
- return jsNontrivialString(callFrame, "function");
+ return globalData.smallStrings.functionString(&globalData);
}
- return jsNontrivialString(callFrame, "object");
+ return globalData.smallStrings.objectString(&globalData);
}
bool jsIsObjectType(JSValue v)
diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h
index 945283899..b2081f3dd 100644
--- a/Source/JavaScriptCore/runtime/Operations.h
+++ b/Source/JavaScriptCore/runtime/Operations.h
@@ -47,7 +47,7 @@ namespace JSC {
if ((length1 + length2) < length1)
return throwOutOfMemoryError(exec);
- return JSString::create(globalData, s1, s2);
+ return JSRopeString::create(globalData, s1, s2);
}
ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2, const UString& u3)
@@ -69,13 +69,13 @@ namespace JSC {
if ((length1 + length2 + length3) < length3)
return throwOutOfMemoryError(exec);
- return JSString::create(exec->globalData(), jsString(globalData, u1), jsString(globalData, u2), jsString(globalData, u3));
+ return JSRopeString::create(exec->globalData(), jsString(globalData, u1), jsString(globalData, u2), jsString(globalData, u3));
}
ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count)
{
JSGlobalData* globalData = &exec->globalData();
- JSString::RopeBuilder ropeBuilder(*globalData);
+ JSRopeString::RopeBuilder ropeBuilder(*globalData);
unsigned oldLength = 0;
@@ -93,7 +93,7 @@ namespace JSC {
ALWAYS_INLINE JSValue jsStringFromArguments(ExecState* exec, JSValue thisValue)
{
JSGlobalData* globalData = &exec->globalData();
- JSString::RopeBuilder ropeBuilder(*globalData);
+ JSRopeString::RopeBuilder ropeBuilder(*globalData);
ropeBuilder.append(thisValue.toString(exec));
unsigned oldLength = 0;
diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp
index c4bf39db4..8f5a05067 100644
--- a/Source/JavaScriptCore/runtime/Options.cpp
+++ b/Source/JavaScriptCore/runtime/Options.cpp
@@ -75,6 +75,7 @@ double osrExitProminenceForFrequentExitSite;
unsigned largeFailCountThresholdBase;
unsigned largeFailCountThresholdBaseForLoop;
+unsigned forcedOSRExitCountForReoptimization;
unsigned reoptimizationRetryCounterMax;
unsigned reoptimizationRetryCounterStep;
@@ -174,8 +175,9 @@ void initializeOptions()
SET(osrExitProminenceForFrequentExitSite, 0.3);
- SET(largeFailCountThresholdBase, 20);
- SET(largeFailCountThresholdBaseForLoop, 1);
+ SET(largeFailCountThresholdBase, 20);
+ SET(largeFailCountThresholdBaseForLoop, 1);
+ SET(forcedOSRExitCountForReoptimization, 250);
SET(reoptimizationRetryCounterStep, 1);
diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h
index fae6a7376..d1ad2ca87 100644
--- a/Source/JavaScriptCore/runtime/Options.h
+++ b/Source/JavaScriptCore/runtime/Options.h
@@ -61,6 +61,7 @@ extern double osrExitProminenceForFrequentExitSite;
extern unsigned largeFailCountThresholdBase;
extern unsigned largeFailCountThresholdBaseForLoop;
+extern unsigned forcedOSRExitCountForReoptimization;
extern unsigned reoptimizationRetryCounterMax;
extern unsigned reoptimizationRetryCounterStep;
diff --git a/Source/JavaScriptCore/runtime/PropertyNameArray.cpp b/Source/JavaScriptCore/runtime/PropertyNameArray.cpp
index 8efb4065e..9bae94097 100644
--- a/Source/JavaScriptCore/runtime/PropertyNameArray.cpp
+++ b/Source/JavaScriptCore/runtime/PropertyNameArray.cpp
@@ -45,7 +45,7 @@ void PropertyNameArray::add(StringImpl* identifier)
for (size_t i = 0; i < size; ++i)
m_set.add(m_data->propertyNameVector()[i].impl());
}
- if (!m_set.add(identifier).second)
+ if (!m_set.add(identifier).isNewEntry)
return;
}
diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp
index 1a3362b2d..b0f67607e 100644
--- a/Source/JavaScriptCore/runtime/RegExp.cpp
+++ b/Source/JavaScriptCore/runtime/RegExp.cpp
@@ -131,11 +131,11 @@ void RegExpFunctionalTestCollector::outputOneTest(RegExp* regExp, UString s, int
outputEscapedUString(s);
fprintf(m_file, "\", %d, %d, (", startOffset, result);
for (unsigned i = 0; i <= regExp->numSubpatterns(); i++) {
- int subPatternBegin = ovector[i * 2];
- int subPatternEnd = ovector[i * 2 + 1];
- if (subPatternBegin == -1)
- subPatternEnd = -1;
- fprintf(m_file, "%d, %d", subPatternBegin, subPatternEnd);
+ int subpatternBegin = ovector[i * 2];
+ int subpatternEnd = ovector[i * 2 + 1];
+ if (subpatternBegin == -1)
+ subpatternEnd = -1;
+ fprintf(m_file, "%d, %d", subpatternBegin, subpatternEnd);
if (i < regExp->numSubpatterns())
fputs(", ", m_file);
}
@@ -217,13 +217,6 @@ void RegExpFunctionalTestCollector::outputEscapedUString(const UString& s, bool
}
#endif
-struct RegExpRepresentation {
-#if ENABLE(YARR_JIT)
- Yarr::YarrCodeBlock m_regExpJITCode;
-#endif
- OwnPtr<Yarr::BytecodePattern> m_regExpBytecode;
-};
-
RegExp::RegExp(JSGlobalData& globalData, const UString& patternString, RegExpFlags flags)
: JSCell(globalData, globalData.regExpStructure.get())
, m_state(NotCompiled)
@@ -279,23 +272,22 @@ void RegExp::compile(JSGlobalData* globalData, Yarr::YarrCharSize charSize)
}
ASSERT(m_numSubpatterns == pattern.m_numSubpatterns);
- if (!m_representation) {
+ if (!hasCode()) {
ASSERT(m_state == NotCompiled);
- m_representation = adoptPtr(new RegExpRepresentation);
globalData->regExpCache()->addToStrongCache(this);
m_state = ByteCode;
}
#if ENABLE(YARR_JIT)
- if (!pattern.m_containsBackreferences && globalData->canUseJIT()) {
- Yarr::jitCompile(pattern, charSize, globalData, m_representation->m_regExpJITCode);
+ if (!pattern.m_containsBackreferences && globalData->canUseRegExpJIT()) {
+ Yarr::jitCompile(pattern, charSize, globalData, m_regExpJITCode);
#if ENABLE(YARR_JIT_DEBUG)
- if (!m_representation->m_regExpJITCode.isFallBack())
+ if (!m_regExpJITCode.isFallBack())
m_state = JITCode;
else
m_state = ByteCode;
#else
- if (!m_representation->m_regExpJITCode.isFallBack()) {
+ if (!m_regExpJITCode.isFallBack()) {
m_state = JITCode;
return;
}
@@ -305,22 +297,18 @@ void RegExp::compile(JSGlobalData* globalData, Yarr::YarrCharSize charSize)
UNUSED_PARAM(charSize);
#endif
- m_representation->m_regExpBytecode = Yarr::byteCompile(pattern, &globalData->m_regExpAllocator);
+ m_regExpBytecode = Yarr::byteCompile(pattern, &globalData->m_regExpAllocator);
}
void RegExp::compileIfNecessary(JSGlobalData& globalData, Yarr::YarrCharSize charSize)
{
- // If the state is NotCompiled or ParseError, then there is no representation.
- // If there is a representation, and the state must be either JITCode or ByteCode.
- ASSERT(!!m_representation == (m_state == JITCode || m_state == ByteCode));
-
- if (m_representation) {
+ if (hasCode()) {
#if ENABLE(YARR_JIT)
if (m_state != JITCode)
return;
- if ((charSize == Yarr::Char8) && (m_representation->m_regExpJITCode.has8BitCode()))
+ if ((charSize == Yarr::Char8) && (m_regExpJITCode.has8BitCode()))
return;
- if ((charSize == Yarr::Char16) && (m_representation->m_regExpJITCode.has16BitCode()))
+ if ((charSize == Yarr::Char16) && (m_regExpJITCode.has16BitCode()))
return;
#else
return;
@@ -330,7 +318,7 @@ void RegExp::compileIfNecessary(JSGlobalData& globalData, Yarr::YarrCharSize cha
compile(&globalData, charSize);
}
-int RegExp::match(JSGlobalData& globalData, const UString& s, unsigned startOffset, Vector<int, 32>* ovector)
+int RegExp::match(JSGlobalData& globalData, const UString& s, unsigned startOffset, Vector<int, 32>& ovector)
{
#if ENABLE(REGEXP_TRACING)
m_rtMatchCallCount++;
@@ -340,30 +328,22 @@ int RegExp::match(JSGlobalData& globalData, const UString& s, unsigned startOffs
compileIfNecessary(globalData, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
int offsetVectorSize = (m_numSubpatterns + 1) * 2;
- int* offsetVector;
- Vector<int, 32> nonReturnedOvector;
- if (ovector) {
- ovector->resize(offsetVectorSize);
- offsetVector = ovector->data();
- } else {
- nonReturnedOvector.resize(offsetVectorSize);
- offsetVector = nonReturnedOvector.data();
- }
- ASSERT(offsetVector);
+ ovector.resize(offsetVectorSize);
+ int* offsetVector = ovector.data();
int result;
#if ENABLE(YARR_JIT)
if (m_state == JITCode) {
if (s.is8Bit())
- result = Yarr::execute(m_representation->m_regExpJITCode, s.characters8(), startOffset, s.length(), offsetVector);
+ result = m_regExpJITCode.execute(s.characters8(), startOffset, s.length(), offsetVector).start;
else
- result = Yarr::execute(m_representation->m_regExpJITCode, s.characters16(), startOffset, s.length(), offsetVector);
+ result = m_regExpJITCode.execute(s.characters16(), startOffset, s.length(), offsetVector).start;
#if ENABLE(YARR_JIT_DEBUG)
matchCompareWithInterpreter(s, startOffset, offsetVector, result);
#endif
} else
#endif
- result = Yarr::interpret(m_representation->m_regExpBytecode.get(), s, startOffset, s.length(), reinterpret_cast<unsigned*>(offsetVector));
+ result = Yarr::interpret(m_regExpBytecode.get(), s, startOffset, reinterpret_cast<unsigned*>(offsetVector));
// FIXME: The YARR engine should handle unsigned or size_t length matches.
// The YARR Interpreter is "unsigned" clean, while the YARR JIT hasn't been addressed.
@@ -404,12 +384,113 @@ int RegExp::match(JSGlobalData& globalData, const UString& s, unsigned startOffs
return result;
}
+void RegExp::compileMatchOnly(JSGlobalData* globalData, Yarr::YarrCharSize charSize)
+{
+ Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
+ if (m_constructionError) {
+ ASSERT_NOT_REACHED();
+ m_state = ParseError;
+ return;
+ }
+ ASSERT(m_numSubpatterns == pattern.m_numSubpatterns);
+
+ if (!hasCode()) {
+ ASSERT(m_state == NotCompiled);
+ globalData->regExpCache()->addToStrongCache(this);
+ m_state = ByteCode;
+ }
+
+#if ENABLE(YARR_JIT)
+ if (!pattern.m_containsBackreferences && globalData->canUseRegExpJIT()) {
+ Yarr::jitCompile(pattern, charSize, globalData, m_regExpJITCode, Yarr::MatchOnly);
+#if ENABLE(YARR_JIT_DEBUG)
+ if (!m_regExpJITCode.isFallBack())
+ m_state = JITCode;
+ else
+ m_state = ByteCode;
+#else
+ if (!m_regExpJITCode.isFallBack()) {
+ m_state = JITCode;
+ return;
+ }
+#endif
+ }
+#else
+ UNUSED_PARAM(charSize);
+#endif
+
+ m_regExpBytecode = Yarr::byteCompile(pattern, &globalData->m_regExpAllocator);
+}
+
+void RegExp::compileIfNecessaryMatchOnly(JSGlobalData& globalData, Yarr::YarrCharSize charSize)
+{
+ if (hasCode()) {
+#if ENABLE(YARR_JIT)
+ if (m_state != JITCode)
+ return;
+ if ((charSize == Yarr::Char8) && (m_regExpJITCode.has8BitCodeMatchOnly()))
+ return;
+ if ((charSize == Yarr::Char16) && (m_regExpJITCode.has16BitCodeMatchOnly()))
+ return;
+#else
+ return;
+#endif
+ }
+
+ compileMatchOnly(&globalData, charSize);
+}
+
+MatchResult RegExp::match(JSGlobalData& globalData, const UString& s, unsigned startOffset)
+{
+#if ENABLE(REGEXP_TRACING)
+ m_rtMatchCallCount++;
+#endif
+
+ ASSERT(m_state != ParseError);
+ compileIfNecessaryMatchOnly(globalData, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
+
+#if ENABLE(YARR_JIT)
+ if (m_state == JITCode) {
+ MatchResult result = s.is8Bit() ?
+ m_regExpJITCode.execute(s.characters8(), startOffset, s.length()) :
+ m_regExpJITCode.execute(s.characters16(), startOffset, s.length());
+#if ENABLE(REGEXP_TRACING)
+ if (!result)
+ m_rtMatchFoundCount++;
+#endif
+ return result;
+ }
+#endif
+
+ int offsetVectorSize = (m_numSubpatterns + 1) * 2;
+ int* offsetVector;
+ Vector<int, 32> nonReturnedOvector;
+ nonReturnedOvector.resize(offsetVectorSize);
+ offsetVector = nonReturnedOvector.data();
+ int r = Yarr::interpret(m_regExpBytecode.get(), s, startOffset, reinterpret_cast<unsigned*>(offsetVector));
+#if REGEXP_FUNC_TEST_DATA_GEN
+ RegExpFunctionalTestCollector::get()->outputOneTest(this, s, startOffset, offsetVector, result);
+#endif
+
+ if (r >= 0) {
+#if ENABLE(REGEXP_TRACING)
+ m_rtMatchFoundCount++;
+#endif
+ return MatchResult(r, reinterpret_cast<unsigned*>(offsetVector)[1]);
+ }
+
+ return MatchResult::failed();
+}
+
void RegExp::invalidateCode()
{
- if (!m_representation)
+ if (!hasCode())
return;
m_state = NotCompiled;
- m_representation.clear();
+#if ENABLE(YARR_JIT)
+ m_regExpJITCode.clear();
+#endif
+ m_regExpBytecode.clear();
}
#if ENABLE(YARR_JIT_DEBUG)
@@ -428,7 +509,7 @@ void RegExp::matchCompareWithInterpreter(const UString& s, int startOffset, int*
for (unsigned j = 0, i = 0; i < m_numSubpatterns + 1; j += 2, i++)
interpreterOffsetVector[j] = -1;
- interpreterResult = Yarr::interpret(m_representation->m_regExpBytecode.get(), s, startOffset, s.length(), interpreterOffsetVector);
+ interpreterResult = Yarr::interpret(m_regExpBytecode.get(), s, startOffset, interpreterOffsetVector);
if (jitResult != interpreterResult)
differences++;
@@ -477,7 +558,7 @@ void RegExp::matchCompareWithInterpreter(const UString& s, int startOffset, int*
snprintf(formattedPattern, 41, (pattLen <= 38) ? "/%.38s/" : "/%.36s...", rawPattern);
#if ENABLE(YARR_JIT)
- Yarr::YarrCodeBlock& codeBlock = m_representation->m_regExpJITCode;
+ Yarr::YarrCodeBlock& codeBlock = m_regExpJITCode;
const size_t jitAddrSize = 20;
char jitAddr[jitAddrSize];
diff --git a/Source/JavaScriptCore/runtime/RegExp.h b/Source/JavaScriptCore/runtime/RegExp.h
index d0201cbfb..ad1020376 100644
--- a/Source/JavaScriptCore/runtime/RegExp.h
+++ b/Source/JavaScriptCore/runtime/RegExp.h
@@ -22,14 +22,19 @@
#ifndef RegExp_h
#define RegExp_h
-#include "UString.h"
#include "ExecutableAllocator.h"
-#include "Structure.h"
+#include "MatchResult.h"
#include "RegExpKey.h"
+#include "Structure.h"
+#include "UString.h"
#include "yarr/Yarr.h"
#include <wtf/Forward.h>
#include <wtf/RefCounted.h>
+#if ENABLE(YARR_JIT)
+#include "yarr/YarrJIT.h"
+#endif
+
namespace JSC {
struct RegExpRepresentation;
@@ -53,12 +58,13 @@ namespace JSC {
bool isValid() const { return !m_constructionError && m_flags != InvalidFlags; }
const char* errorMessage() const { return m_constructionError; }
- JS_EXPORT_PRIVATE int match(JSGlobalData&, const UString&, unsigned startOffset, Vector<int, 32>* ovector = 0);
+ JS_EXPORT_PRIVATE int match(JSGlobalData&, const UString&, unsigned startOffset, Vector<int, 32>& ovector);
+ MatchResult match(JSGlobalData&, const UString&, unsigned startOffset);
unsigned numSubpatterns() const { return m_numSubpatterns; }
bool hasCode()
{
- return m_representation;
+ return m_state != NotCompiled;
}
void invalidateCode();
@@ -95,6 +101,9 @@ namespace JSC {
void compile(JSGlobalData*, Yarr::YarrCharSize);
void compileIfNecessary(JSGlobalData&, Yarr::YarrCharSize);
+ void compileMatchOnly(JSGlobalData*, Yarr::YarrCharSize);
+ void compileIfNecessaryMatchOnly(JSGlobalData&, Yarr::YarrCharSize);
+
#if ENABLE(YARR_JIT_DEBUG)
void matchCompareWithInterpreter(const UString&, int startOffset, int* offsetVector, int jitResult);
#endif
@@ -108,7 +117,10 @@ namespace JSC {
unsigned m_rtMatchFoundCount;
#endif
- OwnPtr<RegExpRepresentation> m_representation;
+#if ENABLE(YARR_JIT)
+ Yarr::YarrCodeBlock m_regExpJITCode;
+#endif
+ OwnPtr<Yarr::BytecodePattern> m_regExpBytecode;
};
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpCache.cpp b/Source/JavaScriptCore/runtime/RegExpCache.cpp
index d5edbbc7f..36ea326e6 100644
--- a/Source/JavaScriptCore/runtime/RegExpCache.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpCache.cpp
@@ -46,7 +46,7 @@ RegExp* RegExpCache::lookupOrCreate(const UString& patternString, RegExpFlags fl
// We need to do a second lookup to add the RegExp as
// allocating it may have caused a gc cycle, which in
// turn may have removed items from the cache.
- m_weakCache.add(key, PassWeak<RegExp>(*m_globalData, regExp, this));
+ m_weakCache.add(key, PassWeak<RegExp>(regExp, this));
return regExp;
}
diff --git a/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp b/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp
new file mode 100644
index 000000000..07881451a
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpCachedResult.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
+ * 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 "RegExpCachedResult.h"
+
+#include "RegExpMatchesArray.h"
+
+namespace JSC {
+
+void RegExpCachedResult::visitChildren(SlotVisitor& visitor)
+{
+ if (m_result) {
+ visitor.append(&m_lastInput);
+ visitor.append(&m_lastRegExp);
+ } else {
+ visitor.append(&m_reifiedInput);
+ visitor.append(&m_reifiedResult);
+ }
+}
+
+RegExpMatchesArray* RegExpCachedResult::lastResult(ExecState* exec, JSObject* owner)
+{
+ if (m_result) {
+ m_reifiedInput.set(exec->globalData(), owner, m_lastInput.get());
+ m_reifiedResult.set(exec->globalData(), owner, RegExpMatchesArray::create(exec, m_lastInput.get(), m_lastRegExp.get(), m_result));
+ m_result = MatchResult::failed();
+ }
+ return m_reifiedResult.get();
+}
+
+void RegExpCachedResult::setInput(ExecState* exec, JSObject* owner, JSString* input)
+{
+ // Make sure we're reified, otherwise m_reifiedInput will be ignored.
+ lastResult(exec, owner);
+ ASSERT(!m_result);
+ m_reifiedInput.set(exec->globalData(), owner, input);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpCachedResult.h b/Source/JavaScriptCore/runtime/RegExpCachedResult.h
new file mode 100644
index 000000000..a72244025
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpCachedResult.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2012 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
+ * 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 RegExpCachedResult_h
+#define RegExpCachedResult_h
+
+#include "RegExpObject.h"
+
+namespace JSC {
+
+ class JSString;
+ class RegExpMatchesArray;
+
+ // RegExpCachedResult is used to track the cached results of the last
+ // match, stores on the RegExp constructor (e.g. $&, $_, $1, $2 ...).
+ // These values will be lazily generated on demand, so the cached result
+ // may be in a lazy or reified state. A lazy state is indicated by a
+ // value of m_result indicating a successful match, and a reified state
+ // is indicated by setting m_result to MatchResult::failed().
+ // Following a successful match, m_result, m_lastInput and m_lastRegExp
+ // can be used to reify the results from the match, following reification
+ // m_reifiedResult and m_reifiedInput hold the cached results.
+ class RegExpCachedResult {
+ public:
+ RegExpCachedResult(JSGlobalData& globalData, JSObject* owner, RegExp* emptyRegExp)
+ : m_result(0, 0)
+ {
+ m_lastInput.set(globalData, owner, jsEmptyString(&globalData));
+ m_lastRegExp.set(globalData, owner, emptyRegExp);
+ m_reifiedResult.clear();
+ m_reifiedInput.clear();
+ }
+
+ ALWAYS_INLINE void record(JSGlobalData& globalData, JSObject* owner, RegExp* regExp, JSString* input, MatchResult result)
+ {
+ m_lastRegExp.set(globalData, owner, regExp);
+ m_lastInput.set(globalData, owner, input);
+ m_result = result;
+ }
+
+ RegExpMatchesArray* lastResult(ExecState*, JSObject* owner);
+ void setInput(ExecState*, JSObject* owner, JSString*);
+
+ JSString* input()
+ {
+ // If m_result showas a match then we're in a lazy state, so m_lastInput
+ // is the most recent value of the input property. If not then we have
+ // reified, in which case m_reifiedInput will contain the correct value.
+ return m_result ? m_lastInput.get() : m_reifiedInput.get();
+ }
+
+ void visitChildren(SlotVisitor&);
+
+ private:
+ MatchResult m_result;
+ WriteBarrier<JSString> m_lastInput;
+ WriteBarrier<RegExp> m_lastRegExp;
+ WriteBarrier<RegExpMatchesArray> m_reifiedResult;
+ WriteBarrier<JSString> m_reifiedInput;
+ };
+
+} // namespace JSC
+
+#endif // RegExpCachedResult_h
diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
index 90082f07e..fd03db569 100644
--- a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
@@ -22,21 +22,9 @@
#include "config.h"
#include "RegExpConstructor.h"
-#include "ArrayPrototype.h"
#include "Error.h"
-#include "ExceptionHelpers.h"
-#include "JSArray.h"
-#include "JSFunction.h"
-#include "JSString.h"
-#include "Lookup.h"
-#include "ObjectPrototype.h"
#include "RegExpMatchesArray.h"
-#include "RegExpObject.h"
#include "RegExpPrototype.h"
-#include "RegExp.h"
-#include "RegExpCache.h"
-#include "UStringConcatenate.h"
-#include <wtf/PassOwnPtr.h>
namespace JSC {
@@ -69,8 +57,6 @@ ASSERT_CLASS_FITS_IN_CELL(RegExpConstructor);
const ClassInfo RegExpConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::regExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) };
-const ClassInfo RegExpMatchesArray::s_info = {"Array", &JSArray::s_info, 0, 0, CREATE_METHOD_TABLE(RegExpMatchesArray)};
-
/* Source for RegExpConstructor.lut.h
@begin regExpConstructorTable
input regExpConstructorInput None
@@ -97,18 +83,10 @@ const ClassInfo RegExpMatchesArray::s_info = {"Array", &JSArray::s_info, 0, 0, C
@end
*/
-RegExpResult& RegExpResult::operator=(const RegExpConstructorPrivate& rhs)
-{
- this->input = rhs.input;
- this->ovector = rhs.lastOvector();
- this->lastNumSubPatterns = rhs.lastNumSubPatterns;
-
- return *this;
-}
-
-
-RegExpConstructor::RegExpConstructor(JSGlobalObject* globalObject, Structure* structure)
+RegExpConstructor::RegExpConstructor(JSGlobalObject* globalObject, Structure* structure, RegExpPrototype* regExpPrototype)
: InternalFunction(globalObject, structure)
+ , m_cachedResult(globalObject->globalData(), this, regExpPrototype->regExp())
+ , m_multiline(false)
{
}
@@ -129,81 +107,51 @@ void RegExpConstructor::destroy(JSCell* cell)
jsCast<RegExpConstructor*>(cell)->RegExpConstructor::~RegExpConstructor();
}
-RegExpMatchesArray::RegExpMatchesArray(ExecState* exec)
- : JSArray(exec->globalData(), exec->lexicalGlobalObject()->regExpMatchesArrayStructure())
- , m_didFillArrayInstance(false)
-{
-}
-
-void RegExpMatchesArray::finishCreation(JSGlobalData& globalData, const RegExpConstructorPrivate& data)
+void RegExpConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
- Base::finishCreation(globalData, data.lastNumSubPatterns + 1);
- m_regExpResult = data;
-}
-
-void RegExpMatchesArray::destroy(JSCell* cell)
-{
- jsCast<RegExpMatchesArray*>(cell)->RegExpMatchesArray::~RegExpMatchesArray();
-}
-
-void RegExpMatchesArray::fillArrayInstance(ExecState* exec)
-{
- unsigned lastNumSubpatterns = m_regExpResult.lastNumSubPatterns;
-
- for (unsigned i = 0; i <= lastNumSubpatterns; ++i) {
- int start = m_regExpResult.ovector[2 * i];
- if (start >= 0)
- putDirectIndex(exec, i, jsSubstring(exec, m_regExpResult.input, start, m_regExpResult.ovector[2 * i + 1] - start), false);
- else
- putDirectIndex(exec, i, jsUndefined(), false);
- }
+ RegExpConstructor* thisObject = jsCast<RegExpConstructor*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
- PutPropertySlot slot;
- JSArray::put(this, exec, exec->propertyNames().index, jsNumber(m_regExpResult.ovector[0]), slot);
- JSArray::put(this, exec, exec->propertyNames().input, jsString(exec, m_regExpResult.input), slot);
-
- m_didFillArrayInstance = true;
+ Base::visitChildren(thisObject, visitor);
+ thisObject->m_cachedResult.visitChildren(visitor);
}
-JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const
+JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i)
{
- return RegExpMatchesArray::create(exec, d);
-}
+ RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this);
-JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) const
-{
- if (!d.lastOvector().isEmpty() && i <= d.lastNumSubPatterns) {
- int start = d.lastOvector()[2 * i];
- if (start >= 0)
- return jsSubstring(exec, d.lastInput, start, d.lastOvector()[2 * i + 1] - start);
+ if (i < array->length()) {
+ JSValue result = JSValue(array).get(exec, i);
+ ASSERT(result.isString() || result.isUndefined());
+ if (!result.isUndefined())
+ return result;
}
return jsEmptyString(exec);
}
-JSValue RegExpConstructor::getLastParen(ExecState* exec) const
+JSValue RegExpConstructor::getLastParen(ExecState* exec)
{
- unsigned i = d.lastNumSubPatterns;
- if (i > 0) {
- ASSERT(!d.lastOvector().isEmpty());
- int start = d.lastOvector()[2 * i];
- if (start >= 0)
- return jsSubstring(exec, d.lastInput, start, d.lastOvector()[2 * i + 1] - start);
+ RegExpMatchesArray* array = m_cachedResult.lastResult(exec, this);
+ unsigned length = array->length();
+ if (length > 1) {
+ JSValue result = JSValue(array).get(exec, length - 1);
+ ASSERT(result.isString() || result.isUndefined());
+ if (!result.isUndefined())
+ return result;
}
return jsEmptyString(exec);
}
-JSValue RegExpConstructor::getLeftContext(ExecState* exec) const
+JSValue RegExpConstructor::getLeftContext(ExecState* exec)
{
- if (!d.lastOvector().isEmpty())
- return jsSubstring(exec, d.lastInput, 0, d.lastOvector()[0]);
- return jsEmptyString(exec);
+ return m_cachedResult.lastResult(exec, this)->leftContext(exec);
}
-JSValue RegExpConstructor::getRightContext(ExecState* exec) const
+JSValue RegExpConstructor::getRightContext(ExecState* exec)
{
- if (!d.lastOvector().isEmpty())
- return jsSubstring(exec, d.lastInput, d.lastOvector()[1], d.lastInput.length() - d.lastOvector()[1]);
- return jsEmptyString(exec);
+ return m_cachedResult.lastResult(exec, this)->rightContext(exec);
}
bool RegExpConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
@@ -261,9 +209,9 @@ JSValue regExpConstructorDollar9(ExecState* exec, JSValue slotBase, const Identi
return asRegExpConstructor(slotBase)->getBackref(exec, 9);
}
-JSValue regExpConstructorInput(ExecState* exec, JSValue slotBase, const Identifier&)
+JSValue regExpConstructorInput(ExecState*, JSValue slotBase, const Identifier&)
{
- return jsString(exec, asRegExpConstructor(slotBase)->input());
+ return asRegExpConstructor(slotBase)->input();
}
JSValue regExpConstructorMultiline(ExecState*, JSValue slotBase, const Identifier&)
@@ -298,7 +246,7 @@ void RegExpConstructor::put(JSCell* cell, ExecState* exec, const Identifier& pro
void setRegExpConstructorInput(ExecState* exec, JSObject* baseObject, JSValue value)
{
- asRegExpConstructor(baseObject)->setInput(value.toString(exec)->value(exec));
+ asRegExpConstructor(baseObject)->setInput(exec, value.toString(exec));
}
void setRegExpConstructorMultiline(ExecState* exec, JSObject* baseObject, JSValue value)
@@ -367,26 +315,4 @@ CallType RegExpConstructor::getCallData(JSCell*, CallData& callData)
return CallTypeHost;
}
-void RegExpConstructor::setInput(const UString& input)
-{
- d.input = input;
-}
-
-const UString& RegExpConstructor::input() const
-{
- // Can detect a distinct initial state that is invisible to JavaScript, by checking for null
- // state (since jsString turns null strings to empty strings).
- return d.input;
-}
-
-void RegExpConstructor::setMultiline(bool multiline)
-{
- d.multiline = multiline;
-}
-
-bool RegExpConstructor::multiline() const
-{
- return d.multiline;
-}
-
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.h b/Source/JavaScriptCore/runtime/RegExpConstructor.h
index 08a96b544..0093f9484 100644
--- a/Source/JavaScriptCore/runtime/RegExpConstructor.h
+++ b/Source/JavaScriptCore/runtime/RegExpConstructor.h
@@ -23,60 +23,22 @@
#include "InternalFunction.h"
#include "RegExp.h"
+#include "RegExpCachedResult.h"
+#include "RegExpObject.h"
#include <wtf/OwnPtr.h>
+
namespace JSC {
- class RegExp;
class RegExpPrototype;
- struct RegExpConstructorPrivate;
-
- struct RegExpConstructorPrivate {
- WTF_MAKE_FAST_ALLOCATED;
- public:
- // Global search cache / settings
- RegExpConstructorPrivate()
- : lastNumSubPatterns(0)
- , multiline(false)
- , lastOvectorIndex(0)
- {
- }
-
- const Vector<int, 32>& lastOvector() const { return ovector[lastOvectorIndex]; }
- Vector<int, 32>& lastOvector() { return ovector[lastOvectorIndex]; }
- Vector<int, 32>& tempOvector() { return ovector[lastOvectorIndex ? 0 : 1]; }
- void changeLastOvector() { lastOvectorIndex = lastOvectorIndex ? 0 : 1; }
-
- UString input;
- UString lastInput;
- Vector<int, 32> ovector[2];
- unsigned lastNumSubPatterns : 30;
- bool multiline : 1;
- unsigned lastOvectorIndex : 1;
- };
- struct RegExpResult {
- WTF_MAKE_FAST_ALLOCATED;
- public:
- RegExpResult()
- : lastNumSubPatterns(0)
- {
- }
-
- RegExpResult& operator=(const RegExpConstructorPrivate&);
-
- UString input;
- unsigned lastNumSubPatterns;
- Vector<int, 32> ovector;
- };
-
class RegExpConstructor : public InternalFunction {
public:
typedef InternalFunction Base;
static RegExpConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, RegExpPrototype* regExpPrototype)
{
- RegExpConstructor* constructor = new (NotNull, allocateCell<RegExpConstructor>(*exec->heap())) RegExpConstructor(globalObject, structure);
+ RegExpConstructor* constructor = new (NotNull, allocateCell<RegExpConstructor>(*exec->heap())) RegExpConstructor(globalObject, structure, regExpPrototype);
constructor->finishCreation(exec, regExpPrototype);
return constructor;
}
@@ -93,31 +55,35 @@ namespace JSC {
static const ClassInfo s_info;
- void performMatch(JSGlobalData&, RegExp*, const UString&, int startOffset, int& position, int& length, int** ovector = 0);
- JSObject* arrayOfMatches(ExecState*) const;
+ MatchResult performMatch(JSGlobalData&, RegExp*, JSString*, const UString&, int startOffset, int** ovector);
+ MatchResult performMatch(JSGlobalData&, RegExp*, JSString*, const UString&, int startOffset);
+
+ void setMultiline(bool multiline) { m_multiline = multiline; }
+ bool multiline() const { return m_multiline; }
- void setInput(const UString&);
- const UString& input() const;
+ JSValue getBackref(ExecState*, unsigned);
+ JSValue getLastParen(ExecState*);
+ JSValue getLeftContext(ExecState*);
+ JSValue getRightContext(ExecState*);
- void setMultiline(bool);
- bool multiline() const;
+ void setInput(ExecState* exec, JSString* string) { m_cachedResult.setInput(exec, this, string); }
+ JSString* input() { return m_cachedResult.input(); }
- JSValue getBackref(ExecState*, unsigned) const;
- JSValue getLastParen(ExecState*) const;
- JSValue getLeftContext(ExecState*) const;
- JSValue getRightContext(ExecState*) const;
+ static void visitChildren(JSCell*, SlotVisitor&);
protected:
void finishCreation(ExecState*, RegExpPrototype*);
- static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | InternalFunction::StructureFlags;
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | Base::StructureFlags;
private:
- RegExpConstructor(JSGlobalObject*, Structure*);
+ RegExpConstructor(JSGlobalObject*, Structure*, RegExpPrototype*);
static void destroy(JSCell*);
static ConstructType getConstructData(JSCell*, ConstructData&);
static CallType getCallData(JSCell*, CallData&);
- RegExpConstructorPrivate d;
+ RegExpCachedResult m_cachedResult;
+ bool m_multiline;
+ Vector<int, 32> m_ovector;
};
RegExpConstructor* asRegExpConstructor(JSValue);
@@ -135,23 +101,31 @@ namespace JSC {
expression matching through the performMatch function. We use cached results to calculate,
e.g., RegExp.lastMatch and RegExp.leftParen.
*/
- ALWAYS_INLINE void RegExpConstructor::performMatch(JSGlobalData& globalData, RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector)
+ ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(JSGlobalData& globalData, RegExp* regExp, JSString* string, const UString& input, int startOffset, int** ovector)
{
- position = r->match(globalData, s, startOffset, &d.tempOvector());
+ int position = regExp->match(globalData, input, startOffset, m_ovector);
if (ovector)
- *ovector = d.tempOvector().data();
+ *ovector = m_ovector.data();
- if (position != -1) {
- ASSERT(!d.tempOvector().isEmpty());
+ if (position == -1)
+ return MatchResult::failed();
- length = d.tempOvector()[1] - d.tempOvector()[0];
+ ASSERT(!m_ovector.isEmpty());
+ ASSERT(m_ovector[0] == position);
+ ASSERT(m_ovector[1] >= position);
+ size_t end = m_ovector[1];
- d.input = s;
- d.lastInput = s;
- d.changeLastOvector();
- d.lastNumSubPatterns = r->numSubpatterns();
- }
+ m_cachedResult.record(globalData, this, regExp, string, MatchResult(position, end));
+
+ return MatchResult(position, end);
+ }
+ ALWAYS_INLINE MatchResult RegExpConstructor::performMatch(JSGlobalData& globalData, RegExp* regExp, JSString* string, const UString& input, int startOffset)
+ {
+ MatchResult result = regExp->match(globalData, input, startOffset);
+ if (result)
+ m_cachedResult.record(globalData, this, regExp, string, result);
+ return result;
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
new file mode 100644
index 000000000..80f1068f2
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.cpp
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2012 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 INC. OR
+ * 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 "RegExpMatchesArray.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(RegExpMatchesArray);
+
+const ClassInfo RegExpMatchesArray::s_info = {"Array", &JSArray::s_info, 0, 0, CREATE_METHOD_TABLE(RegExpMatchesArray)};
+
+void RegExpMatchesArray::finishCreation(JSGlobalData& globalData)
+{
+ Base::finishCreation(globalData, m_regExp->numSubpatterns() + 1);
+}
+
+void RegExpMatchesArray::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+
+ Base::visitChildren(thisObject, visitor);
+ visitor.append(&thisObject->m_input);
+ visitor.append(&thisObject->m_regExp);
+}
+
+void RegExpMatchesArray::reifyAllProperties(ExecState* exec)
+{
+ ASSERT(m_state != ReifiedAll);
+ ASSERT(m_result);
+
+ reifyMatchPropertyIfNecessary(exec);
+
+ if (unsigned numSubpatterns = m_regExp->numSubpatterns()) {
+ Vector<int, 32> subpatternResults;
+ int position = m_regExp->match(exec->globalData(), m_input->value(exec), m_result.start, subpatternResults);
+ ASSERT_UNUSED(position, position >= 0 && static_cast<size_t>(position) == m_result.start);
+ ASSERT(m_result.start == static_cast<size_t>(subpatternResults[0]));
+ ASSERT(m_result.end == static_cast<size_t>(subpatternResults[1]));
+
+ for (unsigned i = 1; i <= numSubpatterns; ++i) {
+ int start = subpatternResults[2 * i];
+ if (start >= 0)
+ putDirectIndex(exec, i, jsSubstring(exec, m_input.get(), start, subpatternResults[2 * i + 1] - start), false);
+ else
+ putDirectIndex(exec, i, jsUndefined(), false);
+ }
+ }
+
+ PutPropertySlot slot;
+ JSArray::put(this, exec, exec->propertyNames().index, jsNumber(m_result.start), slot);
+ JSArray::put(this, exec, exec->propertyNames().input, m_input.get(), slot);
+
+ m_state = ReifiedAll;
+}
+
+void RegExpMatchesArray::reifyMatchProperty(ExecState* exec)
+{
+ ASSERT(m_state == ReifiedNone);
+ ASSERT(m_result);
+ putDirectIndex(exec, 0, jsSubstring(exec, m_input.get(), m_result.start, m_result.end - m_result.start), false);
+ m_state = ReifiedMatch;
+}
+
+JSString* RegExpMatchesArray::leftContext(ExecState* exec)
+{
+ if (!m_result.start)
+ return jsEmptyString(exec);
+ return jsSubstring(exec, m_input.get(), 0, m_result.start);
+}
+
+JSString* RegExpMatchesArray::rightContext(ExecState* exec)
+{
+ unsigned length = m_input->length();
+ if (m_result.end == length)
+ return jsEmptyString(exec);
+ return jsSubstring(exec, m_input.get(), m_result.end, length - m_result.end);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.h b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h
index a3c4497fc..595457bca 100644
--- a/Source/JavaScriptCore/runtime/RegExpMatchesArray.h
+++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h
@@ -21,23 +21,38 @@
#define RegExpMatchesArray_h
#include "JSArray.h"
+#include "JSGlobalObject.h"
+#include "RegExpObject.h"
namespace JSC {
class RegExpMatchesArray : public JSArray {
private:
- RegExpMatchesArray(ExecState*);
+ RegExpMatchesArray(JSGlobalData& globalData, JSGlobalObject* globalObject, JSString* input, RegExp* regExp, MatchResult result)
+ : JSArray(globalData, globalObject->regExpMatchesArrayStructure())
+ , m_result(result)
+ , m_state(ReifiedNone)
+ {
+ m_input.set(globalData, this, input);
+ m_regExp.set(globalData, this, regExp);
+ }
+
+ enum ReifiedState { ReifiedNone, ReifiedMatch, ReifiedAll };
public:
typedef JSArray Base;
- static RegExpMatchesArray* create(ExecState* exec, const RegExpConstructorPrivate& ctorPrivate)
+ static RegExpMatchesArray* create(ExecState* exec, JSString* input, RegExp* regExp, MatchResult result)
{
- RegExpMatchesArray* regExp = new (NotNull, allocateCell<RegExpMatchesArray>(*exec->heap())) RegExpMatchesArray(exec);
- regExp->finishCreation(exec->globalData(), ctorPrivate);
- return regExp;
+ ASSERT(result);
+ JSGlobalData& globalData = exec->globalData();
+ RegExpMatchesArray* array = new (NotNull, allocateCell<RegExpMatchesArray>(globalData.heap)) RegExpMatchesArray(globalData, exec->lexicalGlobalObject(), input, regExp, result);
+ array->finishCreation(globalData);
+ return array;
}
- static void destroy(JSCell*);
+
+ JSString* leftContext(ExecState*);
+ JSString* rightContext(ExecState*);
static const ClassInfo s_info;
@@ -46,78 +61,99 @@ namespace JSC {
return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
}
+ static void visitChildren(JSCell*, SlotVisitor&);
+
protected:
- void finishCreation(JSGlobalData&, const RegExpConstructorPrivate& data);
+ void finishCreation(JSGlobalData&);
+
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | Base::StructureFlags;
private:
+ ALWAYS_INLINE void reifyAllPropertiesIfNecessary(ExecState* exec)
+ {
+ if (m_state != ReifiedAll)
+ reifyAllProperties(exec);
+ }
+
+ ALWAYS_INLINE void reifyMatchPropertyIfNecessary(ExecState* exec)
+ {
+ if (m_state == ReifiedNone)
+ reifyMatchProperty(exec);
+ }
+
static bool getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
{
RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
- if (!thisObject->m_didFillArrayInstance)
- thisObject->fillArrayInstance(exec);
+ thisObject->reifyAllPropertiesIfNecessary(exec);
return JSArray::getOwnPropertySlot(thisObject, exec, propertyName, slot);
}
static bool getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot)
{
RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
- if (!thisObject->m_didFillArrayInstance)
- thisObject->fillArrayInstance(exec);
+ if (propertyName)
+ thisObject->reifyAllPropertiesIfNecessary(exec);
+ else
+ thisObject->reifyMatchPropertyIfNecessary(exec);
return JSArray::getOwnPropertySlotByIndex(thisObject, exec, propertyName, slot);
}
static bool getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
{
RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object);
- if (!thisObject->m_didFillArrayInstance)
- thisObject->fillArrayInstance(exec);
+ thisObject->reifyAllPropertiesIfNecessary(exec);
return JSArray::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
}
static void put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue v, PutPropertySlot& slot)
{
RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
- if (!thisObject->m_didFillArrayInstance)
- thisObject->fillArrayInstance(exec);
+ thisObject->reifyAllPropertiesIfNecessary(exec);
JSArray::put(thisObject, exec, propertyName, v, slot);
}
static void putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue v, bool shouldThrow)
{
RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
- if (!thisObject->m_didFillArrayInstance)
- thisObject->fillArrayInstance(exec);
+ thisObject->reifyAllPropertiesIfNecessary(exec);
JSArray::putByIndex(thisObject, exec, propertyName, v, shouldThrow);
}
static bool deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
{
RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
- if (!thisObject->m_didFillArrayInstance)
- thisObject->fillArrayInstance(exec);
+ thisObject->reifyAllPropertiesIfNecessary(exec);
return JSArray::deleteProperty(thisObject, exec, propertyName);
}
static bool deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
{
RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
- if (!thisObject->m_didFillArrayInstance)
- thisObject->fillArrayInstance(exec);
+ thisObject->reifyAllPropertiesIfNecessary(exec);
return JSArray::deletePropertyByIndex(thisObject, exec, propertyName);
}
static void getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& arr, EnumerationMode mode = ExcludeDontEnumProperties)
{
RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object);
- if (!thisObject->m_didFillArrayInstance)
- thisObject->fillArrayInstance(exec);
+ thisObject->reifyAllPropertiesIfNecessary(exec);
JSArray::getOwnPropertyNames(thisObject, exec, arr, mode);
}
- void fillArrayInstance(ExecState*);
+ static bool defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool shouldThrow)
+ {
+ RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object);
+ thisObject->reifyAllPropertiesIfNecessary(exec);
+ return JSArray::defineOwnProperty(object, exec, propertyName, descriptor, shouldThrow);
+ }
+
+ void reifyAllProperties(ExecState*);
+ void reifyMatchProperty(ExecState*);
- RegExpResult m_regExpResult;
- bool m_didFillArrayInstance;
+ WriteBarrier<JSString> m_input;
+ WriteBarrier<RegExp> m_regExp;
+ MatchResult m_result;
+ ReifiedState m_state;
};
}
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp
index a81799c46..da4ea0446 100644
--- a/Source/JavaScriptCore/runtime/RegExpObject.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp
@@ -29,6 +29,7 @@
#include "Lexer.h"
#include "Lookup.h"
#include "RegExpConstructor.h"
+#include "RegExpMatchesArray.h"
#include "RegExpPrototype.h"
#include "UStringBuilder.h"
#include "UStringConcatenate.h"
@@ -276,30 +277,22 @@ void RegExpObject::put(JSCell* cell, ExecState* exec, const Identifier& property
lookupPut<RegExpObject, JSObject>(exec, propertyName, value, ExecState::regExpTable(exec), jsCast<RegExpObject*>(cell), slot);
}
-JSValue RegExpObject::test(ExecState* exec)
+JSValue RegExpObject::exec(ExecState* exec, JSString* string)
{
- return jsBoolean(match(exec));
-}
-
-JSValue RegExpObject::exec(ExecState* exec)
-{
- if (match(exec))
- return exec->lexicalGlobalObject()->regExpConstructor()->arrayOfMatches(exec);
+ if (MatchResult result = match(exec, string))
+ return RegExpMatchesArray::create(exec, string, regExp(), result);
return jsNull();
}
// Shared implementation used by test and exec.
-bool RegExpObject::match(ExecState* exec)
+MatchResult RegExpObject::match(ExecState* exec, JSString* string)
{
+ RegExp* regExp = this->regExp();
RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
- UString input = exec->argument(0).toString(exec)->value(exec);
- JSGlobalData* globalData = &exec->globalData();
- if (!regExp()->global()) {
- int position;
- int length;
- regExpConstructor->performMatch(*globalData, m_regExp.get(), input, 0, position, length);
- return position >= 0;
- }
+ UString input = string->value(exec);
+ JSGlobalData& globalData = exec->globalData();
+ if (!regExp->global())
+ return regExpConstructor->performMatch(globalData, regExp, string, input, 0);
JSValue jsLastIndex = getLastIndex();
unsigned lastIndex;
@@ -307,27 +300,20 @@ bool RegExpObject::match(ExecState* exec)
lastIndex = jsLastIndex.asUInt32();
if (lastIndex > input.length()) {
setLastIndex(exec, 0);
- return false;
+ return MatchResult::failed();
}
} else {
double doubleLastIndex = jsLastIndex.toInteger(exec);
if (doubleLastIndex < 0 || doubleLastIndex > input.length()) {
setLastIndex(exec, 0);
- return false;
+ return MatchResult::failed();
}
lastIndex = static_cast<unsigned>(doubleLastIndex);
}
- int position;
- int length = 0;
- regExpConstructor->performMatch(*globalData, m_regExp.get(), input, lastIndex, position, length);
- if (position < 0) {
- setLastIndex(exec, 0);
- return false;
- }
-
- setLastIndex(exec, position + length);
- return true;
+ MatchResult result = regExpConstructor->performMatch(globalData, regExp, string, input, lastIndex);
+ setLastIndex(exec, result.end);
+ return result;
}
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.h b/Source/JavaScriptCore/runtime/RegExpObject.h
index 456cfa683..a7dd54705 100644
--- a/Source/JavaScriptCore/runtime/RegExpObject.h
+++ b/Source/JavaScriptCore/runtime/RegExpObject.h
@@ -67,8 +67,8 @@ namespace JSC {
return m_lastIndex.get();
}
- JSValue test(ExecState*);
- JSValue exec(ExecState*);
+ bool test(ExecState* exec, JSString* string) { return match(exec, string); }
+ JSValue exec(ExecState*, JSString*);
static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
@@ -95,7 +95,7 @@ namespace JSC {
JS_EXPORT_PRIVATE static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
private:
- bool match(ExecState*);
+ MatchResult match(ExecState*, JSString*);
WriteBarrier<RegExp> m_regExp;
WriteBarrier<Unknown> m_lastIndex;
diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
index 8e4b5a9d5..fba4de2b4 100644
--- a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
@@ -84,7 +84,7 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec)
JSValue thisValue = exec->hostThisValue();
if (!thisValue.inherits(&RegExpObject::s_info))
return throwVMTypeError(exec);
- return JSValue::encode(asRegExpObject(thisValue)->test(exec));
+ return JSValue::encode(jsBoolean(asRegExpObject(thisValue)->test(exec, exec->argument(0).toString(exec))));
}
EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec)
@@ -92,7 +92,7 @@ EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec)
JSValue thisValue = exec->hostThisValue();
if (!thisValue.inherits(&RegExpObject::s_info))
return throwVMTypeError(exec);
- return JSValue::encode(asRegExpObject(thisValue)->exec(exec));
+ return JSValue::encode(asRegExpObject(thisValue)->exec(exec, exec->argument(0).toString(exec)));
}
EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec)
diff --git a/Source/JavaScriptCore/runtime/SmallStrings.cpp b/Source/JavaScriptCore/runtime/SmallStrings.cpp
index caf201c3d..f50f73d27 100644
--- a/Source/JavaScriptCore/runtime/SmallStrings.cpp
+++ b/Source/JavaScriptCore/runtime/SmallStrings.cpp
@@ -68,9 +68,15 @@ SmallStringsStorage::SmallStringsStorage()
}
SmallStrings::SmallStrings()
+ : m_emptyString(0)
+#define JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE(name) , m_##name(0)
+ JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE)
+#undef JSC_COMMON_STRINGS_ATTRIBUTE_INITIALIZE
{
COMPILE_ASSERT(singleCharacterStringCount == sizeof(m_singleCharacterStrings) / sizeof(m_singleCharacterStrings[0]), IsNumCharactersConstInSyncWithClassUsage);
- clear();
+
+ for (unsigned i = 0; i < singleCharacterStringCount; ++i)
+ m_singleCharacterStrings[i] = 0;
}
SmallStrings::~SmallStrings()
@@ -82,25 +88,9 @@ void SmallStrings::finalizeSmallStrings()
finalize(m_emptyString);
for (unsigned i = 0; i < singleCharacterStringCount; ++i)
finalize(m_singleCharacterStrings[i]);
-}
-
-void SmallStrings::clear()
-{
- m_emptyString = 0;
- for (unsigned i = 0; i < singleCharacterStringCount; ++i)
- m_singleCharacterStrings[i] = 0;
-}
-
-unsigned SmallStrings::count() const
-{
- unsigned count = 0;
- if (m_emptyString)
- ++count;
- for (unsigned i = 0; i < singleCharacterStringCount; ++i) {
- if (m_singleCharacterStrings[i])
- ++count;
- }
- return count;
+#define JSC_COMMON_STRINGS_ATTRIBUTE_FINALIZE(name) finalize(m_##name);
+ JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_FINALIZE)
+#undef JSC_COMMON_STRINGS_ATTRIBUTE_FINALIZE
}
void SmallStrings::createEmptyString(JSGlobalData* globalData)
@@ -124,4 +114,9 @@ StringImpl* SmallStrings::singleCharacterStringRep(unsigned char character)
return m_storage->rep(character);
}
+void SmallStrings::initialize(JSGlobalData* globalData, JSString*& string, const char* value) const
+{
+ string = JSString::create(*globalData, StringImpl::create(value));
+}
+
} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/SmallStrings.h b/Source/JavaScriptCore/runtime/SmallStrings.h
index cd8e63095..e609c5092 100644
--- a/Source/JavaScriptCore/runtime/SmallStrings.h
+++ b/Source/JavaScriptCore/runtime/SmallStrings.h
@@ -30,6 +30,17 @@
#include <wtf/FixedArray.h>
#include <wtf/OwnPtr.h>
+#define JSC_COMMON_STRINGS_EACH_NAME(macro) \
+ macro(boolean) \
+ macro(false) \
+ macro(function) \
+ macro(number) \
+ macro(null) \
+ macro(object) \
+ macro(undefined) \
+ macro(string) \
+ macro(true)
+
namespace JSC {
class HeapRootVisitor;
@@ -63,19 +74,31 @@ namespace JSC {
JS_EXPORT_PRIVATE StringImpl* singleCharacterStringRep(unsigned char character);
void finalizeSmallStrings();
- void clear();
-
- unsigned count() const;
JSString** singleCharacterStrings() { return &m_singleCharacterStrings[0]; }
+#define JSC_COMMON_STRINGS_ACCESSOR_DEFINITION(name) \
+ JSString* name##String(JSGlobalData* globalData) const \
+ { \
+ if (!m_##name) \
+ initialize(globalData, m_##name, #name); \
+ return m_##name; \
+ }
+ JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ACCESSOR_DEFINITION)
+#undef JSC_COMMON_STRINGS_ACCESSOR_DEFINITION
+
private:
static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1;
JS_EXPORT_PRIVATE void createEmptyString(JSGlobalData*);
JS_EXPORT_PRIVATE void createSingleCharacterString(JSGlobalData*, unsigned char);
+ void initialize(JSGlobalData* globalData, JSString*& string, const char* value) const;
+
JSString* m_emptyString;
+#define JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION(name) mutable JSString* m_##name;
+ JSC_COMMON_STRINGS_EACH_NAME(JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION)
+#undef JSC_COMMON_STRINGS_ATTRIBUTE_DECLARATION
JSString* m_singleCharacterStrings[singleCharacterStringCount];
OwnPtr<SmallStringsStorage> m_storage;
};
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp
index 708c1fb77..81129f2a2 100644
--- a/Source/JavaScriptCore/runtime/StringPrototype.cpp
+++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp
@@ -35,6 +35,7 @@
#include "PropertyNameArray.h"
#include "RegExpCache.h"
#include "RegExpConstructor.h"
+#include "RegExpMatchesArray.h"
#include "RegExpObject.h"
#include <wtf/ASCIICType.h>
#include <wtf/MathExtras.h>
@@ -239,7 +240,7 @@ static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacem
static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg)
{
- size_t i = replacement.find('$', 0);
+ size_t i = replacement.find('$');
if (UNLIKELY(i != notFound)) {
if (replacement.is8Bit() && source.is8Bit())
return substituteBackreferencesSlow<LChar>(replacement, source, ovector, reg, i);
@@ -404,7 +405,7 @@ static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, J
static NEVER_INLINE EncodedJSValue removeUsingRegExpSearch(ExecState* exec, JSString* string, const UString& source, RegExp* regExp)
{
- int lastIndex = 0;
+ size_t lastIndex = 0;
unsigned startPosition = 0;
Vector<StringRange, 16> sourceRanges;
@@ -413,21 +414,18 @@ static NEVER_INLINE EncodedJSValue removeUsingRegExpSearch(ExecState* exec, JSSt
unsigned sourceLen = source.length();
while (true) {
- int matchIndex;
- int matchLen = 0;
- int* ovector;
- regExpConstructor->performMatch(*globalData, regExp, source, startPosition, matchIndex, matchLen, &ovector);
- if (matchIndex < 0)
+ MatchResult result = regExpConstructor->performMatch(*globalData, regExp, string, source, startPosition);
+ if (!result)
break;
- if (lastIndex < matchIndex)
- sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
+ if (lastIndex < result.start)
+ sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
- lastIndex = matchIndex + matchLen;
+ lastIndex = result.end;
startPosition = lastIndex;
// special case of empty match
- if (!matchLen) {
+ if (result.empty()) {
startPosition++;
if (startPosition > sourceLen)
break;
@@ -443,8 +441,9 @@ static NEVER_INLINE EncodedJSValue removeUsingRegExpSearch(ExecState* exec, JSSt
return JSValue::encode(jsSpliceSubstrings(exec, string, source, sourceRanges.data(), sourceRanges.size()));
}
-static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue)
+static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSString* string, JSValue searchValue)
{
+ JSValue replaceValue = exec->argument(1);
UString replacementString;
CallData callData;
CallType callType = getCallData(replaceValue, callData);
@@ -471,7 +470,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
- int lastIndex = 0;
+ size_t lastIndex = 0;
unsigned startPosition = 0;
Vector<StringRange, 16> sourceRanges;
@@ -481,23 +480,20 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
if (global && callType == CallTypeJS) {
// regExp->numSubpatterns() + 1 for pattern args, + 2 for match start and string
int argCount = regExp->numSubpatterns() + 1 + 2;
- JSFunction* func = asFunction(replaceValue);
+ JSFunction* func = jsCast<JSFunction*>(replaceValue);
CachedCall cachedCall(exec, func, argCount);
if (exec->hadException())
return JSValue::encode(jsNull());
JSGlobalData* globalData = &exec->globalData();
if (source.is8Bit()) {
while (true) {
- int matchIndex;
- int matchLen = 0;
int* ovector;
- regExpConstructor->performMatch(*globalData, regExp, source, startPosition, matchIndex, matchLen, &ovector);
- if (matchIndex < 0)
+ MatchResult result = regExpConstructor->performMatch(*globalData, regExp, string, source, startPosition, &ovector);
+ if (!result)
break;
- sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
+ sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
- int completeMatchStart = ovector[0];
unsigned i = 0;
for (; i < regExp->numSubpatterns() + 1; ++i) {
int matchStart = ovector[i * 2];
@@ -509,20 +505,20 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
cachedCall.setArgument(i, jsSubstring8(globalData, source, matchStart, matchLen));
}
- cachedCall.setArgument(i++, jsNumber(completeMatchStart));
+ cachedCall.setArgument(i++, jsNumber(result.start));
cachedCall.setArgument(i++, string);
cachedCall.setThis(jsUndefined());
- JSValue result = cachedCall.call();
- replacements.append(result.toString(cachedCall.newCallFrame(exec))->value(exec));
+ JSValue jsResult = cachedCall.call();
+ replacements.append(jsResult.toString(cachedCall.newCallFrame(exec))->value(exec));
if (exec->hadException())
break;
- lastIndex = matchIndex + matchLen;
+ lastIndex = result.end;
startPosition = lastIndex;
// special case of empty match
- if (!matchLen) {
+ if (result.empty()) {
startPosition++;
if (startPosition > sourceLen)
break;
@@ -530,16 +526,13 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
}
} else {
while (true) {
- int matchIndex;
- int matchLen = 0;
int* ovector;
- regExpConstructor->performMatch(*globalData, regExp, source, startPosition, matchIndex, matchLen, &ovector);
- if (matchIndex < 0)
+ MatchResult result = regExpConstructor->performMatch(*globalData, regExp, string, source, startPosition, &ovector);
+ if (!result)
break;
- sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
+ sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
- int completeMatchStart = ovector[0];
unsigned i = 0;
for (; i < regExp->numSubpatterns() + 1; ++i) {
int matchStart = ovector[i * 2];
@@ -551,20 +544,20 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
cachedCall.setArgument(i, jsSubstring(globalData, source, matchStart, matchLen));
}
- cachedCall.setArgument(i++, jsNumber(completeMatchStart));
+ cachedCall.setArgument(i++, jsNumber(result.start));
cachedCall.setArgument(i++, string);
cachedCall.setThis(jsUndefined());
- JSValue result = cachedCall.call();
- replacements.append(result.toString(cachedCall.newCallFrame(exec))->value(exec));
+ JSValue jsResult = cachedCall.call();
+ replacements.append(jsResult.toString(cachedCall.newCallFrame(exec))->value(exec));
if (exec->hadException())
break;
- lastIndex = matchIndex + matchLen;
+ lastIndex = result.end;
startPosition = lastIndex;
// special case of empty match
- if (!matchLen) {
+ if (result.empty()) {
startPosition++;
if (startPosition > sourceLen)
break;
@@ -574,17 +567,14 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
} else {
JSGlobalData* globalData = &exec->globalData();
do {
- int matchIndex;
- int matchLen = 0;
int* ovector;
- regExpConstructor->performMatch(*globalData, regExp, source, startPosition, matchIndex, matchLen, &ovector);
- if (matchIndex < 0)
+ MatchResult result = regExpConstructor->performMatch(*globalData, regExp, string, source, startPosition, &ovector);
+ if (!result)
break;
if (callType != CallTypeNone) {
- sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
+ sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
- int completeMatchStart = ovector[0];
MarkedArgumentBuffer args;
for (unsigned i = 0; i < regExp->numSubpatterns() + 1; ++i) {
@@ -597,7 +587,7 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
args.append(jsSubstring(exec, source, matchStart, matchLen));
}
- args.append(jsNumber(completeMatchStart));
+ args.append(jsNumber(result.start));
args.append(string);
replacements.append(call(exec, replaceValue, callType, callData, jsUndefined(), args).toString(exec)->value(exec));
@@ -605,8 +595,8 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
break;
} else {
int replLen = replacementString.length();
- if (lastIndex < matchIndex || replLen) {
- sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
+ if (lastIndex < result.start || replLen) {
+ sourceRanges.append(StringRange(lastIndex, result.start - lastIndex));
if (replLen)
replacements.append(substituteBackreferences(replacementString, source, ovector, regExp));
@@ -615,11 +605,11 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
}
}
- lastIndex = matchIndex + matchLen;
+ lastIndex = result.end;
startPosition = lastIndex;
// special case of empty match
- if (!matchLen) {
+ if (result.empty()) {
startPosition++;
if (startPosition > sourceLen)
break;
@@ -636,22 +626,24 @@ static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSS
return JSValue::encode(jsSpliceSubstringsWithSeparators(exec, string, source, sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size()));
}
-static NEVER_INLINE EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* jsString, JSValue searchValue, JSValue replaceValue)
+static inline EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* jsString, JSValue searchValue)
{
const UString& string = jsString->value(exec);
- UString searchString = searchValue.toString(exec)->value(exec);
+ UString searchString = searchValue.toUString(exec);
if (exec->hadException())
return JSValue::encode(jsUndefined());
size_t matchStart = string.find(searchString);
+
if (matchStart == notFound)
return JSValue::encode(jsString);
+ JSValue replaceValue = exec->argument(1);
CallData callData;
CallType callType = getCallData(replaceValue, callData);
if (callType != CallTypeNone) {
MarkedArgumentBuffer args;
- args.append(jsSubstring(exec, string, matchStart, searchString.length()));
+ args.append(jsSubstring(exec, string, matchStart, searchString.impl()->length()));
args.append(jsNumber(matchStart));
args.append(jsString);
replaceValue = call(exec, replaceValue, callType, callData, jsUndefined(), args);
@@ -659,13 +651,20 @@ static NEVER_INLINE EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSS
return JSValue::encode(jsUndefined());
}
- UString replaceString = replaceValue.toString(exec)->value(exec);
+ UString replaceString = replaceValue.toUString(exec);
if (exec->hadException())
return JSValue::encode(jsUndefined());
- size_t matchEnd = matchStart + searchString.length();
+ StringImpl* stringImpl = string.impl();
+ UString leftPart(StringImpl::create(stringImpl, 0, matchStart));
+
+ size_t matchEnd = matchStart + searchString.impl()->length();
int ovector[2] = { matchStart, matchEnd};
- return JSValue::encode(JSC::jsString(exec, string.substringSharingImpl(0, matchStart), substituteBackreferences(replaceString, string, ovector, 0), string.substringSharingImpl(matchEnd)));
+ UString middlePart = substituteBackreferences(replaceString, string, ovector, 0);
+
+ size_t leftLength = stringImpl->length() - matchEnd;
+ UString rightPart(StringImpl::create(stringImpl, matchEnd, leftLength));
+ return JSValue::encode(JSC::jsString(exec, leftPart, middlePart, rightPart));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
@@ -675,11 +674,10 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
return throwVMTypeError(exec);
JSString* string = thisValue.toString(exec);
JSValue searchValue = exec->argument(0);
- JSValue replaceValue = exec->argument(1);
if (searchValue.inherits(&RegExpObject::s_info))
- return replaceUsingRegExpSearch(exec, string, searchValue, replaceValue);
- return replaceUsingStringSearch(exec, string, searchValue, replaceValue);
+ return replaceUsingRegExpSearch(exec, string, searchValue);
+ return replaceUsingStringSearch(exec, string, searchValue);
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec)
@@ -756,26 +754,30 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec)
if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
return throwVMTypeError(exec);
UString s = thisValue.toString(exec)->value(exec);
- int len = s.length();
JSValue a0 = exec->argument(0);
JSValue a1 = exec->argument(1);
UString u2 = a0.toString(exec)->value(exec);
- int pos;
+
+ size_t result;
if (a1.isUndefined())
- pos = 0;
- else if (a1.isUInt32())
- pos = min<uint32_t>(a1.asUInt32(), len);
+ result = s.find(u2);
else {
- double dpos = a1.toInteger(exec);
- if (dpos < 0)
- dpos = 0;
- else if (dpos > len)
- dpos = len;
- pos = static_cast<int>(dpos);
+ unsigned pos;
+ int len = s.length();
+ if (a1.isUInt32())
+ pos = min<uint32_t>(a1.asUInt32(), len);
+ else {
+ double dpos = a1.toInteger(exec);
+ if (dpos < 0)
+ dpos = 0;
+ else if (dpos > len)
+ dpos = len;
+ pos = static_cast<unsigned>(dpos);
+ }
+ result = s.find(u2, pos);
}
- size_t result = s.find(u2, pos);
if (result == notFound)
return JSValue::encode(jsNumber(-1));
return JSValue::encode(jsNumber(result));
@@ -810,17 +812,18 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
JSValue thisValue = exec->hostThisValue();
if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
return throwVMTypeError(exec);
- UString s = thisValue.toString(exec)->value(exec);
+ JSString* string = thisValue.toString(exec);
+ UString s = string->value(exec);
JSGlobalData* globalData = &exec->globalData();
JSValue a0 = exec->argument(0);
- RegExp* reg;
+ RegExp* regExp;
bool global = false;
if (a0.inherits(&RegExpObject::s_info)) {
RegExpObject* regExpObject = asRegExpObject(a0);
- reg = regExpObject->regExp();
- if ((global = reg->global())) {
+ regExp = regExpObject->regExp();
+ if ((global = regExp->global())) {
// ES5.1 15.5.4.10 step 8.a.
regExpObject->setLastIndex(exec, 0);
if (exec->hadException())
@@ -833,27 +836,25 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
* replaced with the result of the expression new RegExp(regexp).
* Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string.
*/
- reg = RegExp::create(exec->globalData(), a0.isUndefined() ? UString("") : a0.toString(exec)->value(exec), NoFlags);
- if (!reg->isValid())
- return throwVMError(exec, createSyntaxError(exec, reg->errorMessage()));
+ regExp = RegExp::create(exec->globalData(), a0.isUndefined() ? UString("") : a0.toString(exec)->value(exec), NoFlags);
+ if (!regExp->isValid())
+ return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage()));
}
RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
- int pos;
- int matchLength = 0;
- regExpConstructor->performMatch(*globalData, reg, s, 0, pos, matchLength);
- if (!global) {
- // case without 'g' flag is handled like RegExp.prototype.exec
- if (pos < 0)
- return JSValue::encode(jsNull());
- return JSValue::encode(regExpConstructor->arrayOfMatches(exec));
- }
+ MatchResult result = regExpConstructor->performMatch(*globalData, regExp, string, s, 0);
+ // case without 'g' flag is handled like RegExp.prototype.exec
+ if (!global)
+ return JSValue::encode(result ? RegExpMatchesArray::create(exec, string, regExp, result) : jsNull());
// return array of matches
MarkedArgumentBuffer list;
- while (pos >= 0) {
- list.append(jsSubstring(exec, s, pos, matchLength));
- pos += matchLength == 0 ? 1 : matchLength;
- regExpConstructor->performMatch(*globalData, reg, s, pos, pos, matchLength);
+ while (result) {
+ size_t end = result.end;
+ size_t length = end - result.start;
+ list.append(jsSubstring(exec, s, result.start, length));
+ if (!length)
+ ++end;
+ result = regExpConstructor->performMatch(*globalData, regExp, string, s, end);
}
if (list.isEmpty()) {
// if there are no matches at all, it's important to return
@@ -870,7 +871,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec)
JSValue thisValue = exec->hostThisValue();
if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
return throwVMTypeError(exec);
- UString s = thisValue.toString(exec)->value(exec);
+ JSString* string = thisValue.toString(exec);
+ UString s = string->value(exec);
JSGlobalData* globalData = &exec->globalData();
JSValue a0 = exec->argument(0);
@@ -890,10 +892,8 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec)
return throwVMError(exec, createSyntaxError(exec, reg->errorMessage()));
}
RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
- int pos;
- int matchLength = 0;
- regExpConstructor->performMatch(*globalData, reg, s, 0, pos, matchLength);
- return JSValue::encode(jsNumber(pos));
+ MatchResult result = regExpConstructor->performMatch(*globalData, reg, string, s, 0);
+ return JSValue::encode(result ? jsNumber(result.start) : jsNumber(-1));
}
EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec)
@@ -923,6 +923,35 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec)
return JSValue::encode(jsEmptyString(exec));
}
+// Return true in case of early return (resultLength got to limitLength).
+template<typename CharacterType>
+static ALWAYS_INLINE bool splitStringByOneCharacterImpl(ExecState* exec, JSArray* result, const UString& input, StringImpl* string, UChar separatorCharacter, size_t& position, unsigned& resultLength, unsigned limitLength)
+{
+ // 12. Let q = p.
+ size_t matchPosition;
+ const CharacterType* characters = string->getCharacters<CharacterType>();
+ // 13. Repeat, while q != s
+ // a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
+ // b. If z is failure, then let q = q+1.
+ // c. Else, z is not failure
+ while ((matchPosition = WTF::find(characters, string->length(), separatorCharacter, position)) != notFound) {
+ // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
+ // through q (exclusive).
+ // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
+ // Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
+ result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position), false);
+ // 3. Increment lengthA by 1.
+ // 4. If lengthA == lim, return A.
+ if (++resultLength == limitLength)
+ return true;
+
+ // 5. Let p = e.
+ // 8. Let q = p.
+ position = matchPosition + 1;
+ }
+ return false;
+}
+
// ES 5.1 - 15.5.4.14 String.prototype.split (separator, limit)
EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
{
@@ -976,7 +1005,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
// c. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
// Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
// d. Return A.
- if (reg->match(*globalData, input, 0) < 0)
+ if (!reg->match(*globalData, input, 0))
result->putDirectIndex(exec, 0, jsStringWithReuse(exec, thisValue, input), false);
return JSValue::encode(result);
}
@@ -987,7 +1016,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
while (matchPosition < input.length()) {
// a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
Vector<int, 32> ovector;
- int mpos = reg->match(*globalData, input, matchPosition, &ovector);
+ int mpos = reg->match(*globalData, input, matchPosition, ovector);
// b. If z is failure, then let q = q + 1.
if (mpos < 0)
break;
@@ -1076,26 +1105,50 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
return JSValue::encode(result);
}
- // 12. Let q = p.
- size_t matchPosition;
- // 13. Repeat, while q != s
- // a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
- // b. If z is failure, then let q = q+1.
- // c. Else, z is not failure
- while ((matchPosition = input.find(separator, position)) != notFound) {
- // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
- // through q (exclusive).
- // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
- // Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
- result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position), false);
- // 3. Increment lengthA by 1.
- // 4. If lengthA == lim, return A.
- if (++resultLength == limit)
- return JSValue::encode(result);
+ // 3 cases:
+ // -separator length == 1, 8 bits
+ // -separator length == 1, 16 bits
+ // -separator length > 1
+ StringImpl* stringImpl = input.impl();
+ StringImpl* separatorImpl = separator.impl();
+ size_t separatorLength = separatorImpl->length();
+
+ if (separatorLength == 1) {
+ UChar separatorCharacter;
+ if (separatorImpl->is8Bit())
+ separatorCharacter = separatorImpl->characters8()[0];
+ else
+ separatorCharacter = separatorImpl->characters16()[0];
+
+ if (stringImpl->is8Bit()) {
+ if (splitStringByOneCharacterImpl<LChar>(exec, result, input, stringImpl, separatorCharacter, position, resultLength, limit))
+ return JSValue::encode(result);
+ } else {
+ if (splitStringByOneCharacterImpl<UChar>(exec, result, input, stringImpl, separatorCharacter, position, resultLength, limit))
+ return JSValue::encode(result);
+ }
+ } else {
+ // 12. Let q = p.
+ size_t matchPosition;
+ // 13. Repeat, while q != s
+ // a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
+ // b. If z is failure, then let q = q+1.
+ // c. Else, z is not failure
+ while ((matchPosition = stringImpl->find(separatorImpl, position)) != notFound) {
+ // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
+ // through q (exclusive).
+ // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
+ // Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
+ result->putDirectIndex(exec, resultLength, jsSubstring(exec, input, position, matchPosition - position), false);
+ // 3. Increment lengthA by 1.
+ // 4. If lengthA == lim, return A.
+ if (++resultLength == limit)
+ return JSValue::encode(result);
- // 5. Let p = e.
- // 8. Let q = p.
- position = matchPosition + separator.length();
+ // 5. Let p = e.
+ // 8. Let q = p.
+ position = matchPosition + separator.length();
+ }
}
}
@@ -1116,7 +1169,7 @@ EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec)
JSString* jsString = 0;
UString uString;
if (thisValue.isString()) {
- jsString = static_cast<JSString*>(thisValue.asCell());
+ jsString = jsCast<JSString*>(thisValue.asCell());
len = jsString->length();
} else if (thisValue.isUndefinedOrNull()) {
// CheckObjectCoercible
diff --git a/Source/JavaScriptCore/runtime/StringRecursionChecker.h b/Source/JavaScriptCore/runtime/StringRecursionChecker.h
index e3408b08b..127d028e0 100644
--- a/Source/JavaScriptCore/runtime/StringRecursionChecker.h
+++ b/Source/JavaScriptCore/runtime/StringRecursionChecker.h
@@ -48,7 +48,7 @@ inline JSValue StringRecursionChecker::performCheck()
int size = m_exec->globalData().stringRecursionCheckVisitedObjects.size();
if (size >= MaxSmallThreadReentryDepth && size >= m_exec->globalData().maxReentryDepth)
return throwStackOverflowError();
- bool alreadyVisited = !m_exec->globalData().stringRecursionCheckVisitedObjects.add(m_thisObject).second;
+ bool alreadyVisited = !m_exec->globalData().stringRecursionCheckVisitedObjects.add(m_thisObject).isNewEntry;
if (alreadyVisited)
return emptyString(); // Return empty string to avoid infinite recursion.
return JSValue(); // Indicate success.
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
index 6ee419da6..074c8b354 100644
--- a/Source/JavaScriptCore/runtime/Structure.cpp
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -102,12 +102,12 @@ inline void StructureTransitionTable::add(JSGlobalData& globalData, Structure* s
// Newer versions of the STL have an std::make_pair function that takes rvalue references.
// When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
// See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details
- std::pair<TransitionMap::iterator, bool> result = map()->add(globalData, make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious), structure);
- if (!result.second) {
+ TransitionMap::AddResult result = map()->add(globalData, make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious), structure);
+ if (!result.isNewEntry) {
// There already is an entry! - we should only hit this when despecifying.
- ASSERT(result.first.get().second->m_specificValueInPrevious);
+ ASSERT(result.iterator.get().second->m_specificValueInPrevious);
ASSERT(!structure->m_specificValueInPrevious);
- map()->set(result.first, structure);
+ map()->set(globalData, result.iterator.get().first, structure);
}
}
@@ -267,6 +267,13 @@ void Structure::growPropertyStorageCapacity()
m_propertyStorageCapacity *= 2;
}
+size_t Structure::suggestedNewPropertyStorageSize()
+{
+ if (isUsingInlineStorage())
+ return JSObject::baseExternalStorageCapacity;
+ return m_propertyStorageCapacity * 2;
+}
+
void Structure::despecifyDictionaryFunction(JSGlobalData& globalData, const Identifier& propertyName)
{
StringImpl* rep = propertyName.impl();
@@ -787,6 +794,8 @@ void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
visitor.append(&ptr->specificValue);
}
}
+ if (thisObject->m_objectToStringValue)
+ visitor.append(&thisObject->m_objectToStringValue);
}
#if DO_PROPERTYMAP_CONSTENCY_CHECK
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
index 46cf732e1..00bc76177 100644
--- a/Source/JavaScriptCore/runtime/Structure.h
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -50,6 +50,7 @@ namespace JSC {
class PropertyNameArrayData;
class StructureChain;
class SlotVisitor;
+ class JSString;
class Structure : public JSCell {
public:
@@ -101,6 +102,8 @@ namespace JSC {
bool isFrozen(JSGlobalData&);
bool isExtensible() const { return !m_preventExtensions; }
bool didTransition() const { return m_didTransition; }
+ bool shouldGrowPropertyStorage() { return propertyStorageCapacity() == propertyStorageSize(); }
+ JS_EXPORT_PRIVATE size_t suggestedNewPropertyStorageSize();
Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
@@ -169,6 +172,13 @@ namespace JSC {
JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
void getPropertyNamesFromStructure(JSGlobalData&, PropertyNameArray&, EnumerationMode);
+ JSString* objectToStringValue() { return m_objectToStringValue.get(); }
+
+ void setObjectToStringValue(JSGlobalData& globalData, const JSCell* owner, JSString* value)
+ {
+ m_objectToStringValue.set(globalData, owner, value);
+ }
+
bool staticFunctionsReified()
{
return m_staticFunctionReified;
@@ -289,6 +299,8 @@ namespace JSC {
uint32_t m_propertyStorageCapacity;
+ WriteBarrier<JSString> m_objectToStringValue;
+
// m_offset does not account for anonymous slots
int m_offset;
@@ -406,7 +418,7 @@ namespace JSC {
{
#if ENABLE(GC_VALIDATION)
ASSERT(globalData.isInitializingObject());
- globalData.setInitializingObject(false);
+ globalData.setInitializingObjectClass(0);
if (structure)
#endif
m_structure.setEarlyValue(globalData, this, structure);
diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
index 517992470..2067a8995 100644
--- a/Source/JavaScriptCore/runtime/StructureTransitionTable.h
+++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
@@ -34,6 +34,7 @@
namespace JSC {
+class JSCell;
class Structure;
class StructureTransitionTable {
@@ -83,10 +84,10 @@ public:
return;
}
- HandleSlot slot = this->slot();
- if (!slot)
+ WeakImpl* impl = this->weakImpl();
+ if (!impl)
return;
- HandleHeap::heapFor(slot)->deallocate(slot);
+ WeakSet::deallocate(impl);
}
inline void add(JSGlobalData&, Structure*);
@@ -105,18 +106,18 @@ private:
return reinterpret_cast<TransitionMap*>(m_data);
}
- HandleSlot slot() const
+ WeakImpl* weakImpl() const
{
ASSERT(isUsingSingleSlot());
- return reinterpret_cast<HandleSlot>(m_data & ~UsingSingleSlotFlag);
+ return reinterpret_cast<WeakImpl*>(m_data & ~UsingSingleSlotFlag);
}
void setMap(TransitionMap* map)
{
ASSERT(isUsingSingleSlot());
- if (HandleSlot slot = this->slot())
- HandleHeap::heapFor(slot)->deallocate(slot);
+ if (WeakImpl* impl = this->weakImpl())
+ WeakSet::deallocate(impl);
// This implicitly clears the flag that indicates we're using a single transition
m_data = reinterpret_cast<intptr_t>(map);
@@ -127,24 +128,20 @@ private:
Structure* singleTransition() const
{
ASSERT(isUsingSingleSlot());
- if (HandleSlot slot = this->slot()) {
- if (*slot)
- return reinterpret_cast<Structure*>(slot->asCell());
+ if (WeakImpl* impl = this->weakImpl()) {
+ if (impl->state() == WeakImpl::Live)
+ return reinterpret_cast<Structure*>(impl->jsValue().asCell());
}
return 0;
}
- void setSingleTransition(JSGlobalData& globalData, Structure* structure)
+ void setSingleTransition(JSGlobalData&, Structure* structure)
{
ASSERT(isUsingSingleSlot());
- HandleSlot slot = this->slot();
- if (!slot) {
- slot = globalData.heap.handleHeap()->allocate();
- HandleHeap::heapFor(slot)->makeWeak(slot, 0, 0);
- m_data = reinterpret_cast<intptr_t>(slot) | UsingSingleSlotFlag;
- }
- HandleHeap::heapFor(slot)->writeBarrier(slot, reinterpret_cast<JSCell*>(structure));
- *slot = reinterpret_cast<JSCell*>(structure);
+ if (WeakImpl* impl = this->weakImpl())
+ WeakSet::deallocate(impl);
+ WeakImpl* impl = WeakSet::allocate(reinterpret_cast<JSCell*>(structure));
+ m_data = reinterpret_cast<intptr_t>(impl) | UsingSingleSlotFlag;
}
intptr_t m_data;
diff --git a/Source/JavaScriptCore/runtime/TimeoutChecker.cpp b/Source/JavaScriptCore/runtime/TimeoutChecker.cpp
index 3065c99ed..8f3d1a578 100644
--- a/Source/JavaScriptCore/runtime/TimeoutChecker.cpp
+++ b/Source/JavaScriptCore/runtime/TimeoutChecker.cpp
@@ -38,7 +38,7 @@
#elif OS(WINDOWS)
#include <windows.h>
#else
-#include "CurrentTime.h"
+#include <wtf/CurrentTime.h>
#endif
using namespace std;
diff --git a/Source/JavaScriptCore/runtime/UString.h b/Source/JavaScriptCore/runtime/UString.h
index 668eb0489..7677161a3 100644
--- a/Source/JavaScriptCore/runtime/UString.h
+++ b/Source/JavaScriptCore/runtime/UString.h
@@ -121,8 +121,12 @@ public:
// Find a single character or string, also with match function & latin1 forms.
size_t find(UChar c, unsigned start = 0) const
{ return m_impl ? m_impl->find(c, start) : notFound; }
- size_t find(const UString& str, unsigned start = 0) const
+
+ size_t find(const UString& str) const
+ { return m_impl ? m_impl->find(str.impl()) : notFound; }
+ size_t find(const UString& str, unsigned start) const
{ return m_impl ? m_impl->find(str.impl(), start) : notFound; }
+
size_t find(const LChar* str, unsigned start = 0) const
{ return m_impl ? m_impl->find(str, start) : notFound; }
diff --git a/Source/JavaScriptCore/runtime/WeakGCMap.h b/Source/JavaScriptCore/runtime/WeakGCMap.h
index 1bb3cd5bb..ec010fb4b 100644
--- a/Source/JavaScriptCore/runtime/WeakGCMap.h
+++ b/Source/JavaScriptCore/runtime/WeakGCMap.h
@@ -51,7 +51,7 @@ class WeakGCMap : private WeakHandleOwner {
WTF_MAKE_FAST_ALLOCATED;
WTF_MAKE_NONCOPYABLE(WeakGCMap);
- typedef HashMap<KeyType, HandleSlot, HashArg, KeyTraitsArg> MapType;
+ typedef HashMap<KeyType, WeakImpl*, HashArg, KeyTraitsArg> MapType;
typedef typename HandleTypes<MappedType>::ExternalType ExternalType;
typedef typename MapType::iterator map_iterator;
@@ -64,8 +64,7 @@ public:
{
}
- std::pair<KeyType, ExternalType> get() const { return std::make_pair(m_iterator->first, HandleTypes<MappedType>::getFromSlot(m_iterator->second)); }
- std::pair<KeyType, HandleSlot> getSlot() const { return *m_iterator; }
+ std::pair<KeyType, ExternalType> get() const { return std::make_pair(m_iterator->first, HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&m_iterator->second->jsValue()))); }
iterator& operator++() { ++m_iterator; return *this; }
@@ -79,6 +78,8 @@ public:
map_iterator m_iterator;
};
+ typedef WTF::HashTableAddResult<iterator> AddResult;
+
WeakGCMap()
{
}
@@ -88,7 +89,7 @@ public:
{
map_iterator end = m_map.end();
for (map_iterator ptr = m_map.begin(); ptr != end; ++ptr)
- HandleHeap::heapFor(ptr->second)->deallocate(ptr->second);
+ WeakSet::deallocate(ptr->second);
m_map.clear();
}
@@ -105,63 +106,42 @@ public:
void remove(iterator iter)
{
ASSERT(iter.m_iterator != m_map.end());
- HandleSlot slot = iter.m_iterator->second;
- ASSERT(slot);
- HandleHeap::heapFor(slot)->deallocate(slot);
+ WeakImpl* impl = iter.m_iterator->second;
+ ASSERT(impl);
+ WeakSet::deallocate(impl);
m_map.remove(iter.m_iterator);
}
ExternalType get(const KeyType& key) const
{
- return HandleTypes<MappedType>::getFromSlot(m_map.get(key));
+ return HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&m_map.get(key)->jsValue()));
}
- HandleSlot getSlot(const KeyType& key) const
+ AddResult add(JSGlobalData&, const KeyType& key, ExternalType value)
{
- return m_map.get(key);
- }
+ typename MapType::AddResult result = m_map.add(key, 0);
+ if (result.isNewEntry)
+ result.iterator->second = WeakSet::allocate(value, this, FinalizerCallback::finalizerContextFor(key));
- pair<iterator, bool> add(JSGlobalData& globalData, const KeyType& key, ExternalType value)
- {
- pair<typename MapType::iterator, bool> iter = m_map.add(key, 0);
- if (iter.second) {
- HandleSlot slot = globalData.heap.handleHeap()->allocate();
- iter.first->second = slot;
- HandleHeap::heapFor(slot)->makeWeak(slot, this, FinalizerCallback::finalizerContextFor(key));
- HandleHeap::heapFor(slot)->writeBarrier(slot, value);
- *slot = value;
- }
- return iter;
- }
-
- void set(iterator iter, ExternalType value)
- {
- HandleSlot slot = iter.m_iterator->second;
- ASSERT(slot);
- HandleHeap::heapFor(slot)->writeBarrier(slot, value);
- *slot = value;
+ // WeakGCMap exposes a different iterator, so we need to wrap it and create our own AddResult.
+ return AddResult(iterator(result.iterator), result.isNewEntry);
}
- void set(JSGlobalData& globalData, const KeyType& key, ExternalType value)
+ void set(JSGlobalData&, const KeyType& key, ExternalType value)
{
- pair<typename MapType::iterator, bool> iter = m_map.add(key, 0);
- HandleSlot slot = iter.first->second;
- if (iter.second) {
- slot = globalData.heap.handleHeap()->allocate();
- HandleHeap::heapFor(slot)->makeWeak(slot, this, key);
- iter.first->second = slot;
- }
- HandleHeap::heapFor(slot)->writeBarrier(slot, value);
- *slot = value;
+ typename MapType::AddResult result = m_map.add(key, 0);
+ if (!result.isNewEntry)
+ WeakSet::deallocate(result.iterator->second);
+ result.iterator->second = WeakSet::allocate(value, this, FinalizerCallback::finalizerContextFor(key));
}
ExternalType take(const KeyType& key)
{
- HandleSlot slot = m_map.take(key);
- if (!slot)
+ WeakImpl* impl = m_map.take(key);
+ if (!impl)
return HashTraits<ExternalType>::emptyValue();
- ExternalType result = HandleTypes<MappedType>::getFromSlot(slot);
- HandleHeap::heapFor(slot)->deallocate(slot);
+ ExternalType result = HandleTypes<MappedType>::getFromSlot(const_cast<JSValue*>(&impl->jsValue()));
+ WeakSet::deallocate(impl);
return result;
}
@@ -178,9 +158,9 @@ public:
private:
virtual void finalize(Handle<Unknown> handle, void* context)
{
- HandleSlot slot = m_map.take(FinalizerCallback::keyForFinalizer(context, HandleTypes<MappedType>::getFromSlot(handle.slot())));
- ASSERT(slot);
- HandleHeap::heapFor(slot)->deallocate(slot);
+ WeakImpl* impl = m_map.take(FinalizerCallback::keyForFinalizer(context, HandleTypes<MappedType>::getFromSlot(handle.slot())));
+ ASSERT(impl);
+ WeakSet::deallocate(impl);
}
MapType m_map;