diff options
Diffstat (limited to 'JavaScriptCore/runtime/JSONObject.cpp')
| -rw-r--r-- | JavaScriptCore/runtime/JSONObject.cpp | 158 |
1 files changed, 82 insertions, 76 deletions
diff --git a/JavaScriptCore/runtime/JSONObject.cpp b/JavaScriptCore/runtime/JSONObject.cpp index acd9280..b5477a1 100644 --- a/JavaScriptCore/runtime/JSONObject.cpp +++ b/JavaScriptCore/runtime/JSONObject.cpp @@ -30,17 +30,20 @@ #include "Error.h" #include "ExceptionHelpers.h" #include "JSArray.h" +#include "JSGlobalObject.h" #include "LiteralParser.h" +#include "Lookup.h" #include "PropertyNameArray.h" -#include "StringBuilder.h" +#include "UStringBuilder.h" +#include "UStringConcatenate.h" #include <wtf/MathExtras.h> namespace JSC { ASSERT_CLASS_FITS_IN_CELL(JSONObject); -static JSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*, JSObject*, JSValue, const ArgList&); -static JSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*, JSObject*, JSValue, const ArgList&); +static EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*); +static EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*); } @@ -48,6 +51,11 @@ static JSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*, JSObject*, JSVal namespace JSC { +JSONObject::JSONObject(JSGlobalObject* globalObject, NonNullPassRefPtr<Structure> structure) + : JSObjectWithGlobalObject(globalObject, structure) +{ +} + // PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked. class PropertyNameForFunctionCall { public: @@ -77,7 +85,7 @@ private: JSObject* object() const { return m_object; } - bool appendNextProperty(Stringifier&, StringBuilder&); + bool appendNextProperty(Stringifier&, UStringBuilder&); private: JSObject* const m_object; @@ -90,17 +98,17 @@ private: friend class Holder; - static void appendQuotedString(StringBuilder&, const UString&); + static void appendQuotedString(UStringBuilder&, const UString&); JSValue toJSON(JSValue, const PropertyNameForFunctionCall&); enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedValue }; - StringifyResult appendStringifiedValue(StringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&); + StringifyResult appendStringifiedValue(UStringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&); bool willIndent() const; void indent(); void unindent(); - void startNewLine(StringBuilder&) const; + void startNewLine(UStringBuilder&) const; Stringifier* const m_nextStringifierToMark; ExecState* const m_exec; @@ -125,7 +133,7 @@ static inline JSValue unwrapBoxedPrimitive(ExecState* exec, JSValue value) return value; JSObject* object = asObject(value); if (object->inherits(&NumberObject::info)) - return jsNumber(exec, object->toNumber(exec)); + return jsNumber(object->toNumber(exec)); if (object->inherits(&StringObject::info)) return jsString(exec, object->toString(exec)); if (object->inherits(&BooleanObject::info)) @@ -135,7 +143,7 @@ static inline JSValue unwrapBoxedPrimitive(ExecState* exec, JSValue value) static inline UString gap(ExecState* exec, JSValue space) { - const int maxGapLength = 10; + const unsigned maxGapLength = 10; space = unwrapBoxedPrimitive(exec, space); // If the space value is a number, create a gap string with that number of spaces. @@ -156,8 +164,8 @@ static inline UString gap(ExecState* exec, JSValue space) // If the space value is a string, use it as the gap string, otherwise use no gap string. UString spaces = space.getString(exec); - if (spaces.size() > maxGapLength) { - spaces = spaces.substr(0, maxGapLength); + if (spaces.length() > maxGapLength) { + spaces = spaces.substringSharingImpl(0, maxGapLength); } return spaces; } @@ -181,7 +189,7 @@ JSValue PropertyNameForFunctionCall::value(ExecState* exec) const if (m_identifier) m_value = jsString(exec, m_identifier->ustring()); else - m_value = jsNumber(exec, m_number); + m_value = jsNumber(m_number); } return m_value; } @@ -262,25 +270,25 @@ JSValue Stringifier::stringify(JSValue value) PropertyNameForFunctionCall emptyPropertyName(m_exec->globalData().propertyNames->emptyIdentifier); object->putDirect(m_exec->globalData().propertyNames->emptyIdentifier, value); - StringBuilder result; + UStringBuilder result; if (appendStringifiedValue(result, value, object, emptyPropertyName) != StringifySucceeded) return jsUndefined(); if (m_exec->hadException()) return jsNull(); - return jsString(m_exec, result.build()); + return jsString(m_exec, result.toUString()); } -void Stringifier::appendQuotedString(StringBuilder& builder, const UString& value) +void Stringifier::appendQuotedString(UStringBuilder& builder, const UString& value) { - int length = value.size(); + int length = value.length(); // String length plus 2 for quote marks plus 8 so we can accomodate a few escaped characters. - builder.reserveCapacity(builder.size() + length + 2 + 8); + builder.reserveCapacity(builder.length() + length + 2 + 8); builder.append('"'); - const UChar* data = value.data(); + const UChar* data = value.characters(); for (int i = 0; i < length; ++i) { int start = i; while (i < length && (data[i] > 0x1F && data[i] != '"' && data[i] != '\\')) @@ -321,7 +329,7 @@ void Stringifier::appendQuotedString(StringBuilder& builder, const UString& valu static const char hexDigits[] = "0123456789abcdef"; UChar ch = data[i]; UChar hex[] = { '\\', 'u', hexDigits[(ch >> 12) & 0xF], hexDigits[(ch >> 8) & 0xF], hexDigits[(ch >> 4) & 0xF], hexDigits[ch & 0xF] }; - builder.append(hex, sizeof(hex) / sizeof(UChar)); + builder.append(hex, WTF_ARRAY_LENGTH(hex)); break; } } @@ -349,11 +357,11 @@ inline JSValue Stringifier::toJSON(JSValue value, const PropertyNameForFunctionC return value; JSValue list[] = { propertyName.value(m_exec) }; - ArgList args(list, sizeof(list) / sizeof(JSValue)); + ArgList args(list, WTF_ARRAY_LENGTH(list)); return call(m_exec, object, callType, callData, value, args); } -Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& builder, JSValue value, JSObject* holder, const PropertyNameForFunctionCall& propertyName) +Stringifier::StringifyResult Stringifier::appendStringifiedValue(UStringBuilder& builder, JSValue value, JSObject* holder, const PropertyNameForFunctionCall& propertyName) { // Call the toJSON function. value = toJSON(value, propertyName); @@ -363,7 +371,7 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& // Call the replacer function. if (m_replacerCallType != CallTypeNone) { JSValue list[] = { propertyName.value(m_exec), value }; - ArgList args(list, sizeof(list) / sizeof(JSValue)); + ArgList args(list, WTF_ARRAY_LENGTH(list)); value = call(m_exec, m_replacer, m_replacerCallType, m_replacerCallData, holder, args); if (m_exec->hadException()) return StringifyFailed; @@ -398,7 +406,7 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& if (!isfinite(numericValue)) builder.append("null"); else - builder.append(UString::from(numericValue)); + builder.append(UString::number(numericValue)); return StringifySucceeded; } @@ -418,7 +426,7 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& // Handle cycle detection, and put the holder on the stack. if (!m_holderCycleDetector.add(object).second) { - throwError(m_exec, TypeError, "JSON.stringify cannot serialize cyclic structures."); + throwError(m_exec, createTypeError(m_exec, "JSON.stringify cannot serialize cyclic structures.")); return StringifyFailed; } bool holderStackWasEmpty = m_holderStack.isEmpty(); @@ -436,7 +444,7 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& return StringifyFailed; if (!--tickCount) { if (localTimeoutChecker.didTimeOut(m_exec)) { - m_exec->setException(createInterruptedExecutionException(&m_exec->globalData())); + throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData())); return StringifyFailed; } tickCount = localTimeoutChecker.ticksUntilNextCheck(); @@ -456,20 +464,20 @@ inline bool Stringifier::willIndent() const inline void Stringifier::indent() { // Use a single shared string, m_repeatedGap, so we don't keep allocating new ones as we indent and unindent. - int newSize = m_indent.size() + m_gap.size(); - if (newSize > m_repeatedGap.size()) - m_repeatedGap = makeString(m_repeatedGap, m_gap); - ASSERT(newSize <= m_repeatedGap.size()); - m_indent = m_repeatedGap.substr(0, newSize); + unsigned newSize = m_indent.length() + m_gap.length(); + if (newSize > m_repeatedGap.length()) + m_repeatedGap = makeUString(m_repeatedGap, m_gap); + ASSERT(newSize <= m_repeatedGap.length()); + m_indent = m_repeatedGap.substringSharingImpl(0, newSize); } inline void Stringifier::unindent() { - ASSERT(m_indent.size() >= m_gap.size()); - m_indent = m_repeatedGap.substr(0, m_indent.size() - m_gap.size()); + ASSERT(m_indent.length() >= m_gap.length()); + m_indent = m_repeatedGap.substringSharingImpl(0, m_indent.length() - m_gap.length()); } -inline void Stringifier::startNewLine(StringBuilder& builder) const +inline void Stringifier::startNewLine(UStringBuilder& builder) const { if (m_gap.isEmpty()) return; @@ -484,7 +492,7 @@ inline Stringifier::Holder::Holder(JSObject* object) { } -bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBuilder& builder) +bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, UStringBuilder& builder) { ASSERT(m_index <= m_size); @@ -513,7 +521,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui // Last time through, finish up and return false. if (m_index == m_size) { stringifier.unindent(); - if (m_size && builder[builder.size() - 1] != '{') + if (m_size && builder[builder.length() - 1] != '{') stringifier.startNewLine(builder); builder.append(m_isArray ? ']' : '}'); return false; @@ -554,7 +562,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui if (exec->hadException()) return false; - rollBackPoint = builder.size(); + rollBackPoint = builder.length(); // Append the separator string. if (builder[rollBackPoint - 1] != '{') @@ -672,10 +680,8 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) case ArrayStartState: { ASSERT(inValue.isObject()); ASSERT(isJSArray(&m_exec->globalData(), asObject(inValue)) || asObject(inValue)->inherits(&JSArray::info)); - if (objectStack.size() + arrayStack.size() > maximumFilterRecursion) { - m_exec->setException(createStackOverflowError(m_exec)); - return jsUndefined(); - } + if (objectStack.size() + arrayStack.size() > maximumFilterRecursion) + return throwError(m_exec, createStackOverflowError(m_exec)); JSArray* array = asArray(inValue); arrayStack.append(array); @@ -685,10 +691,8 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) arrayStartVisitMember: case ArrayStartVisitMember: { if (!--tickCount) { - if (localTimeoutChecker.didTimeOut(m_exec)) { - m_exec->setException(createInterruptedExecutionException(&m_exec->globalData())); - return jsUndefined(); - } + if (localTimeoutChecker.didTimeOut(m_exec)) + return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData())); tickCount = localTimeoutChecker.ticksUntilNextCheck(); } @@ -719,7 +723,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) } case ArrayEndVisitMember: { JSArray* array = arrayStack.last(); - JSValue filteredValue = callReviver(array, jsString(m_exec, UString::from(indexStack.last())), outValue); + JSValue filteredValue = callReviver(array, jsString(m_exec, UString::number(indexStack.last())), outValue); if (filteredValue.isUndefined()) array->deleteProperty(m_exec, indexStack.last()); else { @@ -737,10 +741,8 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) case ObjectStartState: { ASSERT(inValue.isObject()); ASSERT(!isJSArray(&m_exec->globalData(), asObject(inValue)) && !asObject(inValue)->inherits(&JSArray::info)); - if (objectStack.size() + arrayStack.size() > maximumFilterRecursion) { - m_exec->setException(createStackOverflowError(m_exec)); - return jsUndefined(); - } + if (objectStack.size() + arrayStack.size() > maximumFilterRecursion) + return throwError(m_exec, createStackOverflowError(m_exec)); JSObject* object = asObject(inValue); objectStack.append(object); @@ -752,10 +754,8 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) objectStartVisitMember: case ObjectStartVisitMember: { if (!--tickCount) { - if (localTimeoutChecker.didTimeOut(m_exec)) { - m_exec->setException(createInterruptedExecutionException(&m_exec->globalData())); - return jsUndefined(); - } + if (localTimeoutChecker.didTimeOut(m_exec)) + return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData())); tickCount = localTimeoutChecker.ticksUntilNextCheck(); } @@ -818,10 +818,8 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) stateStack.removeLast(); if (!--tickCount) { - if (localTimeoutChecker.didTimeOut(m_exec)) { - m_exec->setException(createInterruptedExecutionException(&m_exec->globalData())); - return jsUndefined(); - } + if (localTimeoutChecker.didTimeOut(m_exec)) + return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData())); tickCount = localTimeoutChecker.ticksUntilNextCheck(); } } @@ -832,40 +830,48 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) } // ECMA-262 v5 15.12.2 -JSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec, JSObject*, JSValue, const ArgList& args) +EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec) { - if (args.isEmpty()) - return throwError(exec, GeneralError, "JSON.parse requires at least one parameter"); - JSValue value = args.at(0); + if (!exec->argumentCount()) + return throwVMError(exec, createError(exec, "JSON.parse requires at least one parameter")); + JSValue value = exec->argument(0); UString source = value.toString(exec); if (exec->hadException()) - return jsNull(); + return JSValue::encode(jsNull()); LiteralParser jsonParser(exec, source, LiteralParser::StrictJSON); JSValue unfiltered = jsonParser.tryLiteralParse(); if (!unfiltered) - return throwError(exec, SyntaxError, "Unable to parse JSON string"); + return throwVMError(exec, createSyntaxError(exec, "Unable to parse JSON string")); - if (args.size() < 2) - return unfiltered; + if (exec->argumentCount() < 2) + return JSValue::encode(unfiltered); - JSValue function = args.at(1); + JSValue function = exec->argument(1); CallData callData; - CallType callType = function.getCallData(callData); + CallType callType = getCallData(function, callData); if (callType == CallTypeNone) - return unfiltered; - return Walker(exec, asObject(function), callType, callData).walk(unfiltered); + return JSValue::encode(unfiltered); + return JSValue::encode(Walker(exec, asObject(function), callType, callData).walk(unfiltered)); } // ECMA-262 v5 15.12.3 -JSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec, JSObject*, JSValue, const ArgList& args) +EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec) +{ + if (!exec->argumentCount()) + return throwVMError(exec, createError(exec, "No input to stringify")); + JSValue value = exec->argument(0); + JSValue replacer = exec->argument(1); + JSValue space = exec->argument(2); + return JSValue::encode(Stringifier(exec, replacer, space).stringify(value)); +} + +UString JSONStringify(ExecState* exec, JSValue value, unsigned indent) { - if (args.isEmpty()) - return throwError(exec, GeneralError, "No input to stringify"); - JSValue value = args.at(0); - JSValue replacer = args.at(1); - JSValue space = args.at(2); - return Stringifier(exec, replacer, space).stringify(value); + JSValue result = Stringifier(exec, jsNull(), jsNumber(indent)).stringify(value); + if (result.isUndefinedOrNull()) + return UString(); + return result.getString(exec); } } // namespace JSC |
