PageRenderTime 45ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/src/qt/qtwebkit/Source/JavaScriptCore/runtime/JSONObject.cpp

https://gitlab.com/x33n/phantomjs
C++ | 834 lines | 756 code | 48 blank | 30 comment | 29 complexity | 01941fdeb53707df39801c82339587bd MD5 | raw file
  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. #include "config.h"
  26. #include "JSONObject.h"
  27. #include "BooleanObject.h"
  28. #include "Error.h"
  29. #include "ExceptionHelpers.h"
  30. #include "JSArray.h"
  31. #include "JSGlobalObject.h"
  32. #include "LiteralParser.h"
  33. #include "Local.h"
  34. #include "LocalScope.h"
  35. #include "Lookup.h"
  36. #include "ObjectConstructor.h"
  37. #include "Operations.h"
  38. #include "PropertyNameArray.h"
  39. #include <wtf/MathExtras.h>
  40. #include <wtf/text/StringBuilder.h>
  41. namespace JSC {
  42. ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSONObject);
  43. static EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*);
  44. static EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*);
  45. }
  46. #include "JSONObject.lut.h"
  47. namespace JSC {
  48. JSONObject::JSONObject(JSGlobalObject* globalObject, Structure* structure)
  49. : JSNonFinalObject(globalObject->vm(), structure)
  50. {
  51. }
  52. void JSONObject::finishCreation(JSGlobalObject* globalObject)
  53. {
  54. Base::finishCreation(globalObject->vm());
  55. ASSERT(inherits(&s_info));
  56. }
  57. // PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked.
  58. class PropertyNameForFunctionCall {
  59. public:
  60. PropertyNameForFunctionCall(const Identifier&);
  61. PropertyNameForFunctionCall(unsigned);
  62. JSValue value(ExecState*) const;
  63. private:
  64. const Identifier* m_identifier;
  65. unsigned m_number;
  66. mutable JSValue m_value;
  67. };
  68. class Stringifier {
  69. WTF_MAKE_NONCOPYABLE(Stringifier);
  70. public:
  71. Stringifier(ExecState*, const Local<Unknown>& replacer, const Local<Unknown>& space);
  72. Local<Unknown> stringify(Handle<Unknown>);
  73. void visitAggregate(SlotVisitor&);
  74. private:
  75. class Holder {
  76. public:
  77. Holder(VM&, JSObject*);
  78. JSObject* object() const { return m_object.get(); }
  79. bool appendNextProperty(Stringifier&, StringBuilder&);
  80. private:
  81. Local<JSObject> m_object;
  82. const bool m_isArray;
  83. bool m_isJSArray;
  84. unsigned m_index;
  85. unsigned m_size;
  86. RefPtr<PropertyNameArrayData> m_propertyNames;
  87. };
  88. friend class Holder;
  89. static void appendQuotedString(StringBuilder&, const String&);
  90. JSValue toJSON(JSValue, const PropertyNameForFunctionCall&);
  91. enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedValue };
  92. StringifyResult appendStringifiedValue(StringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&);
  93. bool willIndent() const;
  94. void indent();
  95. void unindent();
  96. void startNewLine(StringBuilder&) const;
  97. ExecState* const m_exec;
  98. const Local<Unknown> m_replacer;
  99. bool m_usingArrayReplacer;
  100. PropertyNameArray m_arrayReplacerPropertyNames;
  101. CallType m_replacerCallType;
  102. CallData m_replacerCallData;
  103. const String m_gap;
  104. Vector<Holder, 16, UnsafeVectorOverflow> m_holderStack;
  105. String m_repeatedGap;
  106. String m_indent;
  107. };
  108. // ------------------------------ helper functions --------------------------------
  109. static inline JSValue unwrapBoxedPrimitive(ExecState* exec, JSValue value)
  110. {
  111. if (!value.isObject())
  112. return value;
  113. JSObject* object = asObject(value);
  114. if (object->inherits(&NumberObject::s_info))
  115. return jsNumber(object->toNumber(exec));
  116. if (object->inherits(&StringObject::s_info))
  117. return object->toString(exec);
  118. if (object->inherits(&BooleanObject::s_info))
  119. return object->toPrimitive(exec);
  120. return value;
  121. }
  122. static inline String gap(ExecState* exec, JSValue space)
  123. {
  124. const unsigned maxGapLength = 10;
  125. space = unwrapBoxedPrimitive(exec, space);
  126. // If the space value is a number, create a gap string with that number of spaces.
  127. if (space.isNumber()) {
  128. double spaceCount = space.asNumber();
  129. int count;
  130. if (spaceCount > maxGapLength)
  131. count = maxGapLength;
  132. else if (!(spaceCount > 0))
  133. count = 0;
  134. else
  135. count = static_cast<int>(spaceCount);
  136. UChar spaces[maxGapLength];
  137. for (int i = 0; i < count; ++i)
  138. spaces[i] = ' ';
  139. return String(spaces, count);
  140. }
  141. // If the space value is a string, use it as the gap string, otherwise use no gap string.
  142. String spaces = space.getString(exec);
  143. if (spaces.length() > maxGapLength) {
  144. spaces = spaces.substringSharingImpl(0, maxGapLength);
  145. }
  146. return spaces;
  147. }
  148. // ------------------------------ PropertyNameForFunctionCall --------------------------------
  149. inline PropertyNameForFunctionCall::PropertyNameForFunctionCall(const Identifier& identifier)
  150. : m_identifier(&identifier)
  151. {
  152. }
  153. inline PropertyNameForFunctionCall::PropertyNameForFunctionCall(unsigned number)
  154. : m_identifier(0)
  155. , m_number(number)
  156. {
  157. }
  158. JSValue PropertyNameForFunctionCall::value(ExecState* exec) const
  159. {
  160. if (!m_value) {
  161. if (m_identifier)
  162. m_value = jsString(exec, m_identifier->string());
  163. else
  164. m_value = jsNumber(m_number);
  165. }
  166. return m_value;
  167. }
  168. // ------------------------------ Stringifier --------------------------------
  169. Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const Local<Unknown>& space)
  170. : m_exec(exec)
  171. , m_replacer(replacer)
  172. , m_usingArrayReplacer(false)
  173. , m_arrayReplacerPropertyNames(exec)
  174. , m_replacerCallType(CallTypeNone)
  175. , m_gap(gap(exec, space.get()))
  176. {
  177. if (!m_replacer.isObject())
  178. return;
  179. if (m_replacer.asObject()->inherits(&JSArray::s_info)) {
  180. m_usingArrayReplacer = true;
  181. Handle<JSObject> array = m_replacer.asObject();
  182. unsigned length = array->get(exec, exec->vm().propertyNames->length).toUInt32(exec);
  183. for (unsigned i = 0; i < length; ++i) {
  184. JSValue name = array->get(exec, i);
  185. if (exec->hadException())
  186. break;
  187. if (name.isObject()) {
  188. if (!asObject(name)->inherits(&NumberObject::s_info) && !asObject(name)->inherits(&StringObject::s_info))
  189. continue;
  190. }
  191. m_arrayReplacerPropertyNames.add(Identifier(exec, name.toString(exec)->value(exec)));
  192. }
  193. return;
  194. }
  195. m_replacerCallType = m_replacer.asObject()->methodTable()->getCallData(m_replacer.asObject().get(), m_replacerCallData);
  196. }
  197. Local<Unknown> Stringifier::stringify(Handle<Unknown> value)
  198. {
  199. JSObject* object = constructEmptyObject(m_exec);
  200. if (m_exec->hadException())
  201. return Local<Unknown>(m_exec->vm(), jsNull());
  202. PropertyNameForFunctionCall emptyPropertyName(m_exec->vm().propertyNames->emptyIdentifier);
  203. object->putDirect(m_exec->vm(), m_exec->vm().propertyNames->emptyIdentifier, value.get());
  204. StringBuilder result;
  205. if (appendStringifiedValue(result, value.get(), object, emptyPropertyName) != StringifySucceeded)
  206. return Local<Unknown>(m_exec->vm(), jsUndefined());
  207. if (m_exec->hadException())
  208. return Local<Unknown>(m_exec->vm(), jsNull());
  209. return Local<Unknown>(m_exec->vm(), jsString(m_exec, result.toString()));
  210. }
  211. template <typename CharType>
  212. static void appendStringToStringBuilder(StringBuilder& builder, const CharType* data, int length)
  213. {
  214. for (int i = 0; i < length; ++i) {
  215. int start = i;
  216. while (i < length && (data[i] > 0x1F && data[i] != '"' && data[i] != '\\'))
  217. ++i;
  218. builder.append(data + start, i - start);
  219. if (i >= length)
  220. break;
  221. switch (data[i]) {
  222. case '\t':
  223. builder.append('\\');
  224. builder.append('t');
  225. break;
  226. case '\r':
  227. builder.append('\\');
  228. builder.append('r');
  229. break;
  230. case '\n':
  231. builder.append('\\');
  232. builder.append('n');
  233. break;
  234. case '\f':
  235. builder.append('\\');
  236. builder.append('f');
  237. break;
  238. case '\b':
  239. builder.append('\\');
  240. builder.append('b');
  241. break;
  242. case '"':
  243. builder.append('\\');
  244. builder.append('"');
  245. break;
  246. case '\\':
  247. builder.append('\\');
  248. builder.append('\\');
  249. break;
  250. default:
  251. static const char hexDigits[] = "0123456789abcdef";
  252. UChar ch = data[i];
  253. 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]) };
  254. builder.append(hex, WTF_ARRAY_LENGTH(hex));
  255. break;
  256. }
  257. }
  258. }
  259. void Stringifier::appendQuotedString(StringBuilder& builder, const String& value)
  260. {
  261. int length = value.length();
  262. builder.append('"');
  263. if (value.is8Bit())
  264. appendStringToStringBuilder<LChar>(builder, value.characters8(), length);
  265. else
  266. appendStringToStringBuilder<UChar>(builder, value.characters16(), length);
  267. builder.append('"');
  268. }
  269. inline JSValue Stringifier::toJSON(JSValue value, const PropertyNameForFunctionCall& propertyName)
  270. {
  271. ASSERT(!m_exec->hadException());
  272. if (!value.isObject() || !asObject(value)->hasProperty(m_exec, m_exec->vm().propertyNames->toJSON))
  273. return value;
  274. JSValue toJSONFunction = asObject(value)->get(m_exec, m_exec->vm().propertyNames->toJSON);
  275. if (m_exec->hadException())
  276. return jsNull();
  277. if (!toJSONFunction.isObject())
  278. return value;
  279. JSObject* object = asObject(toJSONFunction);
  280. CallData callData;
  281. CallType callType = object->methodTable()->getCallData(object, callData);
  282. if (callType == CallTypeNone)
  283. return value;
  284. MarkedArgumentBuffer args;
  285. args.append(propertyName.value(m_exec));
  286. return call(m_exec, object, callType, callData, value, args);
  287. }
  288. Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& builder, JSValue value, JSObject* holder, const PropertyNameForFunctionCall& propertyName)
  289. {
  290. // Call the toJSON function.
  291. value = toJSON(value, propertyName);
  292. if (m_exec->hadException())
  293. return StringifyFailed;
  294. // Call the replacer function.
  295. if (m_replacerCallType != CallTypeNone) {
  296. MarkedArgumentBuffer args;
  297. args.append(propertyName.value(m_exec));
  298. args.append(value);
  299. value = call(m_exec, m_replacer.get(), m_replacerCallType, m_replacerCallData, holder, args);
  300. if (m_exec->hadException())
  301. return StringifyFailed;
  302. }
  303. if (value.isUndefined() && !holder->inherits(&JSArray::s_info))
  304. return StringifyFailedDueToUndefinedValue;
  305. if (value.isNull()) {
  306. builder.appendLiteral("null");
  307. return StringifySucceeded;
  308. }
  309. value = unwrapBoxedPrimitive(m_exec, value);
  310. if (m_exec->hadException())
  311. return StringifyFailed;
  312. if (value.isBoolean()) {
  313. if (value.isTrue())
  314. builder.appendLiteral("true");
  315. else
  316. builder.appendLiteral("false");
  317. return StringifySucceeded;
  318. }
  319. String stringValue;
  320. if (value.getString(m_exec, stringValue)) {
  321. appendQuotedString(builder, stringValue);
  322. return StringifySucceeded;
  323. }
  324. if (value.isNumber()) {
  325. double number = value.asNumber();
  326. if (!std::isfinite(number))
  327. builder.appendLiteral("null");
  328. else
  329. builder.append(String::numberToStringECMAScript(number));
  330. return StringifySucceeded;
  331. }
  332. if (!value.isObject())
  333. return StringifyFailed;
  334. JSObject* object = asObject(value);
  335. CallData callData;
  336. if (object->methodTable()->getCallData(object, callData) != CallTypeNone) {
  337. if (holder->inherits(&JSArray::s_info)) {
  338. builder.appendLiteral("null");
  339. return StringifySucceeded;
  340. }
  341. return StringifyFailedDueToUndefinedValue;
  342. }
  343. // Handle cycle detection, and put the holder on the stack.
  344. for (unsigned i = 0; i < m_holderStack.size(); i++) {
  345. if (m_holderStack[i].object() == object) {
  346. throwError(m_exec, createTypeError(m_exec, ASCIILiteral("JSON.stringify cannot serialize cyclic structures.")));
  347. return StringifyFailed;
  348. }
  349. }
  350. bool holderStackWasEmpty = m_holderStack.isEmpty();
  351. m_holderStack.append(Holder(m_exec->vm(), object));
  352. if (!holderStackWasEmpty)
  353. return StringifySucceeded;
  354. do {
  355. while (m_holderStack.last().appendNextProperty(*this, builder)) {
  356. if (m_exec->hadException())
  357. return StringifyFailed;
  358. }
  359. m_holderStack.removeLast();
  360. } while (!m_holderStack.isEmpty());
  361. return StringifySucceeded;
  362. }
  363. inline bool Stringifier::willIndent() const
  364. {
  365. return !m_gap.isEmpty();
  366. }
  367. inline void Stringifier::indent()
  368. {
  369. // Use a single shared string, m_repeatedGap, so we don't keep allocating new ones as we indent and unindent.
  370. unsigned newSize = m_indent.length() + m_gap.length();
  371. if (newSize > m_repeatedGap.length())
  372. m_repeatedGap = makeString(m_repeatedGap, m_gap);
  373. ASSERT(newSize <= m_repeatedGap.length());
  374. m_indent = m_repeatedGap.substringSharingImpl(0, newSize);
  375. }
  376. inline void Stringifier::unindent()
  377. {
  378. ASSERT(m_indent.length() >= m_gap.length());
  379. m_indent = m_repeatedGap.substringSharingImpl(0, m_indent.length() - m_gap.length());
  380. }
  381. inline void Stringifier::startNewLine(StringBuilder& builder) const
  382. {
  383. if (m_gap.isEmpty())
  384. return;
  385. builder.append('\n');
  386. builder.append(m_indent);
  387. }
  388. inline Stringifier::Holder::Holder(VM& vm, JSObject* object)
  389. : m_object(vm, object)
  390. , m_isArray(object->inherits(&JSArray::s_info))
  391. , m_index(0)
  392. #ifndef NDEBUG
  393. , m_size(0)
  394. #endif
  395. {
  396. }
  397. bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBuilder& builder)
  398. {
  399. ASSERT(m_index <= m_size);
  400. ExecState* exec = stringifier.m_exec;
  401. // First time through, initialize.
  402. if (!m_index) {
  403. if (m_isArray) {
  404. m_isJSArray = isJSArray(m_object.get());
  405. m_size = m_object->get(exec, exec->vm().propertyNames->length).toUInt32(exec);
  406. builder.append('[');
  407. } else {
  408. if (stringifier.m_usingArrayReplacer)
  409. m_propertyNames = stringifier.m_arrayReplacerPropertyNames.data();
  410. else {
  411. PropertyNameArray objectPropertyNames(exec);
  412. m_object->methodTable()->getOwnPropertyNames(m_object.get(), exec, objectPropertyNames, ExcludeDontEnumProperties);
  413. m_propertyNames = objectPropertyNames.releaseData();
  414. }
  415. m_size = m_propertyNames->propertyNameVector().size();
  416. builder.append('{');
  417. }
  418. stringifier.indent();
  419. }
  420. // Last time through, finish up and return false.
  421. if (m_index == m_size) {
  422. stringifier.unindent();
  423. if (m_size && builder[builder.length() - 1] != '{')
  424. stringifier.startNewLine(builder);
  425. builder.append(m_isArray ? ']' : '}');
  426. return false;
  427. }
  428. // Handle a single element of the array or object.
  429. unsigned index = m_index++;
  430. unsigned rollBackPoint = 0;
  431. StringifyResult stringifyResult;
  432. if (m_isArray) {
  433. // Get the value.
  434. JSValue value;
  435. if (m_isJSArray && asArray(m_object.get())->canGetIndexQuickly(index))
  436. value = asArray(m_object.get())->getIndexQuickly(index);
  437. else {
  438. PropertySlot slot(m_object.get());
  439. if (!m_object->methodTable()->getOwnPropertySlotByIndex(m_object.get(), exec, index, slot))
  440. slot.setUndefined();
  441. if (exec->hadException())
  442. return false;
  443. value = slot.getValue(exec, index);
  444. }
  445. // Append the separator string.
  446. if (index)
  447. builder.append(',');
  448. stringifier.startNewLine(builder);
  449. // Append the stringified value.
  450. stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object.get(), index);
  451. } else {
  452. // Get the value.
  453. PropertySlot slot(m_object.get());
  454. Identifier& propertyName = m_propertyNames->propertyNameVector()[index];
  455. if (!m_object->methodTable()->getOwnPropertySlot(m_object.get(), exec, propertyName, slot))
  456. return true;
  457. JSValue value = slot.getValue(exec, propertyName);
  458. if (exec->hadException())
  459. return false;
  460. rollBackPoint = builder.length();
  461. // Append the separator string.
  462. if (builder[rollBackPoint - 1] != '{')
  463. builder.append(',');
  464. stringifier.startNewLine(builder);
  465. // Append the property name.
  466. appendQuotedString(builder, propertyName.string());
  467. builder.append(':');
  468. if (stringifier.willIndent())
  469. builder.append(' ');
  470. // Append the stringified value.
  471. stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object.get(), propertyName);
  472. }
  473. // From this point on, no access to the this pointer or to any members, because the
  474. // Holder object may have moved if the call to stringify pushed a new Holder onto
  475. // m_holderStack.
  476. switch (stringifyResult) {
  477. case StringifyFailed:
  478. builder.appendLiteral("null");
  479. break;
  480. case StringifySucceeded:
  481. break;
  482. case StringifyFailedDueToUndefinedValue:
  483. // This only occurs when get an undefined value for an object property.
  484. // In this case we don't want the separator and property name that we
  485. // already appended, so roll back.
  486. builder.resize(rollBackPoint);
  487. break;
  488. }
  489. return true;
  490. }
  491. // ------------------------------ JSONObject --------------------------------
  492. const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, 0, ExecState::jsonTable, CREATE_METHOD_TABLE(JSONObject) };
  493. /* Source for JSONObject.lut.h
  494. @begin jsonTable
  495. parse JSONProtoFuncParse DontEnum|Function 2
  496. stringify JSONProtoFuncStringify DontEnum|Function 3
  497. @end
  498. */
  499. // ECMA 15.8
  500. bool JSONObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, PropertyName propertyName, PropertySlot& slot)
  501. {
  502. return getStaticFunctionSlot<JSObject>(exec, ExecState::jsonTable(exec), jsCast<JSONObject*>(cell), propertyName, slot);
  503. }
  504. bool JSONObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, PropertyName propertyName, PropertyDescriptor& descriptor)
  505. {
  506. return getStaticFunctionDescriptor<JSObject>(exec, ExecState::jsonTable(exec), jsCast<JSONObject*>(object), propertyName, descriptor);
  507. }
  508. class Walker {
  509. public:
  510. Walker(ExecState* exec, Handle<JSObject> function, CallType callType, CallData callData)
  511. : m_exec(exec)
  512. , m_function(exec->vm(), function)
  513. , m_callType(callType)
  514. , m_callData(callData)
  515. {
  516. }
  517. JSValue walk(JSValue unfiltered);
  518. private:
  519. JSValue callReviver(JSObject* thisObj, JSValue property, JSValue unfiltered)
  520. {
  521. MarkedArgumentBuffer args;
  522. args.append(property);
  523. args.append(unfiltered);
  524. return call(m_exec, m_function.get(), m_callType, m_callData, thisObj, args);
  525. }
  526. friend class Holder;
  527. ExecState* m_exec;
  528. Local<JSObject> m_function;
  529. CallType m_callType;
  530. CallData m_callData;
  531. };
  532. // We clamp recursion well beyond anything reasonable.
  533. static const unsigned maximumFilterRecursion = 40000;
  534. enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
  535. ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember };
  536. NEVER_INLINE JSValue Walker::walk(JSValue unfiltered)
  537. {
  538. Vector<PropertyNameArray, 16, UnsafeVectorOverflow> propertyStack;
  539. Vector<uint32_t, 16, UnsafeVectorOverflow> indexStack;
  540. LocalStack<JSObject, 16> objectStack(m_exec->vm());
  541. LocalStack<JSArray, 16> arrayStack(m_exec->vm());
  542. Vector<WalkerState, 16, UnsafeVectorOverflow> stateStack;
  543. WalkerState state = StateUnknown;
  544. JSValue inValue = unfiltered;
  545. JSValue outValue = jsNull();
  546. while (1) {
  547. switch (state) {
  548. arrayStartState:
  549. case ArrayStartState: {
  550. ASSERT(inValue.isObject());
  551. ASSERT(isJSArray(asObject(inValue)) || asObject(inValue)->inherits(&JSArray::s_info));
  552. if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
  553. return throwError(m_exec, createStackOverflowError(m_exec));
  554. JSArray* array = asArray(inValue);
  555. arrayStack.push(array);
  556. indexStack.append(0);
  557. // fallthrough
  558. }
  559. arrayStartVisitMember:
  560. case ArrayStartVisitMember: {
  561. JSArray* array = arrayStack.peek();
  562. uint32_t index = indexStack.last();
  563. if (index == array->length()) {
  564. outValue = array;
  565. arrayStack.pop();
  566. indexStack.removeLast();
  567. break;
  568. }
  569. if (isJSArray(array) && array->canGetIndexQuickly(index))
  570. inValue = array->getIndexQuickly(index);
  571. else {
  572. PropertySlot slot;
  573. if (array->methodTable()->getOwnPropertySlotByIndex(array, m_exec, index, slot))
  574. inValue = slot.getValue(m_exec, index);
  575. else
  576. inValue = jsUndefined();
  577. }
  578. if (inValue.isObject()) {
  579. stateStack.append(ArrayEndVisitMember);
  580. goto stateUnknown;
  581. } else
  582. outValue = inValue;
  583. // fallthrough
  584. }
  585. case ArrayEndVisitMember: {
  586. JSArray* array = arrayStack.peek();
  587. JSValue filteredValue = callReviver(array, jsString(m_exec, String::number(indexStack.last())), outValue);
  588. if (filteredValue.isUndefined())
  589. array->methodTable()->deletePropertyByIndex(array, m_exec, indexStack.last());
  590. else
  591. array->putDirectIndex(m_exec, indexStack.last(), filteredValue);
  592. if (m_exec->hadException())
  593. return jsNull();
  594. indexStack.last()++;
  595. goto arrayStartVisitMember;
  596. }
  597. objectStartState:
  598. case ObjectStartState: {
  599. ASSERT(inValue.isObject());
  600. ASSERT(!isJSArray(asObject(inValue)) && !asObject(inValue)->inherits(&JSArray::s_info));
  601. if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
  602. return throwError(m_exec, createStackOverflowError(m_exec));
  603. JSObject* object = asObject(inValue);
  604. objectStack.push(object);
  605. indexStack.append(0);
  606. propertyStack.append(PropertyNameArray(m_exec));
  607. object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
  608. // fallthrough
  609. }
  610. objectStartVisitMember:
  611. case ObjectStartVisitMember: {
  612. JSObject* object = objectStack.peek();
  613. uint32_t index = indexStack.last();
  614. PropertyNameArray& properties = propertyStack.last();
  615. if (index == properties.size()) {
  616. outValue = object;
  617. objectStack.pop();
  618. indexStack.removeLast();
  619. propertyStack.removeLast();
  620. break;
  621. }
  622. PropertySlot slot;
  623. if (object->methodTable()->getOwnPropertySlot(object, m_exec, properties[index], slot))
  624. inValue = slot.getValue(m_exec, properties[index]);
  625. else
  626. inValue = jsUndefined();
  627. // The holder may be modified by the reviver function so any lookup may throw
  628. if (m_exec->hadException())
  629. return jsNull();
  630. if (inValue.isObject()) {
  631. stateStack.append(ObjectEndVisitMember);
  632. goto stateUnknown;
  633. } else
  634. outValue = inValue;
  635. // fallthrough
  636. }
  637. case ObjectEndVisitMember: {
  638. JSObject* object = objectStack.peek();
  639. Identifier prop = propertyStack.last()[indexStack.last()];
  640. PutPropertySlot slot;
  641. JSValue filteredValue = callReviver(object, jsString(m_exec, prop.string()), outValue);
  642. if (filteredValue.isUndefined())
  643. object->methodTable()->deleteProperty(object, m_exec, prop);
  644. else
  645. object->methodTable()->put(object, m_exec, prop, filteredValue, slot);
  646. if (m_exec->hadException())
  647. return jsNull();
  648. indexStack.last()++;
  649. goto objectStartVisitMember;
  650. }
  651. stateUnknown:
  652. case StateUnknown:
  653. if (!inValue.isObject()) {
  654. outValue = inValue;
  655. break;
  656. }
  657. JSObject* object = asObject(inValue);
  658. if (isJSArray(object) || object->inherits(&JSArray::s_info))
  659. goto arrayStartState;
  660. goto objectStartState;
  661. }
  662. if (stateStack.isEmpty())
  663. break;
  664. state = stateStack.last();
  665. stateStack.removeLast();
  666. }
  667. JSObject* finalHolder = constructEmptyObject(m_exec);
  668. PutPropertySlot slot;
  669. finalHolder->methodTable()->put(finalHolder, m_exec, m_exec->vm().propertyNames->emptyIdentifier, outValue, slot);
  670. return callReviver(finalHolder, jsEmptyString(m_exec), outValue);
  671. }
  672. // ECMA-262 v5 15.12.2
  673. EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec)
  674. {
  675. if (!exec->argumentCount())
  676. return throwVMError(exec, createError(exec, ASCIILiteral("JSON.parse requires at least one parameter")));
  677. String source = exec->argument(0).toString(exec)->value(exec);
  678. if (exec->hadException())
  679. return JSValue::encode(jsNull());
  680. JSValue unfiltered;
  681. LocalScope scope(exec->vm());
  682. if (source.is8Bit()) {
  683. LiteralParser<LChar> jsonParser(exec, source.characters8(), source.length(), StrictJSON);
  684. unfiltered = jsonParser.tryLiteralParse();
  685. if (!unfiltered)
  686. return throwVMError(exec, createSyntaxError(exec, jsonParser.getErrorMessage()));
  687. } else {
  688. LiteralParser<UChar> jsonParser(exec, source.characters16(), source.length(), StrictJSON);
  689. unfiltered = jsonParser.tryLiteralParse();
  690. if (!unfiltered)
  691. return throwVMError(exec, createSyntaxError(exec, jsonParser.getErrorMessage()));
  692. }
  693. if (exec->argumentCount() < 2)
  694. return JSValue::encode(unfiltered);
  695. JSValue function = exec->argument(1);
  696. CallData callData;
  697. CallType callType = getCallData(function, callData);
  698. if (callType == CallTypeNone)
  699. return JSValue::encode(unfiltered);
  700. return JSValue::encode(Walker(exec, Local<JSObject>(exec->vm(), asObject(function)), callType, callData).walk(unfiltered));
  701. }
  702. // ECMA-262 v5 15.12.3
  703. EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec)
  704. {
  705. if (!exec->argumentCount())
  706. return throwVMError(exec, createError(exec, ASCIILiteral("No input to stringify")));
  707. LocalScope scope(exec->vm());
  708. Local<Unknown> value(exec->vm(), exec->argument(0));
  709. Local<Unknown> replacer(exec->vm(), exec->argument(1));
  710. Local<Unknown> space(exec->vm(), exec->argument(2));
  711. return JSValue::encode(Stringifier(exec, replacer, space).stringify(value).get());
  712. }
  713. String JSONStringify(ExecState* exec, JSValue value, unsigned indent)
  714. {
  715. LocalScope scope(exec->vm());
  716. Local<Unknown> result = Stringifier(exec, Local<Unknown>(exec->vm(), jsNull()), Local<Unknown>(exec->vm(), jsNumber(indent))).stringify(Local<Unknown>(exec->vm(), value));
  717. if (result.isUndefinedOrNull())
  718. return String();
  719. return result.getString(exec);
  720. }
  721. } // namespace JSC