summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime/JSONObject.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSONObject.cpp')
-rw-r--r--Source/JavaScriptCore/runtime/JSONObject.cpp137
1 files changed, 99 insertions, 38 deletions
diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp
index f67ba7ece..982628917 100644
--- a/Source/JavaScriptCore/runtime/JSONObject.cpp
+++ b/Source/JavaScriptCore/runtime/JSONObject.cpp
@@ -36,7 +36,7 @@
#include "LocalScope.h"
#include "Lookup.h"
#include "ObjectConstructor.h"
-#include "JSCInlines.h"
+#include "Operations.h"
#include "PropertyNameArray.h"
#include <wtf/MathExtras.h>
#include <wtf/text/StringBuilder.h>
@@ -45,8 +45,8 @@ namespace JSC {
STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSONObject);
-EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*);
-EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*);
+static EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*);
+static EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*);
}
@@ -107,8 +107,9 @@ private:
friend class Holder;
+ static void appendQuotedString(StringBuilder&, const String&);
+
JSValue toJSON(JSValue, const PropertyNameForFunctionCall&);
- JSValue toJSONImpl(JSValue, const PropertyNameForFunctionCall&);
enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedValue };
StringifyResult appendStringifiedValue(StringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&);
@@ -206,7 +207,7 @@ Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const
: m_exec(exec)
, m_replacer(replacer)
, m_usingArrayReplacer(false)
- , m_arrayReplacerPropertyNames(exec, PropertyNameMode::Strings)
+ , m_arrayReplacerPropertyNames(exec)
, m_replacerCallType(CallTypeNone)
, m_gap(gap(exec, space.get()))
{
@@ -225,10 +226,9 @@ Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const
if (name.isObject()) {
if (!asObject(name)->inherits(NumberObject::info()) && !asObject(name)->inherits(StringObject::info()))
continue;
- } else if (!name.isNumber() && !name.isString())
- continue;
+ }
- m_arrayReplacerPropertyNames.add(name.toString(exec)->toIdentifier(exec));
+ m_arrayReplacerPropertyNames.add(Identifier(exec, name.toString(exec)->value(exec)));
}
return;
}
@@ -254,16 +254,83 @@ Local<Unknown> Stringifier::stringify(Handle<Unknown> value)
return Local<Unknown>(m_exec->vm(), jsString(m_exec, result.toString()));
}
-ALWAYS_INLINE JSValue Stringifier::toJSON(JSValue value, const PropertyNameForFunctionCall& propertyName)
+template <typename CharType>
+static void appendStringToStringBuilder(StringBuilder& builder, const CharType* data, int length)
+{
+ for (int i = 0; i < length; ++i) {
+ int start = i;
+ while (i < length && (data[i] > 0x1F && data[i] != '"' && data[i] != '\\'))
+ ++i;
+ builder.append(data + start, i - start);
+ if (i >= length)
+ break;
+ switch (data[i]) {
+ case '\t':
+ builder.append('\\');
+ builder.append('t');
+ break;
+ case '\r':
+ builder.append('\\');
+ builder.append('r');
+ break;
+ case '\n':
+ builder.append('\\');
+ builder.append('n');
+ break;
+ case '\f':
+ builder.append('\\');
+ builder.append('f');
+ break;
+ case '\b':
+ builder.append('\\');
+ builder.append('b');
+ break;
+ case '"':
+ builder.append('\\');
+ builder.append('"');
+ break;
+ case '\\':
+ builder.append('\\');
+ builder.append('\\');
+ break;
+ default:
+ static const char hexDigits[] = "0123456789abcdef";
+ UChar ch = data[i];
+ LChar hex[] = { '\\', 'u', static_cast<LChar>(hexDigits[(ch >> 12) & 0xF]), static_cast<LChar>(hexDigits[(ch >> 8) & 0xF]), static_cast<LChar>(hexDigits[(ch >> 4) & 0xF]), static_cast<LChar>(hexDigits[ch & 0xF]) };
+ builder.append(hex, WTF_ARRAY_LENGTH(hex));
+ break;
+ }
+ }
+}
+
+void escapeStringToBuilder(StringBuilder& builder, const String& message)
+{
+ if (message.is8Bit())
+ appendStringToStringBuilder(builder, message.characters8(), message.length());
+ else
+ appendStringToStringBuilder(builder, message.characters16(), message.length());
+}
+
+void Stringifier::appendQuotedString(StringBuilder& builder, const String& value)
+{
+ int length = value.length();
+
+ builder.append('"');
+
+ if (value.is8Bit())
+ appendStringToStringBuilder<LChar>(builder, value.characters8(), length);
+ else
+ appendStringToStringBuilder<UChar>(builder, value.characters16(), length);
+
+ builder.append('"');
+}
+
+inline JSValue Stringifier::toJSON(JSValue value, const PropertyNameForFunctionCall& propertyName)
{
ASSERT(!m_exec->hadException());
if (!value.isObject() || !asObject(value)->hasProperty(m_exec, m_exec->vm().propertyNames->toJSON))
return value;
- return toJSONImpl(value, propertyName);
-}
-JSValue Stringifier::toJSONImpl(JSValue value, const PropertyNameForFunctionCall& propertyName)
-{
JSValue toJSONFunction = asObject(value)->get(m_exec, m_exec->vm().propertyNames->toJSON);
if (m_exec->hadException())
return jsNull();
@@ -320,21 +387,18 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder&
return StringifySucceeded;
}
- if (value.isString()) {
- builder.appendQuotedJSONString(asString(value)->value(m_exec));
+ String stringValue;
+ if (value.getString(m_exec, stringValue)) {
+ appendQuotedString(builder, stringValue);
return StringifySucceeded;
}
if (value.isNumber()) {
- if (value.isInt32())
- builder.appendNumber(value.asInt32());
- else {
- double number = value.asNumber();
- if (!std::isfinite(number))
- builder.appendLiteral("null");
- else
- builder.appendECMAScriptNumber(number);
- }
+ double number = value.asNumber();
+ if (!std::isfinite(number))
+ builder.appendLiteral("null");
+ else
+ builder.append(String::numberToStringECMAScript(number));
return StringifySucceeded;
}
@@ -423,17 +487,14 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui
if (!m_index) {
if (m_isArray) {
m_isJSArray = isJSArray(m_object.get());
- if (m_isJSArray)
- m_size = asArray(m_object.get())->length();
- else
- m_size = m_object->get(exec, exec->vm().propertyNames->length).toUInt32(exec);
+ m_size = m_object->get(exec, exec->vm().propertyNames->length).toUInt32(exec);
builder.append('[');
} else {
if (stringifier.m_usingArrayReplacer)
m_propertyNames = stringifier.m_arrayReplacerPropertyNames.data();
else {
- PropertyNameArray objectPropertyNames(exec, PropertyNameMode::Strings);
- m_object->methodTable()->getOwnPropertyNames(m_object.get(), exec, objectPropertyNames, EnumerationMode());
+ PropertyNameArray objectPropertyNames(exec);
+ m_object->methodTable()->getOwnPropertyNames(m_object.get(), exec, objectPropertyNames, ExcludeDontEnumProperties);
m_propertyNames = objectPropertyNames.releaseData();
}
m_size = m_propertyNames->propertyNameVector().size();
@@ -495,7 +556,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui
stringifier.startNewLine(builder);
// Append the property name.
- builder.appendQuotedJSONString(propertyName.string());
+ appendQuotedString(builder, propertyName.string());
builder.append(':');
if (stringifier.willIndent())
builder.append(' ');
@@ -527,7 +588,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui
// ------------------------------ JSONObject --------------------------------
-const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, &jsonTable, CREATE_METHOD_TABLE(JSONObject) };
+const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, 0, ExecState::jsonTable, CREATE_METHOD_TABLE(JSONObject) };
/* Source for JSONObject.lut.h
@begin jsonTable
@@ -540,7 +601,7 @@ const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, &jsonT
bool JSONObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
{
- return getStaticFunctionSlot<JSObject>(exec, jsonTable, jsCast<JSONObject*>(object), propertyName, slot);
+ return getStaticFunctionSlot<JSObject>(exec, ExecState::jsonTable(exec->vm()), jsCast<JSONObject*>(object), propertyName, slot);
}
class Walker {
@@ -593,7 +654,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered)
ASSERT(inValue.isObject());
ASSERT(isJSArray(asObject(inValue)) || asObject(inValue)->inherits(JSArray::info()));
if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
- return throwStackOverflowError(m_exec);
+ return m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec));
JSArray* array = asArray(inValue);
arrayStack.push(array);
@@ -644,13 +705,13 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered)
ASSERT(inValue.isObject());
ASSERT(!isJSArray(asObject(inValue)) && !asObject(inValue)->inherits(JSArray::info()));
if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
- return throwStackOverflowError(m_exec);
+ return m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec));
JSObject* object = asObject(inValue);
objectStack.push(object);
indexStack.append(0);
- propertyStack.append(PropertyNameArray(m_exec, PropertyNameMode::Strings));
- object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode());
+ propertyStack.append(PropertyNameArray(m_exec));
+ object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
}
objectStartVisitMember:
FALLTHROUGH;
@@ -724,7 +785,7 @@ EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec)
{
if (!exec->argumentCount())
return throwVMError(exec, createError(exec, ASCIILiteral("JSON.parse requires at least one parameter")));
- StringView source = exec->uncheckedArgument(0).toString(exec)->view(exec);
+ String source = exec->uncheckedArgument(0).toString(exec)->value(exec);
if (exec->hadException())
return JSValue::encode(jsNull());