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