1// Copyright 2018 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "src/string-constants.h"
6
7#include "src/base/functional.h"
8#include "src/dtoa.h"
9#include "src/objects.h"
10#include "src/objects/string-inl.h"
11
12namespace v8 {
13namespace internal {
14
15Handle<String> StringConstantBase::AllocateStringConstant(
16 Isolate* isolate) const {
17 if (!flattened_.is_null()) {
18 return flattened_;
19 }
20
21 Handle<String> result;
22 switch (kind()) {
23 case StringConstantKind::kStringLiteral: {
24 result = static_cast<const StringLiteral*>(this)->str();
25 break;
26 }
27 case StringConstantKind::kNumberToStringConstant: {
28 auto num_constant = static_cast<const NumberToStringConstant*>(this);
29 Handle<Object> num_obj =
30 isolate->factory()->NewNumber(num_constant->num());
31 result = isolate->factory()->NumberToString(num_obj);
32 break;
33 }
34 case StringConstantKind::kStringCons: {
35 Handle<String> lhs =
36 static_cast<const StringCons*>(this)->lhs()->AllocateStringConstant(
37 isolate);
38 Handle<String> rhs =
39 static_cast<const StringCons*>(this)->rhs()->AllocateStringConstant(
40 isolate);
41 result = isolate->factory()->NewConsString(lhs, rhs).ToHandleChecked();
42 break;
43 }
44 }
45
46 // TODO(mslekova): Normally we'd want to flatten the string here
47 // but that results in OOM for too long strings.
48 Memoize(result);
49 return flattened_;
50}
51
52bool StringConstantBase::operator==(const StringConstantBase& other) const {
53 if (kind() != other.kind()) return false;
54
55 switch (kind()) {
56 case StringConstantKind::kStringLiteral: {
57 return static_cast<const StringLiteral*>(this) ==
58 static_cast<const StringLiteral*>(&other);
59 }
60 case StringConstantKind::kNumberToStringConstant: {
61 return static_cast<const NumberToStringConstant*>(this) ==
62 static_cast<const NumberToStringConstant*>(&other);
63 }
64 case StringConstantKind::kStringCons: {
65 return static_cast<const StringCons*>(this) ==
66 static_cast<const StringCons*>(&other);
67 }
68 }
69 UNREACHABLE();
70}
71
72size_t hash_value(StringConstantBase const& base) {
73 switch (base.kind()) {
74 case StringConstantKind::kStringLiteral: {
75 return hash_value(*static_cast<const StringLiteral*>(&base));
76 }
77 case StringConstantKind::kNumberToStringConstant: {
78 return hash_value(*static_cast<const NumberToStringConstant*>(&base));
79 }
80 case StringConstantKind::kStringCons: {
81 return hash_value(*static_cast<const StringCons*>(&base));
82 }
83 }
84 UNREACHABLE();
85}
86
87bool operator==(StringLiteral const& lhs, StringLiteral const& rhs) {
88 return lhs.str().address() == rhs.str().address();
89}
90
91bool operator!=(StringLiteral const& lhs, StringLiteral const& rhs) {
92 return !(lhs == rhs);
93}
94
95size_t hash_value(StringLiteral const& p) {
96 return base::hash_combine(p.str().address());
97}
98
99std::ostream& operator<<(std::ostream& os, StringLiteral const& p) {
100 return os << Brief(*p.str());
101}
102
103bool operator==(NumberToStringConstant const& lhs,
104 NumberToStringConstant const& rhs) {
105 return lhs.num() == rhs.num();
106}
107
108bool operator!=(NumberToStringConstant const& lhs,
109 NumberToStringConstant const& rhs) {
110 return !(lhs == rhs);
111}
112
113size_t hash_value(NumberToStringConstant const& p) {
114 return base::hash_combine(p.num());
115}
116
117std::ostream& operator<<(std::ostream& os, NumberToStringConstant const& p) {
118 return os << p.num();
119}
120
121bool operator==(StringCons const& lhs, StringCons const& rhs) {
122 // TODO(mslekova): Think if we can express this in a more readable manner
123 return *(lhs.lhs()) == *(rhs.lhs()) && *(lhs.rhs()) == *(rhs.rhs());
124}
125
126bool operator!=(StringCons const& lhs, StringCons const& rhs) {
127 return !(lhs == rhs);
128}
129
130size_t hash_value(StringCons const& p) {
131 return base::hash_combine(*(p.lhs()), *(p.rhs()));
132}
133
134std::ostream& operator<<(std::ostream& os, const StringConstantBase* base) {
135 os << "DelayedStringConstant: ";
136 switch (base->kind()) {
137 case StringConstantKind::kStringLiteral: {
138 os << *static_cast<const StringLiteral*>(base);
139 break;
140 }
141 case StringConstantKind::kNumberToStringConstant: {
142 os << *static_cast<const NumberToStringConstant*>(base);
143 break;
144 }
145 case StringConstantKind::kStringCons: {
146 os << *static_cast<const StringCons*>(base);
147 break;
148 }
149 }
150 return os;
151}
152
153std::ostream& operator<<(std::ostream& os, StringCons const& p) {
154 return os << p.lhs() << ", " << p.rhs();
155}
156
157size_t StringConstantBase::GetMaxStringConstantLength() const {
158 switch (kind()) {
159 case StringConstantKind::kStringLiteral: {
160 return static_cast<const StringLiteral*>(this)
161 ->GetMaxStringConstantLength();
162 }
163 case StringConstantKind::kNumberToStringConstant: {
164 return static_cast<const NumberToStringConstant*>(this)
165 ->GetMaxStringConstantLength();
166 }
167 case StringConstantKind::kStringCons: {
168 return static_cast<const StringCons*>(this)->GetMaxStringConstantLength();
169 }
170 }
171 UNREACHABLE();
172}
173
174size_t StringLiteral::GetMaxStringConstantLength() const { return length_; }
175
176size_t NumberToStringConstant::GetMaxStringConstantLength() const {
177 return kBase10MaximalLength + 1;
178}
179
180size_t StringCons::GetMaxStringConstantLength() const {
181 return lhs()->GetMaxStringConstantLength() +
182 rhs()->GetMaxStringConstantLength();
183}
184
185} // namespace internal
186} // namespace v8
187