/src/3rdparty/webkit/Source/JavaScriptCore/runtime/JSONObject.cpp

https://bitbucket.org/ultra_iter/qt-vtl · C++ · 909 lines · 831 code · 48 blank · 30 comment · 32 complexity · e0a26ea4be61f57a294e61312de6ee51 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 "PropertyNameArray.h"
  37. #include "UStringBuilder.h"
  38. #include "UStringConcatenate.h"
  39. #include <wtf/MathExtras.h>
  40. namespace JSC {
  41. ASSERT_CLASS_FITS_IN_CELL(JSONObject);
  42. static EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*);
  43. static EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*);
  44. }
  45. #include "JSONObject.lut.h"
  46. namespace JSC {
  47. JSONObject::JSONObject(JSGlobalObject* globalObject, Structure* structure)
  48. : JSObjectWithGlobalObject(globalObject, structure)
  49. {
  50. ASSERT(inherits(&s_info));
  51. }
  52. // PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked.
  53. class PropertyNameForFunctionCall {
  54. public:
  55. PropertyNameForFunctionCall(const Identifier&);
  56. PropertyNameForFunctionCall(unsigned);
  57. JSValue value(ExecState*) const;
  58. private:
  59. const Identifier* m_identifier;
  60. unsigned m_number;
  61. mutable JSValue m_value;
  62. };
  63. class Stringifier {
  64. WTF_MAKE_NONCOPYABLE(Stringifier);
  65. public:
  66. #if COMPILER(WINSCW)
  67. Stringifier(ExecState*, const Local<Unknown>* replacer, const Local<Unknown>* space);
  68. Local<Unknown> stringify(Handle<Unknown>*);
  69. #else
  70. Stringifier(ExecState*, const Local<Unknown>& replacer, const Local<Unknown>& space);
  71. Local<Unknown> stringify(Handle<Unknown>);
  72. #endif
  73. void visitAggregate(SlotVisitor&);
  74. private:
  75. class Holder {
  76. public:
  77. Holder(JSGlobalData&, JSObject*);
  78. JSObject* object() const { return m_object.get(); }
  79. bool appendNextProperty(Stringifier&, UStringBuilder&);
  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(UStringBuilder&, const UString&);
  90. JSValue toJSON(JSValue, const PropertyNameForFunctionCall&);
  91. enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedValue };
  92. StringifyResult appendStringifiedValue(UStringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&);
  93. bool willIndent() const;
  94. void indent();
  95. void unindent();
  96. void startNewLine(UStringBuilder&) 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 UString m_gap;
  104. Vector<Holder, 16> m_holderStack;
  105. UString m_repeatedGap;
  106. UString 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 jsString(exec, object->toString(exec));
  118. if (object->inherits(&BooleanObject::s_info))
  119. return object->toPrimitive(exec);
  120. return value;
  121. }
  122. static inline UString 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. double spaceCount;
  128. if (space.getNumber(spaceCount)) {
  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 UString(spaces, count);
  140. }
  141. // If the space value is a string, use it as the gap string, otherwise use no gap string.
  142. UString 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->ustring());
  163. else
  164. m_value = jsNumber(m_number);
  165. }
  166. return m_value;
  167. }
  168. // ------------------------------ Stringifier --------------------------------
  169. #if COMPILER(WINSCW)
  170. Stringifier::Stringifier(ExecState* exec, const Local<Unknown>* replacer, const Local<Unknown>* space)
  171. : m_exec(exec)
  172. , m_replacer(*replacer)
  173. , m_usingArrayReplacer(false)
  174. , m_arrayReplacerPropertyNames(exec)
  175. , m_replacerCallType(CallTypeNone)
  176. , m_gap(gap(exec, space->get()))
  177. #else
  178. Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const Local<Unknown>& space)
  179. : m_exec(exec)
  180. , m_replacer(replacer)
  181. , m_usingArrayReplacer(false)
  182. , m_arrayReplacerPropertyNames(exec)
  183. , m_replacerCallType(CallTypeNone)
  184. , m_gap(gap(exec, space.get()))
  185. #endif
  186. {
  187. if (!m_replacer.isObject())
  188. return;
  189. if (m_replacer.asObject()->inherits(&JSArray::s_info)) {
  190. m_usingArrayReplacer = true;
  191. Handle<JSObject> array = m_replacer.asObject();
  192. unsigned length = array->get(exec, exec->globalData().propertyNames->length).toUInt32(exec);
  193. for (unsigned i = 0; i < length; ++i) {
  194. JSValue name = array->get(exec, i);
  195. if (exec->hadException())
  196. break;
  197. UString propertyName;
  198. if (name.getString(exec, propertyName)) {
  199. m_arrayReplacerPropertyNames.add(Identifier(exec, propertyName));
  200. continue;
  201. }
  202. double value = 0;
  203. if (name.getNumber(value)) {
  204. m_arrayReplacerPropertyNames.add(Identifier::from(exec, value));
  205. continue;
  206. }
  207. if (name.isObject()) {
  208. if (!asObject(name)->inherits(&NumberObject::s_info) && !asObject(name)->inherits(&StringObject::s_info))
  209. continue;
  210. propertyName = name.toString(exec);
  211. if (exec->hadException())
  212. break;
  213. m_arrayReplacerPropertyNames.add(Identifier(exec, propertyName));
  214. }
  215. }
  216. return;
  217. }
  218. m_replacerCallType = m_replacer.asObject()->getCallData(m_replacerCallData);
  219. }
  220. #if COMPILER(WINSCW)
  221. Local<Unknown> Stringifier::stringify(Handle<Unknown>* value)
  222. #else
  223. Local<Unknown> Stringifier::stringify(Handle<Unknown> value)
  224. #endif
  225. {
  226. JSObject* object = constructEmptyObject(m_exec);
  227. if (m_exec->hadException())
  228. return Local<Unknown>(m_exec->globalData(), jsNull());
  229. PropertyNameForFunctionCall emptyPropertyName(m_exec->globalData().propertyNames->emptyIdentifier);
  230. #if COMPILER(WINSCW)
  231. object->putDirect(m_exec->globalData(), m_exec->globalData().propertyNames->emptyIdentifier, value->get());
  232. #else
  233. object->putDirect(m_exec->globalData(), m_exec->globalData().propertyNames->emptyIdentifier, value.get());
  234. #endif
  235. UStringBuilder result;
  236. #if COMPILER(WINSCW)
  237. if (appendStringifiedValue(result, value->get(), object, emptyPropertyName) != StringifySucceeded)
  238. #else
  239. if (appendStringifiedValue(result, value.get(), object, emptyPropertyName) != StringifySucceeded)
  240. #endif
  241. return Local<Unknown>(m_exec->globalData(), jsUndefined());
  242. if (m_exec->hadException())
  243. return Local<Unknown>(m_exec->globalData(), jsNull());
  244. return Local<Unknown>(m_exec->globalData(), jsString(m_exec, result.toUString()));
  245. }
  246. void Stringifier::appendQuotedString(UStringBuilder& builder, const UString& value)
  247. {
  248. int length = value.length();
  249. builder.append('"');
  250. const UChar* data = value.characters();
  251. for (int i = 0; i < length; ++i) {
  252. int start = i;
  253. while (i < length && (data[i] > 0x1F && data[i] != '"' && data[i] != '\\'))
  254. ++i;
  255. builder.append(data + start, i - start);
  256. if (i >= length)
  257. break;
  258. switch (data[i]) {
  259. case '\t':
  260. builder.append('\\');
  261. builder.append('t');
  262. break;
  263. case '\r':
  264. builder.append('\\');
  265. builder.append('r');
  266. break;
  267. case '\n':
  268. builder.append('\\');
  269. builder.append('n');
  270. break;
  271. case '\f':
  272. builder.append('\\');
  273. builder.append('f');
  274. break;
  275. case '\b':
  276. builder.append('\\');
  277. builder.append('b');
  278. break;
  279. case '"':
  280. builder.append('\\');
  281. builder.append('"');
  282. break;
  283. case '\\':
  284. builder.append('\\');
  285. builder.append('\\');
  286. break;
  287. default:
  288. static const char hexDigits[] = "0123456789abcdef";
  289. UChar ch = data[i];
  290. UChar hex[] = { '\\', 'u', hexDigits[(ch >> 12) & 0xF], hexDigits[(ch >> 8) & 0xF], hexDigits[(ch >> 4) & 0xF], hexDigits[ch & 0xF] };
  291. builder.append(hex, WTF_ARRAY_LENGTH(hex));
  292. break;
  293. }
  294. }
  295. builder.append('"');
  296. }
  297. inline JSValue Stringifier::toJSON(JSValue value, const PropertyNameForFunctionCall& propertyName)
  298. {
  299. ASSERT(!m_exec->hadException());
  300. if (!value.isObject() || !asObject(value)->hasProperty(m_exec, m_exec->globalData().propertyNames->toJSON))
  301. return value;
  302. JSValue toJSONFunction = asObject(value)->get(m_exec, m_exec->globalData().propertyNames->toJSON);
  303. if (m_exec->hadException())
  304. return jsNull();
  305. if (!toJSONFunction.isObject())
  306. return value;
  307. JSObject* object = asObject(toJSONFunction);
  308. CallData callData;
  309. CallType callType = object->getCallData(callData);
  310. if (callType == CallTypeNone)
  311. return value;
  312. JSValue list[] = { propertyName.value(m_exec) };
  313. ArgList args(list, WTF_ARRAY_LENGTH(list));
  314. return call(m_exec, object, callType, callData, value, args);
  315. }
  316. Stringifier::StringifyResult Stringifier::appendStringifiedValue(UStringBuilder& builder, JSValue value, JSObject* holder, const PropertyNameForFunctionCall& propertyName)
  317. {
  318. // Call the toJSON function.
  319. value = toJSON(value, propertyName);
  320. if (m_exec->hadException())
  321. return StringifyFailed;
  322. // Call the replacer function.
  323. if (m_replacerCallType != CallTypeNone) {
  324. JSValue list[] = { propertyName.value(m_exec), value };
  325. ArgList args(list, WTF_ARRAY_LENGTH(list));
  326. value = call(m_exec, m_replacer.get(), m_replacerCallType, m_replacerCallData, holder, args);
  327. if (m_exec->hadException())
  328. return StringifyFailed;
  329. }
  330. if (value.isUndefined() && !holder->inherits(&JSArray::s_info))
  331. return StringifyFailedDueToUndefinedValue;
  332. if (value.isNull()) {
  333. builder.append("null");
  334. return StringifySucceeded;
  335. }
  336. value = unwrapBoxedPrimitive(m_exec, value);
  337. if (m_exec->hadException())
  338. return StringifyFailed;
  339. if (value.isBoolean()) {
  340. builder.append(value.getBoolean() ? "true" : "false");
  341. return StringifySucceeded;
  342. }
  343. UString stringValue;
  344. if (value.getString(m_exec, stringValue)) {
  345. appendQuotedString(builder, stringValue);
  346. return StringifySucceeded;
  347. }
  348. double numericValue;
  349. if (value.getNumber(numericValue)) {
  350. if (!isfinite(numericValue))
  351. builder.append("null");
  352. else
  353. builder.append(UString::number(numericValue));
  354. return StringifySucceeded;
  355. }
  356. if (!value.isObject())
  357. return StringifyFailed;
  358. JSObject* object = asObject(value);
  359. CallData callData;
  360. if (object->getCallData(callData) != CallTypeNone) {
  361. if (holder->inherits(&JSArray::s_info)) {
  362. builder.append("null");
  363. return StringifySucceeded;
  364. }
  365. return StringifyFailedDueToUndefinedValue;
  366. }
  367. // Handle cycle detection, and put the holder on the stack.
  368. for (unsigned i = 0; i < m_holderStack.size(); i++) {
  369. if (m_holderStack[i].object() == object) {
  370. throwError(m_exec, createTypeError(m_exec, "JSON.stringify cannot serialize cyclic structures."));
  371. return StringifyFailed;
  372. }
  373. }
  374. bool holderStackWasEmpty = m_holderStack.isEmpty();
  375. m_holderStack.append(Holder(m_exec->globalData(), object));
  376. if (!holderStackWasEmpty)
  377. return StringifySucceeded;
  378. // If this is the outermost call, then loop to handle everything on the holder stack.
  379. TimeoutChecker localTimeoutChecker(m_exec->globalData().timeoutChecker);
  380. localTimeoutChecker.reset();
  381. unsigned tickCount = localTimeoutChecker.ticksUntilNextCheck();
  382. do {
  383. while (m_holderStack.last().appendNextProperty(*this, builder)) {
  384. if (m_exec->hadException())
  385. return StringifyFailed;
  386. if (!--tickCount) {
  387. if (localTimeoutChecker.didTimeOut(m_exec)) {
  388. throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
  389. return StringifyFailed;
  390. }
  391. tickCount = localTimeoutChecker.ticksUntilNextCheck();
  392. }
  393. }
  394. m_holderStack.removeLast();
  395. } while (!m_holderStack.isEmpty());
  396. return StringifySucceeded;
  397. }
  398. inline bool Stringifier::willIndent() const
  399. {
  400. return !m_gap.isEmpty();
  401. }
  402. inline void Stringifier::indent()
  403. {
  404. // Use a single shared string, m_repeatedGap, so we don't keep allocating new ones as we indent and unindent.
  405. unsigned newSize = m_indent.length() + m_gap.length();
  406. if (newSize > m_repeatedGap.length())
  407. m_repeatedGap = makeUString(m_repeatedGap, m_gap);
  408. ASSERT(newSize <= m_repeatedGap.length());
  409. m_indent = m_repeatedGap.substringSharingImpl(0, newSize);
  410. }
  411. inline void Stringifier::unindent()
  412. {
  413. ASSERT(m_indent.length() >= m_gap.length());
  414. m_indent = m_repeatedGap.substringSharingImpl(0, m_indent.length() - m_gap.length());
  415. }
  416. inline void Stringifier::startNewLine(UStringBuilder& builder) const
  417. {
  418. if (m_gap.isEmpty())
  419. return;
  420. builder.append('\n');
  421. builder.append(m_indent);
  422. }
  423. inline Stringifier::Holder::Holder(JSGlobalData& globalData, JSObject* object)
  424. : m_object(globalData, object)
  425. , m_isArray(object->inherits(&JSArray::s_info))
  426. , m_index(0)
  427. {
  428. }
  429. bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, UStringBuilder& builder)
  430. {
  431. ASSERT(m_index <= m_size);
  432. ExecState* exec = stringifier.m_exec;
  433. // First time through, initialize.
  434. if (!m_index) {
  435. if (m_isArray) {
  436. m_isJSArray = isJSArray(&exec->globalData(), m_object.get());
  437. m_size = m_object->get(exec, exec->globalData().propertyNames->length).toUInt32(exec);
  438. builder.append('[');
  439. } else {
  440. if (stringifier.m_usingArrayReplacer)
  441. m_propertyNames = stringifier.m_arrayReplacerPropertyNames.data();
  442. else {
  443. PropertyNameArray objectPropertyNames(exec);
  444. m_object->getOwnPropertyNames(exec, objectPropertyNames);
  445. m_propertyNames = objectPropertyNames.releaseData();
  446. }
  447. m_size = m_propertyNames->propertyNameVector().size();
  448. builder.append('{');
  449. }
  450. stringifier.indent();
  451. }
  452. // Last time through, finish up and return false.
  453. if (m_index == m_size) {
  454. stringifier.unindent();
  455. if (m_size && builder[builder.length() - 1] != '{')
  456. stringifier.startNewLine(builder);
  457. builder.append(m_isArray ? ']' : '}');
  458. return false;
  459. }
  460. // Handle a single element of the array or object.
  461. unsigned index = m_index++;
  462. unsigned rollBackPoint = 0;
  463. StringifyResult stringifyResult;
  464. if (m_isArray) {
  465. // Get the value.
  466. JSValue value;
  467. if (m_isJSArray && asArray(m_object.get())->canGetIndex(index))
  468. value = asArray(m_object.get())->getIndex(index);
  469. else {
  470. PropertySlot slot(m_object.get());
  471. if (!m_object->getOwnPropertySlot(exec, index, slot))
  472. slot.setUndefined();
  473. if (exec->hadException())
  474. return false;
  475. value = slot.getValue(exec, index);
  476. }
  477. // Append the separator string.
  478. if (index)
  479. builder.append(',');
  480. stringifier.startNewLine(builder);
  481. // Append the stringified value.
  482. stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object.get(), index);
  483. } else {
  484. // Get the value.
  485. PropertySlot slot(m_object.get());
  486. Identifier& propertyName = m_propertyNames->propertyNameVector()[index];
  487. if (!m_object->getOwnPropertySlot(exec, propertyName, slot))
  488. return true;
  489. JSValue value = slot.getValue(exec, propertyName);
  490. if (exec->hadException())
  491. return false;
  492. rollBackPoint = builder.length();
  493. // Append the separator string.
  494. if (builder[rollBackPoint - 1] != '{')
  495. builder.append(',');
  496. stringifier.startNewLine(builder);
  497. // Append the property name.
  498. appendQuotedString(builder, propertyName.ustring());
  499. builder.append(':');
  500. if (stringifier.willIndent())
  501. builder.append(' ');
  502. // Append the stringified value.
  503. stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object.get(), propertyName);
  504. }
  505. // From this point on, no access to the this pointer or to any members, because the
  506. // Holder object may have moved if the call to stringify pushed a new Holder onto
  507. // m_holderStack.
  508. switch (stringifyResult) {
  509. case StringifyFailed:
  510. builder.append("null");
  511. break;
  512. case StringifySucceeded:
  513. break;
  514. case StringifyFailedDueToUndefinedValue:
  515. // This only occurs when get an undefined value for an object property.
  516. // In this case we don't want the separator and property name that we
  517. // already appended, so roll back.
  518. builder.resize(rollBackPoint);
  519. break;
  520. }
  521. return true;
  522. }
  523. // ------------------------------ JSONObject --------------------------------
  524. const ClassInfo JSONObject::s_info = { "JSON", &JSObjectWithGlobalObject::s_info, 0, ExecState::jsonTable };
  525. /* Source for JSONObject.lut.h
  526. @begin jsonTable
  527. parse JSONProtoFuncParse DontEnum|Function 2
  528. stringify JSONProtoFuncStringify DontEnum|Function 3
  529. @end
  530. */
  531. // ECMA 15.8
  532. bool JSONObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
  533. {
  534. return getStaticFunctionSlot<JSObject>(exec, ExecState::jsonTable(exec), this, propertyName, slot);
  535. }
  536. bool JSONObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
  537. {
  538. return getStaticFunctionDescriptor<JSObject>(exec, ExecState::jsonTable(exec), this, propertyName, descriptor);
  539. }
  540. class Walker {
  541. public:
  542. #if COMPILER(WINSCW)
  543. Walker(ExecState* exec, Handle<JSObject>* function, CallType callType, CallData callData)
  544. : m_exec(exec)
  545. , m_function(exec->globalData(), *function)
  546. , m_callType(callType)
  547. , m_callData(callData)
  548. {
  549. }
  550. #else
  551. Walker(ExecState* exec, Handle<JSObject> function, CallType callType, CallData callData)
  552. : m_exec(exec)
  553. , m_function(exec->globalData(), function)
  554. , m_callType(callType)
  555. , m_callData(callData)
  556. {
  557. }
  558. #endif
  559. JSValue walk(JSValue unfiltered);
  560. private:
  561. JSValue callReviver(JSObject* thisObj, JSValue property, JSValue unfiltered)
  562. {
  563. JSValue args[] = { property, unfiltered };
  564. ArgList argList(args, 2);
  565. return call(m_exec, m_function.get(), m_callType, m_callData, thisObj, argList);
  566. }
  567. friend class Holder;
  568. ExecState* m_exec;
  569. Local<JSObject> m_function;
  570. CallType m_callType;
  571. CallData m_callData;
  572. };
  573. // We clamp recursion well beyond anything reasonable, but we also have a timeout check
  574. // to guard against "infinite" execution by inserting arbitrarily large objects.
  575. static const unsigned maximumFilterRecursion = 40000;
  576. enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
  577. ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember };
  578. NEVER_INLINE JSValue Walker::walk(JSValue unfiltered)
  579. {
  580. Vector<PropertyNameArray, 16> propertyStack;
  581. Vector<uint32_t, 16> indexStack;
  582. LocalStack<JSObject, 16> objectStack(m_exec->globalData());
  583. LocalStack<JSArray, 16> arrayStack(m_exec->globalData());
  584. Vector<WalkerState, 16> stateStack;
  585. WalkerState state = StateUnknown;
  586. JSValue inValue = unfiltered;
  587. JSValue outValue = jsNull();
  588. TimeoutChecker localTimeoutChecker(m_exec->globalData().timeoutChecker);
  589. localTimeoutChecker.reset();
  590. unsigned tickCount = localTimeoutChecker.ticksUntilNextCheck();
  591. while (1) {
  592. switch (state) {
  593. arrayStartState:
  594. case ArrayStartState: {
  595. ASSERT(inValue.isObject());
  596. ASSERT(isJSArray(&m_exec->globalData(), asObject(inValue)) || asObject(inValue)->inherits(&JSArray::s_info));
  597. if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
  598. return throwError(m_exec, createStackOverflowError(m_exec));
  599. JSArray* array = asArray(inValue);
  600. arrayStack.push(array);
  601. indexStack.append(0);
  602. // fallthrough
  603. }
  604. arrayStartVisitMember:
  605. case ArrayStartVisitMember: {
  606. if (!--tickCount) {
  607. if (localTimeoutChecker.didTimeOut(m_exec))
  608. return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
  609. tickCount = localTimeoutChecker.ticksUntilNextCheck();
  610. }
  611. JSArray* array = arrayStack.peek();
  612. uint32_t index = indexStack.last();
  613. if (index == array->length()) {
  614. outValue = array;
  615. arrayStack.pop();
  616. indexStack.removeLast();
  617. break;
  618. }
  619. if (isJSArray(&m_exec->globalData(), array) && array->canGetIndex(index))
  620. inValue = array->getIndex(index);
  621. else {
  622. PropertySlot slot;
  623. if (array->getOwnPropertySlot(m_exec, index, slot))
  624. inValue = slot.getValue(m_exec, index);
  625. else
  626. inValue = jsUndefined();
  627. }
  628. if (inValue.isObject()) {
  629. stateStack.append(ArrayEndVisitMember);
  630. goto stateUnknown;
  631. } else
  632. outValue = inValue;
  633. // fallthrough
  634. }
  635. case ArrayEndVisitMember: {
  636. JSArray* array = arrayStack.peek();
  637. JSValue filteredValue = callReviver(array, jsString(m_exec, UString::number(indexStack.last())), outValue);
  638. if (filteredValue.isUndefined())
  639. array->deleteProperty(m_exec, indexStack.last());
  640. else {
  641. if (isJSArray(&m_exec->globalData(), array) && array->canSetIndex(indexStack.last()))
  642. array->setIndex(m_exec->globalData(), indexStack.last(), filteredValue);
  643. else
  644. array->put(m_exec, indexStack.last(), filteredValue);
  645. }
  646. if (m_exec->hadException())
  647. return jsNull();
  648. indexStack.last()++;
  649. goto arrayStartVisitMember;
  650. }
  651. objectStartState:
  652. case ObjectStartState: {
  653. ASSERT(inValue.isObject());
  654. ASSERT(!isJSArray(&m_exec->globalData(), asObject(inValue)) && !asObject(inValue)->inherits(&JSArray::s_info));
  655. if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
  656. return throwError(m_exec, createStackOverflowError(m_exec));
  657. JSObject* object = asObject(inValue);
  658. objectStack.push(object);
  659. indexStack.append(0);
  660. propertyStack.append(PropertyNameArray(m_exec));
  661. object->getOwnPropertyNames(m_exec, propertyStack.last());
  662. // fallthrough
  663. }
  664. objectStartVisitMember:
  665. case ObjectStartVisitMember: {
  666. if (!--tickCount) {
  667. if (localTimeoutChecker.didTimeOut(m_exec))
  668. return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
  669. tickCount = localTimeoutChecker.ticksUntilNextCheck();
  670. }
  671. JSObject* object = objectStack.peek();
  672. uint32_t index = indexStack.last();
  673. PropertyNameArray& properties = propertyStack.last();
  674. if (index == properties.size()) {
  675. outValue = object;
  676. objectStack.pop();
  677. indexStack.removeLast();
  678. propertyStack.removeLast();
  679. break;
  680. }
  681. PropertySlot slot;
  682. if (object->getOwnPropertySlot(m_exec, properties[index], slot))
  683. inValue = slot.getValue(m_exec, properties[index]);
  684. else
  685. inValue = jsUndefined();
  686. // The holder may be modified by the reviver function so any lookup may throw
  687. if (m_exec->hadException())
  688. return jsNull();
  689. if (inValue.isObject()) {
  690. stateStack.append(ObjectEndVisitMember);
  691. goto stateUnknown;
  692. } else
  693. outValue = inValue;
  694. // fallthrough
  695. }
  696. case ObjectEndVisitMember: {
  697. JSObject* object = objectStack.peek();
  698. Identifier prop = propertyStack.last()[indexStack.last()];
  699. PutPropertySlot slot;
  700. JSValue filteredValue = callReviver(object, jsString(m_exec, prop.ustring()), outValue);
  701. if (filteredValue.isUndefined())
  702. object->deleteProperty(m_exec, prop);
  703. else
  704. object->put(m_exec, prop, filteredValue, slot);
  705. if (m_exec->hadException())
  706. return jsNull();
  707. indexStack.last()++;
  708. goto objectStartVisitMember;
  709. }
  710. stateUnknown:
  711. case StateUnknown:
  712. if (!inValue.isObject()) {
  713. outValue = inValue;
  714. break;
  715. }
  716. JSObject* object = asObject(inValue);
  717. if (isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::s_info))
  718. goto arrayStartState;
  719. goto objectStartState;
  720. }
  721. if (stateStack.isEmpty())
  722. break;
  723. state = stateStack.last();
  724. stateStack.removeLast();
  725. if (!--tickCount) {
  726. if (localTimeoutChecker.didTimeOut(m_exec))
  727. return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
  728. tickCount = localTimeoutChecker.ticksUntilNextCheck();
  729. }
  730. }
  731. JSObject* finalHolder = constructEmptyObject(m_exec);
  732. PutPropertySlot slot;
  733. finalHolder->put(m_exec, m_exec->globalData().propertyNames->emptyIdentifier, outValue, slot);
  734. return callReviver(finalHolder, jsEmptyString(m_exec), outValue);
  735. }
  736. // ECMA-262 v5 15.12.2
  737. EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec)
  738. {
  739. if (!exec->argumentCount())
  740. return throwVMError(exec, createError(exec, "JSON.parse requires at least one parameter"));
  741. JSValue value = exec->argument(0);
  742. UString source = value.toString(exec);
  743. if (exec->hadException())
  744. return JSValue::encode(jsNull());
  745. LocalScope scope(exec->globalData());
  746. LiteralParser jsonParser(exec, source, LiteralParser::StrictJSON);
  747. JSValue unfiltered = jsonParser.tryLiteralParse();
  748. if (!unfiltered)
  749. return throwVMError(exec, createSyntaxError(exec, "Unable to parse JSON string"));
  750. if (exec->argumentCount() < 2)
  751. return JSValue::encode(unfiltered);
  752. JSValue function = exec->argument(1);
  753. CallData callData;
  754. CallType callType = getCallData(function, callData);
  755. if (callType == CallTypeNone)
  756. return JSValue::encode(unfiltered);
  757. #if COMPILER(WINSCW)
  758. Local<JSObject> handle(exec->globalData(), asObject(function));
  759. return JSValue::encode(Walker(exec, &handle, callType, callData).walk(unfiltered));
  760. #else
  761. return JSValue::encode(Walker(exec, Local<JSObject>(exec->globalData(), asObject(function)), callType, callData).walk(unfiltered));
  762. #endif
  763. }
  764. // ECMA-262 v5 15.12.3
  765. EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec)
  766. {
  767. if (!exec->argumentCount())
  768. return throwVMError(exec, createError(exec, "No input to stringify"));
  769. LocalScope scope(exec->globalData());
  770. Local<Unknown> value(exec->globalData(), exec->argument(0));
  771. Local<Unknown> replacer(exec->globalData(), exec->argument(1));
  772. Local<Unknown> space(exec->globalData(), exec->argument(2));
  773. #if COMPILER(WINSCW)
  774. return JSValue::encode(Stringifier(exec, &replacer, &space).stringify(&value).get());
  775. #else
  776. return JSValue::encode(Stringifier(exec, replacer, space).stringify(value).get());
  777. #endif
  778. }
  779. UString JSONStringify(ExecState* exec, JSValue value, unsigned indent)
  780. {
  781. LocalScope scope(exec->globalData());
  782. #if COMPILER(WINSCW)
  783. Local<Unknown> replacer(exec->globalData(), jsNull());
  784. Local<Unknown> space(exec->globalData(), jsNumber(indent));
  785. Local<Unknown> valueHandle(exec->globalData(), value);
  786. Local<Unknown> result = Stringifier(exec, &replacer, &space).stringify(&valueHandle);
  787. #else
  788. Local<Unknown> result = Stringifier(exec, Local<Unknown>(exec->globalData(), jsNull()), Local<Unknown>(exec->globalData(), jsNumber(indent))).stringify(Local<Unknown>(exec->globalData(), value));
  789. #endif
  790. if (result.isUndefinedOrNull())
  791. return UString();
  792. return result.getString(exec);
  793. }
  794. } // namespace JSC