diff options
Diffstat (limited to 'Source/JavaScriptCore/runtime/JSONObject.cpp')
-rw-r--r-- | Source/JavaScriptCore/runtime/JSONObject.cpp | 166 |
1 files changed, 55 insertions, 111 deletions
diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp index 982628917..20244652f 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 "Operations.h" +#include "JSCInlines.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); -static EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*); -static EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*); +EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*); +EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*); } @@ -63,6 +63,8 @@ void JSONObject::finishCreation(VM& vm) { Base::finishCreation(vm); ASSERT(inherits(info())); + + putDirectWithoutTransition(vm, vm.propertyNames->toStringTagSymbol, jsString(&vm, "JSON"), DontEnum | ReadOnly); } // PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked. @@ -107,11 +109,10 @@ 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 }; + enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedOrSymbolValue }; StringifyResult appendStringifiedValue(StringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&); bool willIndent() const; @@ -145,6 +146,9 @@ static inline JSValue unwrapBoxedPrimitive(ExecState* exec, JSValue value) return object->toString(exec); if (object->inherits(BooleanObject::info())) return object->toPrimitive(exec); + + // Do not unwrap SymbolObject to Symbol. It is not performed in the spec. + // http://www.ecma-international.org/ecma-262/6.0/#sec-serializejsonproperty return value; } @@ -207,7 +211,7 @@ Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const : m_exec(exec) , m_replacer(replacer) , m_usingArrayReplacer(false) - , m_arrayReplacerPropertyNames(exec) + , m_arrayReplacerPropertyNames(exec, PropertyNameMode::Strings) , m_replacerCallType(CallTypeNone) , m_gap(gap(exec, space.get())) { @@ -226,9 +230,10 @@ 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(Identifier(exec, name.toString(exec)->value(exec))); + m_arrayReplacerPropertyNames.add(name.toString(exec)->toIdentifier(exec)); } return; } @@ -254,83 +259,16 @@ Local<Unknown> Stringifier::stringify(Handle<Unknown> value) return Local<Unknown>(m_exec->vm(), jsString(m_exec, result.toString())); } -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) +ALWAYS_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(); @@ -366,8 +304,8 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& return StringifyFailed; } - if (value.isUndefined() && !holder->inherits(JSArray::info())) - return StringifyFailedDueToUndefinedValue; + if ((value.isUndefined() || value.isSymbol()) && !holder->inherits(JSArray::info())) + return StringifyFailedDueToUndefinedOrSymbolValue; if (value.isNull()) { builder.appendLiteral("null"); @@ -387,18 +325,21 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& return StringifySucceeded; } - String stringValue; - if (value.getString(m_exec, stringValue)) { - appendQuotedString(builder, stringValue); + if (value.isString()) { + builder.appendQuotedJSONString(asString(value)->value(m_exec)); return StringifySucceeded; } if (value.isNumber()) { - double number = value.asNumber(); - if (!std::isfinite(number)) - builder.appendLiteral("null"); - else - builder.append(String::numberToStringECMAScript(number)); + if (value.isInt32()) + builder.appendNumber(value.asInt32()); + else { + double number = value.asNumber(); + if (!std::isfinite(number)) + builder.appendLiteral("null"); + else + builder.appendECMAScriptNumber(number); + } return StringifySucceeded; } @@ -413,7 +354,7 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& builder.appendLiteral("null"); return StringifySucceeded; } - return StringifyFailedDueToUndefinedValue; + return StringifyFailedDueToUndefinedOrSymbolValue; } // Handle cycle detection, and put the holder on the stack. @@ -487,14 +428,17 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui if (!m_index) { if (m_isArray) { m_isJSArray = isJSArray(m_object.get()); - m_size = m_object->get(exec, exec->vm().propertyNames->length).toUInt32(exec); + if (m_isJSArray) + m_size = asArray(m_object.get())->length(); + else + 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); - m_object->methodTable()->getOwnPropertyNames(m_object.get(), exec, objectPropertyNames, ExcludeDontEnumProperties); + PropertyNameArray objectPropertyNames(exec, PropertyNameMode::Strings); + m_object->methodTable()->getOwnPropertyNames(m_object.get(), exec, objectPropertyNames, EnumerationMode()); m_propertyNames = objectPropertyNames.releaseData(); } m_size = m_propertyNames->propertyNameVector().size(); @@ -522,7 +466,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui if (m_isJSArray && asArray(m_object.get())->canGetIndexQuickly(index)) value = asArray(m_object.get())->getIndexQuickly(index); else { - PropertySlot slot(m_object.get()); + PropertySlot slot(m_object.get(), PropertySlot::InternalMethodType::Get); if (m_object->methodTable()->getOwnPropertySlotByIndex(m_object.get(), exec, index, slot)) { value = slot.getValue(exec, index); if (exec->hadException()) @@ -540,7 +484,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object.get(), index); } else { // Get the value. - PropertySlot slot(m_object.get()); + PropertySlot slot(m_object.get(), PropertySlot::InternalMethodType::Get); Identifier& propertyName = m_propertyNames->propertyNameVector()[index]; if (!m_object->methodTable()->getOwnPropertySlot(m_object.get(), exec, propertyName, slot)) return true; @@ -556,7 +500,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui stringifier.startNewLine(builder); // Append the property name. - appendQuotedString(builder, propertyName.string()); + builder.appendQuotedJSONString(propertyName.string()); builder.append(':'); if (stringifier.willIndent()) builder.append(' '); @@ -575,10 +519,10 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui break; case StringifySucceeded: break; - case StringifyFailedDueToUndefinedValue: - // This only occurs when get an undefined value for an object property. - // In this case we don't want the separator and property name that we - // already appended, so roll back. + case StringifyFailedDueToUndefinedOrSymbolValue: + // This only occurs when get an undefined value or a symbol value for + // an object property. In this case we don't want the separator and + // property name that we already appended, so roll back. builder.resize(rollBackPoint); break; } @@ -588,7 +532,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui // ------------------------------ JSONObject -------------------------------- -const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, 0, ExecState::jsonTable, CREATE_METHOD_TABLE(JSONObject) }; +const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, &jsonTable, CREATE_METHOD_TABLE(JSONObject) }; /* Source for JSONObject.lut.h @begin jsonTable @@ -601,7 +545,7 @@ const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, 0, Exe bool JSONObject::getOwnPropertySlot(JSObject* object, ExecState* exec, PropertyName propertyName, PropertySlot& slot) { - return getStaticFunctionSlot<JSObject>(exec, ExecState::jsonTable(exec->vm()), jsCast<JSONObject*>(object), propertyName, slot); + return getStaticFunctionSlot<JSObject>(exec, jsonTable, jsCast<JSONObject*>(object), propertyName, slot); } class Walker { @@ -654,7 +598,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 m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec)); + return throwStackOverflowError(m_exec); JSArray* array = asArray(inValue); arrayStack.push(array); @@ -674,7 +618,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) if (isJSArray(array) && array->canGetIndexQuickly(index)) inValue = array->getIndexQuickly(index); else { - PropertySlot slot(array); + PropertySlot slot(array, PropertySlot::InternalMethodType::Get); if (array->methodTable()->getOwnPropertySlotByIndex(array, m_exec, index, slot)) inValue = slot.getValue(m_exec, index); else @@ -705,13 +649,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 m_exec->vm().throwException(m_exec, createStackOverflowError(m_exec)); + return throwStackOverflowError(m_exec); JSObject* object = asObject(inValue); objectStack.push(object); indexStack.append(0); - propertyStack.append(PropertyNameArray(m_exec)); - object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), ExcludeDontEnumProperties); + propertyStack.append(PropertyNameArray(m_exec, PropertyNameMode::Strings)); + object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), EnumerationMode()); } objectStartVisitMember: FALLTHROUGH; @@ -726,7 +670,7 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) propertyStack.removeLast(); break; } - PropertySlot slot(object); + PropertySlot slot(object, PropertySlot::InternalMethodType::Get); if (object->methodTable()->getOwnPropertySlot(object, m_exec, properties[index], slot)) inValue = slot.getValue(m_exec, properties[index]); else @@ -785,7 +729,7 @@ EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec) { if (!exec->argumentCount()) return throwVMError(exec, createError(exec, ASCIILiteral("JSON.parse requires at least one parameter"))); - String source = exec->uncheckedArgument(0).toString(exec)->value(exec); + JSString::SafeView source = exec->uncheckedArgument(0).toString(exec)->view(exec); if (exec->hadException()) return JSValue::encode(jsNull()); |