Commit 862c90b4 authored by oliver@apple.com's avatar oliver@apple.com

Bug 26249: Support JSON.stringify

<https://bugs.webkit.org/show_bug.cgi?id=26249>

Reviewed by Sam Weinig.

Implement JSON.stringify.  This patch handles all the semantics of the ES5
JSON.stringify function, including replacer functions and arrays and both
string and numeric gap arguments.

Currently uses a clamped recursive algorithm basically identical to the spec
description but with a few minor tweaks for performance and corrected semantics
discussed in the es-discuss mailing list.


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@44550 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 9056afec
2009-06-07 Oliver Hunt <oliver@apple.com>
Reviewed by Sam Weinig.
Bug 26249: Support JSON.stringify
<https://bugs.webkit.org/show_bug.cgi?id=26249>
Implement JSON.stringify. This patch handles all the semantics of the ES5
JSON.stringify function, including replacer functions and arrays and both
string and numeric gap arguments.
Currently uses a clamped recursive algorithm basically identical to the spec
description but with a few minor tweaks for performance and corrected semantics
discussed in the es-discuss mailing list.
* DerivedSources.make:
* GNUmakefile.am:
* JavaScriptCore.pri:
* JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj:
* JavaScriptCore.xcodeproj/project.pbxproj:
* interpreter/CallFrame.h:
(JSC::ExecState::jsonTable):
* runtime/CommonIdentifiers.h:
add toJSON to the list of common identifiers
* runtime/JSGlobalData.cpp:
(JSC::JSGlobalData::JSGlobalData):
(JSC::JSGlobalData::~JSGlobalData):
* runtime/JSGlobalData.h:
* runtime/JSGlobalObject.cpp:
(JSC::JSGlobalObject::reset):
Add support for the JSON object lookup table
* runtime/JSONObject.cpp: Added.
(JSC::):
(JSC::JSONObject::getOwnPropertySlot):
(JSC::Stringifier::):
(JSC::Stringifier::Stringifier):
(JSC::Stringifier::stringify):
(JSC::Stringifier::appendString):
(JSC::Stringifier::StringKeyGenerator::StringKeyGenerator):
(JSC::Stringifier::StringKeyGenerator::getKey):
(JSC::Stringifier::IntKeyGenerator::IntKeyGenerator):
(JSC::Stringifier::IntKeyGenerator::getKey):
These KeyGenerator classes are used to abstract away the lazy evaluation of keys for
toJSON and replacer functions.
(JSC::Stringifier::toJSONValue):
(JSC::Stringifier::stringifyArray):
(JSC::Stringifier::stringifyObject):
(JSC::JSONProtoFuncStringify):
* runtime/JSONObject.h: Added.
(JSC::JSONObject:::JSObject):
(JSC::JSONObject::classInfo):
(JSC::JSONObject::createStructure):
2009-06-09 Gavin Barraclough <barraclough@apple.com>
Reviewed by Geoff Garen.
......@@ -40,6 +40,7 @@ all : \
chartables.c \
DatePrototype.lut.h \
Grammar.cpp \
JSONObject.lut.h \
Lexer.lut.h \
MathObject.lut.h \
NumberConstructor.lut.h \
......
......@@ -35,6 +35,7 @@ javascriptcore_built_nosources += \
DerivedSources/Lexer.lut.h \
JavaScriptCore/runtime/ArrayPrototype.lut.h \
JavaScriptCore/runtime/DatePrototype.lut.h \
JavaScriptCore/runtime/JSONObject.lut.h \
JavaScriptCore/runtime/MathObject.lut.h \
JavaScriptCore/runtime/NumberConstructor.lut.h \
JavaScriptCore/runtime/RegExpConstructor.lut.h \
......@@ -182,6 +183,8 @@ javascriptcore_sources += \
JavaScriptCore/runtime/JSGlobalData.h \
JavaScriptCore/runtime/JSNotAnObject.cpp \
JavaScriptCore/runtime/JSNotAnObject.h \
JavaScriptCore/runtime/JSONObject.cpp \
JavaScriptCore/runtime/JSONObject.h \
JavaScriptCore/runtime/JSPropertyNameIterator.cpp \
JavaScriptCore/runtime/JSPropertyNameIterator.h \
JavaScriptCore/runtime/LiteralParser.cpp \
......@@ -590,6 +593,7 @@ javascriptcore_dist += \
CLEANFILES += \
JavaScriptCore/runtime/ArrayPrototype.lut.h \
JavaScriptCore/runtime/DatePrototype.lut.h \
JavaScriptCore/runtime/JSONObject.lut.h \
JavaScriptCore/runtime/MathObject.lut.h \
JavaScriptCore/runtime/NumberConstructor.lut.h \
JavaScriptCore/runtime/RegExpConstructor.lut.h \
......
......@@ -110,6 +110,7 @@ SOURCES += \
runtime/JSVariableObject.cpp \
runtime/JSActivation.cpp \
runtime/JSNotAnObject.cpp \
runtime/JSONObject.cpp \
runtime/LiteralParser.cpp \
runtime/TimeoutChecker.cpp \
bytecode/CodeBlock.cpp \
......
......@@ -794,6 +794,13 @@
<File
RelativePath="..\..\runtime\JSNumberCell.h"
>
<File
RelativePath="..\..\runtime\JSONObject.cpp"
>
</File>
<File
RelativePath="..\..\runtime\JSONObject.h"
>
</File>
<File
RelativePath="..\..\runtime\JSObject.cpp"
......
......@@ -198,6 +198,9 @@
A7B48F490EE8936F00DCBDB6 /* ExecutableAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */; };
A7E2EA6B0FB460CF00601F06 /* LiteralParser.h in Headers */ = {isa = PBXBuildFile; fileRef = A7E2EA690FB460CF00601F06 /* LiteralParser.h */; };
A7E2EA6C0FB460CF00601F06 /* LiteralParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7E2EA6A0FB460CF00601F06 /* LiteralParser.cpp */; };
A7F9935F0FD7325100A0B2D0 /* JSONObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A7F9935D0FD7325100A0B2D0 /* JSONObject.h */; };
A7F993600FD7325100A0B2D0 /* JSONObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7F9935E0FD7325100A0B2D0 /* JSONObject.cpp */; };
A7F9949B0FD746A300A0B2D0 /* JSONObject.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = A7F9949A0FD746A300A0B2D0 /* JSONObject.lut.h */; };
BC02E90D0E1839DB000F9297 /* ErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9050E1839DB000F9297 /* ErrorConstructor.h */; };
BC02E90F0E1839DB000F9297 /* ErrorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9070E1839DB000F9297 /* ErrorPrototype.h */; };
BC02E9110E1839DB000F9297 /* NativeErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9090E1839DB000F9297 /* NativeErrorConstructor.h */; };
......@@ -734,6 +737,9 @@
A7E42C190E3938830065A544 /* JSStaticScopeObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSStaticScopeObject.cpp; sourceTree = "<group>"; };
A7F8690E0F9584A100558697 /* CachedCall.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedCall.h; sourceTree = "<group>"; };
A7F869EC0F95C2EC00558697 /* CallFrameClosure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallFrameClosure.h; sourceTree = "<group>"; };
A7F9935D0FD7325100A0B2D0 /* JSONObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONObject.h; sourceTree = "<group>"; };
A7F9935E0FD7325100A0B2D0 /* JSONObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSONObject.cpp; sourceTree = "<group>"; };
A7F9949A0FD746A300A0B2D0 /* JSONObject.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSONObject.lut.h; path = /Users/oliver/builds/Debug/DerivedSources/JavaScriptCore/JSONObject.lut.h; sourceTree = "<absolute>"; };
A8E894310CD0602400367179 /* JSCallbackObjectFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCallbackObjectFunctions.h; sourceTree = "<group>"; };
A8E894330CD0603F00367179 /* JSGlobalObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObject.h; sourceTree = "<group>"; };
BC02E9040E1839DB000F9297 /* ErrorConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ErrorConstructor.cpp; sourceTree = "<group>"; };
......@@ -1142,6 +1148,7 @@
children = (
BC18C5230E16FC8A00B34460 /* ArrayPrototype.lut.h */,
BCD203E70E1718F4002C7E82 /* DatePrototype.lut.h */,
A7F9949A0FD746A300A0B2D0 /* JSONObject.lut.h */,
BC18C5290E16FCC200B34460 /* MathObject.lut.h */,
BC2680E60E16D52300A06E92 /* NumberConstructor.lut.h */,
BCD202D50E170708002C7E82 /* RegExpConstructor.lut.h */,
......@@ -1462,6 +1469,8 @@
6507D2970E871E4A00D7D896 /* TypeInfo.h */,
F692A8850255597D01FF60F7 /* UString.cpp */,
F692A8860255597D01FF60F7 /* UString.h */,
A7F9935D0FD7325100A0B2D0 /* JSONObject.h */,
A7F9935E0FD7325100A0B2D0 /* JSONObject.cpp */,
);
path = runtime;
sourceTree = "<group>";
......@@ -1846,6 +1855,8 @@
960626960FB8EC02009798AB /* JITStubCall.h in Headers */,
0BDFFAE00FC6192900D69EF4 /* CrossThreadRefCounted.h in Headers */,
0BDFFAE10FC6193100D69EF4 /* OwnFastMallocPtr.h in Headers */,
A7F9935F0FD7325100A0B2D0 /* JSONObject.h in Headers */,
A7F9949B0FD746A300A0B2D0 /* JSONObject.lut.h in Headers */,
86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */,
86ADD1460FDDEA980006EEC2 /* MacroAssemblerARMv7.h in Headers */,
);
......@@ -2209,6 +2220,7 @@
A7E2EA6C0FB460CF00601F06 /* LiteralParser.cpp in Sources */,
93052C340FB792190048FDC3 /* ParserArena.cpp in Sources */,
BCDD51EB0FB8DF74004A8BDC /* JITOpcodes.cpp in Sources */,
A7F993600FD7325100A0B2D0 /* JSONObject.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -89,6 +89,7 @@ namespace JSC {
#endif
static const HashTable* arrayTable(CallFrame* callFrame) { return callFrame->globalData().arrayTable; }
static const HashTable* dateTable(CallFrame* callFrame) { return callFrame->globalData().dateTable; }
static const HashTable* jsonTable(CallFrame* callFrame) { return callFrame->globalData().jsonTable; }
static const HashTable* mathTable(CallFrame* callFrame) { return callFrame->globalData().mathTable; }
static const HashTable* numberTable(CallFrame* callFrame) { return callFrame->globalData().numberTable; }
static const HashTable* regExpTable(CallFrame* callFrame) { return callFrame->globalData().regExpTable; }
......
......@@ -59,6 +59,7 @@
macro(test) \
macro(toExponential) \
macro(toFixed) \
macro(toJSON) \
macro(toLocaleString) \
macro(toPrecision) \
macro(toString) \
......
......@@ -60,6 +60,7 @@ using namespace WTF;
namespace JSC {
extern const HashTable arrayTable;
extern const HashTable jsonTable;
extern const HashTable dateTable;
extern const HashTable mathTable;
extern const HashTable numberTable;
......@@ -105,6 +106,7 @@ JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet)
, clientData(0)
, arrayTable(fastNew<HashTable>(JSC::arrayTable))
, dateTable(fastNew<HashTable>(JSC::dateTable))
, jsonTable(fastNew<HashTable>(JSC::jsonTable))
, mathTable(fastNew<HashTable>(JSC::mathTable))
, numberTable(fastNew<HashTable>(JSC::numberTable))
, regExpTable(fastNew<HashTable>(JSC::regExpTable))
......@@ -155,6 +157,7 @@ JSGlobalData::~JSGlobalData()
arrayTable->deleteTable();
dateTable->deleteTable();
jsonTable->deleteTable();
mathTable->deleteTable();
numberTable->deleteTable();
regExpTable->deleteTable();
......@@ -166,6 +169,7 @@ JSGlobalData::~JSGlobalData()
fastDelete(const_cast<HashTable*>(arrayTable));
fastDelete(const_cast<HashTable*>(dateTable));
fastDelete(const_cast<HashTable*>(jsonTable));
fastDelete(const_cast<HashTable*>(mathTable));
fastDelete(const_cast<HashTable*>(numberTable));
fastDelete(const_cast<HashTable*>(regExpTable));
......
......@@ -82,6 +82,7 @@ namespace JSC {
const HashTable* arrayTable;
const HashTable* dateTable;
const HashTable* jsonTable;
const HashTable* mathTable;
const HashTable* numberTable;
const HashTable* regExpTable;
......
......@@ -50,6 +50,7 @@
#include "JSFunction.h"
#include "JSGlobalObjectFunctions.h"
#include "JSLock.h"
#include "JSONObject.h"
#include "Interpreter.h"
#include "MathObject.h"
#include "NativeErrorConstructor.h"
......@@ -318,7 +319,8 @@ void JSGlobalObject::reset(JSValue prototype)
GlobalPropertyInfo(Identifier(exec, "Math"), new (exec) MathObject(exec, MathObject::createStructure(d()->objectPrototype)), DontEnum | DontDelete),
GlobalPropertyInfo(Identifier(exec, "NaN"), jsNaN(exec), DontEnum | DontDelete),
GlobalPropertyInfo(Identifier(exec, "Infinity"), jsNumber(exec, Inf), DontEnum | DontDelete),
GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete)
GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete),
GlobalPropertyInfo(Identifier(exec, "JSON"), new (exec) JSONObject(JSONObject::createStructure(d()->objectPrototype)), DontEnum | DontDelete)
};
addStaticGlobals(staticGlobals, sizeof(staticGlobals) / sizeof(GlobalPropertyInfo));
......
This diff is collapsed.
/*
* Copyright (C) 2009 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef JSONObject_h
#define JSONObject_h
#include "JSObject.h"
namespace JSC {
class JSONObject : public JSObject {
public:
JSONObject(PassRefPtr<Structure> structure)
:JSObject(structure)
{
}
virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
virtual const ClassInfo* classInfo() const { return &info; }
static const ClassInfo info;
static PassRefPtr<Structure> createStructure(JSValue prototype)
{
return Structure::create(prototype, TypeInfo(ObjectType));
}
};
} // namespace JSC
#endif // JSONObject_h
2009-06-07 Oliver Hunt <oliver@apple.com>
Reviewed by Sam Weinig.
Bug 26249: Support JSON.stringify
<https://bugs.webkit.org/show_bug.cgi?id=26249>
Add test coverage for JSON.stringify -- covers use of replacer function,
replacer array, no replacer, numeric and string gaps. Also tests call
sequencing (toJSON, toString, replacer functions, and getters).
* fast/js/JSON-stringify-expected.txt: Added.
* fast/js/JSON-stringify.html: Added.
* fast/js/resources/JSON-stringify.js: Added.
* fast/js/resources/json2-es5-compat.js: Added.
Modified version of json2.js to force strict es5 semantics on stringify
to allow us to compare our results to the expected without having to
stuff large arbitrary strings into the testcase
2009-06-09 Brent Fulgham <bfulgham@webkit.org>
No review, build fix only.
This diff is collapsed.
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<link rel="stylesheet" href="resources/js-test-style.css">
<script src="resources/js-test-pre.js"></script>
</head>
<body>
<p id="description"></p>
<div id="console"></div>
<script>
var nativeJSON = this.JSON;
this.JSON = null;
</script>
<script src="resources/json2-es5-compat.js"></script>
<script src="resources/JSON-stringify.js"></script>
<script src="resources/js-test-post.js"></script>
</body>
</html>
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment