]> git.saurik.com Git - apple/javascriptcore.git/blob - runtime/JSONObject.cpp
4a89c55c394835fe0a523f81f3cfffa275703f90
[apple/javascriptcore.git] / runtime / JSONObject.cpp
1 /*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
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.
12 *
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.
24 */
25
26 #include "config.h"
27 #include "JSONObject.h"
28
29 #include "BooleanObject.h"
30 #include "Error.h"
31 #include "ExceptionHelpers.h"
32 #include "JSArray.h"
33 #include "LiteralParser.h"
34 #include "PropertyNameArray.h"
35 #include <wtf/MathExtras.h>
36
37 namespace JSC {
38
39 ASSERT_CLASS_FITS_IN_CELL(JSONObject);
40
41 static JSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*, JSObject*, JSValue, const ArgList&);
42 static JSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*, JSObject*, JSValue, const ArgList&);
43
44 }
45
46 #include "JSONObject.lut.h"
47
48 namespace JSC {
49
50 // PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked.
51 class PropertyNameForFunctionCall {
52 public:
53 PropertyNameForFunctionCall(const Identifier&);
54 PropertyNameForFunctionCall(unsigned);
55
56 JSValue value(ExecState*) const;
57
58 private:
59 const Identifier* m_identifier;
60 unsigned m_number;
61 mutable JSValue m_value;
62 };
63
64 class Stringifier : Noncopyable {
65 public:
66 Stringifier(ExecState*, JSValue replacer, JSValue space);
67 ~Stringifier();
68 JSValue stringify(JSValue);
69
70 void mark();
71
72 private:
73 typedef UString StringBuilder;
74
75 class Holder {
76 public:
77 Holder(JSObject*);
78
79 JSObject* object() const { return m_object; }
80
81 bool appendNextProperty(Stringifier&, StringBuilder&);
82
83 private:
84 JSObject* const m_object;
85 const bool m_isArray;
86 bool m_isJSArray;
87 unsigned m_index;
88 unsigned m_size;
89 RefPtr<PropertyNameArrayData> m_propertyNames;
90 };
91
92 friend class Holder;
93
94 static void appendQuotedString(StringBuilder&, const UString&);
95
96 JSValue toJSON(JSValue, const PropertyNameForFunctionCall&);
97
98 enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedValue };
99 StringifyResult appendStringifiedValue(StringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&);
100
101 bool willIndent() const;
102 void indent();
103 void unindent();
104 void startNewLine(StringBuilder&) const;
105
106 Stringifier* const m_nextStringifierToMark;
107 ExecState* const m_exec;
108 const JSValue m_replacer;
109 bool m_usingArrayReplacer;
110 PropertyNameArray m_arrayReplacerPropertyNames;
111 CallType m_replacerCallType;
112 CallData m_replacerCallData;
113 const UString m_gap;
114
115 HashSet<JSObject*> m_holderCycleDetector;
116 Vector<Holder, 16> m_holderStack;
117 UString m_repeatedGap;
118 UString m_indent;
119 };
120
121 // ------------------------------ helper functions --------------------------------
122
123 static inline JSValue unwrapBoxedPrimitive(JSValue value)
124 {
125 if (!value.isObject())
126 return value;
127 if (!asObject(value)->inherits(&NumberObject::info) && !asObject(value)->inherits(&StringObject::info) && !asObject(value)->inherits(&BooleanObject::info))
128 return value;
129 return static_cast<JSWrapperObject*>(asObject(value))->internalValue();
130 }
131
132 static inline UString gap(JSValue space)
133 {
134 space = unwrapBoxedPrimitive(space);
135
136 // If the space value is a number, create a gap string with that number of spaces.
137 double spaceCount;
138 if (space.getNumber(spaceCount)) {
139 const int maxSpaceCount = 100;
140 int count;
141 if (spaceCount > maxSpaceCount)
142 count = maxSpaceCount;
143 else if (!(spaceCount > 0))
144 count = 0;
145 else
146 count = static_cast<int>(spaceCount);
147 UChar spaces[maxSpaceCount];
148 for (int i = 0; i < count; ++i)
149 spaces[i] = ' ';
150 return UString(spaces, count);
151 }
152
153 // If the space value is a string, use it as the gap string, otherwise use no gap string.
154 return space.getString();
155 }
156
157 // ------------------------------ PropertyNameForFunctionCall --------------------------------
158
159 inline PropertyNameForFunctionCall::PropertyNameForFunctionCall(const Identifier& identifier)
160 : m_identifier(&identifier)
161 {
162 }
163
164 inline PropertyNameForFunctionCall::PropertyNameForFunctionCall(unsigned number)
165 : m_identifier(0)
166 , m_number(number)
167 {
168 }
169
170 JSValue PropertyNameForFunctionCall::value(ExecState* exec) const
171 {
172 if (!m_value) {
173 if (m_identifier)
174 m_value = jsString(exec, m_identifier->ustring());
175 else
176 m_value = jsNumber(exec, m_number);
177 }
178 return m_value;
179 }
180
181 // ------------------------------ Stringifier --------------------------------
182
183 Stringifier::Stringifier(ExecState* exec, JSValue replacer, JSValue space)
184 : m_nextStringifierToMark(exec->globalData().firstStringifierToMark)
185 , m_exec(exec)
186 , m_replacer(replacer)
187 , m_usingArrayReplacer(false)
188 , m_arrayReplacerPropertyNames(exec)
189 , m_replacerCallType(CallTypeNone)
190 , m_gap(gap(space))
191 {
192 exec->globalData().firstStringifierToMark = this;
193
194 if (!m_replacer.isObject())
195 return;
196
197 if (asObject(m_replacer)->inherits(&JSArray::info)) {
198 m_usingArrayReplacer = true;
199 JSObject* array = asObject(m_replacer);
200 unsigned length = array->get(exec, exec->globalData().propertyNames->length).toUInt32(exec);
201 for (unsigned i = 0; i < length; ++i) {
202 JSValue name = array->get(exec, i);
203 if (exec->hadException())
204 break;
205 UString propertyName;
206 if (!name.getString(propertyName))
207 continue;
208 if (exec->hadException())
209 return;
210 m_arrayReplacerPropertyNames.add(Identifier(exec, propertyName));
211 }
212 return;
213 }
214
215 m_replacerCallType = asObject(m_replacer)->getCallData(m_replacerCallData);
216 }
217
218 Stringifier::~Stringifier()
219 {
220 ASSERT(m_exec->globalData().firstStringifierToMark == this);
221 m_exec->globalData().firstStringifierToMark = m_nextStringifierToMark;
222 }
223
224 void Stringifier::mark()
225 {
226 for (Stringifier* stringifier = this; stringifier; stringifier = stringifier->m_nextStringifierToMark) {
227 size_t size = m_holderStack.size();
228 for (size_t i = 0; i < size; ++i) {
229 JSObject* object = m_holderStack[i].object();
230 if (!object->marked())
231 object->mark();
232 }
233 }
234 }
235
236 JSValue Stringifier::stringify(JSValue value)
237 {
238 JSObject* object = constructEmptyObject(m_exec);
239 if (m_exec->hadException())
240 return jsNull();
241
242 PropertyNameForFunctionCall emptyPropertyName(m_exec->globalData().propertyNames->emptyIdentifier);
243 object->putDirect(m_exec->globalData().propertyNames->emptyIdentifier, value);
244
245 StringBuilder result;
246 if (appendStringifiedValue(result, value, object, emptyPropertyName) != StringifySucceeded)
247 return jsUndefined();
248 if (m_exec->hadException())
249 return jsNull();
250
251 return jsString(m_exec, result);
252 }
253
254 void Stringifier::appendQuotedString(StringBuilder& builder, const UString& value)
255 {
256 int length = value.size();
257
258 // String length plus 2 for quote marks plus 8 so we can accomodate a few escaped characters.
259 builder.reserveCapacity(builder.size() + length + 2 + 8);
260
261 builder.append('"');
262
263 const UChar* data = value.data();
264 for (int i = 0; i < length; ++i) {
265 int start = i;
266 while (i < length && (data[i] > 0x1F && data[i] != '"' && data[i] != '\\'))
267 ++i;
268 builder.append(data + start, i - start);
269 if (i >= length)
270 break;
271 switch (data[i]) {
272 case '\t':
273 builder.append('\\');
274 builder.append('t');
275 break;
276 case '\r':
277 builder.append('\\');
278 builder.append('r');
279 break;
280 case '\n':
281 builder.append('\\');
282 builder.append('n');
283 break;
284 case '\f':
285 builder.append('\\');
286 builder.append('f');
287 break;
288 case '\b':
289 builder.append('\\');
290 builder.append('b');
291 break;
292 case '"':
293 builder.append('\\');
294 builder.append('"');
295 break;
296 case '\\':
297 builder.append('\\');
298 builder.append('\\');
299 break;
300 default:
301 static const char hexDigits[] = "0123456789abcdef";
302 UChar ch = data[i];
303 UChar hex[] = { '\\', 'u', hexDigits[(ch >> 12) & 0xF], hexDigits[(ch >> 8) & 0xF], hexDigits[(ch >> 4) & 0xF], hexDigits[ch & 0xF] };
304 builder.append(hex, sizeof(hex) / sizeof(UChar));
305 break;
306 }
307 }
308
309 builder.append('"');
310 }
311
312 inline JSValue Stringifier::toJSON(JSValue value, const PropertyNameForFunctionCall& propertyName)
313 {
314 ASSERT(!m_exec->hadException());
315 if (!value.isObject() || !asObject(value)->hasProperty(m_exec, m_exec->globalData().propertyNames->toJSON))
316 return value;
317
318 JSValue toJSONFunction = asObject(value)->get(m_exec, m_exec->globalData().propertyNames->toJSON);
319 if (m_exec->hadException())
320 return jsNull();
321
322 if (!toJSONFunction.isObject())
323 return value;
324
325 JSObject* object = asObject(toJSONFunction);
326 CallData callData;
327 CallType callType = object->getCallData(callData);
328 if (callType == CallTypeNone)
329 return value;
330
331 JSValue list[] = { propertyName.value(m_exec) };
332 ArgList args(list, sizeof(list) / sizeof(JSValue));
333 return call(m_exec, object, callType, callData, value, args);
334 }
335
336 Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& builder, JSValue value, JSObject* holder, const PropertyNameForFunctionCall& propertyName)
337 {
338 // Call the toJSON function.
339 value = toJSON(value, propertyName);
340 if (m_exec->hadException())
341 return StringifyFailed;
342 if (value.isUndefined() && !holder->inherits(&JSArray::info))
343 return StringifyFailedDueToUndefinedValue;
344
345 // Call the replacer function.
346 if (m_replacerCallType != CallTypeNone) {
347 JSValue list[] = { propertyName.value(m_exec), value };
348 ArgList args(list, sizeof(list) / sizeof(JSValue));
349 value = call(m_exec, m_replacer, m_replacerCallType, m_replacerCallData, holder, args);
350 if (m_exec->hadException())
351 return StringifyFailed;
352 }
353
354 if (value.isNull()) {
355 builder.append("null");
356 return StringifySucceeded;
357 }
358
359 value = unwrapBoxedPrimitive(value);
360
361 if (value.isBoolean()) {
362 builder.append(value.getBoolean() ? "true" : "false");
363 return StringifySucceeded;
364 }
365
366 UString stringValue;
367 if (value.getString(stringValue)) {
368 appendQuotedString(builder, stringValue);
369 return StringifySucceeded;
370 }
371
372 double numericValue;
373 if (value.getNumber(numericValue)) {
374 if (!isfinite(numericValue))
375 builder.append("null");
376 else
377 builder.append(UString::from(numericValue));
378 return StringifySucceeded;
379 }
380
381 if (!value.isObject())
382 return StringifyFailed;
383
384 JSObject* object = asObject(value);
385
386 // Handle cycle detection, and put the holder on the stack.
387 if (!m_holderCycleDetector.add(object).second) {
388 throwError(m_exec, TypeError);
389 return StringifyFailed;
390 }
391 bool holderStackWasEmpty = m_holderStack.isEmpty();
392 m_holderStack.append(object);
393 if (!holderStackWasEmpty)
394 return StringifySucceeded;
395
396 // If this is the outermost call, then loop to handle everything on the holder stack.
397 TimeoutChecker localTimeoutChecker(m_exec->globalData().timeoutChecker);
398 localTimeoutChecker.reset();
399 unsigned tickCount = localTimeoutChecker.ticksUntilNextCheck();
400 do {
401 while (m_holderStack.last().appendNextProperty(*this, builder)) {
402 if (m_exec->hadException())
403 return StringifyFailed;
404 if (!--tickCount) {
405 if (localTimeoutChecker.didTimeOut(m_exec)) {
406 m_exec->setException(createInterruptedExecutionException(&m_exec->globalData()));
407 return StringifyFailed;
408 }
409 tickCount = localTimeoutChecker.ticksUntilNextCheck();
410 }
411 }
412 m_holderCycleDetector.remove(m_holderStack.last().object());
413 m_holderStack.removeLast();
414 } while (!m_holderStack.isEmpty());
415 return StringifySucceeded;
416 }
417
418 inline bool Stringifier::willIndent() const
419 {
420 return !m_gap.isEmpty();
421 }
422
423 inline void Stringifier::indent()
424 {
425 // Use a single shared string, m_repeatedGap, so we don't keep allocating new ones as we indent and unindent.
426 int newSize = m_indent.size() + m_gap.size();
427 if (newSize > m_repeatedGap.size())
428 m_repeatedGap.append(m_gap);
429 ASSERT(newSize <= m_repeatedGap.size());
430 m_indent = m_repeatedGap.substr(0, newSize);
431 }
432
433 inline void Stringifier::unindent()
434 {
435 ASSERT(m_indent.size() >= m_gap.size());
436 m_indent = m_repeatedGap.substr(0, m_indent.size() - m_gap.size());
437 }
438
439 inline void Stringifier::startNewLine(StringBuilder& builder) const
440 {
441 if (m_gap.isEmpty())
442 return;
443 builder.append('\n');
444 builder.append(m_indent);
445 }
446
447 inline Stringifier::Holder::Holder(JSObject* object)
448 : m_object(object)
449 , m_isArray(object->inherits(&JSArray::info))
450 , m_index(0)
451 {
452 }
453
454 bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBuilder& builder)
455 {
456 ASSERT(m_index <= m_size);
457
458 ExecState* exec = stringifier.m_exec;
459
460 // First time through, initialize.
461 if (!m_index) {
462 if (m_isArray) {
463 m_isJSArray = isJSArray(&exec->globalData(), m_object);
464 m_size = m_object->get(exec, exec->globalData().propertyNames->length).toUInt32(exec);
465 builder.append('[');
466 } else {
467 if (stringifier.m_usingArrayReplacer)
468 m_propertyNames = stringifier.m_arrayReplacerPropertyNames.data();
469 else {
470 PropertyNameArray objectPropertyNames(exec);
471 m_object->getPropertyNames(exec, objectPropertyNames);
472 m_propertyNames = objectPropertyNames.releaseData();
473 }
474 m_size = m_propertyNames->propertyNameVector().size();
475 builder.append('{');
476 }
477 stringifier.indent();
478 }
479
480 // Last time through, finish up and return false.
481 if (m_index == m_size) {
482 stringifier.unindent();
483 if (m_size && builder[builder.size() - 1] != '{')
484 stringifier.startNewLine(builder);
485 builder.append(m_isArray ? ']' : '}');
486 return false;
487 }
488
489 // Handle a single element of the array or object.
490 unsigned index = m_index++;
491 unsigned rollBackPoint = 0;
492 StringifyResult stringifyResult;
493 if (m_isArray) {
494 // Get the value.
495 JSValue value;
496 if (m_isJSArray && asArray(m_object)->canGetIndex(index))
497 value = asArray(m_object)->getIndex(index);
498 else {
499 PropertySlot slot(m_object);
500 if (!m_object->getOwnPropertySlot(exec, index, slot))
501 slot.setUndefined();
502 if (exec->hadException())
503 return false;
504 value = slot.getValue(exec, index);
505 }
506
507 // Append the separator string.
508 if (index)
509 builder.append(',');
510 stringifier.startNewLine(builder);
511
512 // Append the stringified value.
513 stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object, index);
514 } else {
515 // Get the value.
516 PropertySlot slot(m_object);
517 Identifier& propertyName = m_propertyNames->propertyNameVector()[index];
518 if (!m_object->getOwnPropertySlot(exec, propertyName, slot))
519 return true;
520 JSValue value = slot.getValue(exec, propertyName);
521 if (exec->hadException())
522 return false;
523
524 rollBackPoint = builder.size();
525
526 // Append the separator string.
527 if (builder[rollBackPoint - 1] != '{')
528 builder.append(',');
529 stringifier.startNewLine(builder);
530
531 // Append the property name.
532 appendQuotedString(builder, propertyName.ustring());
533 builder.append(':');
534 if (stringifier.willIndent())
535 builder.append(' ');
536
537 // Append the stringified value.
538 stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object, propertyName);
539 }
540
541 // From this point on, no access to the this pointer or to any members, because the
542 // Holder object may have moved if the call to stringify pushed a new Holder onto
543 // m_holderStack.
544
545 switch (stringifyResult) {
546 case StringifyFailed:
547 builder.append("null");
548 break;
549 case StringifySucceeded:
550 break;
551 case StringifyFailedDueToUndefinedValue:
552 // This only occurs when get an undefined value for an object property.
553 // In this case we don't want the separator and property name that we
554 // already appended, so roll back.
555 builder = builder.substr(0, rollBackPoint);
556 break;
557 }
558
559 return true;
560 }
561
562 // ------------------------------ JSONObject --------------------------------
563
564 const ClassInfo JSONObject::info = { "JSON", 0, 0, ExecState::jsonTable };
565
566 /* Source for JSONObject.lut.h
567 @begin jsonTable
568 parse JSONProtoFuncParse DontEnum|Function 1
569 stringify JSONProtoFuncStringify DontEnum|Function 1
570 @end
571 */
572
573 // ECMA 15.8
574
575 bool JSONObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
576 {
577 const HashEntry* entry = ExecState::jsonTable(exec)->entry(exec, propertyName);
578 if (!entry)
579 return JSObject::getOwnPropertySlot(exec, propertyName, slot);
580
581 ASSERT(entry->attributes() & Function);
582 setUpStaticFunctionSlot(exec, entry, this, propertyName, slot);
583 return true;
584 }
585
586 void JSONObject::markStringifiers(Stringifier* stringifier)
587 {
588 stringifier->mark();
589 }
590
591 class Walker {
592 public:
593 Walker(ExecState* exec, JSObject* function, CallType callType, CallData callData)
594 : m_exec(exec)
595 , m_function(function)
596 , m_callType(callType)
597 , m_callData(callData)
598 {
599 }
600 JSValue walk(JSValue unfiltered);
601 private:
602 JSValue callReviver(JSValue property, JSValue unfiltered)
603 {
604 JSValue args[] = { property, unfiltered };
605 ArgList argList(args, 2);
606 return call(m_exec, m_function, m_callType, m_callData, jsNull(), argList);
607 }
608
609 friend class Holder;
610
611 ExecState* m_exec;
612 JSObject* m_function;
613 CallType m_callType;
614 CallData m_callData;
615 };
616
617 enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
618 ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember };
619 NEVER_INLINE JSValue Walker::walk(JSValue unfiltered)
620 {
621 Vector<PropertyNameArray, 16> propertyStack;
622 Vector<uint32_t, 16> indexStack;
623 Vector<JSObject*, 16> objectStack;
624 Vector<JSArray*, 16> arrayStack;
625
626 Vector<WalkerState, 16> stateStack;
627 WalkerState state = StateUnknown;
628 JSValue inValue = unfiltered;
629 JSValue outValue = jsNull();
630 while (1) {
631 switch (state) {
632 arrayStartState:
633 case ArrayStartState: {
634 ASSERT(inValue.isObject());
635 ASSERT(isJSArray(&m_exec->globalData(), asObject(inValue)));
636 JSArray* array = asArray(inValue);
637 arrayStack.append(array);
638 indexStack.append(0);
639 // fallthrough
640 }
641 arrayStartVisitMember:
642 case ArrayStartVisitMember: {
643 JSArray* array = arrayStack.last();
644 uint32_t index = indexStack.last();
645 if (index == array->length()) {
646 outValue = array;
647 arrayStack.removeLast();
648 indexStack.removeLast();
649 break;
650 }
651 inValue = array->getIndex(index);
652 if (inValue.isObject()) {
653 stateStack.append(ArrayEndVisitMember);
654 goto stateUnknown;
655 } else
656 outValue = inValue;
657 // fallthrough
658 }
659 case ArrayEndVisitMember: {
660 JSArray* array = arrayStack.last();
661 array->setIndex(indexStack.last(), callReviver(jsString(m_exec, UString::from(indexStack.last())), outValue));
662 if (m_exec->hadException())
663 return jsNull();
664 indexStack.last()++;
665 goto arrayStartVisitMember;
666 }
667 objectStartState:
668 case ObjectStartState: {
669 ASSERT(inValue.isObject());
670 ASSERT(!isJSArray(&m_exec->globalData(), asObject(inValue)));
671 JSObject* object = asObject(inValue);
672 objectStack.append(object);
673 indexStack.append(0);
674 propertyStack.append(PropertyNameArray(m_exec));
675 object->getPropertyNames(m_exec, propertyStack.last());
676 // fallthrough
677 }
678 objectStartVisitMember:
679 case ObjectStartVisitMember: {
680 JSObject* object = objectStack.last();
681 uint32_t index = indexStack.last();
682 PropertyNameArray& properties = propertyStack.last();
683 if (index == properties.size()) {
684 outValue = object;
685 objectStack.removeLast();
686 indexStack.removeLast();
687 propertyStack.removeLast();
688 break;
689 }
690 PropertySlot slot;
691 object->getOwnPropertySlot(m_exec, properties[index], slot);
692 inValue = slot.getValue(m_exec, properties[index]);
693 ASSERT(!m_exec->hadException());
694 if (inValue.isObject()) {
695 stateStack.append(ObjectEndVisitMember);
696 goto stateUnknown;
697 } else
698 outValue = inValue;
699 // fallthrough
700 }
701 case ObjectEndVisitMember: {
702 JSObject* object = objectStack.last();
703 Identifier prop = propertyStack.last()[indexStack.last()];
704 PutPropertySlot slot;
705 object->put(m_exec, prop, callReviver(jsString(m_exec, prop.ustring()), outValue), slot);
706 if (m_exec->hadException())
707 return jsNull();
708 indexStack.last()++;
709 goto objectStartVisitMember;
710 }
711 stateUnknown:
712 case StateUnknown:
713 if (!inValue.isObject()) {
714 outValue = inValue;
715 break;
716 }
717 if (isJSArray(&m_exec->globalData(), asObject(inValue)))
718 goto arrayStartState;
719 goto objectStartState;
720 }
721 if (stateStack.isEmpty())
722 break;
723 state = stateStack.last();
724 stateStack.removeLast();
725 }
726 return callReviver(jsEmptyString(m_exec), outValue);
727 }
728
729 // ECMA-262 v5 15.12.2
730 JSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec, JSObject*, JSValue, const ArgList& args)
731 {
732 if (args.isEmpty())
733 return throwError(exec, GeneralError, "JSON.parse requires at least one parameter");
734 JSValue value = args.at(0);
735 UString source = value.toString(exec);
736 if (exec->hadException())
737 return jsNull();
738
739 LiteralParser jsonParser(exec, source, LiteralParser::StrictJSON);
740 JSValue unfiltered = jsonParser.tryLiteralParse();
741 if (!unfiltered)
742 return throwError(exec, SyntaxError, "Unable to parse JSON string");
743
744 if (args.size() < 2)
745 return unfiltered;
746
747 JSValue function = args.at(1);
748 CallData callData;
749 CallType callType = function.getCallData(callData);
750 if (callType == CallTypeNone)
751 return unfiltered;
752 return Walker(exec, asObject(function), callType, callData).walk(unfiltered);
753 }
754
755 // ECMA-262 v5 15.12.3
756 JSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec, JSObject*, JSValue, const ArgList& args)
757 {
758 if (args.isEmpty())
759 return throwError(exec, GeneralError, "No input to stringify");
760 JSValue value = args.at(0);
761 JSValue replacer = args.at(1);
762 JSValue space = args.at(2);
763 return Stringifier(exec, replacer, space).stringify(value);
764 }
765
766 } // namespace JSC