1 // Copyright 2020 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 <cmath>
6 #include <iostream>
7 #include <limits>
8 #include <memory>
9
10 #include "src/ast/ast-value-factory.h"
11 #include "src/ast/ast.h"
12 #include "src/ast/scopes.h"
13 #include "src/common/assert-scope.h"
14 #include "src/common/globals.h"
15 #include "src/handles/handles-inl.h"
16 #include "src/handles/handles.h"
17 #include "src/handles/maybe-handles.h"
18 #include "src/heap/local-factory-inl.h"
19 #include "src/objects/fixed-array.h"
20 #include "src/objects/script.h"
21 #include "src/objects/shared-function-info.h"
22 #include "src/objects/string.h"
23 #include "src/parsing/parse-info.h"
24 #include "src/parsing/parser.h"
25 #include "src/parsing/rewriter.h"
26 #include "src/parsing/scanner-character-streams.h"
27 #include "src/parsing/scanner.h"
28 #include "src/strings/unicode-inl.h"
29 #include "src/utils/utils.h"
30 #include "test/unittests/test-utils.h"
31
32 namespace v8 {
33 namespace internal {
34
35 class LocalIsolate;
36
37 namespace {
38
DecodeUtf8(const std::string & string)39 std::vector<uint16_t> DecodeUtf8(const std::string& string) {
40 if (string.empty()) return {};
41
42 auto utf8_data = base::Vector<const uint8_t>::cast(
43 base::VectorOf(string.data(), string.length()));
44 Utf8Decoder decoder(utf8_data);
45
46 std::vector<uint16_t> utf16(decoder.utf16_length());
47 decoder.Decode(&utf16[0], utf8_data);
48
49 return utf16;
50 }
51
52 } // namespace
53
54 class LocalFactoryTest : public TestWithIsolateAndZone {
55 public:
LocalFactoryTest()56 LocalFactoryTest()
57 : TestWithIsolateAndZone(),
58 state_(isolate()),
59 parse_info_(
60 isolate(),
61 UnoptimizedCompileFlags::ForToplevelCompile(
62 isolate(), true, construct_language_mode(FLAG_use_strict),
63 REPLMode::kNo, ScriptType::kClassic, FLAG_lazy),
64 &state_),
65 local_isolate_(isolate()->main_thread_local_isolate()) {}
66
ParseProgram(const char * source)67 FunctionLiteral* ParseProgram(const char* source) {
68 auto utf16_source = DecodeUtf8(source);
69
70 // Normally this would be an external string or whatever, we don't have to
71 // worry about it for now.
72 source_string_ = factory()
73 ->NewStringFromUtf8(base::CStrVector(source))
74 .ToHandleChecked();
75
76 parse_info_.set_character_stream(
77 ScannerStream::ForTesting(utf16_source.data(), utf16_source.size()));
78
79 {
80 DisallowGarbageCollection no_gc;
81 DisallowHeapAccess no_heap_access;
82
83 Parser parser(parse_info());
84 parser.InitializeEmptyScopeChain(parse_info());
85 parser.ParseOnBackground(parse_info(), 0, 0, kFunctionLiteralIdTopLevel);
86 }
87
88 parse_info()->ast_value_factory()->Internalize(local_isolate());
89 DeclarationScope::AllocateScopeInfos(parse_info(), local_isolate());
90
91 script_ = parse_info_.CreateScript(local_isolate(),
92 local_factory()->empty_string(),
93 kNullMaybeHandle, ScriptOriginOptions());
94
95 // Create the SFI list on the script so that SFI SetScript works.
96 Handle<WeakFixedArray> infos = local_factory()->NewWeakFixedArray(
97 parse_info()->max_function_literal_id() + 1, AllocationType::kOld);
98 script_->set_shared_function_infos(*infos);
99
100 return parse_info()->literal();
101 }
102
parse_info()103 ParseInfo* parse_info() { return &parse_info_; }
104
script()105 Handle<Script> script() { return script_; }
106
local_isolate()107 LocalIsolate* local_isolate() { return local_isolate_; }
local_factory()108 LocalFactory* local_factory() { return local_isolate()->factory(); }
109
110 private:
111 SaveFlags save_flags_;
112 UnoptimizedCompileState state_;
113 ParseInfo parse_info_;
114 LocalIsolate* local_isolate_;
115 Handle<String> source_string_;
116 Handle<Script> script_;
117 };
118
TEST_F(LocalFactoryTest,OneByteInternalizedString_IsAddedToStringTable)119 TEST_F(LocalFactoryTest, OneByteInternalizedString_IsAddedToStringTable) {
120 base::Vector<const uint8_t> string_vector = base::StaticOneByteVector("foo");
121
122 Handle<String> string;
123 {
124 LocalHandleScope handle_scope(local_isolate());
125
126 Handle<String> local_string =
127 local_factory()->InternalizeString(string_vector);
128
129 string = local_isolate()->heap()->NewPersistentHandle(local_string);
130 }
131
132 EXPECT_TRUE(string->IsOneByteEqualTo(base::CStrVector("foo")));
133 EXPECT_TRUE(string->IsInternalizedString());
134
135 Handle<String> same_string = isolate()
136 ->factory()
137 ->NewStringFromOneByte(string_vector)
138 .ToHandleChecked();
139 EXPECT_NE(*string, *same_string);
140 EXPECT_FALSE(same_string->IsInternalizedString());
141
142 Handle<String> internalized_string =
143 isolate()->factory()->InternalizeString(same_string);
144 EXPECT_EQ(*string, *internalized_string);
145 }
146
TEST_F(LocalFactoryTest,OneByteInternalizedString_DuplicateIsDeduplicated)147 TEST_F(LocalFactoryTest, OneByteInternalizedString_DuplicateIsDeduplicated) {
148 base::Vector<const uint8_t> string_vector = base::StaticOneByteVector("foo");
149
150 Handle<String> string_1;
151 Handle<String> string_2;
152 {
153 LocalHandleScope handle_scope(local_isolate());
154
155 Handle<String> local_string_1 =
156 local_factory()->InternalizeString(string_vector);
157 Handle<String> local_string_2 =
158 local_factory()->InternalizeString(string_vector);
159
160 string_1 = local_isolate()->heap()->NewPersistentHandle(local_string_1);
161 string_2 = local_isolate()->heap()->NewPersistentHandle(local_string_2);
162 }
163
164 EXPECT_TRUE(string_1->IsOneByteEqualTo(base::CStrVector("foo")));
165 EXPECT_TRUE(string_1->IsInternalizedString());
166 EXPECT_EQ(*string_1, *string_2);
167 }
168
TEST_F(LocalFactoryTest,AstRawString_IsInternalized)169 TEST_F(LocalFactoryTest, AstRawString_IsInternalized) {
170 AstValueFactory ast_value_factory(zone(), isolate()->ast_string_constants(),
171 HashSeed(isolate()));
172
173 const AstRawString* raw_string = ast_value_factory.GetOneByteString("foo");
174
175 Handle<String> string;
176 {
177 LocalHandleScope handle_scope(local_isolate());
178
179 ast_value_factory.Internalize(local_isolate());
180
181 string = local_isolate()->heap()->NewPersistentHandle(raw_string->string());
182 }
183
184 EXPECT_TRUE(string->IsOneByteEqualTo(base::CStrVector("foo")));
185 EXPECT_TRUE(string->IsInternalizedString());
186 }
187
TEST_F(LocalFactoryTest,AstConsString_CreatesConsString)188 TEST_F(LocalFactoryTest, AstConsString_CreatesConsString) {
189 AstValueFactory ast_value_factory(zone(), isolate()->ast_string_constants(),
190 HashSeed(isolate()));
191
192 Handle<String> string;
193 {
194 LocalHandleScope handle_scope(local_isolate());
195
196 const AstRawString* foo_string = ast_value_factory.GetOneByteString("foo");
197 const AstRawString* bar_string =
198 ast_value_factory.GetOneByteString("bar-plus-padding-for-length");
199 AstConsString* foobar_string =
200 ast_value_factory.NewConsString(foo_string, bar_string);
201
202 ast_value_factory.Internalize(local_isolate());
203
204 string = local_isolate()->heap()->NewPersistentHandle(
205 foobar_string->GetString(local_isolate()));
206 }
207
208 EXPECT_TRUE(string->IsConsString());
209 EXPECT_TRUE(string->Equals(*isolate()->factory()->NewStringFromStaticChars(
210 "foobar-plus-padding-for-length")));
211 }
212
TEST_F(LocalFactoryTest,EmptyScript)213 TEST_F(LocalFactoryTest, EmptyScript) {
214 FunctionLiteral* program = ParseProgram("");
215
216 Handle<SharedFunctionInfo> shared;
217 {
218 LocalHandleScope handle_scope(local_isolate());
219
220 shared = local_isolate()->heap()->NewPersistentHandle(
221 local_factory()->NewSharedFunctionInfoForLiteral(program, script(),
222 true));
223 }
224 Handle<SharedFunctionInfo> root_sfi = shared;
225
226 EXPECT_EQ(root_sfi->function_literal_id(), 0);
227 }
228
TEST_F(LocalFactoryTest,LazyFunction)229 TEST_F(LocalFactoryTest, LazyFunction) {
230 FunctionLiteral* program = ParseProgram("function lazy() {}");
231 FunctionLiteral* lazy = program->scope()
232 ->declarations()
233 ->AtForTest(0)
234 ->AsFunctionDeclaration()
235 ->fun();
236
237 Handle<SharedFunctionInfo> shared;
238 {
239 LocalHandleScope handle_scope(local_isolate());
240
241 shared = local_isolate()->heap()->NewPersistentHandle(
242 local_factory()->NewSharedFunctionInfoForLiteral(lazy, script(), true));
243 }
244 Handle<SharedFunctionInfo> lazy_sfi = shared;
245
246 EXPECT_EQ(lazy_sfi->function_literal_id(), 1);
247 EXPECT_TRUE(lazy_sfi->Name().IsOneByteEqualTo(base::CStrVector("lazy")));
248 EXPECT_FALSE(lazy_sfi->is_compiled());
249 EXPECT_TRUE(lazy_sfi->HasUncompiledDataWithoutPreparseData());
250 }
251
TEST_F(LocalFactoryTest,EagerFunction)252 TEST_F(LocalFactoryTest, EagerFunction) {
253 FunctionLiteral* program = ParseProgram("(function eager() {})");
254 // Rewritten to `.result = (function eager() {}); return .result`
255 FunctionLiteral* eager = program->body()
256 ->at(0)
257 ->AsExpressionStatement()
258 ->expression()
259 ->AsAssignment()
260 ->value()
261 ->AsFunctionLiteral();
262
263 Handle<SharedFunctionInfo> shared;
264 {
265 LocalHandleScope handle_scope(local_isolate());
266
267 shared = local_isolate()->heap()->NewPersistentHandle(
268 local_factory()->NewSharedFunctionInfoForLiteral(eager, script(),
269 true));
270 }
271 Handle<SharedFunctionInfo> eager_sfi = shared;
272
273 EXPECT_EQ(eager_sfi->function_literal_id(), 1);
274 EXPECT_TRUE(eager_sfi->Name().IsOneByteEqualTo(base::CStrVector("eager")));
275 EXPECT_FALSE(eager_sfi->HasUncompiledData());
276 // TODO(leszeks): Add compilation support and enable these checks.
277 // EXPECT_TRUE(eager_sfi->is_compiled());
278 // EXPECT_TRUE(eager_sfi->HasBytecodeArray());
279 }
280
TEST_F(LocalFactoryTest,ImplicitNameFunction)281 TEST_F(LocalFactoryTest, ImplicitNameFunction) {
282 FunctionLiteral* program = ParseProgram("let implicit_name = function() {}");
283 FunctionLiteral* implicit_name = program->body()
284 ->at(0)
285 ->AsBlock()
286 ->statements()
287 ->at(0)
288 ->AsExpressionStatement()
289 ->expression()
290 ->AsAssignment()
291 ->value()
292 ->AsFunctionLiteral();
293
294 Handle<SharedFunctionInfo> shared;
295 {
296 LocalHandleScope handle_scope(local_isolate());
297
298 shared = local_isolate()->heap()->NewPersistentHandle(
299 local_factory()->NewSharedFunctionInfoForLiteral(implicit_name,
300 script(), true));
301 }
302 Handle<SharedFunctionInfo> implicit_name_sfi = shared;
303
304 EXPECT_EQ(implicit_name_sfi->function_literal_id(), 1);
305 EXPECT_TRUE(implicit_name_sfi->Name().IsOneByteEqualTo(
306 base::CStrVector("implicit_name")));
307 }
308
TEST_F(LocalFactoryTest,GCDuringPublish)309 TEST_F(LocalFactoryTest, GCDuringPublish) {
310 FunctionLiteral* program = ParseProgram("let implicit_name = function() {}");
311 FunctionLiteral* implicit_name = program->body()
312 ->at(0)
313 ->AsBlock()
314 ->statements()
315 ->at(0)
316 ->AsExpressionStatement()
317 ->expression()
318 ->AsAssignment()
319 ->value()
320 ->AsFunctionLiteral();
321
322 Handle<SharedFunctionInfo> shared;
323 {
324 LocalHandleScope handle_scope(local_isolate());
325
326 shared = local_isolate()->heap()->NewPersistentHandle(
327 local_factory()->NewSharedFunctionInfoForLiteral(implicit_name,
328 script(), true));
329 }
330 Handle<SharedFunctionInfo> implicit_name_sfi = shared;
331
332 EXPECT_EQ(implicit_name_sfi->function_literal_id(), 1);
333 EXPECT_TRUE(implicit_name_sfi->Name().IsOneByteEqualTo(
334 base::CStrVector("implicit_name")));
335 }
336
337 } // namespace internal
338 } // namespace v8
339