|  | // Copyright 2018 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/codegen/string-constants.h" | 
|  |  | 
|  | #include "src/base/functional.h" | 
|  | #include "src/numbers/dtoa.h" | 
|  | #include "src/objects/objects.h" | 
|  | #include "src/objects/string-inl.h" | 
|  |  | 
|  | namespace v8 { | 
|  | namespace internal { | 
|  |  | 
|  | Handle<String> StringConstantBase::AllocateStringConstant( | 
|  | Isolate* isolate) const { | 
|  | if (!flattened_.is_null()) { | 
|  | return flattened_; | 
|  | } | 
|  |  | 
|  | Handle<String> result; | 
|  | switch (kind()) { | 
|  | case StringConstantKind::kStringLiteral: { | 
|  | result = static_cast<const StringLiteral*>(this)->str(); | 
|  | CHECK(!result.is_null()); | 
|  | break; | 
|  | } | 
|  | case StringConstantKind::kNumberToStringConstant: { | 
|  | auto num_constant = static_cast<const NumberToStringConstant*>(this); | 
|  | Handle<Object> num_obj = | 
|  | isolate->factory()->NewNumber(num_constant->num()); | 
|  | result = isolate->factory()->NumberToString(num_obj); | 
|  | CHECK(!result.is_null()); | 
|  | break; | 
|  | } | 
|  | case StringConstantKind::kStringCons: { | 
|  | Handle<String> lhs = | 
|  | static_cast<const StringCons*>(this)->lhs()->AllocateStringConstant( | 
|  | isolate); | 
|  | Handle<String> rhs = | 
|  | static_cast<const StringCons*>(this)->rhs()->AllocateStringConstant( | 
|  | isolate); | 
|  | result = isolate->factory()->NewConsString(lhs, rhs).ToHandleChecked(); | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // TODO(mslekova): Normally we'd want to flatten the string here | 
|  | // but that results in OOM for too long strings. | 
|  | Memoize(result); | 
|  | return flattened_; | 
|  | } | 
|  |  | 
|  | bool StringConstantBase::operator==(const StringConstantBase& other) const { | 
|  | if (kind() != other.kind()) return false; | 
|  |  | 
|  | switch (kind()) { | 
|  | case StringConstantKind::kStringLiteral: { | 
|  | return static_cast<const StringLiteral*>(this) == | 
|  | static_cast<const StringLiteral*>(&other); | 
|  | } | 
|  | case StringConstantKind::kNumberToStringConstant: { | 
|  | return static_cast<const NumberToStringConstant*>(this) == | 
|  | static_cast<const NumberToStringConstant*>(&other); | 
|  | } | 
|  | case StringConstantKind::kStringCons: { | 
|  | return static_cast<const StringCons*>(this) == | 
|  | static_cast<const StringCons*>(&other); | 
|  | } | 
|  | } | 
|  | UNREACHABLE(); | 
|  | } | 
|  |  | 
|  | size_t hash_value(StringConstantBase const& base) { | 
|  | switch (base.kind()) { | 
|  | case StringConstantKind::kStringLiteral: { | 
|  | return hash_value(*static_cast<const StringLiteral*>(&base)); | 
|  | } | 
|  | case StringConstantKind::kNumberToStringConstant: { | 
|  | return hash_value(*static_cast<const NumberToStringConstant*>(&base)); | 
|  | } | 
|  | case StringConstantKind::kStringCons: { | 
|  | return hash_value(*static_cast<const StringCons*>(&base)); | 
|  | } | 
|  | } | 
|  | UNREACHABLE(); | 
|  | } | 
|  |  | 
|  | bool operator==(StringLiteral const& lhs, StringLiteral const& rhs) { | 
|  | return lhs.str().address() == rhs.str().address(); | 
|  | } | 
|  |  | 
|  | bool operator!=(StringLiteral const& lhs, StringLiteral const& rhs) { | 
|  | return !(lhs == rhs); | 
|  | } | 
|  |  | 
|  | size_t hash_value(StringLiteral const& p) { | 
|  | return base::hash_combine(p.str().address()); | 
|  | } | 
|  |  | 
|  | std::ostream& operator<<(std::ostream& os, StringLiteral const& p) { | 
|  | return os << Brief(*p.str()); | 
|  | } | 
|  |  | 
|  | bool operator==(NumberToStringConstant const& lhs, | 
|  | NumberToStringConstant const& rhs) { | 
|  | return lhs.num() == rhs.num(); | 
|  | } | 
|  |  | 
|  | bool operator!=(NumberToStringConstant const& lhs, | 
|  | NumberToStringConstant const& rhs) { | 
|  | return !(lhs == rhs); | 
|  | } | 
|  |  | 
|  | size_t hash_value(NumberToStringConstant const& p) { | 
|  | return base::hash_combine(p.num()); | 
|  | } | 
|  |  | 
|  | std::ostream& operator<<(std::ostream& os, NumberToStringConstant const& p) { | 
|  | return os << p.num(); | 
|  | } | 
|  |  | 
|  | bool operator==(StringCons const& lhs, StringCons const& rhs) { | 
|  | // TODO(mslekova): Think if we can express this in a more readable manner | 
|  | return *(lhs.lhs()) == *(rhs.lhs()) && *(lhs.rhs()) == *(rhs.rhs()); | 
|  | } | 
|  |  | 
|  | bool operator!=(StringCons const& lhs, StringCons const& rhs) { | 
|  | return !(lhs == rhs); | 
|  | } | 
|  |  | 
|  | size_t hash_value(StringCons const& p) { | 
|  | return base::hash_combine(*(p.lhs()), *(p.rhs())); | 
|  | } | 
|  |  | 
|  | std::ostream& operator<<(std::ostream& os, const StringConstantBase* base) { | 
|  | os << "DelayedStringConstant: "; | 
|  | switch (base->kind()) { | 
|  | case StringConstantKind::kStringLiteral: { | 
|  | os << *static_cast<const StringLiteral*>(base); | 
|  | break; | 
|  | } | 
|  | case StringConstantKind::kNumberToStringConstant: { | 
|  | os << *static_cast<const NumberToStringConstant*>(base); | 
|  | break; | 
|  | } | 
|  | case StringConstantKind::kStringCons: { | 
|  | os << *static_cast<const StringCons*>(base); | 
|  | break; | 
|  | } | 
|  | } | 
|  | return os; | 
|  | } | 
|  |  | 
|  | std::ostream& operator<<(std::ostream& os, StringCons const& p) { | 
|  | return os << p.lhs() << ", " << p.rhs(); | 
|  | } | 
|  |  | 
|  | size_t StringConstantBase::GetMaxStringConstantLength() const { | 
|  | switch (kind()) { | 
|  | case StringConstantKind::kStringLiteral: { | 
|  | return static_cast<const StringLiteral*>(this) | 
|  | ->GetMaxStringConstantLength(); | 
|  | } | 
|  | case StringConstantKind::kNumberToStringConstant: { | 
|  | return static_cast<const NumberToStringConstant*>(this) | 
|  | ->GetMaxStringConstantLength(); | 
|  | } | 
|  | case StringConstantKind::kStringCons: { | 
|  | return static_cast<const StringCons*>(this)->GetMaxStringConstantLength(); | 
|  | } | 
|  | } | 
|  | UNREACHABLE(); | 
|  | } | 
|  |  | 
|  | size_t StringLiteral::GetMaxStringConstantLength() const { return length_; } | 
|  |  | 
|  | size_t NumberToStringConstant::GetMaxStringConstantLength() const { | 
|  | return kBase10MaximalLength + 1; | 
|  | } | 
|  |  | 
|  | size_t StringCons::GetMaxStringConstantLength() const { | 
|  | return lhs()->GetMaxStringConstantLength() + | 
|  | rhs()->GetMaxStringConstantLength(); | 
|  | } | 
|  |  | 
|  | }  // namespace internal | 
|  | }  // namespace v8 |