summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/runtime/JSONObject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'JavaScriptCore/runtime/JSONObject.cpp')
-rw-r--r--JavaScriptCore/runtime/JSONObject.cpp158
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