// Copyright 2016 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/json-parser.h" #include "src/char-predicates-inl.h" #include "src/conversions.h" #include "src/debug/debug.h" #include "src/field-type.h" #include "src/messages.h" #include "src/objects-inl.h" #include "src/objects/hash-table-inl.h" #include "src/property-descriptor.h" #include "src/string-hasher.h" #include "src/transitions.h" #include "src/unicode-cache.h" namespace v8 { namespace internal { namespace { // A vector-like data structure that uses a larger vector for allocation, and // provides limited utility access. The original vector must not be used for the // duration, and it may even be reallocated. This allows vector storage to be // reused for the properties of sibling objects. template class VectorSegment { public: using value_type = typename Container::value_type; explicit VectorSegment(Container* container) : container_(*container), begin_(container->size()) {} ~VectorSegment() { container_.resize(begin_); } Vector GetVector() const { return Vector(container_.data() + begin_, container_.size() - begin_); } template void push_back(T&& value) { container_.push_back(std::forward(value)); } private: Container& container_; const typename Container::size_type begin_; }; } // namespace MaybeHandle JsonParseInternalizer::Internalize(Isolate* isolate, Handle object, Handle reviver) { DCHECK(reviver->IsCallable()); JsonParseInternalizer internalizer(isolate, Handle::cast(reviver)); Handle holder = isolate->factory()->NewJSObject(isolate->object_function()); Handle name = isolate->factory()->empty_string(); JSObject::AddProperty(isolate, holder, name, object, NONE); return internalizer.InternalizeJsonProperty(holder, name); } MaybeHandle JsonParseInternalizer::InternalizeJsonProperty( Handle holder, Handle name) { HandleScope outer_scope(isolate_); Handle value; ASSIGN_RETURN_ON_EXCEPTION( isolate_, value, Object::GetPropertyOrElement(isolate_, holder, name), Object); if (value->IsJSReceiver()) { Handle object = Handle::cast(value); Maybe is_array = Object::IsArray(object); if (is_array.IsNothing()) return MaybeHandle(); if (is_array.FromJust()) { Handle length_object; ASSIGN_RETURN_ON_EXCEPTION( isolate_, length_object, Object::GetLengthFromArrayLike(isolate_, object), Object); double length = length_object->Number(); for (double i = 0; i < length; i++) { HandleScope inner_scope(isolate_); Handle index = isolate_->factory()->NewNumber(i); Handle name = isolate_->factory()->NumberToString(index); if (!RecurseAndApply(object, name)) return MaybeHandle(); } } else { Handle contents; ASSIGN_RETURN_ON_EXCEPTION( isolate_, contents, KeyAccumulator::GetKeys(object, KeyCollectionMode::kOwnOnly, ENUMERABLE_STRINGS, GetKeysConversion::kConvertToString), Object); for (int i = 0; i < contents->length(); i++) { HandleScope inner_scope(isolate_); Handle name(String::cast(contents->get(i)), isolate_); if (!RecurseAndApply(object, name)) return MaybeHandle(); } } } Handle argv[] = {name, value}; Handle result; ASSIGN_RETURN_ON_EXCEPTION( isolate_, result, Execution::Call(isolate_, reviver_, holder, 2, argv), Object); return outer_scope.CloseAndEscape(result); } bool JsonParseInternalizer::RecurseAndApply(Handle holder, Handle name) { STACK_CHECK(isolate_, false); Handle result; ASSIGN_RETURN_ON_EXCEPTION_VALUE( isolate_, result, InternalizeJsonProperty(holder, name), false); Maybe change_result = Nothing(); if (result->IsUndefined(isolate_)) { change_result = JSReceiver::DeletePropertyOrElement(holder, name, LanguageMode::kSloppy); } else { PropertyDescriptor desc; desc.set_value(result); desc.set_configurable(true); desc.set_enumerable(true); desc.set_writable(true); change_result = JSReceiver::DefineOwnProperty(isolate_, holder, name, &desc, kDontThrow); } MAYBE_RETURN(change_result, false); return true; } template JsonParser::JsonParser(Isolate* isolate, Handle source) : source_(source), source_length_(source->length()), isolate_(isolate), zone_(isolate_->allocator(), ZONE_NAME), object_constructor_(isolate_->native_context()->object_function(), isolate_), position_(-1), properties_(&zone_) { source_ = String::Flatten(isolate, source_); pretenure_ = (source_length_ >= kPretenureTreshold) ? TENURED : NOT_TENURED; // Optimized fast case where we only have Latin1 characters. if (seq_one_byte) { seq_source_ = Handle::cast(source_); } } template MaybeHandle JsonParser::ParseJson() { // Advance to the first character (possibly EOS) AdvanceSkipWhitespace(); Handle result = ParseJsonValue(); if (result.is_null() || c0_ != kEndOfString) { // Some exception (for example stack overflow) is already pending. if (isolate_->has_pending_exception()) return Handle::null(); // Parse failed. Current character is the unexpected token. Factory* factory = this->factory(); MessageTemplate::Template message; Handle arg1 = Handle(Smi::FromInt(position_), isolate()); Handle arg2; switch (c0_) { case kEndOfString: message = MessageTemplate::kJsonParseUnexpectedEOS; break; case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': message = MessageTemplate::kJsonParseUnexpectedTokenNumber; break; case '"': message = MessageTemplate::kJsonParseUnexpectedTokenString; break; default: message = MessageTemplate::kJsonParseUnexpectedToken; arg2 = arg1; arg1 = factory->LookupSingleCharacterStringFromCode(c0_); break; } Handle