// 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 StringConstantBase::AllocateStringConstant( Isolate* isolate) const { if (!flattened_.is_null()) { return flattened_; } Handle result; switch (kind()) { case StringConstantKind::kStringLiteral: { result = static_cast(this)->str(); CHECK(!result.is_null()); break; } case StringConstantKind::kNumberToStringConstant: { auto num_constant = static_cast(this); Handle num_obj = isolate->factory()->NewNumber(num_constant->num()); result = isolate->factory()->NumberToString(num_obj); CHECK(!result.is_null()); break; } case StringConstantKind::kStringCons: { Handle lhs = static_cast(this)->lhs()->AllocateStringConstant( isolate); Handle rhs = static_cast(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(this) == static_cast(&other); } case StringConstantKind::kNumberToStringConstant: { return static_cast(this) == static_cast(&other); } case StringConstantKind::kStringCons: { return static_cast(this) == static_cast(&other); } } UNREACHABLE(); } size_t hash_value(StringConstantBase const& base) { switch (base.kind()) { case StringConstantKind::kStringLiteral: { return hash_value(*static_cast(&base)); } case StringConstantKind::kNumberToStringConstant: { return hash_value(*static_cast(&base)); } case StringConstantKind::kStringCons: { return hash_value(*static_cast(&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(base); break; } case StringConstantKind::kNumberToStringConstant: { os << *static_cast(base); break; } case StringConstantKind::kStringCons: { os << *static_cast(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(this) ->GetMaxStringConstantLength(); } case StringConstantKind::kNumberToStringConstant: { return static_cast(this) ->GetMaxStringConstantLength(); } case StringConstantKind::kStringCons: { return static_cast(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