OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 (function(global, utils) { | 5 (function(global, utils) { |
6 | 6 |
7 "use strict"; | 7 "use strict"; |
8 | 8 |
9 %CheckIsBootstrapping(); | 9 %CheckIsBootstrapping(); |
10 | 10 |
11 // ------------------------------------------------------------------- | 11 // ------------------------------------------------------------------- |
12 // Imports | 12 // Imports |
13 | 13 |
14 var GlobalJSON = global.JSON; | 14 var GlobalJSON = global.JSON; |
| 15 var GlobalSet = global.Set; |
15 var InternalArray = utils.InternalArray; | 16 var InternalArray = utils.InternalArray; |
16 var MakeTypeError; | 17 var MakeTypeError; |
17 var MaxSimple; | 18 var MaxSimple; |
18 var MinSimple; | 19 var MinSimple; |
19 var ObjectHasOwnProperty; | 20 var ObjectHasOwnProperty; |
20 var ObjectKeys; | 21 var ObjectKeys; |
21 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); | 22 var toStringTagSymbol = utils.ImportNow("to_string_tag_symbol"); |
22 | 23 |
23 utils.Import(function(from) { | 24 utils.Import(function(from) { |
24 MakeTypeError = from.MakeTypeError; | 25 MakeTypeError = from.MakeTypeError; |
25 MaxSimple = from.MaxSimple; | 26 MaxSimple = from.MaxSimple; |
26 MinSimple = from.MinSimple; | 27 MinSimple = from.MinSimple; |
27 ObjectHasOwnProperty = from.ObjectHasOwnProperty; | 28 ObjectHasOwnProperty = from.ObjectHasOwnProperty; |
28 ObjectKeys = from.ObjectKeys; | 29 ObjectKeys = from.ObjectKeys; |
29 }); | 30 }); |
30 | 31 |
31 // ------------------------------------------------------------------- | 32 // ------------------------------------------------------------------- |
32 | 33 |
| 34 function CreateDataProperty(o, p, v) { |
| 35 var desc = {value: v, enumerable: true, writable: true, configurable: true}; |
| 36 return %reflect_define_property(o, p, desc); |
| 37 } |
| 38 |
| 39 |
33 function InternalizeJSONProperty(holder, name, reviver) { | 40 function InternalizeJSONProperty(holder, name, reviver) { |
34 var val = holder[name]; | 41 var val = holder[name]; |
35 if (IS_OBJECT(val) && val !== null) { | 42 if (IS_SPEC_OBJECT(val)) { |
36 if (IS_ARRAY(val)) { | 43 if (%is_arraylike(val)) { |
37 var length = val.length; | 44 var length = TO_LENGTH(val.length); |
38 for (var i = 0; i < length; i++) { | 45 for (var i = 0; i < length; i++) { |
39 var newElement = | 46 var newElement = |
40 InternalizeJSONProperty(val, %_NumberToString(i), reviver); | 47 InternalizeJSONProperty(val, %_NumberToString(i), reviver); |
41 if (IS_UNDEFINED(newElement)) { | 48 if (IS_UNDEFINED(newElement)) { |
42 delete val[i]; | 49 %reflect_delete_property(val, i); |
43 } else { | 50 } else { |
44 val[i] = newElement; | 51 CreateDataProperty(val, i, newElement); |
45 } | 52 } |
46 } | 53 } |
47 } else { | 54 } else { |
48 for (var p of ObjectKeys(val)) { | 55 for (var p of ObjectKeys(val)) { |
49 var newElement = InternalizeJSONProperty(val, p, reviver); | 56 var newElement = InternalizeJSONProperty(val, p, reviver); |
50 if (IS_UNDEFINED(newElement)) { | 57 if (IS_UNDEFINED(newElement)) { |
51 delete val[p]; | 58 %reflect_delete_property(val, p); |
52 } else { | 59 } else { |
53 val[p] = newElement; | 60 CreateDataProperty(val, p, newElement); |
54 } | 61 } |
55 } | 62 } |
56 } | 63 } |
57 } | 64 } |
58 return %_Call(reviver, holder, name, val); | 65 return %_Call(reviver, holder, name, val); |
59 } | 66 } |
60 | 67 |
61 | 68 |
62 function JSONParse(text, reviver) { | 69 function JSONParse(text, reviver) { |
63 var unfiltered = %ParseJson(text); | 70 var unfiltered = %ParseJson(text); |
64 if (IS_CALLABLE(reviver)) { | 71 if (IS_CALLABLE(reviver)) { |
65 return InternalizeJSONProperty({'': unfiltered}, '', reviver); | 72 return InternalizeJSONProperty({'': unfiltered}, '', reviver); |
66 } else { | 73 } else { |
67 return unfiltered; | 74 return unfiltered; |
68 } | 75 } |
69 } | 76 } |
70 | 77 |
71 | 78 |
72 function SerializeArray(value, replacer, stack, indent, gap) { | 79 function SerializeArray(value, replacer, stack, indent, gap) { |
73 if (!%PushIfAbsent(stack, value)) throw MakeTypeError(kCircularStructure); | 80 if (!%PushIfAbsent(stack, value)) throw MakeTypeError(kCircularStructure); |
74 var stepback = indent; | 81 var stepback = indent; |
75 indent += gap; | 82 indent += gap; |
76 var partial = new InternalArray(); | 83 var partial = new InternalArray(); |
77 var len = value.length; | 84 var len = TO_LENGTH(value.length); |
78 for (var i = 0; i < len; i++) { | 85 for (var i = 0; i < len; i++) { |
79 var strP = JSONSerialize(%_NumberToString(i), value, replacer, stack, | 86 var strP = JSONSerialize(%_NumberToString(i), value, replacer, stack, |
80 indent, gap); | 87 indent, gap); |
81 if (IS_UNDEFINED(strP)) { | 88 if (IS_UNDEFINED(strP)) { |
82 strP = "null"; | 89 strP = "null"; |
83 } | 90 } |
84 partial.push(strP); | 91 partial.push(strP); |
85 } | 92 } |
86 var final; | 93 var final; |
87 if (gap == "") { | 94 if (gap == "") { |
(...skipping 11 matching lines...) Expand all Loading... |
99 | 106 |
100 | 107 |
101 function SerializeObject(value, replacer, stack, indent, gap) { | 108 function SerializeObject(value, replacer, stack, indent, gap) { |
102 if (!%PushIfAbsent(stack, value)) throw MakeTypeError(kCircularStructure); | 109 if (!%PushIfAbsent(stack, value)) throw MakeTypeError(kCircularStructure); |
103 var stepback = indent; | 110 var stepback = indent; |
104 indent += gap; | 111 indent += gap; |
105 var partial = new InternalArray(); | 112 var partial = new InternalArray(); |
106 if (IS_ARRAY(replacer)) { | 113 if (IS_ARRAY(replacer)) { |
107 var length = replacer.length; | 114 var length = replacer.length; |
108 for (var i = 0; i < length; i++) { | 115 for (var i = 0; i < length; i++) { |
109 if (HAS_OWN_PROPERTY(replacer, i)) { | 116 var p = replacer[i]; |
110 var p = replacer[i]; | 117 var strP = JSONSerialize(p, value, replacer, stack, indent, gap); |
111 var strP = JSONSerialize(p, value, replacer, stack, indent, gap); | 118 if (!IS_UNDEFINED(strP)) { |
112 if (!IS_UNDEFINED(strP)) { | 119 var member = %QuoteJSONString(p) + ":"; |
113 var member = %QuoteJSONString(p) + ":"; | 120 if (gap != "") member += " "; |
114 if (gap != "") member += " "; | 121 member += strP; |
115 member += strP; | 122 partial.push(member); |
116 partial.push(member); | |
117 } | |
118 } | 123 } |
119 } | 124 } |
120 } else { | 125 } else { |
121 for (var p in value) { | 126 for (var p of ObjectKeys(value)) { |
122 if (HAS_OWN_PROPERTY(value, p)) { | 127 var strP = JSONSerialize(p, value, replacer, stack, indent, gap); |
123 var strP = JSONSerialize(p, value, replacer, stack, indent, gap); | 128 if (!IS_UNDEFINED(strP)) { |
124 if (!IS_UNDEFINED(strP)) { | 129 var member = %QuoteJSONString(p) + ":"; |
125 var member = %QuoteJSONString(p) + ":"; | 130 if (gap != "") member += " "; |
126 if (gap != "") member += " "; | 131 member += strP; |
127 member += strP; | 132 partial.push(member); |
128 partial.push(member); | |
129 } | |
130 } | 133 } |
131 } | 134 } |
132 } | 135 } |
133 var final; | 136 var final; |
134 if (gap == "") { | 137 if (gap == "") { |
135 final = "{" + partial.join(",") + "}"; | 138 final = "{" + partial.join(",") + "}"; |
136 } else if (partial.length > 0) { | 139 } else if (partial.length > 0) { |
137 var separator = ",\n" + indent; | 140 var separator = ",\n" + indent; |
138 final = "{\n" + indent + partial.join(separator) + "\n" + | 141 final = "{\n" + indent + partial.join(separator) + "\n" + |
139 stepback + "}"; | 142 stepback + "}"; |
(...skipping 19 matching lines...) Expand all Loading... |
159 if (IS_STRING(value)) { | 162 if (IS_STRING(value)) { |
160 return %QuoteJSONString(value); | 163 return %QuoteJSONString(value); |
161 } else if (IS_NUMBER(value)) { | 164 } else if (IS_NUMBER(value)) { |
162 return JSON_NUMBER_TO_STRING(value); | 165 return JSON_NUMBER_TO_STRING(value); |
163 } else if (IS_BOOLEAN(value)) { | 166 } else if (IS_BOOLEAN(value)) { |
164 return value ? "true" : "false"; | 167 return value ? "true" : "false"; |
165 } else if (IS_NULL(value)) { | 168 } else if (IS_NULL(value)) { |
166 return "null"; | 169 return "null"; |
167 } else if (IS_SPEC_OBJECT(value) && !IS_CALLABLE(value)) { | 170 } else if (IS_SPEC_OBJECT(value) && !IS_CALLABLE(value)) { |
168 // Non-callable object. If it's a primitive wrapper, it must be unwrapped. | 171 // Non-callable object. If it's a primitive wrapper, it must be unwrapped. |
169 if (IS_ARRAY(value)) { | 172 if (%is_arraylike(value)) { |
170 return SerializeArray(value, replacer, stack, indent, gap); | 173 return SerializeArray(value, replacer, stack, indent, gap); |
171 } else if (IS_NUMBER_WRAPPER(value)) { | 174 } else if (IS_NUMBER_WRAPPER(value)) { |
172 value = TO_NUMBER(value); | 175 value = TO_NUMBER(value); |
173 return JSON_NUMBER_TO_STRING(value); | 176 return JSON_NUMBER_TO_STRING(value); |
174 } else if (IS_STRING_WRAPPER(value)) { | 177 } else if (IS_STRING_WRAPPER(value)) { |
175 return %QuoteJSONString(TO_STRING(value)); | 178 return %QuoteJSONString(TO_STRING(value)); |
176 } else if (IS_BOOLEAN_WRAPPER(value)) { | 179 } else if (IS_BOOLEAN_WRAPPER(value)) { |
177 return %_ValueOf(value) ? "true" : "false"; | 180 return %_ValueOf(value) ? "true" : "false"; |
178 } else { | 181 } else { |
179 return SerializeObject(value, replacer, stack, indent, gap); | 182 return SerializeObject(value, replacer, stack, indent, gap); |
180 } | 183 } |
181 } | 184 } |
182 // Undefined or a callable object. | 185 // Undefined or a callable object. |
183 return UNDEFINED; | 186 return UNDEFINED; |
184 } | 187 } |
185 | 188 |
186 | 189 |
187 function JSONStringify(value, replacer, space) { | 190 function JSONStringify(value, replacer, space) { |
188 if (%_ArgumentsLength() == 1) { | 191 if (%_ArgumentsLength() == 1 && !%_IsJSProxy(value)) { |
189 return %BasicJSONStringify(value); | 192 return %BasicJSONStringify(value); |
190 } | 193 } |
191 if (IS_ARRAY(replacer)) { | 194 if (!IS_CALLABLE(replacer) && %is_arraylike(replacer)) { |
192 // Deduplicate replacer array items. | |
193 var property_list = new InternalArray(); | 195 var property_list = new InternalArray(); |
194 var seen_properties = { __proto__: null }; | 196 var seen_properties = new GlobalSet(); |
195 var length = replacer.length; | 197 var length = TO_LENGTH(replacer.length); |
196 for (var i = 0; i < length; i++) { | 198 for (var i = 0; i < length; i++) { |
197 var v = replacer[i]; | 199 var v = replacer[i]; |
198 var item; | 200 var item; |
199 if (IS_STRING(v)) { | 201 if (IS_STRING(v)) { |
200 item = v; | 202 item = v; |
201 } else if (IS_NUMBER(v)) { | 203 } else if (IS_NUMBER(v)) { |
202 item = %_NumberToString(v); | 204 item = %_NumberToString(v); |
203 } else if (IS_STRING_WRAPPER(v) || IS_NUMBER_WRAPPER(v)) { | 205 } else if (IS_STRING_WRAPPER(v) || IS_NUMBER_WRAPPER(v)) { |
204 item = TO_STRING(v); | 206 item = TO_STRING(v); |
205 } else { | 207 } else { |
206 continue; | 208 continue; |
207 } | 209 } |
208 if (!seen_properties[item]) { | 210 if (!seen_properties.has(item)) { |
209 property_list.push(item); | 211 property_list.push(item); |
210 seen_properties[item] = true; | 212 seen_properties.add(item); |
211 } | 213 } |
212 } | 214 } |
213 replacer = property_list; | 215 replacer = property_list; |
214 } | 216 } |
215 if (IS_OBJECT(space)) { | 217 if (IS_OBJECT(space)) { |
216 // Unwrap 'space' if it is wrapped | 218 // Unwrap 'space' if it is wrapped |
217 if (IS_NUMBER_WRAPPER(space)) { | 219 if (IS_NUMBER_WRAPPER(space)) { |
218 space = TO_NUMBER(space); | 220 space = TO_NUMBER(space); |
219 } else if (IS_STRING_WRAPPER(space)) { | 221 } else if (IS_STRING_WRAPPER(space)) { |
220 space = TO_STRING(space); | 222 space = TO_STRING(space); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 function JsonSerializeAdapter(key, object) { | 254 function JsonSerializeAdapter(key, object) { |
253 var holder = {}; | 255 var holder = {}; |
254 holder[key] = object; | 256 holder[key] = object; |
255 // No need to pass the actual holder since there is no replacer function. | 257 // No need to pass the actual holder since there is no replacer function. |
256 return JSONSerialize(key, holder, UNDEFINED, new InternalArray(), "", ""); | 258 return JSONSerialize(key, holder, UNDEFINED, new InternalArray(), "", ""); |
257 } | 259 } |
258 | 260 |
259 %InstallToContext(["json_serialize_adapter", JsonSerializeAdapter]); | 261 %InstallToContext(["json_serialize_adapter", JsonSerializeAdapter]); |
260 | 262 |
261 }) | 263 }) |
OLD | NEW |