2 * Copyright (C) 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "JSONObject.h"
29 #include "BooleanObject.h"
31 #include "ExceptionHelpers.h"
33 #include "JSGlobalObject.h"
34 #include "LiteralParser.h"
36 #include "LocalScope.h"
38 #include "ObjectConstructor.h"
39 #include "JSCInlines.h"
40 #include "PropertyNameArray.h"
41 #include <wtf/MathExtras.h>
42 #include <wtf/text/StringBuilder.h>
46 STATIC_ASSERT_IS_TRIVIALLY_DESTRUCTIBLE(JSONObject
);
48 EncodedJSValue JSC_HOST_CALL
JSONProtoFuncParse(ExecState
*);
49 EncodedJSValue JSC_HOST_CALL
JSONProtoFuncStringify(ExecState
*);
53 #include "JSONObject.lut.h"
57 JSONObject::JSONObject(VM
& vm
, Structure
* structure
)
58 : JSNonFinalObject(vm
, structure
)
62 void JSONObject::finishCreation(VM
& vm
)
64 Base::finishCreation(vm
);
65 ASSERT(inherits(info()));
68 // PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked.
69 class PropertyNameForFunctionCall
{
71 PropertyNameForFunctionCall(const Identifier
&);
72 PropertyNameForFunctionCall(unsigned);
74 JSValue
value(ExecState
*) const;
77 const Identifier
* m_identifier
;
79 mutable JSValue m_value
;
83 WTF_MAKE_NONCOPYABLE(Stringifier
);
85 Stringifier(ExecState
*, const Local
<Unknown
>& replacer
, const Local
<Unknown
>& space
);
86 Local
<Unknown
> stringify(Handle
<Unknown
>);
88 void visitAggregate(SlotVisitor
&);
93 Holder(VM
&, JSObject
*);
95 JSObject
* object() const { return m_object
.get(); }
97 bool appendNextProperty(Stringifier
&, StringBuilder
&);
100 Local
<JSObject
> m_object
;
101 const bool m_isArray
;
105 RefPtr
<PropertyNameArrayData
> m_propertyNames
;
110 JSValue
toJSON(JSValue
, const PropertyNameForFunctionCall
&);
112 enum StringifyResult
{ StringifyFailed
, StringifySucceeded
, StringifyFailedDueToUndefinedValue
};
113 StringifyResult
appendStringifiedValue(StringBuilder
&, JSValue
, JSObject
* holder
, const PropertyNameForFunctionCall
&);
115 bool willIndent() const;
118 void startNewLine(StringBuilder
&) const;
120 ExecState
* const m_exec
;
121 const Local
<Unknown
> m_replacer
;
122 bool m_usingArrayReplacer
;
123 PropertyNameArray m_arrayReplacerPropertyNames
;
124 CallType m_replacerCallType
;
125 CallData m_replacerCallData
;
128 Vector
<Holder
, 16, UnsafeVectorOverflow
> m_holderStack
;
129 String m_repeatedGap
;
133 // ------------------------------ helper functions --------------------------------
135 static inline JSValue
unwrapBoxedPrimitive(ExecState
* exec
, JSValue value
)
137 if (!value
.isObject())
139 JSObject
* object
= asObject(value
);
140 if (object
->inherits(NumberObject::info()))
141 return jsNumber(object
->toNumber(exec
));
142 if (object
->inherits(StringObject::info()))
143 return object
->toString(exec
);
144 if (object
->inherits(BooleanObject::info()))
145 return object
->toPrimitive(exec
);
149 static inline String
gap(ExecState
* exec
, JSValue space
)
151 const unsigned maxGapLength
= 10;
152 space
= unwrapBoxedPrimitive(exec
, space
);
154 // If the space value is a number, create a gap string with that number of spaces.
155 if (space
.isNumber()) {
156 double spaceCount
= space
.asNumber();
158 if (spaceCount
> maxGapLength
)
159 count
= maxGapLength
;
160 else if (!(spaceCount
> 0))
163 count
= static_cast<int>(spaceCount
);
164 UChar spaces
[maxGapLength
];
165 for (int i
= 0; i
< count
; ++i
)
167 return String(spaces
, count
);
170 // If the space value is a string, use it as the gap string, otherwise use no gap string.
171 String spaces
= space
.getString(exec
);
172 if (spaces
.length() > maxGapLength
) {
173 spaces
= spaces
.substringSharingImpl(0, maxGapLength
);
178 // ------------------------------ PropertyNameForFunctionCall --------------------------------
180 inline PropertyNameForFunctionCall::PropertyNameForFunctionCall(const Identifier
& identifier
)
181 : m_identifier(&identifier
)
185 inline PropertyNameForFunctionCall::PropertyNameForFunctionCall(unsigned number
)
191 JSValue
PropertyNameForFunctionCall::value(ExecState
* exec
) const
195 m_value
= jsString(exec
, m_identifier
->string());
197 m_value
= jsNumber(m_number
);
202 // ------------------------------ Stringifier --------------------------------
204 Stringifier::Stringifier(ExecState
* exec
, const Local
<Unknown
>& replacer
, const Local
<Unknown
>& space
)
206 , m_replacer(replacer
)
207 , m_usingArrayReplacer(false)
208 , m_arrayReplacerPropertyNames(exec
)
209 , m_replacerCallType(CallTypeNone
)
210 , m_gap(gap(exec
, space
.get()))
212 if (!m_replacer
.isObject())
215 if (m_replacer
.asObject()->inherits(JSArray::info())) {
216 m_usingArrayReplacer
= true;
217 Handle
<JSObject
> array
= m_replacer
.asObject();
218 unsigned length
= array
->get(exec
, exec
->vm().propertyNames
->length
).toUInt32(exec
);
219 for (unsigned i
= 0; i
< length
; ++i
) {
220 JSValue name
= array
->get(exec
, i
);
221 if (exec
->hadException())
224 if (name
.isObject()) {
225 if (!asObject(name
)->inherits(NumberObject::info()) && !asObject(name
)->inherits(StringObject::info()))
227 } else if (!name
.isNumber() && !name
.isString())
230 m_arrayReplacerPropertyNames
.add(name
.toString(exec
)->toIdentifier(exec
));
235 m_replacerCallType
= m_replacer
.asObject()->methodTable()->getCallData(m_replacer
.asObject().get(), m_replacerCallData
);
238 Local
<Unknown
> Stringifier::stringify(Handle
<Unknown
> value
)
240 JSObject
* object
= constructEmptyObject(m_exec
);
241 if (m_exec
->hadException())
242 return Local
<Unknown
>(m_exec
->vm(), jsNull());
244 PropertyNameForFunctionCall
emptyPropertyName(m_exec
->vm().propertyNames
->emptyIdentifier
);
245 object
->putDirect(m_exec
->vm(), m_exec
->vm().propertyNames
->emptyIdentifier
, value
.get());
247 StringBuilder result
;
248 if (appendStringifiedValue(result
, value
.get(), object
, emptyPropertyName
) != StringifySucceeded
)
249 return Local
<Unknown
>(m_exec
->vm(), jsUndefined());
250 if (m_exec
->hadException())
251 return Local
<Unknown
>(m_exec
->vm(), jsNull());
253 return Local
<Unknown
>(m_exec
->vm(), jsString(m_exec
, result
.toString()));
256 inline JSValue
Stringifier::toJSON(JSValue value
, const PropertyNameForFunctionCall
& propertyName
)
258 ASSERT(!m_exec
->hadException());
259 if (!value
.isObject() || !asObject(value
)->hasProperty(m_exec
, m_exec
->vm().propertyNames
->toJSON
))
262 JSValue toJSONFunction
= asObject(value
)->get(m_exec
, m_exec
->vm().propertyNames
->toJSON
);
263 if (m_exec
->hadException())
266 if (!toJSONFunction
.isObject())
269 JSObject
* object
= asObject(toJSONFunction
);
271 CallType callType
= object
->methodTable()->getCallData(object
, callData
);
272 if (callType
== CallTypeNone
)
275 MarkedArgumentBuffer args
;
276 args
.append(propertyName
.value(m_exec
));
277 return call(m_exec
, object
, callType
, callData
, value
, args
);
280 Stringifier::StringifyResult
Stringifier::appendStringifiedValue(StringBuilder
& builder
, JSValue value
, JSObject
* holder
, const PropertyNameForFunctionCall
& propertyName
)
282 // Call the toJSON function.
283 value
= toJSON(value
, propertyName
);
284 if (m_exec
->hadException())
285 return StringifyFailed
;
287 // Call the replacer function.
288 if (m_replacerCallType
!= CallTypeNone
) {
289 MarkedArgumentBuffer args
;
290 args
.append(propertyName
.value(m_exec
));
292 value
= call(m_exec
, m_replacer
.get(), m_replacerCallType
, m_replacerCallData
, holder
, args
);
293 if (m_exec
->hadException())
294 return StringifyFailed
;
297 if (value
.isUndefined() && !holder
->inherits(JSArray::info()))
298 return StringifyFailedDueToUndefinedValue
;
300 if (value
.isNull()) {
301 builder
.appendLiteral("null");
302 return StringifySucceeded
;
305 value
= unwrapBoxedPrimitive(m_exec
, value
);
307 if (m_exec
->hadException())
308 return StringifyFailed
;
310 if (value
.isBoolean()) {
312 builder
.appendLiteral("true");
314 builder
.appendLiteral("false");
315 return StringifySucceeded
;
318 if (value
.isString()) {
319 builder
.appendQuotedJSONString(asString(value
)->value(m_exec
));
320 return StringifySucceeded
;
323 if (value
.isNumber()) {
325 builder
.appendNumber(value
.asInt32());
327 double number
= value
.asNumber();
328 if (!std::isfinite(number
))
329 builder
.appendLiteral("null");
331 builder
.appendECMAScriptNumber(number
);
333 return StringifySucceeded
;
336 if (!value
.isObject())
337 return StringifyFailed
;
339 JSObject
* object
= asObject(value
);
342 if (object
->methodTable()->getCallData(object
, callData
) != CallTypeNone
) {
343 if (holder
->inherits(JSArray::info())) {
344 builder
.appendLiteral("null");
345 return StringifySucceeded
;
347 return StringifyFailedDueToUndefinedValue
;
350 // Handle cycle detection, and put the holder on the stack.
351 for (unsigned i
= 0; i
< m_holderStack
.size(); i
++) {
352 if (m_holderStack
[i
].object() == object
) {
353 m_exec
->vm().throwException(m_exec
, createTypeError(m_exec
, ASCIILiteral("JSON.stringify cannot serialize cyclic structures.")));
354 return StringifyFailed
;
357 bool holderStackWasEmpty
= m_holderStack
.isEmpty();
358 m_holderStack
.append(Holder(m_exec
->vm(), object
));
359 if (!holderStackWasEmpty
)
360 return StringifySucceeded
;
363 while (m_holderStack
.last().appendNextProperty(*this, builder
)) {
364 if (m_exec
->hadException())
365 return StringifyFailed
;
367 m_holderStack
.removeLast();
368 } while (!m_holderStack
.isEmpty());
369 return StringifySucceeded
;
372 inline bool Stringifier::willIndent() const
374 return !m_gap
.isEmpty();
377 inline void Stringifier::indent()
379 // Use a single shared string, m_repeatedGap, so we don't keep allocating new ones as we indent and unindent.
380 unsigned newSize
= m_indent
.length() + m_gap
.length();
381 if (newSize
> m_repeatedGap
.length())
382 m_repeatedGap
= makeString(m_repeatedGap
, m_gap
);
383 ASSERT(newSize
<= m_repeatedGap
.length());
384 m_indent
= m_repeatedGap
.substringSharingImpl(0, newSize
);
387 inline void Stringifier::unindent()
389 ASSERT(m_indent
.length() >= m_gap
.length());
390 m_indent
= m_repeatedGap
.substringSharingImpl(0, m_indent
.length() - m_gap
.length());
393 inline void Stringifier::startNewLine(StringBuilder
& builder
) const
397 builder
.append('\n');
398 builder
.append(m_indent
);
401 inline Stringifier::Holder::Holder(VM
& vm
, JSObject
* object
)
402 : m_object(vm
, object
)
403 , m_isArray(object
->inherits(JSArray::info()))
411 bool Stringifier::Holder::appendNextProperty(Stringifier
& stringifier
, StringBuilder
& builder
)
413 ASSERT(m_index
<= m_size
);
415 ExecState
* exec
= stringifier
.m_exec
;
417 // First time through, initialize.
420 m_isJSArray
= isJSArray(m_object
.get());
422 m_size
= asArray(m_object
.get())->length();
424 m_size
= m_object
->get(exec
, exec
->vm().propertyNames
->length
).toUInt32(exec
);
427 if (stringifier
.m_usingArrayReplacer
)
428 m_propertyNames
= stringifier
.m_arrayReplacerPropertyNames
.data();
430 PropertyNameArray
objectPropertyNames(exec
);
431 m_object
->methodTable()->getOwnPropertyNames(m_object
.get(), exec
, objectPropertyNames
, EnumerationMode());
432 m_propertyNames
= objectPropertyNames
.releaseData();
434 m_size
= m_propertyNames
->propertyNameVector().size();
437 stringifier
.indent();
440 // Last time through, finish up and return false.
441 if (m_index
== m_size
) {
442 stringifier
.unindent();
443 if (m_size
&& builder
[builder
.length() - 1] != '{')
444 stringifier
.startNewLine(builder
);
445 builder
.append(m_isArray
? ']' : '}');
449 // Handle a single element of the array or object.
450 unsigned index
= m_index
++;
451 unsigned rollBackPoint
= 0;
452 StringifyResult stringifyResult
;
456 if (m_isJSArray
&& asArray(m_object
.get())->canGetIndexQuickly(index
))
457 value
= asArray(m_object
.get())->getIndexQuickly(index
);
459 PropertySlot
slot(m_object
.get());
460 if (m_object
->methodTable()->getOwnPropertySlotByIndex(m_object
.get(), exec
, index
, slot
)) {
461 value
= slot
.getValue(exec
, index
);
462 if (exec
->hadException())
465 value
= jsUndefined();
468 // Append the separator string.
471 stringifier
.startNewLine(builder
);
473 // Append the stringified value.
474 stringifyResult
= stringifier
.appendStringifiedValue(builder
, value
, m_object
.get(), index
);
477 PropertySlot
slot(m_object
.get());
478 Identifier
& propertyName
= m_propertyNames
->propertyNameVector()[index
];
479 if (!m_object
->methodTable()->getOwnPropertySlot(m_object
.get(), exec
, propertyName
, slot
))
481 JSValue value
= slot
.getValue(exec
, propertyName
);
482 if (exec
->hadException())
485 rollBackPoint
= builder
.length();
487 // Append the separator string.
488 if (builder
[rollBackPoint
- 1] != '{')
490 stringifier
.startNewLine(builder
);
492 // Append the property name.
493 builder
.appendQuotedJSONString(propertyName
.string());
495 if (stringifier
.willIndent())
498 // Append the stringified value.
499 stringifyResult
= stringifier
.appendStringifiedValue(builder
, value
, m_object
.get(), propertyName
);
502 // From this point on, no access to the this pointer or to any members, because the
503 // Holder object may have moved if the call to stringify pushed a new Holder onto
506 switch (stringifyResult
) {
507 case StringifyFailed
:
508 builder
.appendLiteral("null");
510 case StringifySucceeded
:
512 case StringifyFailedDueToUndefinedValue
:
513 // This only occurs when get an undefined value for an object property.
514 // In this case we don't want the separator and property name that we
515 // already appended, so roll back.
516 builder
.resize(rollBackPoint
);
523 // ------------------------------ JSONObject --------------------------------
525 const ClassInfo
JSONObject::s_info
= { "JSON", &JSNonFinalObject::s_info
, &jsonTable
, CREATE_METHOD_TABLE(JSONObject
) };
527 /* Source for JSONObject.lut.h
529 parse JSONProtoFuncParse DontEnum|Function 2
530 stringify JSONProtoFuncStringify DontEnum|Function 3
536 bool JSONObject::getOwnPropertySlot(JSObject
* object
, ExecState
* exec
, PropertyName propertyName
, PropertySlot
& slot
)
538 return getStaticFunctionSlot
<JSObject
>(exec
, jsonTable
, jsCast
<JSONObject
*>(object
), propertyName
, slot
);
543 Walker(ExecState
* exec
, Handle
<JSObject
> function
, CallType callType
, CallData callData
)
545 , m_function(exec
->vm(), function
)
546 , m_callType(callType
)
547 , m_callData(callData
)
550 JSValue
walk(JSValue unfiltered
);
552 JSValue
callReviver(JSObject
* thisObj
, JSValue property
, JSValue unfiltered
)
554 MarkedArgumentBuffer args
;
555 args
.append(property
);
556 args
.append(unfiltered
);
557 return call(m_exec
, m_function
.get(), m_callType
, m_callData
, thisObj
, args
);
563 Local
<JSObject
> m_function
;
568 // We clamp recursion well beyond anything reasonable.
569 static const unsigned maximumFilterRecursion
= 40000;
570 enum WalkerState
{ StateUnknown
, ArrayStartState
, ArrayStartVisitMember
, ArrayEndVisitMember
,
571 ObjectStartState
, ObjectStartVisitMember
, ObjectEndVisitMember
};
572 NEVER_INLINE JSValue
Walker::walk(JSValue unfiltered
)
574 Vector
<PropertyNameArray
, 16, UnsafeVectorOverflow
> propertyStack
;
575 Vector
<uint32_t, 16, UnsafeVectorOverflow
> indexStack
;
576 LocalStack
<JSObject
, 16> objectStack(m_exec
->vm());
577 LocalStack
<JSArray
, 16> arrayStack(m_exec
->vm());
579 Vector
<WalkerState
, 16, UnsafeVectorOverflow
> stateStack
;
580 WalkerState state
= StateUnknown
;
581 JSValue inValue
= unfiltered
;
582 JSValue outValue
= jsNull();
587 case ArrayStartState
: {
588 ASSERT(inValue
.isObject());
589 ASSERT(isJSArray(asObject(inValue
)) || asObject(inValue
)->inherits(JSArray::info()));
590 if (objectStack
.size() + arrayStack
.size() > maximumFilterRecursion
)
591 return throwStackOverflowError(m_exec
);
593 JSArray
* array
= asArray(inValue
);
594 arrayStack
.push(array
);
595 indexStack
.append(0);
597 arrayStartVisitMember
:
599 case ArrayStartVisitMember
: {
600 JSArray
* array
= arrayStack
.peek();
601 uint32_t index
= indexStack
.last();
602 if (index
== array
->length()) {
605 indexStack
.removeLast();
608 if (isJSArray(array
) && array
->canGetIndexQuickly(index
))
609 inValue
= array
->getIndexQuickly(index
);
611 PropertySlot
slot(array
);
612 if (array
->methodTable()->getOwnPropertySlotByIndex(array
, m_exec
, index
, slot
))
613 inValue
= slot
.getValue(m_exec
, index
);
615 inValue
= jsUndefined();
618 if (inValue
.isObject()) {
619 stateStack
.append(ArrayEndVisitMember
);
625 case ArrayEndVisitMember
: {
626 JSArray
* array
= arrayStack
.peek();
627 JSValue filteredValue
= callReviver(array
, jsString(m_exec
, String::number(indexStack
.last())), outValue
);
628 if (filteredValue
.isUndefined())
629 array
->methodTable()->deletePropertyByIndex(array
, m_exec
, indexStack
.last());
631 array
->putDirectIndex(m_exec
, indexStack
.last(), filteredValue
);
632 if (m_exec
->hadException())
635 goto arrayStartVisitMember
;
638 case ObjectStartState
: {
639 ASSERT(inValue
.isObject());
640 ASSERT(!isJSArray(asObject(inValue
)) && !asObject(inValue
)->inherits(JSArray::info()));
641 if (objectStack
.size() + arrayStack
.size() > maximumFilterRecursion
)
642 return throwStackOverflowError(m_exec
);
644 JSObject
* object
= asObject(inValue
);
645 objectStack
.push(object
);
646 indexStack
.append(0);
647 propertyStack
.append(PropertyNameArray(m_exec
));
648 object
->methodTable()->getOwnPropertyNames(object
, m_exec
, propertyStack
.last(), EnumerationMode());
650 objectStartVisitMember
:
652 case ObjectStartVisitMember
: {
653 JSObject
* object
= objectStack
.peek();
654 uint32_t index
= indexStack
.last();
655 PropertyNameArray
& properties
= propertyStack
.last();
656 if (index
== properties
.size()) {
659 indexStack
.removeLast();
660 propertyStack
.removeLast();
663 PropertySlot
slot(object
);
664 if (object
->methodTable()->getOwnPropertySlot(object
, m_exec
, properties
[index
], slot
))
665 inValue
= slot
.getValue(m_exec
, properties
[index
]);
667 inValue
= jsUndefined();
669 // The holder may be modified by the reviver function so any lookup may throw
670 if (m_exec
->hadException())
673 if (inValue
.isObject()) {
674 stateStack
.append(ObjectEndVisitMember
);
680 case ObjectEndVisitMember
: {
681 JSObject
* object
= objectStack
.peek();
682 Identifier prop
= propertyStack
.last()[indexStack
.last()];
683 PutPropertySlot
slot(object
);
684 JSValue filteredValue
= callReviver(object
, jsString(m_exec
, prop
.string()), outValue
);
685 if (filteredValue
.isUndefined())
686 object
->methodTable()->deleteProperty(object
, m_exec
, prop
);
688 object
->methodTable()->put(object
, m_exec
, prop
, filteredValue
, slot
);
689 if (m_exec
->hadException())
692 goto objectStartVisitMember
;
696 if (!inValue
.isObject()) {
700 JSObject
* object
= asObject(inValue
);
701 if (isJSArray(object
) || object
->inherits(JSArray::info()))
702 goto arrayStartState
;
703 goto objectStartState
;
705 if (stateStack
.isEmpty())
708 state
= stateStack
.last();
709 stateStack
.removeLast();
711 JSObject
* finalHolder
= constructEmptyObject(m_exec
);
712 PutPropertySlot
slot(finalHolder
);
713 finalHolder
->methodTable()->put(finalHolder
, m_exec
, m_exec
->vm().propertyNames
->emptyIdentifier
, outValue
, slot
);
714 return callReviver(finalHolder
, jsEmptyString(m_exec
), outValue
);
717 // ECMA-262 v5 15.12.2
718 EncodedJSValue JSC_HOST_CALL
JSONProtoFuncParse(ExecState
* exec
)
720 if (!exec
->argumentCount())
721 return throwVMError(exec
, createError(exec
, ASCIILiteral("JSON.parse requires at least one parameter")));
722 StringView source
= exec
->uncheckedArgument(0).toString(exec
)->view(exec
);
723 if (exec
->hadException())
724 return JSValue::encode(jsNull());
727 LocalScope
scope(exec
->vm());
728 if (source
.is8Bit()) {
729 LiteralParser
<LChar
> jsonParser(exec
, source
.characters8(), source
.length(), StrictJSON
);
730 unfiltered
= jsonParser
.tryLiteralParse();
732 return throwVMError(exec
, createSyntaxError(exec
, jsonParser
.getErrorMessage()));
734 LiteralParser
<UChar
> jsonParser(exec
, source
.characters16(), source
.length(), StrictJSON
);
735 unfiltered
= jsonParser
.tryLiteralParse();
737 return throwVMError(exec
, createSyntaxError(exec
, jsonParser
.getErrorMessage()));
740 if (exec
->argumentCount() < 2)
741 return JSValue::encode(unfiltered
);
743 JSValue function
= exec
->uncheckedArgument(1);
745 CallType callType
= getCallData(function
, callData
);
746 if (callType
== CallTypeNone
)
747 return JSValue::encode(unfiltered
);
748 return JSValue::encode(Walker(exec
, Local
<JSObject
>(exec
->vm(), asObject(function
)), callType
, callData
).walk(unfiltered
));
751 // ECMA-262 v5 15.12.3
752 EncodedJSValue JSC_HOST_CALL
JSONProtoFuncStringify(ExecState
* exec
)
754 if (!exec
->argumentCount())
755 return throwVMError(exec
, createError(exec
, ASCIILiteral("No input to stringify")));
756 LocalScope
scope(exec
->vm());
757 Local
<Unknown
> value(exec
->vm(), exec
->uncheckedArgument(0));
758 Local
<Unknown
> replacer(exec
->vm(), exec
->argument(1));
759 Local
<Unknown
> space(exec
->vm(), exec
->argument(2));
760 JSValue result
= Stringifier(exec
, replacer
, space
).stringify(value
).get();
761 return JSValue::encode(result
);
764 JSValue
JSONParse(ExecState
* exec
, const String
& json
)
766 LocalScope
scope(exec
->vm());
769 LiteralParser
<LChar
> jsonParser(exec
, json
.characters8(), json
.length(), StrictJSON
);
770 return jsonParser
.tryLiteralParse();
773 LiteralParser
<UChar
> jsonParser(exec
, json
.characters16(), json
.length(), StrictJSON
);
774 return jsonParser
.tryLiteralParse();
777 String
JSONStringify(ExecState
* exec
, JSValue value
, unsigned indent
)
779 LocalScope
scope(exec
->vm());
780 Local
<Unknown
> result
= Stringifier(exec
, Local
<Unknown
>(exec
->vm(), jsNull()), Local
<Unknown
>(exec
->vm(), jsNumber(indent
))).stringify(Local
<Unknown
>(exec
->vm(), value
));
781 if (result
.isUndefinedOrNull())
783 return result
.getString(exec
);