diff options
Diffstat (limited to 'JavaScriptCore/runtime')
40 files changed, 551 insertions, 397 deletions
diff --git a/JavaScriptCore/runtime/ArrayPrototype.cpp b/JavaScriptCore/runtime/ArrayPrototype.cpp index ce814b2..b64abad 100644 --- a/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -28,6 +28,7 @@ #include "CachedCall.h" #include "Interpreter.h" #include "JIT.h" +#include "JSStringBuilder.h" #include "ObjectPrototype.h" #include "Lookup.h" #include "Operations.h" @@ -182,8 +183,7 @@ JSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec, JSObject*, JSValue totalSize += str.size(); if (!strBuffer.data()) { - JSObject* error = Error::create(exec, GeneralError, "Out of memory"); - exec->setException(error); + throwOutOfMemoryError(exec); } if (exec->hadException()) @@ -195,7 +195,7 @@ JSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec, JSObject*, JSValue Vector<UChar> buffer; buffer.reserveCapacity(totalSize); if (!buffer.data()) - return throwError(exec, GeneralError, "Out of memory"); + return throwOutOfMemoryError(exec); for (unsigned i = 0; i < length; i++) { if (i) @@ -223,42 +223,28 @@ JSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec, JSObject*, J if (alreadyVisited) return jsEmptyString(exec); // return an empty string, avoding infinite recursion. - Vector<UChar, 256> strBuffer; + JSStringBuilder strBuffer; unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); for (unsigned k = 0; k < length; k++) { if (k >= 1) strBuffer.append(','); - if (!strBuffer.data()) { - JSObject* error = Error::create(exec, GeneralError, "Out of memory"); - exec->setException(error); - break; - } JSValue element = thisObj->get(exec, k); - if (element.isUndefinedOrNull()) - continue; - - JSObject* o = element.toObject(exec); - JSValue conversionFunction = o->get(exec, exec->propertyNames().toLocaleString); - UString str; - CallData callData; - CallType callType = conversionFunction.getCallData(callData); - if (callType != CallTypeNone) - str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toString(exec); - else - str = element.toString(exec); - strBuffer.append(str.data(), str.size()); - - if (!strBuffer.data()) { - JSObject* error = Error::create(exec, GeneralError, "Out of memory"); - exec->setException(error); + if (!element.isUndefinedOrNull()) { + JSObject* o = element.toObject(exec); + JSValue conversionFunction = o->get(exec, exec->propertyNames().toLocaleString); + UString str; + CallData callData; + CallType callType = conversionFunction.getCallData(callData); + if (callType != CallTypeNone) + str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toString(exec); + else + str = element.toString(exec); + strBuffer.append(str); } - - if (exec->hadException()) - break; } arrayVisitedElements.remove(thisObj); - return jsString(exec, UString(strBuffer.data(), strBuffer.data() ? strBuffer.size() : 0)); + return strBuffer.build(exec); } JSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) @@ -275,38 +261,27 @@ JSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec, JSObject*, JSValue thi if (alreadyVisited) return jsEmptyString(exec); // return an empty string, avoding infinite recursion. - Vector<UChar, 256> strBuffer; + JSStringBuilder strBuffer; - UChar comma = ','; - UString separator = args.at(0).isUndefined() ? UString(&comma, 1) : args.at(0).toString(exec); + UString separator; + if (!args.at(0).isUndefined()) + separator = args.at(0).toString(exec); unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); for (unsigned k = 0; k < length; k++) { - if (k >= 1) - strBuffer.append(separator.data(), separator.size()); - if (!strBuffer.data()) { - JSObject* error = Error::create(exec, GeneralError, "Out of memory"); - exec->setException(error); - break; + if (k >= 1) { + if (separator.isNull()) + strBuffer.append(','); + else + strBuffer.append(separator); } JSValue element = thisObj->get(exec, k); - if (element.isUndefinedOrNull()) - continue; - - UString str = element.toString(exec); - strBuffer.append(str.data(), str.size()); - - if (!strBuffer.data()) { - JSObject* error = Error::create(exec, GeneralError, "Out of memory"); - exec->setException(error); - } - - if (exec->hadException()) - break; + if (!element.isUndefinedOrNull()) + strBuffer.append(element.toString(exec)); } arrayVisitedElements.remove(thisObj); - return jsString(exec, UString(strBuffer.data(), strBuffer.data() ? strBuffer.size() : 0)); + return strBuffer.build(exec); } JSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) diff --git a/JavaScriptCore/runtime/Collector.cpp b/JavaScriptCore/runtime/Collector.cpp index 63139a2..2873e0b 100644 --- a/JavaScriptCore/runtime/Collector.cpp +++ b/JavaScriptCore/runtime/Collector.cpp @@ -1122,12 +1122,15 @@ void Heap::markRoots() MarkedArgumentBuffer::markLists(markStack, *m_markListSet); if (m_globalData->exception) markStack.append(m_globalData->exception); - m_globalData->smallStrings.markChildren(markStack); if (m_globalData->functionCodeBlockBeingReparsed) m_globalData->functionCodeBlockBeingReparsed->markAggregate(markStack); if (m_globalData->firstStringifierToMark) JSONObject::markStringifiers(markStack, m_globalData->firstStringifierToMark); + // Mark the small strings cache last, since it will clear itself if nothing + // else has marked it. + m_globalData->smallStrings.markChildren(markStack); + markStack.drain(); markStack.compact(); @@ -1197,12 +1200,13 @@ static const char* typeName(JSCell* cell) return "number"; #endif if (cell->isGetterSetter()) - return "gettersetter"; + return "Getter-Setter"; if (cell->isAPIValueWrapper()) - return "value wrapper"; + return "API wrapper"; if (cell->isPropertyNameIterator()) - return "for-in iterator"; - ASSERT(cell->isObject()); + return "For-in iterator"; + if (!cell->isObject()) + return "[empty cell]"; const ClassInfo* info = cell->classInfo(); return info ? info->className : "Object"; } @@ -1218,6 +1222,18 @@ HashCountedSet<const char*>* Heap::protectedObjectTypeCounts() return counts; } +HashCountedSet<const char*>* Heap::objectTypeCounts() +{ + HashCountedSet<const char*>* counts = new HashCountedSet<const char*>; + + LiveObjectIterator it = primaryHeapBegin(); + LiveObjectIterator heapEnd = primaryHeapEnd(); + for ( ; it != heapEnd; ++it) + counts->add(typeName(*it)); + + return counts; +} + bool Heap::isBusy() { return m_heap.operationInProgress != NoOperation; diff --git a/JavaScriptCore/runtime/Collector.h b/JavaScriptCore/runtime/Collector.h index 7f7a679..82aa8a1 100644 --- a/JavaScriptCore/runtime/Collector.h +++ b/JavaScriptCore/runtime/Collector.h @@ -100,6 +100,7 @@ namespace JSC { size_t protectedObjectCount(); size_t protectedGlobalObjectCount(); HashCountedSet<const char*>* protectedObjectTypeCounts(); + HashCountedSet<const char*>* objectTypeCounts(); void registerThread(); // Only needs to be called by clients that can use the same heap from multiple threads. diff --git a/JavaScriptCore/runtime/CollectorHeapIterator.h b/JavaScriptCore/runtime/CollectorHeapIterator.h index e4f2f91..be6f3c9 100644 --- a/JavaScriptCore/runtime/CollectorHeapIterator.h +++ b/JavaScriptCore/runtime/CollectorHeapIterator.h @@ -38,7 +38,7 @@ namespace JSC { protected: CollectorHeapIterator(CollectorHeap&, size_t startBlock, size_t startCell); - void advance(size_t cellsPerBlock); + void advance(size_t max); CollectorHeap& m_heap; size_t m_block; @@ -80,10 +80,12 @@ namespace JSC { return reinterpret_cast<JSCell*>(m_heap.blocks[m_block]->cells + m_cell); } - inline void CollectorHeapIterator::advance(size_t cellsPerBlock) + // Iterators advance up to the next-to-last -- and not the last -- cell in a + // block, since the last cell is a dummy sentinel. + inline void CollectorHeapIterator::advance(size_t max) { ++m_cell; - if (m_cell == cellsPerBlock) { + if (m_cell == max) { m_cell = 0; ++m_block; } @@ -97,14 +99,12 @@ namespace JSC { inline LiveObjectIterator& LiveObjectIterator::operator++() { - if (m_block < m_heap.nextBlock || m_cell < m_heap.nextCell) { - advance(HeapConstants::cellsPerBlock); + advance(HeapConstants::cellsPerBlock - 1); + if (m_block < m_heap.nextBlock || (m_block == m_heap.nextBlock && m_cell < m_heap.nextCell)) return *this; - } - do { - advance(HeapConstants::cellsPerBlock); - } while (m_block < m_heap.usedBlocks && !m_heap.blocks[m_block]->marked.get(m_cell)); + while (m_block < m_heap.usedBlocks && !m_heap.blocks[m_block]->marked.get(m_cell)) + advance(HeapConstants::cellsPerBlock - 1); return *this; } @@ -117,7 +117,7 @@ namespace JSC { inline DeadObjectIterator& DeadObjectIterator::operator++() { do { - advance(HeapConstants::cellsPerBlock); + advance(HeapConstants::cellsPerBlock - 1); ASSERT(m_block > m_heap.nextBlock || (m_block == m_heap.nextBlock && m_cell >= m_heap.nextCell)); } while (m_block < m_heap.usedBlocks && m_heap.blocks[m_block]->marked.get(m_cell)); return *this; @@ -131,7 +131,7 @@ namespace JSC { inline ObjectIterator& ObjectIterator::operator++() { - advance(HeapConstants::cellsPerBlock); + advance(HeapConstants::cellsPerBlock - 1); return *this; } diff --git a/JavaScriptCore/runtime/CommonIdentifiers.cpp b/JavaScriptCore/runtime/CommonIdentifiers.cpp index 3837817..ed5e304 100644 --- a/JavaScriptCore/runtime/CommonIdentifiers.cpp +++ b/JavaScriptCore/runtime/CommonIdentifiers.cpp @@ -28,8 +28,7 @@ static const char* const nullCString = 0; #define INITIALIZE_PROPERTY_NAME(name) , name(globalData, #name) CommonIdentifiers::CommonIdentifiers(JSGlobalData* globalData) - : nullIdentifier(globalData, nullCString) - , emptyIdentifier(globalData, "") + : emptyIdentifier(globalData, "") , underscoreProto(globalData, "__proto__") , thisIdentifier(globalData, "this") JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME) diff --git a/JavaScriptCore/runtime/CommonIdentifiers.h b/JavaScriptCore/runtime/CommonIdentifiers.h index de24f4a..0a3d774 100644 --- a/JavaScriptCore/runtime/CommonIdentifiers.h +++ b/JavaScriptCore/runtime/CommonIdentifiers.h @@ -90,7 +90,6 @@ namespace JSC { friend class JSGlobalData; public: - const Identifier nullIdentifier; const Identifier emptyIdentifier; const Identifier underscoreProto; const Identifier thisIdentifier; diff --git a/JavaScriptCore/runtime/DateConstructor.cpp b/JavaScriptCore/runtime/DateConstructor.cpp index e9a5c29..ab95d06 100644 --- a/JavaScriptCore/runtime/DateConstructor.cpp +++ b/JavaScriptCore/runtime/DateConstructor.cpp @@ -28,6 +28,7 @@ #include "JSFunction.h" #include "JSGlobalObject.h" #include "JSString.h" +#include "JSStringBuilder.h" #include "ObjectPrototype.h" #include "PrototypeFunction.h" #include <math.h> @@ -137,7 +138,7 @@ static JSValue JSC_HOST_CALL callDate(ExecState* exec, JSObject*, JSValue, const DateConversionBuffer time; formatDate(ts, date); formatTime(ts, time); - return jsNontrivialString(exec, makeString(date, " ", time)); + return jsMakeNontrivialString(exec, date, " ", time); } CallType DateConstructor::getCallData(CallData& callData) diff --git a/JavaScriptCore/runtime/DatePrototype.cpp b/JavaScriptCore/runtime/DatePrototype.cpp index ca9d4ea..25b0ac4 100644 --- a/JavaScriptCore/runtime/DatePrototype.cpp +++ b/JavaScriptCore/runtime/DatePrototype.cpp @@ -26,6 +26,7 @@ #include "DateConversion.h" #include "Error.h" #include "JSString.h" +#include "JSStringBuilder.h" #include "ObjectPrototype.h" #include "DateInstance.h" @@ -427,7 +428,7 @@ JSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec, JSObject*, JSValue DateConversionBuffer time; formatDate(*gregorianDateTime, date); formatTime(*gregorianDateTime, time); - return jsNontrivialString(exec, makeString(date, " ", time)); + return jsMakeNontrivialString(exec, date, " ", time); } JSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -444,7 +445,7 @@ JSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec, JSObject*, JSVal DateConversionBuffer time; formatDateUTCVariant(*gregorianDateTime, date); formatTimeUTC(*gregorianDateTime, time); - return jsNontrivialString(exec, makeString(date, " ", time)); + return jsMakeNontrivialString(exec, date, " ", time); } JSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -570,7 +571,7 @@ JSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec, JSObject*, JSVal DateConversionBuffer time; formatDateUTCVariant(*gregorianDateTime, date); formatTimeUTC(*gregorianDateTime, time); - return jsNontrivialString(exec, makeString(date, " ", time)); + return jsMakeNontrivialString(exec, date, " ", time); } JSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) diff --git a/JavaScriptCore/runtime/Error.cpp b/JavaScriptCore/runtime/Error.cpp index ddd4bc4..69464b7 100644 --- a/JavaScriptCore/runtime/Error.cpp +++ b/JavaScriptCore/runtime/Error.cpp @@ -94,7 +94,7 @@ JSObject* Error::create(ExecState* exec, ErrorType type, const UString& message, JSObject* Error::create(ExecState* exec, ErrorType type, const char* message) { - return create(exec, type, message, -1, -1, NULL); + return create(exec, type, message, -1, -1, UString()); } JSObject* throwError(ExecState* exec, JSObject* error) @@ -105,21 +105,21 @@ JSObject* throwError(ExecState* exec, JSObject* error) JSObject* throwError(ExecState* exec, ErrorType type) { - JSObject* error = Error::create(exec, type, UString(), -1, -1, NULL); + JSObject* error = Error::create(exec, type, UString(), -1, -1, UString()); exec->setException(error); return error; } JSObject* throwError(ExecState* exec, ErrorType type, const UString& message) { - JSObject* error = Error::create(exec, type, message, -1, -1, NULL); + JSObject* error = Error::create(exec, type, message, -1, -1, UString()); exec->setException(error); return error; } JSObject* throwError(ExecState* exec, ErrorType type, const char* message) { - JSObject* error = Error::create(exec, type, message, -1, -1, NULL); + JSObject* error = Error::create(exec, type, message, -1, -1, UString()); exec->setException(error); return error; } diff --git a/JavaScriptCore/runtime/ErrorPrototype.cpp b/JavaScriptCore/runtime/ErrorPrototype.cpp index be9e4b8..eb35733 100644 --- a/JavaScriptCore/runtime/ErrorPrototype.cpp +++ b/JavaScriptCore/runtime/ErrorPrototype.cpp @@ -23,6 +23,7 @@ #include "JSFunction.h" #include "JSString.h" +#include "JSStringBuilder.h" #include "ObjectPrototype.h" #include "PrototypeFunction.h" #include "UString.h" @@ -55,11 +56,11 @@ JSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec, JSObject*, JSValue if (!name.isUndefined()) { if (!message.isUndefined()) - return jsNontrivialString(exec, makeString(name.toString(exec), ": ", message.toString(exec))); + return jsMakeNontrivialString(exec, name.toString(exec), ": ", message.toString(exec)); return jsNontrivialString(exec, name.toString(exec)); } if (!message.isUndefined()) - return jsNontrivialString(exec, makeString("Error: ", message.toString(exec))); + return jsMakeNontrivialString(exec, "Error: ", message.toString(exec)); return jsNontrivialString(exec, "Error"); } diff --git a/JavaScriptCore/runtime/ExceptionHelpers.cpp b/JavaScriptCore/runtime/ExceptionHelpers.cpp index 9bb740e..b9c6319 100644 --- a/JavaScriptCore/runtime/ExceptionHelpers.cpp +++ b/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -58,7 +58,7 @@ JSValue createInterruptedExecutionException(JSGlobalData* globalData) static JSValue createError(ExecState* exec, ErrorType e, const char* msg) { - return Error::create(exec, e, msg, -1, -1, 0); + return Error::create(exec, e, msg, -1, -1, UString()); } JSValue createStackOverflowError(ExecState* exec) @@ -188,4 +188,9 @@ JSObject* createNotAnObjectError(ExecState* exec, JSNotAnObjectErrorStub* error, return exception; } +JSValue throwOutOfMemoryError(ExecState* exec) +{ + return throwError(exec, GeneralError, "Out of memory"); +} + } // namespace JSC diff --git a/JavaScriptCore/runtime/ExceptionHelpers.h b/JavaScriptCore/runtime/ExceptionHelpers.h index e739d09..b6e7373 100644 --- a/JavaScriptCore/runtime/ExceptionHelpers.h +++ b/JavaScriptCore/runtime/ExceptionHelpers.h @@ -51,6 +51,7 @@ namespace JSC { JSObject* createNotAConstructorError(ExecState*, JSValue, unsigned bytecodeOffset, CodeBlock*); JSValue createNotAFunctionError(ExecState*, JSValue, unsigned bytecodeOffset, CodeBlock*); JSObject* createNotAnObjectError(ExecState*, JSNotAnObjectErrorStub*, unsigned bytecodeOffset, CodeBlock*); + JSValue throwOutOfMemoryError(ExecState*); } // namespace JSC diff --git a/JavaScriptCore/runtime/Executable.cpp b/JavaScriptCore/runtime/Executable.cpp index bc18cc9..79900dc 100644 --- a/JavaScriptCore/runtime/Executable.cpp +++ b/JavaScriptCore/runtime/Executable.cpp @@ -272,7 +272,7 @@ UString FunctionExecutable::paramString() const builder.append(", "); builder.append(parameters[pos].ustring()); } - return builder.release(); + return builder.build(); } }; diff --git a/JavaScriptCore/runtime/FunctionConstructor.cpp b/JavaScriptCore/runtime/FunctionConstructor.cpp index 9d55dd1..9b0b1bb 100644 --- a/JavaScriptCore/runtime/FunctionConstructor.cpp +++ b/JavaScriptCore/runtime/FunctionConstructor.cpp @@ -89,7 +89,7 @@ JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifi builder.append(") { "); builder.append(args.at(args.size() - 1).toString(exec)); builder.append("\n})"); - program = builder.release(); + program = builder.build(); } int errLine; diff --git a/JavaScriptCore/runtime/FunctionPrototype.cpp b/JavaScriptCore/runtime/FunctionPrototype.cpp index f08bd5e..3475f08 100644 --- a/JavaScriptCore/runtime/FunctionPrototype.cpp +++ b/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -25,6 +25,7 @@ #include "JSArray.h" #include "JSFunction.h" #include "JSString.h" +#include "JSStringBuilder.h" #include "Interpreter.h" #include "Lexer.h" #include "PrototypeFunction.h" @@ -38,7 +39,7 @@ static JSValue JSC_HOST_CALL functionProtoFuncApply(ExecState*, JSObject*, JSVal static JSValue JSC_HOST_CALL functionProtoFuncCall(ExecState*, JSObject*, JSValue, const ArgList&); FunctionPrototype::FunctionPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure) - : InternalFunction(&exec->globalData(), structure, exec->propertyNames().nullIdentifier) + : InternalFunction(&exec->globalData(), structure, exec->propertyNames().emptyIdentifier) { putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 0), DontDelete | ReadOnly | DontEnum); } @@ -90,13 +91,13 @@ JSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec, JSObject*, JSVa FunctionExecutable* executable = function->jsExecutable(); UString sourceString = executable->source().toString(); insertSemicolonIfNeeded(sourceString); - return jsString(exec, makeString("function ", function->name(exec), "(", executable->paramString(), ") ", sourceString)); + return jsMakeNontrivialString(exec, "function ", function->name(exec), "(", executable->paramString(), ") ", sourceString); } } if (thisValue.inherits(&InternalFunction::info)) { InternalFunction* function = asInternalFunction(thisValue); - return jsString(exec, makeString("function ", function->name(exec), "() {\n [native code]\n}")); + return jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}"); } return throwError(exec, TypeError); diff --git a/JavaScriptCore/runtime/Identifier.cpp b/JavaScriptCore/runtime/Identifier.cpp index 747c4ac..97929e2 100644 --- a/JavaScriptCore/runtime/Identifier.cpp +++ b/JavaScriptCore/runtime/Identifier.cpp @@ -123,10 +123,8 @@ struct CStringTranslator { PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const char* c) { - if (!c) { - UString::Rep::null().hash(); - return &UString::Rep::null(); - } + ASSERT(c); + if (!c[0]) { UString::Rep::empty().hash(); return &UString::Rep::empty(); diff --git a/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index 0bc1274..3ddac7c 100644 --- a/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -30,11 +30,11 @@ #include "Interpreter.h" #include "JSGlobalObject.h" #include "JSString.h" +#include "JSStringBuilder.h" #include "Lexer.h" #include "LiteralParser.h" #include "Nodes.h" #include "Parser.h" -#include "StringBuilder.h" #include "StringExtras.h" #include "dtoa.h" #include <stdio.h> @@ -57,7 +57,7 @@ static JSValue encode(ExecState* exec, const ArgList& args, const char* doNotEsc if (!cstr.c_str()) return throwError(exec, URIError, "String contained an illegal UTF-16 sequence."); - StringBuilder builder; + JSStringBuilder builder; const char* p = cstr.c_str(); for (size_t k = 0; k < cstr.size(); k++, p++) { char c = *p; @@ -66,15 +66,15 @@ static JSValue encode(ExecState* exec, const ArgList& args, const char* doNotEsc else { char tmp[4]; snprintf(tmp, 4, "%%%02X", static_cast<unsigned char>(c)); - builder.append((const char*)tmp); + builder.append(tmp); } } - return jsString(exec, builder.release()); + return builder.build(exec); } static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUnescape, bool strict) { - StringBuilder builder; + JSStringBuilder builder; UString str = args.at(0).toString(exec); int k = 0; int len = str.size(); @@ -135,7 +135,7 @@ static JSValue decode(ExecState* exec, const ArgList& args, const char* doNotUne k++; builder.append(c); } - return jsString(exec, builder.release()); + return builder.build(exec); } bool isStrWhiteSpace(UChar c) @@ -378,8 +378,7 @@ JSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec, JSObject*, JSValue, cons "0123456789" "*+-./@_"; - StringBuilder builder; - UString s; + JSStringBuilder builder; UString str = args.at(0).toString(exec); const UChar* c = str.data(); for (int k = 0; k < str.size(); k++, c++) { @@ -387,18 +386,17 @@ JSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec, JSObject*, JSValue, cons if (u > 255) { char tmp[7]; sprintf(tmp, "%%u%04X", u); - s = UString(tmp); + builder.append(tmp); } else if (u != 0 && strchr(do_not_escape, static_cast<char>(u))) - s = UString(c, 1); + builder.append(c, 1); else { char tmp[4]; sprintf(tmp, "%%%02X", u); - s = UString(tmp); + builder.append(tmp); } - builder.append(s); } - return jsString(exec, builder.release()); + return builder.build(exec); } JSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec, JSObject*, JSValue, const ArgList& args) @@ -425,7 +423,7 @@ JSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec, JSObject*, JSValue, co builder.append(*c); } - return jsString(exec, builder.release()); + return jsString(exec, builder.build()); } #ifndef NDEBUG diff --git a/JavaScriptCore/runtime/JSONObject.cpp b/JavaScriptCore/runtime/JSONObject.cpp index ce0dcff..acd9280 100644 --- a/JavaScriptCore/runtime/JSONObject.cpp +++ b/JavaScriptCore/runtime/JSONObject.cpp @@ -268,7 +268,7 @@ JSValue Stringifier::stringify(JSValue value) if (m_exec->hadException()) return jsNull(); - return jsString(m_exec, result.release()); + return jsString(m_exec, result.build()); } void Stringifier::appendQuotedString(StringBuilder& builder, const UString& value) diff --git a/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/JavaScriptCore/runtime/JSPropertyNameIterator.cpp index d3dcb83..a5d4da0 100644 --- a/JavaScriptCore/runtime/JSPropertyNameIterator.cpp +++ b/JavaScriptCore/runtime/JSPropertyNameIterator.cpp @@ -35,6 +35,24 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(JSPropertyNameIterator); +inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots) + : JSCell(exec->globalData().propertyNameIteratorStructure.get()) + , m_cachedStructure(0) + , m_numCacheableSlots(numCacheableSlots) + , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size()) + , m_jsStrings(new JSValue[m_jsStringsSize]) +{ + PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector(); + for (size_t i = 0; i < m_jsStringsSize; ++i) + m_jsStrings[i] = jsOwnedString(exec, propertyNameVector[i].ustring()); +} + +JSPropertyNameIterator::~JSPropertyNameIterator() +{ + if (m_cachedStructure) + m_cachedStructure->clearEnumerationCache(this); +} + JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject* o) { ASSERT(!o->structure()->enumerationCache() || diff --git a/JavaScriptCore/runtime/JSPropertyNameIterator.h b/JavaScriptCore/runtime/JSPropertyNameIterator.h index d18c2c5..3f533a0 100644 --- a/JavaScriptCore/runtime/JSPropertyNameIterator.h +++ b/JavaScriptCore/runtime/JSPropertyNameIterator.h @@ -49,6 +49,8 @@ namespace JSC { { return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren), AnonymousSlotCount); } + + virtual ~JSPropertyNameIterator(); virtual bool isPropertyNameIterator() const { return true; } @@ -81,23 +83,21 @@ namespace JSC { OwnArrayPtr<JSValue> m_jsStrings; }; -inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots) - : JSCell(exec->globalData().propertyNameIteratorStructure.get()) - , m_cachedStructure(0) - , m_numCacheableSlots(numCacheableSlots) - , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size()) - , m_jsStrings(new JSValue[m_jsStringsSize]) -{ - PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector(); - for (size_t i = 0; i < m_jsStringsSize; ++i) - m_jsStrings[i] = jsOwnedString(exec, propertyNameVector[i].ustring()); -} - -inline void Structure::setEnumerationCache(JSPropertyNameIterator* enumerationCache) -{ - ASSERT(!isDictionary()); - m_enumerationCache = enumerationCache; -} + inline void Structure::setEnumerationCache(JSPropertyNameIterator* enumerationCache) + { + ASSERT(!isDictionary()); + m_enumerationCache = enumerationCache; + } + + inline void Structure::clearEnumerationCache(JSPropertyNameIterator* enumerationCache) + { + m_enumerationCache.clear(enumerationCache); + } + + inline JSPropertyNameIterator* Structure::enumerationCache() + { + return m_enumerationCache.get(); + } } // namespace JSC diff --git a/JavaScriptCore/runtime/JSString.h b/JavaScriptCore/runtime/JSString.h index af03025..cff8e3a 100644 --- a/JavaScriptCore/runtime/JSString.h +++ b/JavaScriptCore/runtime/JSString.h @@ -283,8 +283,9 @@ namespace JSC { } const UString tryGetValue() const { - if (isRope()) - UString(); + // If this is a rope, m_value should be null - + // if this is not a rope, m_value should be non-null. + ASSERT(isRope() == m_value.isNull()); return m_value; } unsigned length() { return m_stringLength; } diff --git a/JavaScriptCore/runtime/JSStringBuilder.h b/JavaScriptCore/runtime/JSStringBuilder.h new file mode 100644 index 0000000..2b11736 --- /dev/null +++ b/JavaScriptCore/runtime/JSStringBuilder.h @@ -0,0 +1,105 @@ +/* + * 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 JSStringBuilder_h +#define JSStringBuilder_h + +#include "ExceptionHelpers.h" +#include "JSString.h" +#include "StringBuilder.h" + +namespace JSC { + +class JSStringBuilder : public StringBuilder { +public: + JSValue build(ExecState* exec) + { + buffer.shrinkToFit(); + if (!buffer.data()) + return throwOutOfMemoryError(exec); + return jsString(exec, UString::adopt(buffer)); + } + +private: + // Make attempts to call this compile error - if you only wanted a UString, + // Why didn't you just use a StringBuilder?! (This may change, maybe at some + // point in the future we'll need to start building a string not knowing whether + // we'll want a UString or a JSValue - but until we have this requirement, + // block this). + UString build() + { + ASSERT_NOT_REACHED(); + return StringBuilder::build(); + } +}; + +template<typename StringType1, typename StringType2> +inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2) +{ + PassRefPtr<UStringImpl> result = tryMakeString(string1, string2); + if (!result) + return throwOutOfMemoryError(exec); + return jsNontrivialString(exec, result); +} + +template<typename StringType1, typename StringType2, typename StringType3> +inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3) +{ + PassRefPtr<UStringImpl> result = tryMakeString(string1, string2, string3); + if (!result) + return throwOutOfMemoryError(exec); + return jsNontrivialString(exec, result); +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4> +inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4) +{ + PassRefPtr<UStringImpl> result = tryMakeString(string1, string2, string3, string4); + if (!result) + return throwOutOfMemoryError(exec); + return jsNontrivialString(exec, result); +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5> +inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5) +{ + PassRefPtr<UStringImpl> result = tryMakeString(string1, string2, string3, string4, string5); + if (!result) + return throwOutOfMemoryError(exec); + return jsNontrivialString(exec, result); +} + +template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6> +inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6) +{ + PassRefPtr<UStringImpl> result = tryMakeString(string1, string2, string3, string4, string5, string6); + if (!result) + return throwOutOfMemoryError(exec); + return jsNontrivialString(exec, result); +} + +} + +#endif diff --git a/JavaScriptCore/runtime/JSValue.cpp b/JavaScriptCore/runtime/JSValue.cpp index 699c1cd..502312c 100644 --- a/JavaScriptCore/runtime/JSValue.cpp +++ b/JavaScriptCore/runtime/JSValue.cpp @@ -174,7 +174,11 @@ uint32_t toUInt32SlowCase(double d, bool& ok) NEVER_INLINE double nonInlineNaN() { +#if OS(SYMBIAN) + return nanval(); +#else return std::numeric_limits<double>::quiet_NaN(); +#endif } } // namespace JSC diff --git a/JavaScriptCore/runtime/LiteralParser.cpp b/JavaScriptCore/runtime/LiteralParser.cpp index aa1e5ed..cc33bae 100644 --- a/JavaScriptCore/runtime/LiteralParser.cpp +++ b/JavaScriptCore/runtime/LiteralParser.cpp @@ -200,7 +200,7 @@ template <LiteralParser::ParserMode mode> inline LiteralParser::TokenType Litera if (m_ptr >= m_end || *m_ptr != '"') return TokError; - token.stringToken = builder.release(); + token.stringToken = builder.build(); token.type = TokString; token.end = ++m_ptr; return TokString; diff --git a/JavaScriptCore/runtime/NumberPrototype.cpp b/JavaScriptCore/runtime/NumberPrototype.cpp index 67210fa..fa32b86 100644 --- a/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/JavaScriptCore/runtime/NumberPrototype.cpp @@ -25,6 +25,7 @@ #include "Error.h" #include "JSFunction.h" #include "JSString.h" +#include "JSStringBuilder.h" #include "Operations.h" #include "PrototypeFunction.h" #include "StringBuilder.h" @@ -94,7 +95,7 @@ static UString integerPartNoExp(double d) builder.append((const char*)(buf.data())); } - return builder.release(); + return builder.build(); } static UString charSequence(char c, int count) @@ -262,7 +263,7 @@ JSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec, JSObject*, JSValue for (int i = 0; i < f + 1 - k; i++) z.append('0'); z.append(m); - m = z.release(); + m = z.build(); k = f + 1; ASSERT(k == m.size()); } @@ -432,8 +433,8 @@ JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSV if (m.size() > 1) m = makeString(m.substr(0, 1), ".", m.substr(1)); if (e >= 0) - return jsNontrivialString(exec, makeString(s, m, "e+", UString::from(e))); - return jsNontrivialString(exec, makeString(s, m, "e-", UString::from(-e))); + return jsMakeNontrivialString(exec, s, m, "e+", UString::from(e)); + return jsMakeNontrivialString(exec, s, m, "e-", UString::from(-e)); } } else { m = charSequence('0', precision); @@ -447,7 +448,7 @@ JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec, JSObject*, JSV return jsString(exec, makeString(s, m.substr(0, e + 1), ".", m.substr(e + 1))); return jsString(exec, makeString(s, m)); } - return jsNontrivialString(exec, makeString(s, "0.", charSequence('0', -(e + 1)), m)); + return jsMakeNontrivialString(exec, s, "0.", charSequence('0', -(e + 1)), m); } } // namespace JSC diff --git a/JavaScriptCore/runtime/ObjectPrototype.cpp b/JavaScriptCore/runtime/ObjectPrototype.cpp index 3065c6d..c32a007 100644 --- a/JavaScriptCore/runtime/ObjectPrototype.cpp +++ b/JavaScriptCore/runtime/ObjectPrototype.cpp @@ -24,6 +24,7 @@ #include "Error.h" #include "JSFunction.h" #include "JSString.h" +#include "JSStringBuilder.h" #include "PrototypeFunction.h" namespace JSC { @@ -148,7 +149,7 @@ JSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - return jsNontrivialString(exec, makeString("[object ", thisValue.toThisObject(exec)->className(), "]")); + return jsMakeNontrivialString(exec, "[object ", thisValue.toThisObject(exec)->className(), "]"); } } // namespace JSC diff --git a/JavaScriptCore/runtime/Operations.cpp b/JavaScriptCore/runtime/Operations.cpp index 0e1887c..cf236bf 100644 --- a/JavaScriptCore/runtime/Operations.cpp +++ b/JavaScriptCore/runtime/Operations.cpp @@ -41,13 +41,6 @@ bool JSValue::strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2) return strictEqualSlowCaseInline(exec, v1, v2); } -NEVER_INLINE JSValue throwOutOfMemoryError(ExecState* exec) -{ - JSObject* error = Error::create(exec, GeneralError, "Out of memory"); - exec->setException(error); - return error; -} - NEVER_INLINE JSValue jsAddSlowCase(CallFrame* callFrame, JSValue v1, JSValue v2) { // exception for the Date exception in defaultValue() diff --git a/JavaScriptCore/runtime/Operations.h b/JavaScriptCore/runtime/Operations.h index c3aa0fa..9b27074 100644 --- a/JavaScriptCore/runtime/Operations.h +++ b/JavaScriptCore/runtime/Operations.h @@ -22,6 +22,7 @@ #ifndef Operations_h #define Operations_h +#include "ExceptionHelpers.h" #include "Interpreter.h" #include "JSImmediate.h" #include "JSNumberCell.h" @@ -29,7 +30,6 @@ namespace JSC { - NEVER_INLINE JSValue throwOutOfMemoryError(ExecState*); NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue); JSValue jsTypeStringForValue(CallFrame*, JSValue); bool jsIsObjectType(JSValue); diff --git a/JavaScriptCore/runtime/PropertyNameArray.cpp b/JavaScriptCore/runtime/PropertyNameArray.cpp index 5108272..4937b7c 100644 --- a/JavaScriptCore/runtime/PropertyNameArray.cpp +++ b/JavaScriptCore/runtime/PropertyNameArray.cpp @@ -30,7 +30,7 @@ static const size_t setThreshold = 20; void PropertyNameArray::add(UString::Rep* identifier) { - ASSERT(identifier == &UString::Rep::null() || identifier == &UString::Rep::empty() || identifier->isIdentifier()); + ASSERT(identifier == &UString::Rep::empty() || identifier->isIdentifier()); size_t size = m_data->propertyNameVector().size(); if (size < setThreshold) { diff --git a/JavaScriptCore/runtime/RegExpPrototype.cpp b/JavaScriptCore/runtime/RegExpPrototype.cpp index 5f9d357..dd5fe02 100644 --- a/JavaScriptCore/runtime/RegExpPrototype.cpp +++ b/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -27,6 +27,7 @@ #include "JSFunction.h" #include "JSObject.h" #include "JSString.h" +#include "JSStringBuilder.h" #include "JSValue.h" #include "ObjectPrototype.h" #include "PrototypeFunction.h" @@ -116,7 +117,7 @@ JSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec, JSObject*, JSValu postfix[index] = 'm'; UString source = asRegExpObject(thisValue)->get(exec, exec->propertyNames().source).toString(exec); // If source is empty, use "/(?:)/" to avoid colliding with comment syntax - return jsNontrivialString(exec, makeString("/", source.size() ? source : UString("(?:)"), postfix)); + return jsMakeNontrivialString(exec, "/", source.size() ? source : UString("(?:)"), postfix); } } // namespace JSC diff --git a/JavaScriptCore/runtime/SmallStrings.cpp b/JavaScriptCore/runtime/SmallStrings.cpp index ac71735..d9d4377 100644 --- a/JavaScriptCore/runtime/SmallStrings.cpp +++ b/JavaScriptCore/runtime/SmallStrings.cpp @@ -34,6 +34,11 @@ namespace JSC { static const unsigned numCharactersToStore = 0x100; +static inline bool isMarked(JSString* string) +{ + return string && Heap::isCellMarked(string); +} + class SmallStringsStorage : public Noncopyable { public: SmallStringsStorage(); @@ -55,13 +60,9 @@ SmallStringsStorage::SmallStringsStorage() } SmallStrings::SmallStrings() - : m_emptyString(0) - , m_storage(0) { COMPILE_ASSERT(numCharactersToStore == sizeof(m_singleCharacterStrings) / sizeof(m_singleCharacterStrings[0]), IsNumCharactersConstInSyncWithClassUsage); - - for (unsigned i = 0; i < numCharactersToStore; ++i) - m_singleCharacterStrings[i] = 0; + clear(); } SmallStrings::~SmallStrings() @@ -70,6 +71,25 @@ SmallStrings::~SmallStrings() void SmallStrings::markChildren(MarkStack& markStack) { + /* + Our hypothesis is that small strings are very common. So, we cache them + to avoid GC churn. However, in cases where this hypothesis turns out to + be false -- including the degenerate case where all JavaScript execution + has terminated -- we don't want to waste memory. + + To test our hypothesis, we check if any small string has been marked. If + so, it's probably reasonable to mark the rest. If not, we clear the cache. + */ + + bool isAnyStringMarked = isMarked(m_emptyString); + for (unsigned i = 0; i < numCharactersToStore && !isAnyStringMarked; ++i) + isAnyStringMarked |= isMarked(m_singleCharacterStrings[i]); + + if (!isAnyStringMarked) { + clear(); + return; + } + if (m_emptyString) markStack.append(m_emptyString); for (unsigned i = 0; i < numCharactersToStore; ++i) { @@ -78,6 +98,13 @@ void SmallStrings::markChildren(MarkStack& markStack) } } +void SmallStrings::clear() +{ + m_emptyString = 0; + for (unsigned i = 0; i < numCharactersToStore; ++i) + m_singleCharacterStrings[i] = 0; +} + unsigned SmallStrings::count() const { unsigned count = 0; diff --git a/JavaScriptCore/runtime/SmallStrings.h b/JavaScriptCore/runtime/SmallStrings.h index efecbb0..cc11d0a 100644 --- a/JavaScriptCore/runtime/SmallStrings.h +++ b/JavaScriptCore/runtime/SmallStrings.h @@ -57,6 +57,7 @@ namespace JSC { UString::Rep* singleCharacterStringRep(unsigned char character); void markChildren(MarkStack&); + void clear(); unsigned count() const; diff --git a/JavaScriptCore/runtime/StringBuilder.h b/JavaScriptCore/runtime/StringBuilder.h index 8e18d37..27dbbd7 100644 --- a/JavaScriptCore/runtime/StringBuilder.h +++ b/JavaScriptCore/runtime/StringBuilder.h @@ -39,7 +39,7 @@ public: void append(const char* str) { - buffer.append(str, strlen(str)); + append(str, strlen(str)); } void append(const char* str, size_t len) @@ -66,13 +66,15 @@ public: UChar operator[](size_t i) const { return buffer.at(i); } - UString release() + UString build() { buffer.shrinkToFit(); + if (buffer.size() && !buffer.data()) + CRASH(); return UString::adopt(buffer); } -private: +protected: Vector<UChar, 64> buffer; }; diff --git a/JavaScriptCore/runtime/StringPrototype.cpp b/JavaScriptCore/runtime/StringPrototype.cpp index d002e07..8c014ec 100644 --- a/JavaScriptCore/runtime/StringPrototype.cpp +++ b/JavaScriptCore/runtime/StringPrototype.cpp @@ -28,6 +28,7 @@ #include "JSGlobalObjectFunctions.h" #include "JSArray.h" #include "JSFunction.h" +#include "JSStringBuilder.h" #include "ObjectPrototype.h" #include "Operations.h" #include "PropertyNameArray.h" @@ -227,6 +228,86 @@ static inline int localeCompare(const UString& a, const UString& b) return Collator::userDefault()->collate(reinterpret_cast<const ::UChar*>(a.data()), a.size(), reinterpret_cast<const ::UChar*>(b.data()), b.size()); } +struct StringRange { +public: + StringRange(int pos, int len) + : position(pos) + , length(len) + { + } + + StringRange() + { + } + + int position; + int length; +}; + +JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const UString& source, const StringRange* substringRanges, int rangeCount, const UString* separators, int separatorCount); +JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const UString& source, const StringRange* substringRanges, int rangeCount, const UString* separators, int separatorCount) +{ + if (rangeCount == 1 && separatorCount == 0) { + int sourceSize = source.size(); + int position = substringRanges[0].position; + int length = substringRanges[0].length; + if (position <= 0 && length >= sourceSize) + return sourceVal; + // We could call UString::substr, but this would result in redundant checks + return jsString(exec, UStringImpl::create(source.rep(), max(0, position), min(sourceSize, length))); + } + + int totalLength = 0; + for (int i = 0; i < rangeCount; i++) + totalLength += substringRanges[i].length; + for (int i = 0; i < separatorCount; i++) + totalLength += separators[i].size(); + + if (totalLength == 0) + return jsString(exec, ""); + + UChar* buffer; + PassRefPtr<UStringImpl> impl = UStringImpl::tryCreateUninitialized(totalLength, buffer); + if (!impl) + return throwOutOfMemoryError(exec); + + int maxCount = max(rangeCount, separatorCount); + int bufferPos = 0; + for (int i = 0; i < maxCount; i++) { + if (i < rangeCount) { + UStringImpl::copyChars(buffer + bufferPos, source.data() + substringRanges[i].position, substringRanges[i].length); + bufferPos += substringRanges[i].length; + } + if (i < separatorCount) { + UStringImpl::copyChars(buffer + bufferPos, separators[i].data(), separators[i].size()); + bufferPos += separators[i].size(); + } + } + + return jsString(exec, impl); +} + +JSValue jsReplaceRange(ExecState* exec, const UString& source, int rangeStart, int rangeLength, const UString& replacement); +JSValue jsReplaceRange(ExecState* exec, const UString& source, int rangeStart, int rangeLength, const UString& replacement) +{ + int replacementLength = replacement.size(); + int totalLength = source.size() - rangeLength + replacementLength; + if (totalLength == 0) + return jsString(exec, ""); + + UChar* buffer; + PassRefPtr<UStringImpl> impl = UStringImpl::tryCreateUninitialized(totalLength, buffer); + if (!impl) + return throwOutOfMemoryError(exec); + + UStringImpl::copyChars(buffer, source.data(), rangeStart); + UStringImpl::copyChars(buffer + rangeStart, replacement.data(), replacementLength); + int rangeEnd = rangeStart + rangeLength; + UStringImpl::copyChars(buffer + rangeStart + replacementLength, source.data() + rangeEnd, source.size() - rangeEnd); + + return jsString(exec, impl); +} + JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { JSString* sourceVal = thisValue.toThisJSString(exec); @@ -250,7 +331,7 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue int lastIndex = 0; int startPosition = 0; - Vector<UString::Range, 16> sourceRanges; + Vector<StringRange, 16> sourceRanges; Vector<UString, 16> replacements; // This is either a loop (if global is set) or a one-way (if not). @@ -269,7 +350,7 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue if (matchIndex < 0) break; - sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex)); + sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex)); int completeMatchStart = ovector[0]; unsigned i = 0; @@ -311,7 +392,7 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue if (matchIndex < 0) break; - sourceRanges.append(UString::Range(lastIndex, matchIndex - lastIndex)); + sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex)); if (callType != CallTypeNone) { int completeMatchStart = ovector[0]; @@ -352,10 +433,9 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue return sourceVal; if (lastIndex < source.size()) - sourceRanges.append(UString::Range(lastIndex, source.size() - lastIndex)); + sourceRanges.append(StringRange(lastIndex, source.size() - lastIndex)); - return jsString(exec, source.spliceSubstringsWithSeparators(sourceRanges.data(), sourceRanges.size(), - replacements.data(), replacements.size())); + return jsSpliceSubstringsWithSeparators(exec, sourceVal, source, sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size()); } // Not a regular expression, so treat the pattern as a string. @@ -377,7 +457,7 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue } int ovector[2] = { matchPos, matchPos + matchLen }; - return jsString(exec, source.replaceRange(matchPos, matchLen, substituteBackreferences(replacementString, source, ovector, 0))); + return jsReplaceRange(exec, source, matchPos, matchLen, substituteBackreferences(replacementString, source, ovector, 0)); } JSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) @@ -789,62 +869,62 @@ JSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec, JSObject*, J JSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, makeString("<big>", s, "</big>")); + return jsMakeNontrivialString(exec, "<big>", s, "</big>"); } JSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, makeString("<small>", s, "</small>")); + return jsMakeNontrivialString(exec, "<small>", s, "</small>"); } JSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, makeString("<blink>", s, "</blink>")); + return jsMakeNontrivialString(exec, "<blink>", s, "</blink>"); } JSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, makeString("<b>", s, "</b>")); + return jsMakeNontrivialString(exec, "<b>", s, "</b>"); } JSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsString(exec, makeString("<tt>", s, "</tt>")); + return jsMakeNontrivialString(exec, "<tt>", s, "</tt>"); } JSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, makeString("<i>", s, "</i>")); + return jsMakeNontrivialString(exec, "<i>", s, "</i>"); } JSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, makeString("<strike>", s, "</strike>")); + return jsMakeNontrivialString(exec, "<strike>", s, "</strike>"); } JSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, makeString("<sub>", s, "</sub>")); + return jsMakeNontrivialString(exec, "<sub>", s, "</sub>"); } JSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { UString s = thisValue.toThisString(exec); - return jsNontrivialString(exec, makeString("<sup>", s, "</sup>")); + return jsMakeNontrivialString(exec, "<sup>", s, "</sup>"); } JSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { UString s = thisValue.toThisString(exec); JSValue a0 = args.at(0); - return jsNontrivialString(exec, makeString("<font color=\"", a0.toString(exec), "\">", s, "</font>")); + return jsMakeNontrivialString(exec, "<font color=\"", a0.toString(exec), "\">", s, "</font>"); } JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) @@ -886,14 +966,14 @@ JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValu return jsNontrivialString(exec, impl); } - return jsNontrivialString(exec, makeString("<font size=\"", a0.toString(exec), "\">", s, "</font>")); + return jsMakeNontrivialString(exec, "<font size=\"", a0.toString(exec), "\">", s, "</font>"); } JSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { UString s = thisValue.toThisString(exec); JSValue a0 = args.at(0); - return jsNontrivialString(exec, makeString("<a name=\"", a0.toString(exec), "\">", s, "</a>")); + return jsMakeNontrivialString(exec, "<a name=\"", a0.toString(exec), "\">", s, "</a>"); } JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) diff --git a/JavaScriptCore/runtime/Structure.h b/JavaScriptCore/runtime/Structure.h index 1353a5a..95cf94c 100644 --- a/JavaScriptCore/runtime/Structure.h +++ b/JavaScriptCore/runtime/Structure.h @@ -36,6 +36,7 @@ #include "StructureTransitionTable.h" #include "JSTypeInfo.h" #include "UString.h" +#include "WeakGCPtr.h" #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -101,7 +102,7 @@ namespace JSC { void growPropertyStorageCapacity(); unsigned propertyStorageCapacity() const { return m_propertyStorageCapacity; } - unsigned propertyStorageSize() const { return m_anonymousSlotCount + (m_propertyTable ? m_propertyTable->keyCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1); } + unsigned propertyStorageSize() const { return m_anonymousSlotCount + (m_propertyTable ? m_propertyTable->keyCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : static_cast<unsigned>(m_offset + 1)); } bool isUsingInlineStorage() const; size_t get(const Identifier& propertyName); @@ -135,7 +136,8 @@ namespace JSC { void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; } void setEnumerationCache(JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h. - JSPropertyNameIterator* enumerationCache() { return m_enumerationCache.get(); } + void clearEnumerationCache(JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h. + JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h. void getPropertyNames(PropertyNameArray&, EnumerationMode mode); private: @@ -199,7 +201,7 @@ namespace JSC { StructureTransitionTable table; - ProtectedPtr<JSPropertyNameIterator> m_enumerationCache; + WeakGCPtr<JSPropertyNameIterator> m_enumerationCache; PropertyMapHashTable* m_propertyTable; diff --git a/JavaScriptCore/runtime/UString.cpp b/JavaScriptCore/runtime/UString.cpp index e75a05c..4a89a23 100644 --- a/JavaScriptCore/runtime/UString.cpp +++ b/JavaScriptCore/runtime/UString.cpp @@ -53,7 +53,7 @@ using namespace WTF::Unicode; using namespace std; namespace JSC { - + extern const double NaN; extern const double Inf; @@ -146,95 +146,46 @@ bool operator==(const CString& c1, const CString& c2) return len == c2.size() && (len == 0 || memcmp(c1.c_str(), c2.c_str(), len) == 0); } -// These static strings are immutable, except for rc, whose initial value is chosen to +// These static strings are immutable, except for rc, whose initial value is chosen to // reduce the possibility of it becoming zero due to ref/deref not being thread-safe. static UChar sharedEmptyChar; -UStringImpl* UStringImpl::s_null; UStringImpl* UStringImpl::s_empty; -UString* UString::nullUString; + +UString::Rep* UString::s_nullRep; +UString* UString::s_nullUString; void initializeUString() { - UStringImpl::s_null = new UStringImpl(0, 0, UStringImpl::ConstructStaticString); UStringImpl::s_empty = new UStringImpl(&sharedEmptyChar, 0, UStringImpl::ConstructStaticString); - UString::nullUString = new UString; -} - -static PassRefPtr<UString::Rep> createRep(const char* c) -{ - if (!c) - return &UString::Rep::null(); - - if (!c[0]) - return &UString::Rep::empty(); - size_t length = strlen(c); - UChar* d; - PassRefPtr<UStringImpl> result = UStringImpl::tryCreateUninitialized(length, d); - if (!result) - return &UString::Rep::null(); - - for (size_t i = 0; i < length; i++) - d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend - return result; -} - -static inline PassRefPtr<UString::Rep> createRep(const char* c, int length) -{ - if (!c) - return &UString::Rep::null(); - - if (!length) - return &UString::Rep::empty(); - - UChar* d; - PassRefPtr<UStringImpl> result = UStringImpl::tryCreateUninitialized(length, d); - if (!result) - return &UString::Rep::null(); - - for (int i = 0; i < length; i++) - d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend - return result; + UString::s_nullRep = new UStringImpl(0, 0, UStringImpl::ConstructStaticString); + UString::s_nullUString = new UString; } UString::UString(const char* c) - : m_rep(createRep(c)) + : m_rep(Rep::create(c)) { } UString::UString(const char* c, int length) - : m_rep(createRep(c, length)) + : m_rep(Rep::create(c, length)) { } UString::UString(const UChar* c, int length) { - if (length == 0) + if (length == 0) m_rep = &Rep::empty(); else m_rep = Rep::create(c, length); } -UString UString::createFromUTF8(const char* string) -{ - if (!string) - return null(); - - size_t length = strlen(string); - Vector<UChar, 1024> buffer(length); - UChar* p = buffer.data(); - if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length)) - return null(); - - return UString(buffer.data(), p - buffer.data()); -} - UString UString::from(int i) { UChar buf[1 + sizeof(i) * 3]; UChar* end = buf + sizeof(buf) / sizeof(UChar); UChar* p = end; - + if (i == 0) *--p = '0'; else if (i == INT_MIN) { @@ -296,7 +247,7 @@ UString UString::from(unsigned int u) UChar buf[sizeof(u) * 3]; UChar* end = buf + sizeof(buf) / sizeof(UChar); UChar* p = end; - + if (u == 0) *--p = '0'; else { @@ -305,7 +256,7 @@ UString UString::from(unsigned int u) u /= 10; } } - + return UString(p, static_cast<int>(end - p)); } @@ -346,71 +297,6 @@ UString UString::from(double d) return UString(buffer, length); } -UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const -{ - m_rep->checkConsistency(); - - if (rangeCount == 1 && separatorCount == 0) { - int thisSize = size(); - int position = substringRanges[0].position; - int length = substringRanges[0].length; - if (position <= 0 && length >= thisSize) - return *this; - return UString::Rep::create(m_rep, max(0, position), min(thisSize, length)); - } - - int totalLength = 0; - for (int i = 0; i < rangeCount; i++) - totalLength += substringRanges[i].length; - for (int i = 0; i < separatorCount; i++) - totalLength += separators[i].size(); - - if (totalLength == 0) - return ""; - - UChar* buffer; - PassRefPtr<Rep> rep = Rep::tryCreateUninitialized(totalLength, buffer); - if (!rep) - return null(); - - int maxCount = max(rangeCount, separatorCount); - int bufferPos = 0; - for (int i = 0; i < maxCount; i++) { - if (i < rangeCount) { - UStringImpl::copyChars(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length); - bufferPos += substringRanges[i].length; - } - if (i < separatorCount) { - UStringImpl::copyChars(buffer + bufferPos, separators[i].data(), separators[i].size()); - bufferPos += separators[i].size(); - } - } - - return rep; -} - -UString UString::replaceRange(int rangeStart, int rangeLength, const UString& replacement) const -{ - m_rep->checkConsistency(); - - int replacementLength = replacement.size(); - int totalLength = size() - rangeLength + replacementLength; - if (totalLength == 0) - return ""; - - UChar* buffer; - PassRefPtr<Rep> rep = Rep::tryCreateUninitialized(totalLength, buffer); - if (!rep) - return null(); - - UStringImpl::copyChars(buffer, data(), rangeStart); - UStringImpl::copyChars(buffer + rangeStart, replacement.data(), replacementLength); - int rangeEnd = rangeStart + rangeLength; - UStringImpl::copyChars(buffer + rangeStart + replacementLength, data() + rangeEnd, size() - rangeEnd); - - return rep; -} - bool UString::getCString(CStringBuffer& buffer) const { int length = size(); @@ -456,30 +342,6 @@ char* UString::ascii() const return asciiBuffer; } -UString& UString::operator=(const char* c) -{ - if (!c) { - m_rep = &Rep::null(); - return *this; - } - - if (!c[0]) { - m_rep = &Rep::empty(); - return *this; - } - - int l = static_cast<int>(strlen(c)); - UChar* d = 0; - m_rep = Rep::tryCreateUninitialized(l, d); - if (m_rep) { - for (int i = 0; i < l; i++) - d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend - } else - makeNull(); - - return *this; -} - bool UString::is8Bit() const { const UChar* u = data(); @@ -721,7 +583,7 @@ int UString::find(UChar ch, int pos) const if (*c == ch) return static_cast<int>(c - data()); } - + return -1; } @@ -888,16 +750,4 @@ CString UString::UTF8String(bool strict) const return CString(buffer.data(), p - buffer.data()); } -// For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X. -NEVER_INLINE void UString::makeNull() -{ - m_rep = &Rep::null(); -} - -// For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X. -NEVER_INLINE UString::Rep* UString::nullRep() -{ - return &Rep::null(); -} - } // namespace JSC diff --git a/JavaScriptCore/runtime/UString.h b/JavaScriptCore/runtime/UString.h index 0c13689..7d9ec49 100644 --- a/JavaScriptCore/runtime/UString.h +++ b/JavaScriptCore/runtime/UString.h @@ -81,7 +81,6 @@ namespace JSC { typedef UStringImpl Rep; public: - // UString constructors passed char*s assume ISO Latin-1 encoding; for UTF8 use 'createFromUTF8', below. UString(); UString(const char*); // Constructor for null-terminated string. UString(const char*, int length); @@ -109,34 +108,12 @@ namespace JSC { return Rep::adopt(vector); } - static UString createFromUTF8(const char*); - static UString from(int); static UString from(long long); static UString from(unsigned int); static UString from(long); static UString from(double); - struct Range { - public: - Range(int pos, int len) - : position(pos) - , length(len) - { - } - - Range() - { - } - - int position; - int length; - }; - - UString spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const; - - UString replaceRange(int rangeStart, int RangeEnd, const UString& replacement) const; - bool getCString(CStringBuffer&) const; // NOTE: This method should only be used for *debugging* purposes as it @@ -153,11 +130,9 @@ namespace JSC { */ CString UTF8String(bool strict = false) const; - UString& operator=(const char*c); - const UChar* data() const { return m_rep->data(); } - bool isNull() const { return m_rep == &Rep::null(); } + bool isNull() const { return m_rep == s_nullRep; } bool isEmpty() const { return !m_rep->size(); } bool is8Bit() const; @@ -183,10 +158,9 @@ namespace JSC { UString substr(int pos = 0, int len = -1) const; - static const UString& null() { return *nullUString; } + static const UString& null() { return *s_nullUString; } Rep* rep() const { return m_rep.get(); } - static Rep* nullRep(); UString(PassRefPtr<Rep> r) : m_rep(r) @@ -197,10 +171,10 @@ namespace JSC { size_t cost() const { return m_rep->cost(); } private: - void makeNull(); - RefPtr<Rep> m_rep; - static UString* nullUString; + + JS_EXPORTDATA static Rep* s_nullRep; + static UString* s_nullUString; friend void initializeUString(); friend bool operator==(const UString&, const UString&); @@ -255,7 +229,7 @@ namespace JSC { int compare(const UString&, const UString&); inline UString::UString() - : m_rep(&Rep::null()) + : m_rep(s_nullRep) { } @@ -354,7 +328,7 @@ namespace JSC { }; template<typename StringType1, typename StringType2> - UString makeString(StringType1 string1, StringType2 string2) + PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2) { StringTypeAdapter<StringType1> adapter1(string1); StringTypeAdapter<StringType2> adapter2(string2); @@ -363,7 +337,7 @@ namespace JSC { unsigned length = adapter1.length() + adapter2.length(); PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) - return UString(); + return 0; UChar* result = buffer; adapter1.writeTo(result); @@ -374,7 +348,7 @@ namespace JSC { } template<typename StringType1, typename StringType2, typename StringType3> - UString makeString(StringType1 string1, StringType2 string2, StringType3 string3) + PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3) { StringTypeAdapter<StringType1> adapter1(string1); StringTypeAdapter<StringType2> adapter2(string2); @@ -384,7 +358,7 @@ namespace JSC { unsigned length = adapter1.length() + adapter2.length() + adapter3.length(); PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) - return UString(); + return 0; UChar* result = buffer; adapter1.writeTo(result); @@ -397,7 +371,7 @@ namespace JSC { } template<typename StringType1, typename StringType2, typename StringType3, typename StringType4> - UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4) + PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4) { StringTypeAdapter<StringType1> adapter1(string1); StringTypeAdapter<StringType2> adapter2(string2); @@ -408,7 +382,7 @@ namespace JSC { unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length(); PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) - return UString(); + return 0; UChar* result = buffer; adapter1.writeTo(result); @@ -423,7 +397,7 @@ namespace JSC { } template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5> - UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5) + PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5) { StringTypeAdapter<StringType1> adapter1(string1); StringTypeAdapter<StringType2> adapter2(string2); @@ -435,7 +409,7 @@ namespace JSC { unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length(); PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) - return UString(); + return 0; UChar* result = buffer; adapter1.writeTo(result); @@ -452,7 +426,7 @@ namespace JSC { } template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6> - UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6) + PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6) { StringTypeAdapter<StringType1> adapter1(string1); StringTypeAdapter<StringType2> adapter2(string2); @@ -465,7 +439,7 @@ namespace JSC { unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length(); PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) - return UString(); + return 0; UChar* result = buffer; adapter1.writeTo(result); @@ -484,7 +458,7 @@ namespace JSC { } template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7> - UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7) + PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7) { StringTypeAdapter<StringType1> adapter1(string1); StringTypeAdapter<StringType2> adapter2(string2); @@ -498,7 +472,7 @@ namespace JSC { unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length() + adapter7.length(); PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) - return UString(); + return 0; UChar* result = buffer; adapter1.writeTo(result); @@ -519,7 +493,7 @@ namespace JSC { } template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8> - UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8) + PassRefPtr<UStringImpl> tryMakeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8) { StringTypeAdapter<StringType1> adapter1(string1); StringTypeAdapter<StringType2> adapter2(string2); @@ -534,7 +508,7 @@ namespace JSC { unsigned length = adapter1.length() + adapter2.length() + adapter3.length() + adapter4.length() + adapter5.length() + adapter6.length() + adapter7.length() + adapter8.length(); PassRefPtr<UStringImpl> resultImpl = UStringImpl::tryCreateUninitialized(length, buffer); if (!resultImpl) - return UString(); + return 0; UChar* result = buffer; adapter1.writeTo(result); @@ -556,6 +530,69 @@ namespace JSC { return resultImpl; } + template<typename StringType1, typename StringType2> + UString makeString(StringType1 string1, StringType2 string2) + { + PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2); + if (!resultImpl) + CRASH(); + return resultImpl; + } + + template<typename StringType1, typename StringType2, typename StringType3> + UString makeString(StringType1 string1, StringType2 string2, StringType3 string3) + { + PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2, string3); + if (!resultImpl) + CRASH(); + return resultImpl; + } + + template<typename StringType1, typename StringType2, typename StringType3, typename StringType4> + UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4) + { + PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2, string3, string4); + if (!resultImpl) + CRASH(); + return resultImpl; + } + + template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5> + UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5) + { + PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5); + if (!resultImpl) + CRASH(); + return resultImpl; + } + + template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6> + UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6) + { + PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6); + if (!resultImpl) + CRASH(); + return resultImpl; + } + + template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7> + UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7) + { + PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7); + if (!resultImpl) + CRASH(); + return resultImpl; + } + + template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8> + UString makeString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8) + { + PassRefPtr<UStringImpl> resultImpl = tryMakeString(string1, string2, string3, string4, string5, string6, string7, string8); + if (!resultImpl) + CRASH(); + return resultImpl; + } + } // namespace JSC namespace WTF { diff --git a/JavaScriptCore/runtime/UStringImpl.cpp b/JavaScriptCore/runtime/UStringImpl.cpp index 4b0d1c9..9882007 100644 --- a/JavaScriptCore/runtime/UStringImpl.cpp +++ b/JavaScriptCore/runtime/UStringImpl.cpp @@ -34,7 +34,44 @@ using namespace WTF::Unicode; using namespace std; namespace JSC { - + +PassRefPtr<UStringImpl> UStringImpl::create(const char* c) +{ + ASSERT(c); + + if (!c[0]) + return &UStringImpl::empty(); + + size_t length = strlen(c); + UChar* d; + PassRefPtr<UStringImpl> result = UStringImpl::createUninitialized(length, d); + for (size_t i = 0; i < length; i++) + d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend + return result; +} + +PassRefPtr<UStringImpl> UStringImpl::create(const char* c, int length) +{ + ASSERT(c); + + if (!length) + return &UStringImpl::empty(); + + UChar* d; + PassRefPtr<UStringImpl> result = UStringImpl::createUninitialized(length, d); + for (int i = 0; i < length; i++) + d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend + return result; +} + +PassRefPtr<UStringImpl> UStringImpl::create(const UChar* buffer, int length) +{ + UChar* newBuffer; + PassRefPtr<UStringImpl> impl = createUninitialized(length, newBuffer); + copyChars(newBuffer, buffer, length); + return impl; +} + SharedUChar* UStringImpl::baseSharedBuffer() { ASSERT((bufferOwnership() == BufferShared) diff --git a/JavaScriptCore/runtime/UStringImpl.h b/JavaScriptCore/runtime/UStringImpl.h index abed637..bbea0aa 100644 --- a/JavaScriptCore/runtime/UStringImpl.h +++ b/JavaScriptCore/runtime/UStringImpl.h @@ -87,20 +87,16 @@ public: template<size_t inlineCapacity> static PassRefPtr<UStringImpl> adopt(Vector<UChar, inlineCapacity>& vector) { - if (unsigned length = vector.size()) + if (unsigned length = vector.size()) { + ASSERT(vector.data()); return adoptRef(new UStringImpl(vector.releaseBuffer(), length, BufferOwned)); + } return &empty(); } - static PassRefPtr<UStringImpl> create(const UChar* buffer, int length) - { - UChar* newBuffer; - if (PassRefPtr<UStringImpl> impl = tryCreateUninitialized(length, newBuffer)) { - copyChars(newBuffer, buffer, length); - return impl; - } - return &null(); - } + static PassRefPtr<UStringImpl> create(const char* c); + static PassRefPtr<UStringImpl> create(const char* c, int length); + static PassRefPtr<UStringImpl> create(const UChar* buffer, int length); static PassRefPtr<UStringImpl> create(PassRefPtr<UStringImpl> rep, int offset, int length) { @@ -180,7 +176,6 @@ public: static unsigned computeHash(const char* s, int length) { ASSERT(length >= 0); return WTF::stringHash(s, length); } static unsigned computeHash(const char* s) { return WTF::stringHash(s); } - static UStringImpl& null() { return *s_null; } static UStringImpl& empty() { return *s_empty; } ALWAYS_INLINE void checkConsistency() const @@ -288,7 +283,6 @@ private: mutable unsigned m_isIdentifier : 1; UntypedPtrAndBitfield m_dataBuffer; - JS_EXPORTDATA static UStringImpl* s_null; JS_EXPORTDATA static UStringImpl* s_empty; friend class JIT; diff --git a/JavaScriptCore/runtime/WeakGCPtr.h b/JavaScriptCore/runtime/WeakGCPtr.h index 8653721..3ed4645 100644 --- a/JavaScriptCore/runtime/WeakGCPtr.h +++ b/JavaScriptCore/runtime/WeakGCPtr.h @@ -44,7 +44,11 @@ public: return m_ptr; } - void clear() { m_ptr = 0; } + void clear(JSCell* ptr) + { + if (ptr == m_ptr) + m_ptr = 0; + } T& operator*() const { return *get(); } T* operator->() const { return get(); } |