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