| OLD | NEW |
| 1 // Copyright 2016 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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 #include "src/json-stringifier.h" | 5 #include "src/json-stringifier.h" |
| 6 | 6 |
| 7 #include "src/conversions.h" | 7 #include "src/conversions.h" |
| 8 #include "src/lookup.h" | 8 #include "src/lookup.h" |
| 9 #include "src/messages.h" | 9 #include "src/messages.h" |
| 10 #include "src/objects-inl.h" | 10 #include "src/objects-inl.h" |
| 11 #include "src/utils.h" | 11 #include "src/utils.h" |
| 12 | 12 |
| 13 namespace v8 { | 13 namespace v8 { |
| 14 namespace internal { | 14 namespace internal { |
| 15 | 15 |
| 16 // Translation table to escape Latin1 characters. | 16 // Translation table to escape Latin1 characters. |
| 17 // Table entries start at a multiple of 8 and are null-terminated. | 17 // Table entries start at a multiple of 8 and are null-terminated. |
| 18 const char* const JsonStringifier::JsonEscapeTable = | 18 const char* const BasicJsonStringifier::JsonEscapeTable = |
| 19 "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 " | 19 "\\u0000\0 \\u0001\0 \\u0002\0 \\u0003\0 " |
| 20 "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 " | 20 "\\u0004\0 \\u0005\0 \\u0006\0 \\u0007\0 " |
| 21 "\\b\0 \\t\0 \\n\0 \\u000b\0 " | 21 "\\b\0 \\t\0 \\n\0 \\u000b\0 " |
| 22 "\\f\0 \\r\0 \\u000e\0 \\u000f\0 " | 22 "\\f\0 \\r\0 \\u000e\0 \\u000f\0 " |
| 23 "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 " | 23 "\\u0010\0 \\u0011\0 \\u0012\0 \\u0013\0 " |
| 24 "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 " | 24 "\\u0014\0 \\u0015\0 \\u0016\0 \\u0017\0 " |
| 25 "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 " | 25 "\\u0018\0 \\u0019\0 \\u001a\0 \\u001b\0 " |
| 26 "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 " | 26 "\\u001c\0 \\u001d\0 \\u001e\0 \\u001f\0 " |
| 27 " \0 !\0 \\\"\0 #\0 " | 27 " \0 !\0 \\\"\0 #\0 " |
| 28 "$\0 %\0 &\0 '\0 " | 28 "$\0 %\0 &\0 '\0 " |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 74 "\334\0 \335\0 \336\0 \337\0 " | 74 "\334\0 \335\0 \336\0 \337\0 " |
| 75 "\340\0 \341\0 \342\0 \343\0 " | 75 "\340\0 \341\0 \342\0 \343\0 " |
| 76 "\344\0 \345\0 \346\0 \347\0 " | 76 "\344\0 \345\0 \346\0 \347\0 " |
| 77 "\350\0 \351\0 \352\0 \353\0 " | 77 "\350\0 \351\0 \352\0 \353\0 " |
| 78 "\354\0 \355\0 \356\0 \357\0 " | 78 "\354\0 \355\0 \356\0 \357\0 " |
| 79 "\360\0 \361\0 \362\0 \363\0 " | 79 "\360\0 \361\0 \362\0 \363\0 " |
| 80 "\364\0 \365\0 \366\0 \367\0 " | 80 "\364\0 \365\0 \366\0 \367\0 " |
| 81 "\370\0 \371\0 \372\0 \373\0 " | 81 "\370\0 \371\0 \372\0 \373\0 " |
| 82 "\374\0 \375\0 \376\0 \377\0 "; | 82 "\374\0 \375\0 \376\0 \377\0 "; |
| 83 | 83 |
| 84 JsonStringifier::JsonStringifier(Isolate* isolate) | 84 BasicJsonStringifier::BasicJsonStringifier(Isolate* isolate) |
| 85 : isolate_(isolate), builder_(isolate), gap_(nullptr), indent_(0) { | 85 : isolate_(isolate), builder_(isolate), gap_(nullptr), indent_(0) { |
| 86 tojson_string_ = factory()->toJSON_string(); | 86 tojson_string_ = factory()->toJSON_string(); |
| 87 stack_ = factory()->NewJSArray(8); | 87 stack_ = factory()->NewJSArray(8); |
| 88 } | 88 } |
| 89 | 89 |
| 90 MaybeHandle<Object> JsonStringifier::Stringify(Handle<Object> object, | 90 MaybeHandle<Object> BasicJsonStringifier::Stringify(Handle<Object> object, |
| 91 Handle<Object> replacer, | 91 Handle<Object> replacer, |
| 92 Handle<Object> gap) { | 92 Handle<Object> gap) { |
| 93 if (!InitializeReplacer(replacer)) return MaybeHandle<Object>(); | 93 if (!InitializeReplacer(replacer)) return MaybeHandle<Object>(); |
| 94 if (!gap->IsUndefined() && !InitializeGap(gap)) return MaybeHandle<Object>(); | 94 if (!gap->IsUndefined() && !InitializeGap(gap)) return MaybeHandle<Object>(); |
| 95 Result result = SerializeObject(object); | 95 Result result = SerializeObject(object); |
| 96 if (result == UNCHANGED) return factory()->undefined_value(); | 96 if (result == UNCHANGED) return factory()->undefined_value(); |
| 97 if (result == SUCCESS) return builder_.Finish(); | 97 if (result == SUCCESS) return builder_.Finish(); |
| 98 DCHECK(result == EXCEPTION); | 98 DCHECK(result == EXCEPTION); |
| 99 return MaybeHandle<Object>(); | 99 return MaybeHandle<Object>(); |
| 100 } | 100 } |
| 101 | 101 |
| 102 bool IsInList(Handle<String> key, List<Handle<String> >* list) { | 102 bool IsInList(Handle<String> key, List<Handle<String> >* list) { |
| 103 // TODO(yangguo): This is O(n^2) for n properties in the list. Deal with this | 103 // TODO(yangguo): This is O(n^2) for n properties in the list. Deal with this |
| 104 // if this becomes an issue. | 104 // if this becomes an issue. |
| 105 for (const Handle<String>& existing : *list) { | 105 for (const Handle<String>& existing : *list) { |
| 106 if (String::Equals(existing, key)) return true; | 106 if (String::Equals(existing, key)) return true; |
| 107 } | 107 } |
| 108 return false; | 108 return false; |
| 109 } | 109 } |
| 110 | 110 |
| 111 bool JsonStringifier::InitializeReplacer(Handle<Object> replacer) { | 111 bool BasicJsonStringifier::InitializeReplacer(Handle<Object> replacer) { |
| 112 DCHECK(property_list_.is_null()); | 112 DCHECK(property_list_.is_null()); |
| 113 DCHECK(replacer_function_.is_null()); | |
| 114 Maybe<bool> is_array = Object::IsArray(replacer); | 113 Maybe<bool> is_array = Object::IsArray(replacer); |
| 115 if (is_array.IsNothing()) return false; | 114 if (is_array.IsNothing()) return false; |
| 116 if (is_array.FromJust()) { | 115 if (is_array.FromJust()) { |
| 117 HandleScope handle_scope(isolate_); | 116 HandleScope handle_scope(isolate_); |
| 118 List<Handle<String> > list; | 117 List<Handle<String> > list; |
| 119 Handle<Object> length_obj; | 118 Handle<Object> length_obj; |
| 120 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 119 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 121 isolate_, length_obj, | 120 isolate_, length_obj, |
| 122 Object::GetLengthFromArrayLike(isolate_, replacer), false); | 121 Object::GetLengthFromArrayLike(isolate_, replacer), false); |
| 123 uint32_t length; | 122 uint32_t length; |
| (...skipping 14 matching lines...) Expand all Loading... |
| 138 } | 137 } |
| 139 } | 138 } |
| 140 if (key.is_null()) continue; | 139 if (key.is_null()) continue; |
| 141 if (!IsInList(key, &list)) list.Add(key); | 140 if (!IsInList(key, &list)) list.Add(key); |
| 142 } | 141 } |
| 143 property_list_ = factory()->NewUninitializedFixedArray(list.length()); | 142 property_list_ = factory()->NewUninitializedFixedArray(list.length()); |
| 144 for (int i = 0; i < list.length(); i++) { | 143 for (int i = 0; i < list.length(); i++) { |
| 145 property_list_->set(i, *list[i]); | 144 property_list_->set(i, *list[i]); |
| 146 } | 145 } |
| 147 property_list_ = handle_scope.CloseAndEscape(property_list_); | 146 property_list_ = handle_scope.CloseAndEscape(property_list_); |
| 148 } else if (replacer->IsCallable()) { | |
| 149 replacer_function_ = Handle<JSReceiver>::cast(replacer); | |
| 150 } | 147 } |
| 151 return true; | 148 return true; |
| 152 } | 149 } |
| 153 | 150 |
| 154 bool JsonStringifier::InitializeGap(Handle<Object> gap) { | 151 bool BasicJsonStringifier::InitializeGap(Handle<Object> gap) { |
| 155 DCHECK_NULL(gap_); | 152 DCHECK_NULL(gap_); |
| 156 HandleScope scope(isolate_); | 153 HandleScope scope(isolate_); |
| 157 if (gap->IsJSValue()) { | 154 if (gap->IsJSValue()) { |
| 158 Handle<Object> value(Handle<JSValue>::cast(gap)->value(), isolate_); | 155 Handle<Object> value(Handle<JSValue>::cast(gap)->value(), isolate_); |
| 159 if (value->IsString()) { | 156 if (value->IsString()) { |
| 160 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, | 157 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, |
| 161 Object::ToString(isolate_, gap), false); | 158 Object::ToString(isolate_, gap), false); |
| 162 } else if (value->IsNumber()) { | 159 } else if (value->IsNumber()) { |
| 163 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, Object::ToNumber(gap), | 160 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, gap, Object::ToNumber(gap), |
| 164 false); | 161 false); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 184 if (num_value > 0) { | 181 if (num_value > 0) { |
| 185 int gap_length = std::min(num_value, 10); | 182 int gap_length = std::min(num_value, 10); |
| 186 gap_ = NewArray<uc16>(gap_length + 1); | 183 gap_ = NewArray<uc16>(gap_length + 1); |
| 187 for (int i = 0; i < gap_length; i++) gap_[i] = ' '; | 184 for (int i = 0; i < gap_length; i++) gap_[i] = ' '; |
| 188 gap_[gap_length] = '\0'; | 185 gap_[gap_length] = '\0'; |
| 189 } | 186 } |
| 190 } | 187 } |
| 191 return true; | 188 return true; |
| 192 } | 189 } |
| 193 | 190 |
| 194 MaybeHandle<Object> JsonStringifier::ApplyToJsonFunction(Handle<Object> object, | 191 MaybeHandle<Object> BasicJsonStringifier::StringifyString( |
| 195 Handle<Object> key) { | 192 Isolate* isolate, Handle<String> object) { |
| 196 HandleScope scope(isolate_); | 193 static const int kJsonQuoteWorstCaseBlowup = 6; |
| 194 static const int kSpaceForQuotes = 2; |
| 195 int worst_case_length = |
| 196 object->length() * kJsonQuoteWorstCaseBlowup + kSpaceForQuotes; |
| 197 |
| 198 if (worst_case_length > 32 * KB) { // Slow path if too large. |
| 199 BasicJsonStringifier stringifier(isolate); |
| 200 Handle<Object> undefined = isolate->factory()->undefined_value(); |
| 201 return stringifier.Stringify(object, undefined, undefined); |
| 202 } |
| 203 |
| 204 object = String::Flatten(object); |
| 205 DCHECK(object->IsFlat()); |
| 206 Handle<SeqString> result; |
| 207 if (object->IsOneByteRepresentationUnderneath()) { |
| 208 result = isolate->factory() |
| 209 ->NewRawOneByteString(worst_case_length) |
| 210 .ToHandleChecked(); |
| 211 IncrementalStringBuilder::NoExtendString<uint8_t> no_extend( |
| 212 result, worst_case_length); |
| 213 no_extend.Append('\"'); |
| 214 SerializeStringUnchecked_(object->GetFlatContent().ToOneByteVector(), |
| 215 &no_extend); |
| 216 no_extend.Append('\"'); |
| 217 return no_extend.Finalize(); |
| 218 } else { |
| 219 result = isolate->factory() |
| 220 ->NewRawTwoByteString(worst_case_length) |
| 221 .ToHandleChecked(); |
| 222 IncrementalStringBuilder::NoExtendString<uc16> no_extend(result, |
| 223 worst_case_length); |
| 224 no_extend.Append('\"'); |
| 225 SerializeStringUnchecked_(object->GetFlatContent().ToUC16Vector(), |
| 226 &no_extend); |
| 227 no_extend.Append('\"'); |
| 228 return no_extend.Finalize(); |
| 229 } |
| 230 } |
| 231 |
| 232 MaybeHandle<Object> BasicJsonStringifier::ApplyToJsonFunction( |
| 233 Handle<Object> object, Handle<Object> key) { |
| 197 LookupIterator it(object, tojson_string_, | 234 LookupIterator it(object, tojson_string_, |
| 198 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); | 235 LookupIterator::PROTOTYPE_CHAIN_SKIP_INTERCEPTOR); |
| 199 Handle<Object> fun; | 236 Handle<Object> fun; |
| 200 ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object); | 237 ASSIGN_RETURN_ON_EXCEPTION(isolate_, fun, Object::GetProperty(&it), Object); |
| 201 if (!fun->IsCallable()) return object; | 238 if (!fun->IsCallable()) return object; |
| 202 | 239 |
| 203 // Call toJSON function. | 240 // Call toJSON function. |
| 204 if (key->IsSmi()) key = factory()->NumberToString(key); | 241 if (key->IsSmi()) key = factory()->NumberToString(key); |
| 205 Handle<Object> argv[] = {key}; | 242 Handle<Object> argv[] = {key}; |
| 243 HandleScope scope(isolate_); |
| 206 ASSIGN_RETURN_ON_EXCEPTION(isolate_, object, | 244 ASSIGN_RETURN_ON_EXCEPTION(isolate_, object, |
| 207 Execution::Call(isolate_, fun, object, 1, argv), | 245 Execution::Call(isolate_, fun, object, 1, argv), |
| 208 Object); | 246 Object); |
| 209 return scope.CloseAndEscape(object); | 247 return scope.CloseAndEscape(object); |
| 210 } | 248 } |
| 211 | 249 |
| 212 MaybeHandle<Object> JsonStringifier::ApplyReplacerFunction( | 250 BasicJsonStringifier::Result BasicJsonStringifier::StackPush( |
| 213 Handle<Object> object, Handle<Object> key) { | 251 Handle<Object> object) { |
| 214 HandleScope scope(isolate_); | |
| 215 if (key->IsSmi()) key = factory()->NumberToString(key); | |
| 216 Handle<Object> argv[] = {key, object}; | |
| 217 Handle<JSReceiver> holder = CurrentHolder(object); | |
| 218 ASSIGN_RETURN_ON_EXCEPTION( | |
| 219 isolate_, object, | |
| 220 Execution::Call(isolate_, replacer_function_, holder, 2, argv), Object); | |
| 221 return scope.CloseAndEscape(object); | |
| 222 } | |
| 223 | |
| 224 Handle<JSReceiver> JsonStringifier::CurrentHolder(Handle<Object> value) { | |
| 225 int length = Smi::cast(stack_->length())->value(); | |
| 226 if (length == 0) { | |
| 227 Handle<JSObject> holder = | |
| 228 factory()->NewJSObject(isolate_->object_function()); | |
| 229 JSObject::AddProperty(holder, factory()->empty_string(), value, NONE); | |
| 230 return holder; | |
| 231 } else { | |
| 232 FixedArray* elements = FixedArray::cast(stack_->elements()); | |
| 233 return Handle<JSReceiver>(JSReceiver::cast(elements->get(length - 1)), | |
| 234 isolate_); | |
| 235 } | |
| 236 } | |
| 237 | |
| 238 JsonStringifier::Result JsonStringifier::StackPush(Handle<Object> object) { | |
| 239 StackLimitCheck check(isolate_); | 252 StackLimitCheck check(isolate_); |
| 240 if (check.HasOverflowed()) { | 253 if (check.HasOverflowed()) { |
| 241 isolate_->StackOverflow(); | 254 isolate_->StackOverflow(); |
| 242 return EXCEPTION; | 255 return EXCEPTION; |
| 243 } | 256 } |
| 244 | 257 |
| 245 int length = Smi::cast(stack_->length())->value(); | 258 int length = Smi::cast(stack_->length())->value(); |
| 246 { | 259 { |
| 247 DisallowHeapAllocation no_allocation; | 260 DisallowHeapAllocation no_allocation; |
| 248 FixedArray* elements = FixedArray::cast(stack_->elements()); | 261 FixedArray* elements = FixedArray::cast(stack_->elements()); |
| 249 for (int i = 0; i < length; i++) { | 262 for (int i = 0; i < length; i++) { |
| 250 if (elements->get(i) == *object) { | 263 if (elements->get(i) == *object) { |
| 251 AllowHeapAllocation allow_to_return_error; | 264 AllowHeapAllocation allow_to_return_error; |
| 252 Handle<Object> error = | 265 Handle<Object> error = |
| 253 factory()->NewTypeError(MessageTemplate::kCircularStructure); | 266 factory()->NewTypeError(MessageTemplate::kCircularStructure); |
| 254 isolate_->Throw(*error); | 267 isolate_->Throw(*error); |
| 255 return EXCEPTION; | 268 return EXCEPTION; |
| 256 } | 269 } |
| 257 } | 270 } |
| 258 } | 271 } |
| 259 JSArray::SetLength(stack_, length + 1); | 272 JSArray::SetLength(stack_, length + 1); |
| 260 FixedArray::cast(stack_->elements())->set(length, *object); | 273 FixedArray::cast(stack_->elements())->set(length, *object); |
| 261 return SUCCESS; | 274 return SUCCESS; |
| 262 } | 275 } |
| 263 | 276 |
| 264 void JsonStringifier::StackPop() { | 277 void BasicJsonStringifier::StackPop() { |
| 265 int length = Smi::cast(stack_->length())->value(); | 278 int length = Smi::cast(stack_->length())->value(); |
| 266 stack_->set_length(Smi::FromInt(length - 1)); | 279 stack_->set_length(Smi::FromInt(length - 1)); |
| 267 } | 280 } |
| 268 | 281 |
| 269 template <bool deferred_string_key> | 282 template <bool deferred_string_key> |
| 270 JsonStringifier::Result JsonStringifier::Serialize_(Handle<Object> object, | 283 BasicJsonStringifier::Result BasicJsonStringifier::Serialize_( |
| 271 bool comma, | 284 Handle<Object> object, bool comma, Handle<Object> key) { |
| 272 Handle<Object> key) { | |
| 273 if (object->IsJSReceiver()) { | 285 if (object->IsJSReceiver()) { |
| 274 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 286 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 275 isolate_, object, ApplyToJsonFunction(object, key), EXCEPTION); | 287 isolate_, object, ApplyToJsonFunction(object, key), EXCEPTION); |
| 276 } | 288 } |
| 277 if (!replacer_function_.is_null()) { | |
| 278 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | |
| 279 isolate_, object, ApplyReplacerFunction(object, key), EXCEPTION); | |
| 280 } | |
| 281 | 289 |
| 282 if (object->IsSmi()) { | 290 if (object->IsSmi()) { |
| 283 if (deferred_string_key) SerializeDeferredKey(comma, key); | 291 if (deferred_string_key) SerializeDeferredKey(comma, key); |
| 284 return SerializeSmi(Smi::cast(*object)); | 292 return SerializeSmi(Smi::cast(*object)); |
| 285 } | 293 } |
| 286 | 294 |
| 287 switch (HeapObject::cast(*object)->map()->instance_type()) { | 295 switch (HeapObject::cast(*object)->map()->instance_type()) { |
| 288 case HEAP_NUMBER_TYPE: | 296 case HEAP_NUMBER_TYPE: |
| 289 case MUTABLE_HEAP_NUMBER_TYPE: | 297 case MUTABLE_HEAP_NUMBER_TYPE: |
| 290 if (deferred_string_key) SerializeDeferredKey(comma, key); | 298 if (deferred_string_key) SerializeDeferredKey(comma, key); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 329 return SerializeJSProxy(Handle<JSProxy>::cast(object)); | 337 return SerializeJSProxy(Handle<JSProxy>::cast(object)); |
| 330 } | 338 } |
| 331 return SerializeJSObject(Handle<JSObject>::cast(object)); | 339 return SerializeJSObject(Handle<JSObject>::cast(object)); |
| 332 } | 340 } |
| 333 } | 341 } |
| 334 | 342 |
| 335 UNREACHABLE(); | 343 UNREACHABLE(); |
| 336 return UNCHANGED; | 344 return UNCHANGED; |
| 337 } | 345 } |
| 338 | 346 |
| 339 JsonStringifier::Result JsonStringifier::SerializeJSValue( | 347 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSValue( |
| 340 Handle<JSValue> object) { | 348 Handle<JSValue> object) { |
| 341 String* class_name = object->class_name(); | 349 String* class_name = object->class_name(); |
| 342 if (class_name == isolate_->heap()->String_string()) { | 350 if (class_name == isolate_->heap()->String_string()) { |
| 343 Handle<Object> value; | 351 Handle<Object> value; |
| 344 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 352 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 345 isolate_, value, Object::ToString(isolate_, object), EXCEPTION); | 353 isolate_, value, Object::ToString(isolate_, object), EXCEPTION); |
| 346 SerializeString(Handle<String>::cast(value)); | 354 SerializeString(Handle<String>::cast(value)); |
| 347 } else if (class_name == isolate_->heap()->Number_string()) { | 355 } else if (class_name == isolate_->heap()->Number_string()) { |
| 348 Handle<Object> value; | 356 Handle<Object> value; |
| 349 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, value, Object::ToNumber(object), | 357 ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate_, value, Object::ToNumber(object), |
| 350 EXCEPTION); | 358 EXCEPTION); |
| 351 if (value->IsSmi()) return SerializeSmi(Smi::cast(*value)); | 359 if (value->IsSmi()) return SerializeSmi(Smi::cast(*value)); |
| 352 SerializeHeapNumber(Handle<HeapNumber>::cast(value)); | 360 SerializeHeapNumber(Handle<HeapNumber>::cast(value)); |
| 353 } else if (class_name == isolate_->heap()->Boolean_string()) { | 361 } else if (class_name == isolate_->heap()->Boolean_string()) { |
| 354 Object* value = JSValue::cast(*object)->value(); | 362 Object* value = JSValue::cast(*object)->value(); |
| 355 DCHECK(value->IsBoolean()); | 363 DCHECK(value->IsBoolean()); |
| 356 builder_.AppendCString(value->IsTrue() ? "true" : "false"); | 364 builder_.AppendCString(value->IsTrue() ? "true" : "false"); |
| 357 } else { | 365 } else { |
| 358 // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject. | 366 // ES6 24.3.2.1 step 10.c, serialize as an ordinary JSObject. |
| 359 return SerializeJSObject(object); | 367 return SerializeJSObject(object); |
| 360 } | 368 } |
| 361 return SUCCESS; | 369 return SUCCESS; |
| 362 } | 370 } |
| 363 | 371 |
| 364 JsonStringifier::Result JsonStringifier::SerializeSmi(Smi* object) { | 372 BasicJsonStringifier::Result BasicJsonStringifier::SerializeSmi(Smi* object) { |
| 365 static const int kBufferSize = 100; | 373 static const int kBufferSize = 100; |
| 366 char chars[kBufferSize]; | 374 char chars[kBufferSize]; |
| 367 Vector<char> buffer(chars, kBufferSize); | 375 Vector<char> buffer(chars, kBufferSize); |
| 368 builder_.AppendCString(IntToCString(object->value(), buffer)); | 376 builder_.AppendCString(IntToCString(object->value(), buffer)); |
| 369 return SUCCESS; | 377 return SUCCESS; |
| 370 } | 378 } |
| 371 | 379 |
| 372 JsonStringifier::Result JsonStringifier::SerializeDouble(double number) { | 380 BasicJsonStringifier::Result BasicJsonStringifier::SerializeDouble( |
| 381 double number) { |
| 373 if (std::isinf(number) || std::isnan(number)) { | 382 if (std::isinf(number) || std::isnan(number)) { |
| 374 builder_.AppendCString("null"); | 383 builder_.AppendCString("null"); |
| 375 return SUCCESS; | 384 return SUCCESS; |
| 376 } | 385 } |
| 377 static const int kBufferSize = 100; | 386 static const int kBufferSize = 100; |
| 378 char chars[kBufferSize]; | 387 char chars[kBufferSize]; |
| 379 Vector<char> buffer(chars, kBufferSize); | 388 Vector<char> buffer(chars, kBufferSize); |
| 380 builder_.AppendCString(DoubleToCString(number, buffer)); | 389 builder_.AppendCString(DoubleToCString(number, buffer)); |
| 381 return SUCCESS; | 390 return SUCCESS; |
| 382 } | 391 } |
| 383 | 392 |
| 384 JsonStringifier::Result JsonStringifier::SerializeJSArray( | 393 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSArray( |
| 385 Handle<JSArray> object) { | 394 Handle<JSArray> object) { |
| 386 HandleScope handle_scope(isolate_); | 395 HandleScope handle_scope(isolate_); |
| 387 Result stack_push = StackPush(object); | 396 Result stack_push = StackPush(object); |
| 388 if (stack_push != SUCCESS) return stack_push; | 397 if (stack_push != SUCCESS) return stack_push; |
| 389 uint32_t length = 0; | 398 uint32_t length = 0; |
| 390 CHECK(object->length()->ToArrayLength(&length)); | 399 CHECK(object->length()->ToArrayLength(&length)); |
| 391 DCHECK(!object->IsAccessCheckNeeded()); | 400 DCHECK(!object->IsAccessCheckNeeded()); |
| 392 builder_.AppendCharacter('['); | 401 builder_.AppendCharacter('['); |
| 393 Indent(); | 402 Indent(); |
| 394 uint32_t i = 0; | 403 switch (object->GetElementsKind()) { |
| 395 if (replacer_function_.is_null()) { | 404 case FAST_SMI_ELEMENTS: { |
| 396 switch (object->GetElementsKind()) { | 405 Handle<FixedArray> elements(FixedArray::cast(object->elements()), |
| 397 case FAST_SMI_ELEMENTS: { | 406 isolate_); |
| 398 Handle<FixedArray> elements(FixedArray::cast(object->elements()), | 407 for (uint32_t i = 0; i < length; i++) { |
| 399 isolate_); | 408 Separator(i == 0); |
| 400 while (i < length) { | 409 SerializeSmi(Smi::cast(elements->get(i))); |
| 401 Separator(i == 0); | 410 } |
| 402 SerializeSmi(Smi::cast(elements->get(i))); | 411 break; |
| 403 i++; | 412 } |
| 413 case FAST_DOUBLE_ELEMENTS: { |
| 414 // Empty array is FixedArray but not FixedDoubleArray. |
| 415 if (length == 0) break; |
| 416 Handle<FixedDoubleArray> elements( |
| 417 FixedDoubleArray::cast(object->elements()), isolate_); |
| 418 for (uint32_t i = 0; i < length; i++) { |
| 419 Separator(i == 0); |
| 420 SerializeDouble(elements->get_scalar(i)); |
| 421 } |
| 422 break; |
| 423 } |
| 424 case FAST_ELEMENTS: { |
| 425 Handle<Object> old_length(object->length(), isolate_); |
| 426 for (uint32_t i = 0; i < length; i++) { |
| 427 if (object->length() != *old_length || |
| 428 object->GetElementsKind() != FAST_ELEMENTS) { |
| 429 Result result = SerializeArrayLikeSlow(object, i, length); |
| 430 if (result != SUCCESS) return result; |
| 431 break; |
| 404 } | 432 } |
| 405 break; | 433 Separator(i == 0); |
| 434 Result result = SerializeElement( |
| 435 isolate_, |
| 436 Handle<Object>(FixedArray::cast(object->elements())->get(i), |
| 437 isolate_), |
| 438 i); |
| 439 if (result == SUCCESS) continue; |
| 440 if (result == UNCHANGED) { |
| 441 builder_.AppendCString("null"); |
| 442 } else { |
| 443 return result; |
| 444 } |
| 406 } | 445 } |
| 407 case FAST_DOUBLE_ELEMENTS: { | 446 break; |
| 408 // Empty array is FixedArray but not FixedDoubleArray. | |
| 409 if (length == 0) break; | |
| 410 Handle<FixedDoubleArray> elements( | |
| 411 FixedDoubleArray::cast(object->elements()), isolate_); | |
| 412 while (i < length) { | |
| 413 Separator(i == 0); | |
| 414 SerializeDouble(elements->get_scalar(i)); | |
| 415 i++; | |
| 416 } | |
| 417 break; | |
| 418 } | |
| 419 case FAST_ELEMENTS: { | |
| 420 Handle<Object> old_length(object->length(), isolate_); | |
| 421 while (i < length) { | |
| 422 if (object->length() != *old_length || | |
| 423 object->GetElementsKind() != FAST_ELEMENTS) { | |
| 424 // Fall back to slow path. | |
| 425 break; | |
| 426 } | |
| 427 Separator(i == 0); | |
| 428 Result result = SerializeElement( | |
| 429 isolate_, | |
| 430 Handle<Object>(FixedArray::cast(object->elements())->get(i), | |
| 431 isolate_), | |
| 432 i); | |
| 433 if (result == UNCHANGED) { | |
| 434 builder_.AppendCString("null"); | |
| 435 } else if (result != SUCCESS) { | |
| 436 return result; | |
| 437 } | |
| 438 i++; | |
| 439 } | |
| 440 break; | |
| 441 } | |
| 442 // The FAST_HOLEY_* cases could be handled in a faster way. They resemble | |
| 443 // the non-holey cases except that a lookup is necessary for holes. | |
| 444 default: | |
| 445 break; | |
| 446 } | 447 } |
| 447 } | 448 // The FAST_HOLEY_* cases could be handled in a faster way. They resemble |
| 448 if (i < length) { | 449 // the non-holey cases except that a lookup is necessary for holes. |
| 449 // Slow path for non-fast elements and fall-back in edge case. | 450 default: { |
| 450 Result result = SerializeArrayLikeSlow(object, i, length); | 451 Result result = SerializeArrayLikeSlow(object, 0, length); |
| 451 if (result != SUCCESS) return result; | 452 if (result != SUCCESS) return result; |
| 453 break; |
| 454 } |
| 452 } | 455 } |
| 453 Unindent(); | 456 Unindent(); |
| 454 if (length > 0) NewLine(); | 457 if (length > 0) NewLine(); |
| 455 builder_.AppendCharacter(']'); | 458 builder_.AppendCharacter(']'); |
| 456 StackPop(); | 459 StackPop(); |
| 457 return SUCCESS; | 460 return SUCCESS; |
| 458 } | 461 } |
| 459 | 462 |
| 460 JsonStringifier::Result JsonStringifier::SerializeArrayLikeSlow( | 463 BasicJsonStringifier::Result BasicJsonStringifier::SerializeArrayLikeSlow( |
| 461 Handle<JSReceiver> object, uint32_t start, uint32_t length) { | 464 Handle<JSReceiver> object, uint32_t start, uint32_t length) { |
| 462 for (uint32_t i = start; i < length; i++) { | 465 for (uint32_t i = start; i < length; i++) { |
| 463 Separator(i == 0); | 466 Separator(i == 0); |
| 464 Handle<Object> element; | 467 Handle<Object> element; |
| 465 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 468 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 466 isolate_, element, JSReceiver::GetElement(isolate_, object, i), | 469 isolate_, element, JSReceiver::GetElement(isolate_, object, i), |
| 467 EXCEPTION); | 470 EXCEPTION); |
| 468 Result result = SerializeElement(isolate_, element, i); | 471 if (element->IsUndefined()) { |
| 469 if (result == SUCCESS) continue; | |
| 470 if (result == UNCHANGED) { | |
| 471 builder_.AppendCString("null"); | 472 builder_.AppendCString("null"); |
| 472 } else { | 473 } else { |
| 473 return result; | 474 Result result = SerializeElement(isolate_, element, i); |
| 475 if (result == SUCCESS) continue; |
| 476 if (result == UNCHANGED) { |
| 477 builder_.AppendCString("null"); |
| 478 } else { |
| 479 return result; |
| 480 } |
| 474 } | 481 } |
| 475 } | 482 } |
| 476 return SUCCESS; | 483 return SUCCESS; |
| 477 } | 484 } |
| 478 | 485 |
| 479 JsonStringifier::Result JsonStringifier::SerializeJSObject( | 486 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSObject( |
| 480 Handle<JSObject> object) { | 487 Handle<JSObject> object) { |
| 481 HandleScope handle_scope(isolate_); | 488 HandleScope handle_scope(isolate_); |
| 482 Result stack_push = StackPush(object); | 489 Result stack_push = StackPush(object); |
| 483 if (stack_push != SUCCESS) return stack_push; | 490 if (stack_push != SUCCESS) return stack_push; |
| 484 | 491 |
| 485 if (property_list_.is_null() && | 492 if (property_list_.is_null() && |
| 486 object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && | 493 object->map()->instance_type() > LAST_CUSTOM_ELEMENTS_RECEIVER && |
| 487 object->HasFastProperties() && | 494 object->HasFastProperties() && |
| 488 Handle<JSObject>::cast(object)->elements()->length() == 0) { | 495 Handle<JSObject>::cast(object)->elements()->length() == 0) { |
| 489 DCHECK(object->IsJSObject()); | 496 DCHECK(object->IsJSObject()); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 524 if (comma) NewLine(); | 531 if (comma) NewLine(); |
| 525 builder_.AppendCharacter('}'); | 532 builder_.AppendCharacter('}'); |
| 526 } else { | 533 } else { |
| 527 Result result = SerializeJSReceiverSlow(object); | 534 Result result = SerializeJSReceiverSlow(object); |
| 528 if (result != SUCCESS) return result; | 535 if (result != SUCCESS) return result; |
| 529 } | 536 } |
| 530 StackPop(); | 537 StackPop(); |
| 531 return SUCCESS; | 538 return SUCCESS; |
| 532 } | 539 } |
| 533 | 540 |
| 534 JsonStringifier::Result JsonStringifier::SerializeJSReceiverSlow( | 541 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSReceiverSlow( |
| 535 Handle<JSReceiver> object) { | 542 Handle<JSReceiver> object) { |
| 536 Handle<FixedArray> contents = property_list_; | 543 Handle<FixedArray> contents = property_list_; |
| 537 if (contents.is_null()) { | 544 if (contents.is_null()) { |
| 538 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 545 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 539 isolate_, contents, | 546 isolate_, contents, |
| 540 JSReceiver::GetKeys(object, OWN_ONLY, ENUMERABLE_STRINGS), EXCEPTION); | 547 JSReceiver::GetKeys(object, OWN_ONLY, ENUMERABLE_STRINGS), EXCEPTION); |
| 541 } | 548 } |
| 542 | 549 |
| 543 builder_.AppendCharacter('{'); | 550 builder_.AppendCharacter('{'); |
| 544 Indent(); | 551 Indent(); |
| (...skipping 21 matching lines...) Expand all Loading... |
| 566 Result result = SerializeProperty(property, comma, key_handle); | 573 Result result = SerializeProperty(property, comma, key_handle); |
| 567 if (!comma && result == SUCCESS) comma = true; | 574 if (!comma && result == SUCCESS) comma = true; |
| 568 if (result == EXCEPTION) return result; | 575 if (result == EXCEPTION) return result; |
| 569 } | 576 } |
| 570 Unindent(); | 577 Unindent(); |
| 571 if (comma) NewLine(); | 578 if (comma) NewLine(); |
| 572 builder_.AppendCharacter('}'); | 579 builder_.AppendCharacter('}'); |
| 573 return SUCCESS; | 580 return SUCCESS; |
| 574 } | 581 } |
| 575 | 582 |
| 576 JsonStringifier::Result JsonStringifier::SerializeJSProxy( | 583 BasicJsonStringifier::Result BasicJsonStringifier::SerializeJSProxy( |
| 577 Handle<JSProxy> object) { | 584 Handle<JSProxy> object) { |
| 578 Result stack_push = StackPush(object); | 585 Result stack_push = StackPush(object); |
| 579 if (stack_push != SUCCESS) return stack_push; | 586 if (stack_push != SUCCESS) return stack_push; |
| 580 Maybe<bool> is_array = Object::IsArray(object); | 587 Maybe<bool> is_array = Object::IsArray(object); |
| 581 if (is_array.IsNothing()) return EXCEPTION; | 588 if (is_array.IsNothing()) return EXCEPTION; |
| 582 if (is_array.FromJust()) { | 589 if (is_array.FromJust()) { |
| 583 Handle<Object> length_object; | 590 Handle<Object> length_object; |
| 584 ASSIGN_RETURN_ON_EXCEPTION_VALUE( | 591 ASSIGN_RETURN_ON_EXCEPTION_VALUE( |
| 585 isolate_, length_object, | 592 isolate_, length_object, |
| 586 Object::GetLengthFromArrayLike(isolate_, object), EXCEPTION); | 593 Object::GetLengthFromArrayLike(isolate_, object), EXCEPTION); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 601 builder_.AppendCharacter(']'); | 608 builder_.AppendCharacter(']'); |
| 602 } else { | 609 } else { |
| 603 Result result = SerializeJSReceiverSlow(object); | 610 Result result = SerializeJSReceiverSlow(object); |
| 604 if (result != SUCCESS) return result; | 611 if (result != SUCCESS) return result; |
| 605 } | 612 } |
| 606 StackPop(); | 613 StackPop(); |
| 607 return SUCCESS; | 614 return SUCCESS; |
| 608 } | 615 } |
| 609 | 616 |
| 610 template <typename SrcChar, typename DestChar> | 617 template <typename SrcChar, typename DestChar> |
| 611 void JsonStringifier::SerializeStringUnchecked_( | 618 void BasicJsonStringifier::SerializeStringUnchecked_( |
| 612 Vector<const SrcChar> src, | 619 Vector<const SrcChar> src, |
| 613 IncrementalStringBuilder::NoExtend<DestChar>* dest) { | 620 IncrementalStringBuilder::NoExtend<DestChar>* dest) { |
| 614 // Assert that uc16 character is not truncated down to 8 bit. | 621 // Assert that uc16 character is not truncated down to 8 bit. |
| 615 // The <uc16, char> version of this method must not be called. | 622 // The <uc16, char> version of this method must not be called. |
| 616 DCHECK(sizeof(DestChar) >= sizeof(SrcChar)); | 623 DCHECK(sizeof(DestChar) >= sizeof(SrcChar)); |
| 617 | 624 |
| 618 for (int i = 0; i < src.length(); i++) { | 625 for (int i = 0; i < src.length(); i++) { |
| 619 SrcChar c = src[i]; | 626 SrcChar c = src[i]; |
| 620 if (DoNotEscape(c)) { | 627 if (DoNotEscape(c)) { |
| 621 dest->Append(c); | 628 dest->Append(c); |
| 622 } else { | 629 } else { |
| 623 dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]); | 630 dest->AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]); |
| 624 } | 631 } |
| 625 } | 632 } |
| 626 } | 633 } |
| 627 | 634 |
| 628 template <typename SrcChar, typename DestChar> | 635 template <typename SrcChar, typename DestChar> |
| 629 void JsonStringifier::SerializeString_(Handle<String> string) { | 636 void BasicJsonStringifier::SerializeString_(Handle<String> string) { |
| 630 int length = string->length(); | 637 int length = string->length(); |
| 631 builder_.Append<uint8_t, DestChar>('"'); | 638 builder_.Append<uint8_t, DestChar>('"'); |
| 632 // We make a rough estimate to find out if the current string can be | 639 // We make a rough estimate to find out if the current string can be |
| 633 // serialized without allocating a new string part. The worst case length of | 640 // serialized without allocating a new string part. The worst case length of |
| 634 // an escaped character is 6. Shifting the remainin string length right by 3 | 641 // an escaped character is 6. Shifting the remainin string length right by 3 |
| 635 // is a more pessimistic estimate, but faster to calculate. | 642 // is a more pessimistic estimate, but faster to calculate. |
| 636 int worst_case_length = length << 3; | 643 int worst_case_length = length << 3; |
| 637 if (builder_.CurrentPartCanFit(worst_case_length)) { | 644 if (builder_.CurrentPartCanFit(worst_case_length)) { |
| 638 DisallowHeapAllocation no_gc; | 645 DisallowHeapAllocation no_gc; |
| 639 Vector<const SrcChar> vector = string->GetCharVector<SrcChar>(); | 646 Vector<const SrcChar> vector = string->GetCharVector<SrcChar>(); |
| 640 IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend( | 647 IncrementalStringBuilder::NoExtendBuilder<DestChar> no_extend( |
| 641 &builder_, worst_case_length); | 648 &builder_, worst_case_length); |
| 642 SerializeStringUnchecked_(vector, &no_extend); | 649 SerializeStringUnchecked_(vector, &no_extend); |
| 643 } else { | 650 } else { |
| 644 FlatStringReader reader(isolate_, string); | 651 FlatStringReader reader(isolate_, string); |
| 645 for (int i = 0; i < reader.length(); i++) { | 652 for (int i = 0; i < reader.length(); i++) { |
| 646 SrcChar c = reader.Get<SrcChar>(i); | 653 SrcChar c = reader.Get<SrcChar>(i); |
| 647 if (DoNotEscape(c)) { | 654 if (DoNotEscape(c)) { |
| 648 builder_.Append<SrcChar, DestChar>(c); | 655 builder_.Append<SrcChar, DestChar>(c); |
| 649 } else { | 656 } else { |
| 650 builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]); | 657 builder_.AppendCString(&JsonEscapeTable[c * kJsonEscapeTableEntrySize]); |
| 651 } | 658 } |
| 652 } | 659 } |
| 653 } | 660 } |
| 654 | 661 |
| 655 builder_.Append<uint8_t, DestChar>('"'); | 662 builder_.Append<uint8_t, DestChar>('"'); |
| 656 } | 663 } |
| 657 | 664 |
| 658 template <> | 665 template <> |
| 659 bool JsonStringifier::DoNotEscape(uint8_t c) { | 666 bool BasicJsonStringifier::DoNotEscape(uint8_t c) { |
| 660 return c >= '#' && c <= '~' && c != '\\'; | 667 return c >= '#' && c <= '~' && c != '\\'; |
| 661 } | 668 } |
| 662 | 669 |
| 663 template <> | 670 template <> |
| 664 bool JsonStringifier::DoNotEscape(uint16_t c) { | 671 bool BasicJsonStringifier::DoNotEscape(uint16_t c) { |
| 665 return c >= '#' && c != '\\' && c != 0x7f; | 672 return c >= '#' && c != '\\' && c != 0x7f; |
| 666 } | 673 } |
| 667 | 674 |
| 668 void JsonStringifier::NewLine() { | 675 void BasicJsonStringifier::NewLine() { |
| 669 if (gap_ == nullptr) return; | 676 if (gap_ == nullptr) return; |
| 670 builder_.AppendCharacter('\n'); | 677 builder_.AppendCharacter('\n'); |
| 671 for (int i = 0; i < indent_; i++) builder_.AppendCString(gap_); | 678 for (int i = 0; i < indent_; i++) builder_.AppendCString(gap_); |
| 672 } | 679 } |
| 673 | 680 |
| 674 void JsonStringifier::Separator(bool first) { | 681 void BasicJsonStringifier::Separator(bool first) { |
| 675 if (!first) builder_.AppendCharacter(','); | 682 if (!first) builder_.AppendCharacter(','); |
| 676 NewLine(); | 683 NewLine(); |
| 677 } | 684 } |
| 678 | 685 |
| 679 void JsonStringifier::SerializeDeferredKey(bool deferred_comma, | 686 void BasicJsonStringifier::SerializeDeferredKey(bool deferred_comma, |
| 680 Handle<Object> deferred_key) { | 687 Handle<Object> deferred_key) { |
| 681 Separator(!deferred_comma); | 688 Separator(!deferred_comma); |
| 682 SerializeString(Handle<String>::cast(deferred_key)); | 689 SerializeString(Handle<String>::cast(deferred_key)); |
| 683 builder_.AppendCharacter(':'); | 690 builder_.AppendCharacter(':'); |
| 684 if (gap_ != nullptr) builder_.AppendCharacter(' '); | 691 if (gap_ != nullptr) builder_.AppendCharacter(' '); |
| 685 } | 692 } |
| 686 | 693 |
| 687 void JsonStringifier::SerializeString(Handle<String> object) { | 694 void BasicJsonStringifier::SerializeString(Handle<String> object) { |
| 688 object = String::Flatten(object); | 695 object = String::Flatten(object); |
| 689 if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) { | 696 if (builder_.CurrentEncoding() == String::ONE_BYTE_ENCODING) { |
| 690 if (object->IsOneByteRepresentationUnderneath()) { | 697 if (object->IsOneByteRepresentationUnderneath()) { |
| 691 SerializeString_<uint8_t, uint8_t>(object); | 698 SerializeString_<uint8_t, uint8_t>(object); |
| 692 } else { | 699 } else { |
| 693 builder_.ChangeEncoding(); | 700 builder_.ChangeEncoding(); |
| 694 SerializeString(object); | 701 SerializeString(object); |
| 695 } | 702 } |
| 696 } else { | 703 } else { |
| 697 if (object->IsOneByteRepresentationUnderneath()) { | 704 if (object->IsOneByteRepresentationUnderneath()) { |
| 698 SerializeString_<uint8_t, uc16>(object); | 705 SerializeString_<uint8_t, uc16>(object); |
| 699 } else { | 706 } else { |
| 700 SerializeString_<uc16, uc16>(object); | 707 SerializeString_<uc16, uc16>(object); |
| 701 } | 708 } |
| 702 } | 709 } |
| 703 } | 710 } |
| 704 | 711 |
| 705 } // namespace internal | 712 } // namespace internal |
| 706 } // namespace v8 | 713 } // namespace v8 |
| OLD | NEW |