Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
object_test.cc
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#include <limits>
6#include <memory>
7
8#include "include/dart_api.h"
9
10#include "bin/builtin.h"
11#include "bin/vmservice_impl.h"
12
13#include "platform/globals.h"
14
15#include "vm/class_finalizer.h"
17#include "vm/code_descriptors.h"
22#include "vm/dart_api_impl.h"
23#include "vm/dart_entry.h"
24#include "vm/debugger.h"
26#include "vm/flags.h"
27#include "vm/isolate.h"
28#include "vm/message_handler.h"
29#include "vm/object.h"
30#include "vm/object_store.h"
31#include "vm/resolver.h"
32#include "vm/simulator.h"
33#include "vm/symbols.h"
34#include "vm/tagged_pointer.h"
35#include "vm/unit_test.h"
36#include "vm/zone_text_buffer.h"
37
38namespace dart {
39
40#define Z (thread->zone())
41
42DECLARE_FLAG(bool, write_protect_code);
43
44static ClassPtr CreateDummyClass(const String& class_name,
45 const Script& script) {
46 const Class& cls = Class::Handle(Class::New(
47 Library::Handle(), class_name, script, TokenPosition::kNoSource));
48 cls.set_is_synthesized_class_unsafe(); // Dummy class for testing.
50 return cls.ptr();
51}
52
54 // Allocate the class first.
55 const String& class_name = String::Handle(Symbols::New(thread, "MyClass"));
56 const Script& script = Script::Handle();
57 const Class& cls = Class::Handle(CreateDummyClass(class_name, script));
58
59 // Class has no fields and no functions yet.
60 EXPECT_EQ(Array::Handle(cls.fields()).Length(), 0);
61 EXPECT_EQ(Array::Handle(cls.current_functions()).Length(), 0);
62
63 // Setup the interfaces in the class.
64 // Normally the class finalizer is resolving super types and interfaces
65 // before finalizing the types in a class. A side-effect of this is setting
66 // the is_implemented() bit on a class. We do that manually here.
67 const Array& interfaces = Array::Handle(Array::New(2));
68 Class& interface = Class::Handle();
69 String& interface_name = String::Handle();
70 interface_name = Symbols::New(thread, "Harley");
71 interface = CreateDummyClass(interface_name, script);
72 interfaces.SetAt(0, Type::Handle(Type::NewNonParameterizedType(interface)));
73 interface.set_is_implemented_unsafe();
74 interface_name = Symbols::New(thread, "Norton");
75 interface = CreateDummyClass(interface_name, script);
76 interfaces.SetAt(1, Type::Handle(Type::NewNonParameterizedType(interface)));
77 interface.set_is_implemented_unsafe();
78 cls.set_interfaces(interfaces);
79
80 // Finalization of types happens before the fields and functions have been
81 // parsed.
83
84 // Create and populate the function arrays.
85 const Array& functions = Array::Handle(Array::New(6));
89 function_name = Symbols::New(thread, "foo");
90 signature = FunctionType::New();
92 UntaggedFunction::kRegularFunction, false, false,
93 false, false, false, cls, TokenPosition::kMinSource);
94 functions.SetAt(0, function);
95 function_name = Symbols::New(thread, "bar");
96 signature = FunctionType::New();
98 UntaggedFunction::kRegularFunction, false, false,
99 false, false, false, cls, TokenPosition::kMinSource);
100
101 const int kNumFixedParameters = 2;
102 const int kNumOptionalParameters = 3;
103 const bool kAreOptionalPositional = true;
104 signature.set_num_fixed_parameters(kNumFixedParameters);
105 signature.SetNumOptionalParameters(kNumOptionalParameters,
106 kAreOptionalPositional);
107 functions.SetAt(1, function);
108
109 function_name = Symbols::New(thread, "baz");
110 signature = FunctionType::New();
112 UntaggedFunction::kRegularFunction, false, false,
113 false, false, false, cls, TokenPosition::kMinSource);
114 functions.SetAt(2, function);
115
116 function_name = Symbols::New(thread, "Foo");
117 signature = FunctionType::New();
119 UntaggedFunction::kRegularFunction, true, false,
120 false, false, false, cls, TokenPosition::kMinSource);
121
122 functions.SetAt(3, function);
123 function_name = Symbols::New(thread, "Bar");
124 signature = FunctionType::New();
126 UntaggedFunction::kRegularFunction, true, false,
127 false, false, false, cls, TokenPosition::kMinSource);
128 functions.SetAt(4, function);
129 function_name = Symbols::New(thread, "BaZ");
130 signature = FunctionType::New();
132 UntaggedFunction::kRegularFunction, true, false,
133 false, false, false, cls, TokenPosition::kMinSource);
134 functions.SetAt(5, function);
135
136 // Setup the functions in the class.
137 {
138 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
139 cls.SetFunctions(functions);
140 // The class can now be finalized.
141 cls.Finalize();
142 }
143
144 function_name = String::New("Foo");
146 EXPECT(function.IsNull());
148 EXPECT(!function.IsNull());
150 EXPECT_EQ(cls.ptr(), function.Owner());
151 EXPECT(function.is_static());
152 function_name = String::New("baz");
154 EXPECT(!function.IsNull());
156 EXPECT_EQ(cls.ptr(), function.Owner());
157 EXPECT(!function.is_static());
159 EXPECT(function.IsNull());
160
161 function_name = String::New("foo");
163 EXPECT(!function.IsNull());
164 EXPECT_EQ(0, function.num_fixed_parameters());
165 EXPECT(!function.HasOptionalParameters());
166
167 function_name = String::New("bar");
169 EXPECT(!function.IsNull());
170 EXPECT_EQ(kNumFixedParameters, function.num_fixed_parameters());
171 EXPECT_EQ(kNumOptionalParameters, function.NumOptionalParameters());
172}
173
174ISOLATE_UNIT_TEST_CASE(SixtyThousandDartClasses) {
175 auto zone = thread->zone();
176 auto isolate_group = thread->isolate_group();
177 auto class_table = isolate_group->class_table();
178
179 const intptr_t start_cid = class_table->NumCids();
180 const intptr_t num_classes = std::numeric_limits<uint16_t>::max() - start_cid;
181
182 const Script& script = Script::Handle(zone);
183 String& name = String::Handle(zone);
184 Class& cls = Class::Handle(zone);
185 Field& field = Field::Handle(zone);
186 Array& fields = Array::Handle(zone);
188 Instance& instance2 = Instance::Handle(zone);
189
190 const auto& instances =
192
193 // Create many top-level classes - they should not consume 16-bit range.
194 {
195 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
196 for (intptr_t i = 0; i < (1 << 16); ++i) {
197 cls = CreateDummyClass(Symbols::TopLevel(), script);
198 cls.Finalize();
199 EXPECT(cls.id() > std::numeric_limits<uint16_t>::max());
200 }
201 }
202
203 // Create many concrete classes - they should occupy the entire 16-bit space.
204 for (intptr_t i = 0; i < num_classes; ++i) {
205 name = Symbols::New(thread, OS::SCreate(zone, "MyClass%" Pd "", i));
206 cls = CreateDummyClass(name, script);
207 EXPECT_EQ(start_cid + i, cls.id());
208
209 const intptr_t num_fields = (i % 10);
210 fields = Array::New(num_fields);
211 for (intptr_t f = 0; f < num_fields; ++f) {
212 name =
213 Symbols::New(thread, OS::SCreate(zone, "myField_%" Pd "_%" Pd, i, f));
214 field = Field::New(name, false, false, false, true, false, cls,
215 Object::dynamic_type(), TokenPosition::kMinSource,
217 fields.SetAt(f, field);
218 }
219
220 cls.set_interfaces(Array::empty_array());
221 {
222 SafepointWriteRwLocker ml(thread,
223 thread->isolate_group()->program_lock());
224 cls.SetFunctions(Array::empty_array());
225 cls.SetFields(fields);
226 cls.Finalize();
227 }
228
229 instance = Instance::New(cls);
230 for (intptr_t f = 0; f < num_fields; ++f) {
231 field ^= fields.At(f);
232 name = Symbols::New(thread,
233 OS::SCreate(zone, "myFieldValue_%" Pd "_%" Pd, i, f));
234 instance.SetField(field, name);
235 }
236 instances.Add(instance);
237 }
238 EXPECT_EQ((1 << 16) - 1, class_table->NumCids());
239
240 // Ensure GC runs and can recognize all those new instances.
241 isolate_group->heap()->CollectAllGarbage();
242
243 // Ensure the instances are what we expect.
244 for (intptr_t i = 0; i < num_classes; ++i) {
245 instance ^= instances.At(i);
246 cls = instance.clazz();
247 fields = cls.fields();
248
249 name = cls.Name();
250 EXPECT(strstr(name.ToCString(), OS::SCreate(zone, "MyClass%" Pd "", i)) !=
251 0);
252 EXPECT_EQ((i % 10), fields.Length());
253
254 for (intptr_t f = 0; f < fields.Length(); ++f) {
255 field ^= fields.At(f);
256 instance2 ^= instance.GetField(field);
257 EXPECT(strstr(instance2.ToCString(),
258 OS::SCreate(zone, "myFieldValue_%" Pd "_%" Pd, i, f)) != 0);
259 }
260 }
261}
262
264 const Type& type1 = Type::Handle(Type::Double());
265 const Type& type2 = Type::Handle(Type::StringType());
266 const TypeArguments& type_arguments1 =
268 type_arguments1.SetTypeAt(0, type1);
269 type_arguments1.SetTypeAt(1, type2);
270 const TypeArguments& type_arguments2 =
272 type_arguments2.SetTypeAt(0, type1);
273 type_arguments2.SetTypeAt(1, type2);
274 EXPECT_NE(type_arguments1.ptr(), type_arguments2.ptr());
275 OS::PrintErr("1: %s\n", type_arguments1.ToCString());
276 OS::PrintErr("2: %s\n", type_arguments2.ToCString());
277 EXPECT(type_arguments1.Equals(type_arguments2));
278 TypeArguments& type_arguments3 = TypeArguments::Handle();
279 type_arguments1.Canonicalize(thread);
280 type_arguments3 ^= type_arguments2.Canonicalize(thread);
281 EXPECT_EQ(type_arguments1.ptr(), type_arguments3.ptr());
282}
283
284TEST_CASE(Class_EndTokenPos) {
285 const char* kScript =
286 "\n"
287 "class A {\n"
288 " /**\n"
289 " * Description of foo().\n"
290 " */\n"
291 " foo(a) { return '''\"}'''; }\n"
292 " // }\n"
293 " var bar = '\\'}';\n"
294 "}\n";
295 Dart_Handle lib_h = TestCase::LoadTestScript(kScript, nullptr);
296 EXPECT_VALID(lib_h);
297 TransitionNativeToVM transition(thread);
298 Library& lib = Library::Handle();
299 lib ^= Api::UnwrapHandle(lib_h);
300 EXPECT(!lib.IsNull());
301 const Class& cls =
303 EXPECT(!cls.IsNull());
304 const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
305 EXPECT(error.IsNull());
306 const TokenPosition end_token_pos = cls.end_token_pos();
307 const Script& scr = Script::Handle(cls.script());
308 intptr_t line;
309 intptr_t col;
310 EXPECT(scr.GetTokenLocation(end_token_pos, &line, &col));
311 EXPECT_EQ(9, line);
312 EXPECT_EQ(1, col);
313}
314
316 // Allocate the class first.
317 String& class_name = String::Handle(Symbols::New(thread, "EmptyClass"));
318 Script& script = Script::Handle();
319 const Class& empty_class =
321
322 // EmptyClass has no fields and no functions.
323 EXPECT_EQ(Array::Handle(empty_class.fields()).Length(), 0);
324 EXPECT_EQ(Array::Handle(empty_class.current_functions()).Length(), 0);
325
327 {
328 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
329 empty_class.Finalize();
330 }
331
332 EXPECT_EQ(kObjectAlignment, empty_class.host_instance_size());
334 EXPECT_EQ(empty_class.ptr(), instance.clazz());
335
336 class_name = Symbols::New(thread, "OneFieldClass");
337 const Class& one_field_class =
339
340 // No fields, functions, or super type for the OneFieldClass.
341 EXPECT_EQ(Array::Handle(empty_class.fields()).Length(), 0);
342 EXPECT_EQ(Array::Handle(empty_class.current_functions()).Length(), 0);
343 EXPECT_EQ(empty_class.super_type(), AbstractType::null());
345
346 const Array& one_fields = Array::Handle(Array::New(1));
347 const String& field_name = String::Handle(Symbols::New(thread, "the_field"));
348 const Field& field = Field::Handle(
349 Field::New(field_name, false, false, false, true, false, one_field_class,
350 Object::dynamic_type(), TokenPosition::kMinSource,
352 one_fields.SetAt(0, field);
353 {
354 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
355 one_field_class.SetFields(one_fields);
356 one_field_class.Finalize();
357 }
358 intptr_t header_size = sizeof(UntaggedObject);
359 EXPECT_EQ(Utils::RoundUp((header_size + (1 * kWordSize)), kObjectAlignment),
360 one_field_class.host_instance_size());
361 EXPECT_EQ(header_size, field.HostOffset());
362 EXPECT(!one_field_class.is_implemented());
363 one_field_class.set_is_implemented_unsafe();
364 EXPECT(one_field_class.is_implemented());
365}
366
368 const Smi& smi = Smi::Handle(Smi::New(5));
369 Object& smi_object = Object::Handle(smi.ptr());
370 EXPECT(smi.IsSmi());
371 EXPECT(smi_object.IsSmi());
372 EXPECT_EQ(5, smi.Value());
373 const Object& object = Object::Handle();
374 EXPECT(!object.IsSmi());
375 smi_object = Object::null();
376 EXPECT(!smi_object.IsSmi());
377
380 EXPECT(smi.Equals(smi));
381 EXPECT(!smi.Equals(Smi::Handle()));
382
384 EXPECT(Smi::IsValid(-15));
385 EXPECT(Smi::IsValid(0xFFu));
386// Upper two bits must be either 00 or 11.
387#if defined(ARCH_IS_64_BIT) && !defined(DART_COMPRESSED_POINTERS)
389 EXPECT(Smi::IsValid(0x3FFFFFFFFFFFFFFF));
390 EXPECT(Smi::IsValid(-1));
391#else
393 EXPECT(Smi::IsValid(0x3FFFFFFF));
394 EXPECT(Smi::IsValid(-1));
395 EXPECT(!Smi::IsValid(0xFFFFFFFFu));
396#endif
397
398 EXPECT_EQ(5, smi.AsInt64Value());
399 EXPECT_EQ(5.0, smi.AsDoubleValue());
400
401 Smi& a = Smi::Handle(Smi::New(5));
402 Smi& b = Smi::Handle(Smi::New(3));
403 EXPECT_EQ(1, a.CompareWith(b));
404 EXPECT_EQ(-1, b.CompareWith(a));
405 EXPECT_EQ(0, a.CompareWith(a));
406
407 Smi& c = Smi::Handle(Smi::New(-1));
408
409 Mint& mint1 = Mint::Handle();
410 mint1 ^= Integer::New(DART_2PART_UINT64_C(0x7FFFFFFF, 100));
411 Mint& mint2 = Mint::Handle();
412 mint2 ^= Integer::New(-DART_2PART_UINT64_C(0x7FFFFFFF, 100));
413 EXPECT_EQ(-1, a.CompareWith(mint1));
414 EXPECT_EQ(1, a.CompareWith(mint2));
415 EXPECT_EQ(-1, c.CompareWith(mint1));
416 EXPECT_EQ(1, c.CompareWith(mint2));
417}
418
419ISOLATE_UNIT_TEST_CASE(StringCompareTo) {
420 const String& abcd = String::Handle(String::New("abcd"));
421 const String& abce = String::Handle(String::New("abce"));
422 EXPECT_EQ(0, abcd.CompareTo(abcd));
423 EXPECT_EQ(0, abce.CompareTo(abce));
424 EXPECT(abcd.CompareTo(abce) < 0);
425 EXPECT(abce.CompareTo(abcd) > 0);
426
427 const int kMonkeyLen = 4;
428 const uint8_t monkey_utf8[kMonkeyLen] = {0xf0, 0x9f, 0x90, 0xb5};
429 const String& monkey_face =
430 String::Handle(String::FromUTF8(monkey_utf8, kMonkeyLen));
431 const int kDogLen = 4;
432 // 0x1f436 DOG FACE.
433 const uint8_t dog_utf8[kDogLen] = {0xf0, 0x9f, 0x90, 0xb6};
434 const String& dog_face = String::Handle(String::FromUTF8(dog_utf8, kDogLen));
435 EXPECT_EQ(0, monkey_face.CompareTo(monkey_face));
436 EXPECT_EQ(0, dog_face.CompareTo(dog_face));
437 EXPECT(monkey_face.CompareTo(dog_face) < 0);
438 EXPECT(dog_face.CompareTo(monkey_face) > 0);
439
440 const int kDominoLen = 4;
441 // 0x1f036 DOMINO TILE HORIZONTAL-00-05.
442 const uint8_t domino_utf8[kDominoLen] = {0xf0, 0x9f, 0x80, 0xb6};
443 const String& domino =
444 String::Handle(String::FromUTF8(domino_utf8, kDominoLen));
445 EXPECT_EQ(0, domino.CompareTo(domino));
446 EXPECT(domino.CompareTo(dog_face) < 0);
447 EXPECT(domino.CompareTo(monkey_face) < 0);
448 EXPECT(dog_face.CompareTo(domino) > 0);
449 EXPECT(monkey_face.CompareTo(domino) > 0);
450
451 EXPECT(abcd.CompareTo(monkey_face) < 0);
452 EXPECT(abce.CompareTo(monkey_face) < 0);
453 EXPECT(abcd.CompareTo(domino) < 0);
454 EXPECT(abce.CompareTo(domino) < 0);
455 EXPECT(domino.CompareTo(abcd) > 0);
456 EXPECT(domino.CompareTo(abcd) > 0);
457 EXPECT(monkey_face.CompareTo(abce) > 0);
458 EXPECT(monkey_face.CompareTo(abce) > 0);
459}
460
461ISOLATE_UNIT_TEST_CASE(StringEncodeIRI) {
462 const char* kInput =
463 "file:///usr/local/johnmccutchan/workspace/dart-repo/dart/test.dart";
464 const char* kOutput =
465 "file%3A%2F%2F%2Fusr%2Flocal%2Fjohnmccutchan%2Fworkspace%2F"
466 "dart-repo%2Fdart%2Ftest.dart";
467 const String& input = String::Handle(String::New(kInput));
468 const char* encoded = String::EncodeIRI(input);
469 EXPECT(strcmp(encoded, kOutput) == 0);
470}
471
472ISOLATE_UNIT_TEST_CASE(StringDecodeIRI) {
473 const char* kOutput =
474 "file:///usr/local/johnmccutchan/workspace/dart-repo/dart/test.dart";
475 const char* kInput =
476 "file%3A%2F%2F%2Fusr%2Flocal%2Fjohnmccutchan%2Fworkspace%2F"
477 "dart-repo%2Fdart%2Ftest.dart";
478 const String& input = String::Handle(String::New(kInput));
479 const String& output = String::Handle(String::New(kOutput));
480 const String& decoded = String::Handle(String::DecodeIRI(input));
481 EXPECT(output.Equals(decoded));
482}
483
484ISOLATE_UNIT_TEST_CASE(StringDecodeIRIInvalid) {
485 String& input = String::Handle();
486 input = String::New("file%");
487 String& decoded = String::Handle();
488 decoded = String::DecodeIRI(input);
489 EXPECT(decoded.IsNull());
490 input = String::New("file%3");
491 decoded = String::DecodeIRI(input);
492 EXPECT(decoded.IsNull());
493 input = String::New("file%3g");
494 decoded = String::DecodeIRI(input);
495 EXPECT(decoded.IsNull());
496}
497
498ISOLATE_UNIT_TEST_CASE(StringIRITwoByte) {
499 const intptr_t kInputLen = 3;
500 const uint16_t kInput[kInputLen] = {'x', '/', 256};
501 const String& input = String::Handle(String::FromUTF16(kInput, kInputLen));
502 const intptr_t kOutputLen = 10;
503 const uint16_t kOutput[kOutputLen] = {'x', '%', '2', 'F', '%',
504 'C', '4', '%', '8', '0'};
505 const String& output = String::Handle(String::FromUTF16(kOutput, kOutputLen));
506 const String& encoded = String::Handle(String::New(String::EncodeIRI(input)));
507 EXPECT(output.Equals(encoded));
508 const String& decoded = String::Handle(String::DecodeIRI(output));
509 EXPECT(input.Equals(decoded));
510}
511
513// On 64-bit architectures a Smi is stored in a 64 bit word. A Midint cannot
514// be allocated if it does fit into a Smi.
515#if !defined(ARCH_IS_64_BIT) || defined(DART_COMPRESSED_POINTERS)
516 {
517 Mint& med = Mint::Handle();
518 EXPECT(med.IsNull());
519 int64_t v = DART_2PART_UINT64_C(1, 0);
520 med ^= Integer::New(v);
521 EXPECT_EQ(v, med.value());
522 const String& smi_str = String::Handle(String::New("1"));
523 const String& mint1_str = String::Handle(String::New("2147419168"));
524 const String& mint2_str = String::Handle(String::New("-2147419168"));
526 EXPECT(i.IsSmi());
527 i = Integer::NewCanonical(mint1_str);
528 EXPECT(i.IsMint());
529 EXPECT(!i.IsZero());
530 EXPECT(!i.IsNegative());
531 i = Integer::NewCanonical(mint2_str);
532 EXPECT(i.IsMint());
533 EXPECT(!i.IsZero());
534 EXPECT(i.IsNegative());
535 }
537 EXPECT(i.IsMint());
538 EXPECT(!i.IsZero());
539 EXPECT(!i.IsNegative());
541 Mint& i2 = Mint::Handle();
542 i2 ^= Integer::New(DART_2PART_UINT64_C(1010, 0));
543 EXPECT(i1.Equals(i2));
544 EXPECT(!i.Equals(i1));
545 int64_t test = DART_2PART_UINT64_C(1010, 0);
546 EXPECT_EQ(test, i2.value());
547
548 Mint& a = Mint::Handle();
550 Mint& b = Mint::Handle();
552 EXPECT_EQ(1, a.CompareWith(b));
553 EXPECT_EQ(-1, b.CompareWith(a));
554 EXPECT_EQ(0, a.CompareWith(a));
555
556 Mint& c = Mint::Handle();
558 Smi& smi1 = Smi::Handle(Smi::New(4));
559 Smi& smi2 = Smi::Handle(Smi::New(-4));
560 EXPECT_EQ(1, a.CompareWith(smi1));
561 EXPECT_EQ(1, a.CompareWith(smi2));
562 EXPECT_EQ(-1, c.CompareWith(smi1));
563 EXPECT_EQ(-1, c.CompareWith(smi2));
564
565 int64_t mint_value = DART_2PART_UINT64_C(0x7FFFFFFF, 64);
566 const String& mint_string = String::Handle(String::New("0x7FFFFFFF00000064"));
567 Mint& mint1 = Mint::Handle();
568 mint1 ^= Integer::NewCanonical(mint_string);
569 Mint& mint2 = Mint::Handle();
570 mint2 ^= Integer::NewCanonical(mint_string);
571 EXPECT_EQ(mint1.value(), mint_value);
572 EXPECT_EQ(mint2.value(), mint_value);
573 EXPECT_EQ(mint1.ptr(), mint2.ptr());
574#endif
575}
576
578 {
579 const double dbl_const = 5.0;
580 const Double& dbl = Double::Handle(Double::New(dbl_const));
581 Object& dbl_object = Object::Handle(dbl.ptr());
582 EXPECT(dbl.IsDouble());
583 EXPECT(dbl_object.IsDouble());
584 EXPECT_EQ(dbl_const, dbl.value());
585 }
586
587 {
588 const double dbl_const = -5.0;
589 const Double& dbl = Double::Handle(Double::New(dbl_const));
590 Object& dbl_object = Object::Handle(dbl.ptr());
591 EXPECT(dbl.IsDouble());
592 EXPECT(dbl_object.IsDouble());
593 EXPECT_EQ(dbl_const, dbl.value());
594 }
595
596 {
597 const double dbl_const = 0.0;
598 const Double& dbl = Double::Handle(Double::New(dbl_const));
599 Object& dbl_object = Object::Handle(dbl.ptr());
600 EXPECT(dbl.IsDouble());
601 EXPECT(dbl_object.IsDouble());
602 EXPECT_EQ(dbl_const, dbl.value());
603 }
604
605 {
606 const double dbl_const = 5.0;
607 const String& dbl_str = String::Handle(String::New("5.0"));
608 const Double& dbl1 = Double::Handle(Double::NewCanonical(dbl_const));
609 const Double& dbl2 = Double::Handle(Double::NewCanonical(dbl_const));
610 const Double& dbl3 = Double::Handle(Double::NewCanonical(dbl_str));
611 EXPECT_EQ(dbl_const, dbl1.value());
612 EXPECT_EQ(dbl_const, dbl2.value());
613 EXPECT_EQ(dbl_const, dbl3.value());
614 EXPECT_EQ(dbl1.ptr(), dbl2.ptr());
615 EXPECT_EQ(dbl1.ptr(), dbl3.ptr());
616 }
617
618 {
619 const double dbl_const = 2.0;
620 const Double& dbl1 = Double::Handle(Double::New(dbl_const));
621 const Double& dbl2 = Double::Handle(Double::New(dbl_const));
622 EXPECT(dbl1.OperatorEquals(dbl2));
623 EXPECT(dbl1.IsIdenticalTo(dbl2));
624 EXPECT(dbl1.CanonicalizeEquals(dbl2));
625 const Double& dbl3 = Double::Handle(Double::New(3.3));
626 EXPECT(!dbl1.OperatorEquals(dbl3));
629 const Double& nan0 = Double::Handle(Double::New(NAN));
630 EXPECT(isnan(nan0.value()));
631 EXPECT(nan0.IsIdenticalTo(nan0));
632 EXPECT(nan0.CanonicalizeEquals(nan0));
633 EXPECT(!nan0.OperatorEquals(nan0));
634 const Double& nan1 =
635 Double::Handle(Double::New(bit_cast<double>(kMaxUint64 - 0)));
636 const Double& nan2 =
637 Double::Handle(Double::New(bit_cast<double>(kMaxUint64 - 1)));
638 EXPECT(isnan(nan1.value()));
639 EXPECT(isnan(nan2.value()));
640 EXPECT(!nan1.IsIdenticalTo(nan2));
641 EXPECT(!nan1.CanonicalizeEquals(nan2));
642 EXPECT(!nan1.OperatorEquals(nan2));
643 }
644 {
645 const String& dbl_str0 = String::Handle(String::New("bla"));
646 const Double& dbl0 = Double::Handle(Double::New(dbl_str0));
647 EXPECT(dbl0.IsNull());
648
649 const String& dbl_str1 = String::Handle(String::New("2.0"));
650 const Double& dbl1 = Double::Handle(Double::New(dbl_str1));
651 EXPECT_EQ(2.0, dbl1.value());
652
653 // Disallow legacy form.
654 const String& dbl_str2 = String::Handle(String::New("2.0d"));
655 const Double& dbl2 = Double::Handle(Double::New(dbl_str2));
656 EXPECT(dbl2.IsNull());
657 }
658}
659
663 EXPECT(i.IsSmi());
665 EXPECT(i.IsSmi());
667 EXPECT(i.IsSmi());
669 String::Handle(String::New("12345678901234567890")));
670 EXPECT(i.IsNull());
672 String::Handle(String::New("-12345678901234567890111222")));
673 EXPECT(i.IsNull());
674}
675
677 const char* kHello = "Hello World!";
678 int32_t hello_len = strlen(kHello);
679 const String& str = String::Handle(String::New(kHello));
680 EXPECT(str.IsInstance());
681 EXPECT(str.IsString());
682 EXPECT(str.IsOneByteString());
683 EXPECT(!str.IsTwoByteString());
684 EXPECT(!str.IsNumber());
685 EXPECT_EQ(hello_len, str.Length());
686 EXPECT_EQ('H', str.CharAt(0));
687 EXPECT_EQ('e', str.CharAt(1));
688 EXPECT_EQ('l', str.CharAt(2));
689 EXPECT_EQ('l', str.CharAt(3));
690 EXPECT_EQ('o', str.CharAt(4));
691 EXPECT_EQ(' ', str.CharAt(5));
692 EXPECT_EQ('W', str.CharAt(6));
693 EXPECT_EQ('o', str.CharAt(7));
694 EXPECT_EQ('r', str.CharAt(8));
695 EXPECT_EQ('l', str.CharAt(9));
696 EXPECT_EQ('d', str.CharAt(10));
697 EXPECT_EQ('!', str.CharAt(11));
698
699 const uint8_t* motto =
700 reinterpret_cast<const uint8_t*>("Dart's bescht wos je hets gits");
701 const String& str2 = String::Handle(String::FromUTF8(motto + 7, 4));
702 EXPECT_EQ(4, str2.Length());
703 EXPECT_EQ('b', str2.CharAt(0));
704 EXPECT_EQ('e', str2.CharAt(1));
705 EXPECT_EQ('s', str2.CharAt(2));
706 EXPECT_EQ('c', str2.CharAt(3));
707
708 const String& str3 = String::Handle(String::New(kHello));
709 EXPECT(str.Equals(str));
710 EXPECT_EQ(str.Hash(), str.Hash());
711 EXPECT(!str.Equals(str2));
712 EXPECT(str.Equals(str3));
713 EXPECT_EQ(str.Hash(), str3.Hash());
714 EXPECT(str3.Equals(str));
715
716 const String& str4 = String::Handle(String::New("foo"));
717 const String& str5 = String::Handle(String::New("bar"));
718 const String& str6 = String::Handle(String::Concat(str4, str5));
719 const String& str7 = String::Handle(String::New("foobar"));
720 EXPECT(str6.Equals(str7));
721 EXPECT(!str6.Equals(Smi::Handle(Smi::New(4))));
722
723 const String& empty1 = String::Handle(String::New(""));
724 const String& empty2 = String::Handle(String::New(""));
725 EXPECT(empty1.Equals(empty2, 0, 0));
726
727 const intptr_t kCharsLen = 8;
728 const uint8_t chars[kCharsLen] = {1, 2, 127, 64, 92, 0, 55, 55};
729 const String& str8 = String::Handle(String::FromUTF8(chars, kCharsLen));
730 EXPECT_EQ(kCharsLen, str8.Length());
731 EXPECT_EQ(1, str8.CharAt(0));
732 EXPECT_EQ(127, str8.CharAt(2));
733 EXPECT_EQ(64, str8.CharAt(3));
734 EXPECT_EQ(0, str8.CharAt(5));
735 EXPECT_EQ(55, str8.CharAt(6));
736 EXPECT_EQ(55, str8.CharAt(7));
737 const intptr_t kCharsIndex = 3;
738 const String& sub1 = String::Handle(String::SubString(str8, kCharsIndex));
739 EXPECT_EQ((kCharsLen - kCharsIndex), sub1.Length());
740 EXPECT_EQ(64, sub1.CharAt(0));
741 EXPECT_EQ(92, sub1.CharAt(1));
742 EXPECT_EQ(0, sub1.CharAt(2));
743 EXPECT_EQ(55, sub1.CharAt(3));
744 EXPECT_EQ(55, sub1.CharAt(4));
745
746 const intptr_t kWideCharsLen = 7;
747 uint16_t wide_chars[kWideCharsLen] = {'H', 'e', 'l', 'l', 'o', 256, '!'};
748 const String& two_str =
749 String::Handle(String::FromUTF16(wide_chars, kWideCharsLen));
750 EXPECT(two_str.IsInstance());
751 EXPECT(two_str.IsString());
752 EXPECT(two_str.IsTwoByteString());
753 EXPECT(!two_str.IsOneByteString());
754 EXPECT_EQ(kWideCharsLen, two_str.Length());
755 EXPECT_EQ('H', two_str.CharAt(0));
756 EXPECT_EQ(256, two_str.CharAt(5));
757 const intptr_t kWideCharsIndex = 3;
758 const String& sub2 = String::Handle(String::SubString(two_str, kCharsIndex));
759 EXPECT_EQ((kWideCharsLen - kWideCharsIndex), sub2.Length());
760 EXPECT_EQ('l', sub2.CharAt(0));
761 EXPECT_EQ('o', sub2.CharAt(1));
762 EXPECT_EQ(256, sub2.CharAt(2));
763 EXPECT_EQ('!', sub2.CharAt(3));
764
765 {
766 const String& str1 = String::Handle(String::New("My.create"));
767 const String& str2 = String::Handle(String::New("My"));
768 const String& str3 = String::Handle(String::New("create"));
769 EXPECT_EQ(true, str1.StartsWith(str2));
770 EXPECT_EQ(false, str1.StartsWith(str3));
771 }
772
773 const int32_t four_chars[] = {'C', 0xFF, 'h', 0xFFFF, 'a', 0x10FFFF, 'r'};
774 const String& four_str = String::Handle(String::FromUTF32(four_chars, 7));
775 EXPECT_EQ(four_str.Hash(), four_str.Hash());
776 EXPECT(four_str.IsTwoByteString());
777 EXPECT(!four_str.IsOneByteString());
778 EXPECT_EQ(8, four_str.Length());
779 EXPECT_EQ('C', four_str.CharAt(0));
780 EXPECT_EQ(0xFF, four_str.CharAt(1));
781 EXPECT_EQ('h', four_str.CharAt(2));
782 EXPECT_EQ(0xFFFF, four_str.CharAt(3));
783 EXPECT_EQ('a', four_str.CharAt(4));
784 EXPECT_EQ(0xDBFF, four_str.CharAt(5));
785 EXPECT_EQ(0xDFFF, four_str.CharAt(6));
786 EXPECT_EQ('r', four_str.CharAt(7));
787
788 // Create a 1-byte string from an array of 2-byte elements.
789 {
790 const uint16_t char16[] = {0x00, 0x7F, 0xFF};
791 const String& str8 = String::Handle(String::FromUTF16(char16, 3));
792 EXPECT(str8.IsOneByteString());
793 EXPECT(!str8.IsTwoByteString());
794 EXPECT_EQ(0x00, str8.CharAt(0));
795 EXPECT_EQ(0x7F, str8.CharAt(1));
796 EXPECT_EQ(0xFF, str8.CharAt(2));
797 }
798
799 // Create a 1-byte string from an array of 4-byte elements.
800 {
801 const int32_t char32[] = {0x00, 0x1F, 0x7F};
802 const String& str8 = String::Handle(String::FromUTF32(char32, 3));
803 EXPECT(str8.IsOneByteString());
804 EXPECT(!str8.IsTwoByteString());
805 EXPECT_EQ(0x00, str8.CharAt(0));
806 EXPECT_EQ(0x1F, str8.CharAt(1));
807 EXPECT_EQ(0x7F, str8.CharAt(2));
808 }
809
810 // Create a 2-byte string from an array of 4-byte elements.
811 {
812 const int32_t char32[] = {0, 0x7FFF, 0xFFFF};
813 const String& str16 = String::Handle(String::FromUTF32(char32, 3));
814 EXPECT(!str16.IsOneByteString());
815 EXPECT(str16.IsTwoByteString());
816 EXPECT_EQ(0x0000, str16.CharAt(0));
817 EXPECT_EQ(0x7FFF, str16.CharAt(1));
818 EXPECT_EQ(0xFFFF, str16.CharAt(2));
819 }
820}
821
823 const char* hello_str = "Hello World!";
824 const String& str =
825 String::Handle(String::NewFormatted("Hello %s!", "World"));
826 EXPECT(str.IsInstance());
827 EXPECT(str.IsString());
828 EXPECT(str.IsOneByteString());
829 EXPECT(!str.IsTwoByteString());
830 EXPECT(!str.IsNumber());
831 EXPECT(str.Equals(hello_str));
832}
833
835 // Create strings from concatenated 1-byte empty strings.
836 {
837 const String& empty1 = String::Handle(String::New(""));
838 EXPECT(empty1.IsOneByteString());
839 EXPECT_EQ(0, empty1.Length());
840
841 const String& empty2 = String::Handle(String::New(""));
842 EXPECT(empty2.IsOneByteString());
843 EXPECT_EQ(0, empty2.Length());
844
845 // Concat
846
847 const String& empty3 = String::Handle(String::Concat(empty1, empty2));
848 EXPECT(empty3.IsOneByteString());
849 EXPECT_EQ(0, empty3.Length());
850
851 // ConcatAll
852
853 const Array& array1 = Array::Handle(Array::New(0));
854 EXPECT_EQ(0, array1.Length());
855 const String& empty4 = String::Handle(String::ConcatAll(array1));
856 EXPECT_EQ(0, empty4.Length());
857
858 const Array& array2 = Array::Handle(Array::New(10));
859 EXPECT_EQ(10, array2.Length());
860 for (int i = 0; i < array2.Length(); ++i) {
861 array2.SetAt(i, String::Handle(String::New("")));
862 }
863 const String& empty5 = String::Handle(String::ConcatAll(array2));
864 EXPECT(empty5.IsOneByteString());
865 EXPECT_EQ(0, empty5.Length());
866
867 const Array& array3 = Array::Handle(Array::New(123));
868 EXPECT_EQ(123, array3.Length());
869
870 const String& empty6 = String::Handle(String::New(""));
871 EXPECT(empty6.IsOneByteString());
872 EXPECT_EQ(0, empty6.Length());
873 for (int i = 0; i < array3.Length(); ++i) {
874 array3.SetAt(i, empty6);
875 }
876 const String& empty7 = String::Handle(String::ConcatAll(array3));
877 EXPECT(empty7.IsOneByteString());
878 EXPECT_EQ(0, empty7.Length());
879 }
880
881 // Concatenated empty and non-empty 1-byte strings.
882 {
883 const String& str1 = String::Handle(String::New(""));
884 EXPECT_EQ(0, str1.Length());
885 EXPECT(str1.IsOneByteString());
886
887 const String& str2 = String::Handle(String::New("one"));
888 EXPECT(str2.IsOneByteString());
889 EXPECT_EQ(3, str2.Length());
890
891 // Concat
892
893 const String& str3 = String::Handle(String::Concat(str1, str2));
894 EXPECT(str3.IsOneByteString());
895 EXPECT_EQ(3, str3.Length());
896 EXPECT(str3.Equals(str2));
897
898 const String& str4 = String::Handle(String::Concat(str2, str1));
899 EXPECT(str4.IsOneByteString());
900 EXPECT_EQ(3, str4.Length());
901 EXPECT(str4.Equals(str2));
902
903 // ConcatAll
904
905 const Array& array1 = Array::Handle(Array::New(2));
906 EXPECT_EQ(2, array1.Length());
907 array1.SetAt(0, str1);
908 array1.SetAt(1, str2);
909 const String& str5 = String::Handle(String::ConcatAll(array1));
910 EXPECT(str5.IsOneByteString());
911 EXPECT_EQ(3, str5.Length());
912 EXPECT(str5.Equals(str2));
913
914 const Array& array2 = Array::Handle(Array::New(2));
915 EXPECT_EQ(2, array2.Length());
916 array2.SetAt(0, str1);
917 array2.SetAt(1, str2);
918 const String& str6 = String::Handle(String::ConcatAll(array2));
919 EXPECT(str6.IsOneByteString());
920 EXPECT_EQ(3, str6.Length());
921 EXPECT(str6.Equals(str2));
922
923 const Array& array3 = Array::Handle(Array::New(3));
924 EXPECT_EQ(3, array3.Length());
925 array3.SetAt(0, str2);
926 array3.SetAt(1, str1);
927 array3.SetAt(2, str2);
928 const String& str7 = String::Handle(String::ConcatAll(array3));
929 EXPECT(str7.IsOneByteString());
930 EXPECT_EQ(6, str7.Length());
931 EXPECT(str7.Equals("oneone"));
932 EXPECT(!str7.Equals("oneoneone"));
933 }
934
935 // Create a string by concatenating non-empty 1-byte strings.
936 {
937 const char* one = "one";
938 intptr_t one_len = strlen(one);
939 const String& onestr = String::Handle(String::New(one));
940 EXPECT(onestr.IsOneByteString());
941 EXPECT_EQ(one_len, onestr.Length());
942
943 const char* three = "three";
944 intptr_t three_len = strlen(three);
945 const String& threestr = String::Handle(String::New(three));
946 EXPECT(threestr.IsOneByteString());
947 EXPECT_EQ(three_len, threestr.Length());
948
949 // Concat
950
951 const String& str3 = String::Handle(String::Concat(onestr, threestr));
952 EXPECT(str3.IsOneByteString());
953 const char* one_three = "onethree";
954 EXPECT(str3.Equals(one_three));
955
956 const String& str4 = String::Handle(String::Concat(threestr, onestr));
957 EXPECT(str4.IsOneByteString());
958 const char* three_one = "threeone";
959 intptr_t three_one_len = strlen(three_one);
960 EXPECT_EQ(three_one_len, str4.Length());
961 EXPECT(str4.Equals(three_one));
962
963 // ConcatAll
964
965 const Array& array1 = Array::Handle(Array::New(2));
966 EXPECT_EQ(2, array1.Length());
967 array1.SetAt(0, onestr);
968 array1.SetAt(1, threestr);
969 const String& str5 = String::Handle(String::ConcatAll(array1));
970 EXPECT(str5.IsOneByteString());
971 intptr_t one_three_len = strlen(one_three);
972 EXPECT_EQ(one_three_len, str5.Length());
973 EXPECT(str5.Equals(one_three));
974
975 const Array& array2 = Array::Handle(Array::New(2));
976 EXPECT_EQ(2, array2.Length());
977 array2.SetAt(0, threestr);
978 array2.SetAt(1, onestr);
979 const String& str6 = String::Handle(String::ConcatAll(array2));
980 EXPECT(str6.IsOneByteString());
981 EXPECT_EQ(three_one_len, str6.Length());
982 EXPECT(str6.Equals(three_one));
983
984 const Array& array3 = Array::Handle(Array::New(3));
985 EXPECT_EQ(3, array3.Length());
986 array3.SetAt(0, onestr);
987 array3.SetAt(1, threestr);
988 array3.SetAt(2, onestr);
989 const String& str7 = String::Handle(String::ConcatAll(array3));
990 EXPECT(str7.IsOneByteString());
991 const char* one_three_one = "onethreeone";
992 intptr_t one_three_one_len = strlen(one_three_one);
993 EXPECT_EQ(one_three_one_len, str7.Length());
994 EXPECT(str7.Equals(one_three_one));
995
996 const Array& array4 = Array::Handle(Array::New(3));
997 EXPECT_EQ(3, array4.Length());
998 array4.SetAt(0, threestr);
999 array4.SetAt(1, onestr);
1000 array4.SetAt(2, threestr);
1001 const String& str8 = String::Handle(String::ConcatAll(array4));
1002 EXPECT(str8.IsOneByteString());
1003 const char* three_one_three = "threeonethree";
1004 intptr_t three_one_three_len = strlen(three_one_three);
1005 EXPECT_EQ(three_one_three_len, str8.Length());
1006 EXPECT(str8.Equals(three_one_three));
1007 }
1008
1009 // Concatenate empty and non-empty 2-byte strings.
1010 {
1011 const String& str1 = String::Handle(String::New(""));
1012 EXPECT(str1.IsOneByteString());
1013 EXPECT_EQ(0, str1.Length());
1014
1015 uint16_t two[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1016 intptr_t two_len = sizeof(two) / sizeof(two[0]);
1017 const String& str2 = String::Handle(String::FromUTF16(two, two_len));
1018 EXPECT(str2.IsTwoByteString());
1019 EXPECT_EQ(two_len, str2.Length());
1020
1021 // Concat
1022
1023 const String& str3 = String::Handle(String::Concat(str1, str2));
1024 EXPECT(str3.IsTwoByteString());
1025 EXPECT_EQ(two_len, str3.Length());
1026 EXPECT(str3.Equals(str2));
1027
1028 const String& str4 = String::Handle(String::Concat(str2, str1));
1029 EXPECT(str4.IsTwoByteString());
1030 EXPECT_EQ(two_len, str4.Length());
1031 EXPECT(str4.Equals(str2));
1032
1033 // ConcatAll
1034
1035 const Array& array1 = Array::Handle(Array::New(2));
1036 EXPECT_EQ(2, array1.Length());
1037 array1.SetAt(0, str1);
1038 array1.SetAt(1, str2);
1039 const String& str5 = String::Handle(String::ConcatAll(array1));
1040 EXPECT(str5.IsTwoByteString());
1041 EXPECT_EQ(two_len, str5.Length());
1042 EXPECT(str5.Equals(str2));
1043
1044 const Array& array2 = Array::Handle(Array::New(2));
1045 EXPECT_EQ(2, array2.Length());
1046 array2.SetAt(0, str1);
1047 array2.SetAt(1, str2);
1048 const String& str6 = String::Handle(String::ConcatAll(array2));
1049 EXPECT(str6.IsTwoByteString());
1050 EXPECT_EQ(two_len, str6.Length());
1051 EXPECT(str6.Equals(str2));
1052
1053 const Array& array3 = Array::Handle(Array::New(3));
1054 EXPECT_EQ(3, array3.Length());
1055 array3.SetAt(0, str2);
1056 array3.SetAt(1, str1);
1057 array3.SetAt(2, str2);
1058 const String& str7 = String::Handle(String::ConcatAll(array3));
1059 EXPECT(str7.IsTwoByteString());
1060 EXPECT_EQ(two_len * 2, str7.Length());
1061 uint16_t twotwo[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9,
1062 0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1063 intptr_t twotwo_len = sizeof(twotwo) / sizeof(twotwo[0]);
1064 EXPECT(str7.IsTwoByteString());
1065 EXPECT(str7.Equals(twotwo, twotwo_len));
1066 }
1067
1068 // Concatenating non-empty 2-byte strings.
1069 {
1070 const uint16_t one[] = {0x05D0, 0x05D9, 0x05D9, 0x05DF};
1071 intptr_t one_len = sizeof(one) / sizeof(one[0]);
1072 const String& str1 = String::Handle(String::FromUTF16(one, one_len));
1073 EXPECT(str1.IsTwoByteString());
1074 EXPECT_EQ(one_len, str1.Length());
1075
1076 const uint16_t two[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1077 intptr_t two_len = sizeof(two) / sizeof(two[0]);
1078 const String& str2 = String::Handle(String::FromUTF16(two, two_len));
1079 EXPECT(str2.IsTwoByteString());
1080 EXPECT_EQ(two_len, str2.Length());
1081
1082 // Concat
1083
1084 const String& one_two_str = String::Handle(String::Concat(str1, str2));
1085 EXPECT(one_two_str.IsTwoByteString());
1086 const uint16_t one_two[] = {0x05D0, 0x05D9, 0x05D9, 0x05DF, 0x05E6,
1087 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1088 intptr_t one_two_len = sizeof(one_two) / sizeof(one_two[0]);
1089 EXPECT_EQ(one_two_len, one_two_str.Length());
1090 EXPECT(one_two_str.Equals(one_two, one_two_len));
1091
1092 const String& two_one_str = String::Handle(String::Concat(str2, str1));
1093 EXPECT(two_one_str.IsTwoByteString());
1094 const uint16_t two_one[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9,
1095 0x05D0, 0x05D9, 0x05D9, 0x05DF};
1096 intptr_t two_one_len = sizeof(two_one) / sizeof(two_one[0]);
1097 EXPECT_EQ(two_one_len, two_one_str.Length());
1098 EXPECT(two_one_str.Equals(two_one, two_one_len));
1099
1100 // ConcatAll
1101
1102 const Array& array1 = Array::Handle(Array::New(2));
1103 EXPECT_EQ(2, array1.Length());
1104 array1.SetAt(0, str1);
1105 array1.SetAt(1, str2);
1106 const String& str3 = String::Handle(String::ConcatAll(array1));
1107 EXPECT(str3.IsTwoByteString());
1108 EXPECT_EQ(one_two_len, str3.Length());
1109 EXPECT(str3.Equals(one_two, one_two_len));
1110
1111 const Array& array2 = Array::Handle(Array::New(2));
1112 EXPECT_EQ(2, array2.Length());
1113 array2.SetAt(0, str2);
1114 array2.SetAt(1, str1);
1115 const String& str4 = String::Handle(String::ConcatAll(array2));
1116 EXPECT(str4.IsTwoByteString());
1117 EXPECT_EQ(two_one_len, str4.Length());
1118 EXPECT(str4.Equals(two_one, two_one_len));
1119
1120 const Array& array3 = Array::Handle(Array::New(3));
1121 EXPECT_EQ(3, array3.Length());
1122 array3.SetAt(0, str1);
1123 array3.SetAt(1, str2);
1124 array3.SetAt(2, str1);
1125 const String& str5 = String::Handle(String::ConcatAll(array3));
1126 EXPECT(str5.IsTwoByteString());
1127 const uint16_t one_two_one[] = {0x05D0, 0x05D9, 0x05D9, 0x05DF, 0x05E6,
1128 0x05D5, 0x05D5, 0x05D9, 0x05D9, 0x05D0,
1129 0x05D9, 0x05D9, 0x05DF};
1130 intptr_t one_two_one_len = sizeof(one_two_one) / sizeof(one_two_one[0]);
1131 EXPECT_EQ(one_two_one_len, str5.Length());
1132 EXPECT(str5.Equals(one_two_one, one_two_one_len));
1133
1134 const Array& array4 = Array::Handle(Array::New(3));
1135 EXPECT_EQ(3, array4.Length());
1136 array4.SetAt(0, str2);
1137 array4.SetAt(1, str1);
1138 array4.SetAt(2, str2);
1139 const String& str6 = String::Handle(String::ConcatAll(array4));
1140 EXPECT(str6.IsTwoByteString());
1141 const uint16_t two_one_two[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9,
1142 0x05D0, 0x05D9, 0x05D9, 0x05DF, 0x05E6,
1143 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1144 intptr_t two_one_two_len = sizeof(two_one_two) / sizeof(two_one_two[0]);
1145 EXPECT_EQ(two_one_two_len, str6.Length());
1146 EXPECT(str6.Equals(two_one_two, two_one_two_len));
1147 }
1148
1149 // Concatenated empty and non-empty strings built from 4-byte elements.
1150 {
1151 const String& str1 = String::Handle(String::New(""));
1152 EXPECT(str1.IsOneByteString());
1153 EXPECT_EQ(0, str1.Length());
1154
1155 int32_t four[] = {0x1D4D5, 0x1D4DE, 0x1D4E4, 0x1D4E1};
1156 intptr_t four_len = sizeof(four) / sizeof(four[0]);
1157 intptr_t expected_len = (four_len * 2);
1158 const String& str2 = String::Handle(String::FromUTF32(four, four_len));
1159 EXPECT(str2.IsTwoByteString());
1160 EXPECT_EQ(expected_len, str2.Length());
1161
1162 // Concat
1163
1164 const String& str3 = String::Handle(String::Concat(str1, str2));
1165 EXPECT_EQ(expected_len, str3.Length());
1166 EXPECT(str3.Equals(str2));
1167
1168 const String& str4 = String::Handle(String::Concat(str2, str1));
1169 EXPECT(str4.IsTwoByteString());
1170 EXPECT_EQ(expected_len, str4.Length());
1171 EXPECT(str4.Equals(str2));
1172
1173 // ConcatAll
1174
1175 const Array& array1 = Array::Handle(Array::New(2));
1176 EXPECT_EQ(2, array1.Length());
1177 array1.SetAt(0, str1);
1178 array1.SetAt(1, str2);
1179 const String& str5 = String::Handle(String::ConcatAll(array1));
1180 EXPECT(str5.IsTwoByteString());
1181 EXPECT_EQ(expected_len, str5.Length());
1182 EXPECT(str5.Equals(str2));
1183
1184 const Array& array2 = Array::Handle(Array::New(2));
1185 EXPECT_EQ(2, array2.Length());
1186 array2.SetAt(0, str1);
1187 array2.SetAt(1, str2);
1188 const String& str6 = String::Handle(String::ConcatAll(array2));
1189 EXPECT(str6.IsTwoByteString());
1190 EXPECT_EQ(expected_len, str6.Length());
1191 EXPECT(str6.Equals(str2));
1192
1193 const Array& array3 = Array::Handle(Array::New(3));
1194 EXPECT_EQ(3, array3.Length());
1195 array3.SetAt(0, str2);
1196 array3.SetAt(1, str1);
1197 array3.SetAt(2, str2);
1198 const String& str7 = String::Handle(String::ConcatAll(array3));
1199 EXPECT(str7.IsTwoByteString());
1200 int32_t fourfour[] = {0x1D4D5, 0x1D4DE, 0x1D4E4, 0x1D4E1,
1201 0x1D4D5, 0x1D4DE, 0x1D4E4, 0x1D4E1};
1202 intptr_t fourfour_len = sizeof(fourfour) / sizeof(fourfour[0]);
1203 EXPECT_EQ((fourfour_len * 2), str7.Length());
1204 const String& fourfour_str =
1205 String::Handle(String::FromUTF32(fourfour, fourfour_len));
1206 EXPECT(str7.Equals(fourfour_str));
1207 }
1208
1209 // Concatenate non-empty strings built from 4-byte elements.
1210 {
1211 const int32_t one[] = {0x105D0, 0x105D9, 0x105D9, 0x105DF};
1212 intptr_t one_len = sizeof(one) / sizeof(one[0]);
1213 const String& onestr = String::Handle(String::FromUTF32(one, one_len));
1214 EXPECT(onestr.IsTwoByteString());
1215 EXPECT_EQ((one_len * 2), onestr.Length());
1216
1217 const int32_t two[] = {0x105E6, 0x105D5, 0x105D5, 0x105D9, 0x105D9};
1218 intptr_t two_len = sizeof(two) / sizeof(two[0]);
1219 const String& twostr = String::Handle(String::FromUTF32(two, two_len));
1220 EXPECT(twostr.IsTwoByteString());
1221 EXPECT_EQ((two_len * 2), twostr.Length());
1222
1223 // Concat
1224
1225 const String& str1 = String::Handle(String::Concat(onestr, twostr));
1226 EXPECT(str1.IsTwoByteString());
1227 const int32_t one_two[] = {0x105D0, 0x105D9, 0x105D9, 0x105DF, 0x105E6,
1228 0x105D5, 0x105D5, 0x105D9, 0x105D9};
1229 intptr_t one_two_len = sizeof(one_two) / sizeof(one_two[0]);
1230 EXPECT_EQ((one_two_len * 2), str1.Length());
1231 const String& one_two_str =
1232 String::Handle(String::FromUTF32(one_two, one_two_len));
1233 EXPECT(str1.Equals(one_two_str));
1234
1235 const String& str2 = String::Handle(String::Concat(twostr, onestr));
1236 EXPECT(str2.IsTwoByteString());
1237 const int32_t two_one[] = {0x105E6, 0x105D5, 0x105D5, 0x105D9, 0x105D9,
1238 0x105D0, 0x105D9, 0x105D9, 0x105DF};
1239 intptr_t two_one_len = sizeof(two_one) / sizeof(two_one[0]);
1240 EXPECT_EQ((two_one_len * 2), str2.Length());
1241 const String& two_one_str =
1242 String::Handle(String::FromUTF32(two_one, two_one_len));
1243 EXPECT(str2.Equals(two_one_str));
1244
1245 // ConcatAll
1246
1247 const Array& array1 = Array::Handle(Array::New(2));
1248 EXPECT_EQ(2, array1.Length());
1249 array1.SetAt(0, onestr);
1250 array1.SetAt(1, twostr);
1251 const String& str3 = String::Handle(String::ConcatAll(array1));
1252 EXPECT(str3.IsTwoByteString());
1253 EXPECT_EQ((one_two_len * 2), str3.Length());
1254 EXPECT(str3.Equals(one_two_str));
1255
1256 const Array& array2 = Array::Handle(Array::New(2));
1257 EXPECT_EQ(2, array2.Length());
1258 array2.SetAt(0, twostr);
1259 array2.SetAt(1, onestr);
1260 const String& str4 = String::Handle(String::ConcatAll(array2));
1261 EXPECT(str4.IsTwoByteString());
1262 EXPECT_EQ((two_one_len * 2), str4.Length());
1263 EXPECT(str4.Equals(two_one_str));
1264
1265 const Array& array3 = Array::Handle(Array::New(3));
1266 EXPECT_EQ(3, array3.Length());
1267 array3.SetAt(0, onestr);
1268 array3.SetAt(1, twostr);
1269 array3.SetAt(2, onestr);
1270 const String& str5 = String::Handle(String::ConcatAll(array3));
1271 EXPECT(str5.IsTwoByteString());
1272 const int32_t one_two_one[] = {0x105D0, 0x105D9, 0x105D9, 0x105DF, 0x105E6,
1273 0x105D5, 0x105D5, 0x105D9, 0x105D9, 0x105D0,
1274 0x105D9, 0x105D9, 0x105DF};
1275 intptr_t one_two_one_len = sizeof(one_two_one) / sizeof(one_two_one[0]);
1276 EXPECT_EQ((one_two_one_len * 2), str5.Length());
1277 const String& one_two_one_str =
1278 String::Handle(String::FromUTF32(one_two_one, one_two_one_len));
1279 EXPECT(str5.Equals(one_two_one_str));
1280
1281 const Array& array4 = Array::Handle(Array::New(3));
1282 EXPECT_EQ(3, array4.Length());
1283 array4.SetAt(0, twostr);
1284 array4.SetAt(1, onestr);
1285 array4.SetAt(2, twostr);
1286 const String& str6 = String::Handle(String::ConcatAll(array4));
1287 EXPECT(str6.IsTwoByteString());
1288 const int32_t two_one_two[] = {0x105E6, 0x105D5, 0x105D5, 0x105D9, 0x105D9,
1289 0x105D0, 0x105D9, 0x105D9, 0x105DF, 0x105E6,
1290 0x105D5, 0x105D5, 0x105D9, 0x105D9};
1291 intptr_t two_one_two_len = sizeof(two_one_two) / sizeof(two_one_two[0]);
1292 EXPECT_EQ((two_one_two_len * 2), str6.Length());
1293 const String& two_one_two_str =
1294 String::Handle(String::FromUTF32(two_one_two, two_one_two_len));
1295 EXPECT(str6.Equals(two_one_two_str));
1296 }
1297
1298 // Concatenate 1-byte strings and 2-byte strings.
1299 {
1300 const uint8_t one[] = {'o', 'n', 'e', ' ', 'b', 'y', 't', 'e'};
1301 intptr_t one_len = sizeof(one) / sizeof(one[0]);
1302 const String& onestr = String::Handle(String::FromLatin1(one, one_len));
1303 EXPECT(onestr.IsOneByteString());
1304 EXPECT_EQ(one_len, onestr.Length());
1305 EXPECT(onestr.EqualsLatin1(one, one_len));
1306
1307 uint16_t two[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1308 intptr_t two_len = sizeof(two) / sizeof(two[0]);
1309 const String& twostr = String::Handle(String::FromUTF16(two, two_len));
1310 EXPECT(twostr.IsTwoByteString());
1311 EXPECT_EQ(two_len, twostr.Length());
1312 EXPECT(twostr.Equals(two, two_len));
1313
1314 // Concat
1315
1316 const String& one_two_str = String::Handle(String::Concat(onestr, twostr));
1317 EXPECT(one_two_str.IsTwoByteString());
1318 uint16_t one_two[] = {'o', 'n', 'e', ' ', 'b', 'y', 't',
1319 'e', 0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1320 intptr_t one_two_len = sizeof(one_two) / sizeof(one_two[0]);
1321 EXPECT_EQ(one_two_len, one_two_str.Length());
1322 EXPECT(one_two_str.Equals(one_two, one_two_len));
1323
1324 const String& two_one_str = String::Handle(String::Concat(twostr, onestr));
1325 EXPECT(two_one_str.IsTwoByteString());
1326 uint16_t two_one[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9, 'o', 'n',
1327 'e', ' ', 'b', 'y', 't', 'e'};
1328 intptr_t two_one_len = sizeof(two_one) / sizeof(two_one[0]);
1329 EXPECT_EQ(two_one_len, two_one_str.Length());
1330 EXPECT(two_one_str.Equals(two_one, two_one_len));
1331
1332 // ConcatAll
1333
1334 const Array& array1 = Array::Handle(Array::New(3));
1335 EXPECT_EQ(3, array1.Length());
1336 array1.SetAt(0, onestr);
1337 array1.SetAt(1, twostr);
1338 array1.SetAt(2, onestr);
1339 const String& one_two_one_str = String::Handle(String::ConcatAll(array1));
1340 EXPECT(one_two_one_str.IsTwoByteString());
1341 EXPECT_EQ(onestr.Length() * 2 + twostr.Length(), one_two_one_str.Length());
1342 uint16_t one_two_one[] = {'o', 'n', 'e', ' ', 'b', 'y', 't',
1343 'e', 0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9, 'o',
1344 'n', 'e', ' ', 'b', 'y', 't', 'e'};
1345 intptr_t one_two_one_len = sizeof(one_two_one) / sizeof(one_two_one[0]);
1346 EXPECT(one_two_one_str.Equals(one_two_one, one_two_one_len));
1347
1348 const Array& array2 = Array::Handle(Array::New(3));
1349 EXPECT_EQ(3, array2.Length());
1350 array2.SetAt(0, twostr);
1351 array2.SetAt(1, onestr);
1352 array2.SetAt(2, twostr);
1353 const String& two_one_two_str = String::Handle(String::ConcatAll(array2));
1354 EXPECT(two_one_two_str.IsTwoByteString());
1355 EXPECT_EQ(twostr.Length() * 2 + onestr.Length(), two_one_two_str.Length());
1356 uint16_t two_one_two[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9, 'o',
1357 'n', 'e', ' ', 'b', 'y', 't',
1358 'e', 0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1359 intptr_t two_one_two_len = sizeof(two_one_two) / sizeof(two_one_two[0]);
1360 EXPECT(two_one_two_str.Equals(two_one_two, two_one_two_len));
1361 }
1362}
1363
1364ISOLATE_UNIT_TEST_CASE(StringHashConcat) {
1365 EXPECT_EQ(String::Handle(String::New("onebyte")).Hash(),
1367 String::Handle(String::New("byte"))));
1368 uint16_t clef_utf16[] = {0xD834, 0xDD1E};
1369 const String& clef = String::Handle(String::FromUTF16(clef_utf16, 2));
1370 int32_t clef_utf32[] = {0x1D11E};
1371 EXPECT(clef.Equals(clef_utf32, 1));
1372 uword hash32 = String::Hash(String::FromUTF32(clef_utf32, 1));
1373 EXPECT_EQ(hash32, clef.Hash());
1374 EXPECT_EQ(hash32, String::HashConcat(
1375 String::Handle(String::FromUTF16(clef_utf16, 1)),
1376 String::Handle(String::FromUTF16(clef_utf16 + 1, 1))));
1377}
1378
1379ISOLATE_UNIT_TEST_CASE(StringSubStringDifferentWidth) {
1380 // Create 1-byte substring from a 1-byte source string.
1381 const char* onechars = "\xC3\xB6\xC3\xB1\xC3\xA9";
1382
1383 const String& onestr = String::Handle(String::New(onechars));
1384 EXPECT(!onestr.IsNull());
1385 EXPECT(onestr.IsOneByteString());
1386 EXPECT(!onestr.IsTwoByteString());
1387
1388 const String& onesub = String::Handle(String::SubString(onestr, 0));
1389 EXPECT(!onesub.IsNull());
1390 EXPECT(onestr.IsOneByteString());
1391 EXPECT(!onestr.IsTwoByteString());
1392 EXPECT_EQ(onesub.Length(), 3);
1393
1394 // Create 1- and 2-byte substrings from a 2-byte source string.
1395 const char* twochars =
1396 "\x1f\x2f\x3f"
1397 "\xE1\xB9\xAB\xE1\xBA\x85\xE1\xB9\x93";
1398
1399 const String& twostr = String::Handle(String::New(twochars));
1400 EXPECT(!twostr.IsNull());
1401 EXPECT(twostr.IsTwoByteString());
1402
1403 const String& twosub1 = String::Handle(String::SubString(twostr, 0, 3));
1404 EXPECT(!twosub1.IsNull());
1405 EXPECT(twosub1.IsOneByteString());
1406 EXPECT_EQ(twosub1.Length(), 3);
1407
1408 const String& twosub2 = String::Handle(String::SubString(twostr, 3));
1409 EXPECT(!twosub2.IsNull());
1410 EXPECT(twosub2.IsTwoByteString());
1411 EXPECT_EQ(twosub2.Length(), 3);
1412
1413 // Create substrings from a string built using 1-, 2- and 4-byte elements.
1414 const char* fourchars =
1415 "\x1f\x2f\x3f"
1416 "\xE1\xB9\xAB\xE1\xBA\x85\xE1\xB9\x93"
1417 "\xF0\x9D\x96\xBF\xF0\x9D\x97\x88\xF0\x9D\x97\x8E\xF0\x9D\x97\x8B";
1418
1419 const String& fourstr = String::Handle(String::New(fourchars));
1420 EXPECT(!fourstr.IsNull());
1421 EXPECT(fourstr.IsTwoByteString());
1422
1423 const String& foursub1 = String::Handle(String::SubString(fourstr, 0, 3));
1424 EXPECT(!foursub1.IsNull());
1425 EXPECT(foursub1.IsOneByteString());
1426 EXPECT_EQ(foursub1.Length(), 3);
1427
1428 const String& foursub2 = String::Handle(String::SubString(fourstr, 3, 3));
1429 EXPECT(!foursub2.IsNull());
1430 EXPECT(foursub2.IsTwoByteString());
1431 EXPECT_EQ(foursub2.Length(), 3);
1432
1433 const String& foursub4 = String::Handle(String::SubString(fourstr, 6));
1434 EXPECT_EQ(foursub4.Length(), 8);
1435 EXPECT(!foursub4.IsNull());
1436 EXPECT(foursub4.IsTwoByteString());
1437}
1438
1439ISOLATE_UNIT_TEST_CASE(StringFromUtf8Literal) {
1440 // Create a 1-byte string from a UTF-8 encoded string literal.
1441 {
1442 const char* src =
1443 "\xC2\xA0\xC2\xA1\xC2\xA2\xC2\xA3"
1444 "\xC2\xA4\xC2\xA5\xC2\xA6\xC2\xA7"
1445 "\xC2\xA8\xC2\xA9\xC2\xAA\xC2\xAB"
1446 "\xC2\xAC\xC2\xAD\xC2\xAE\xC2\xAF"
1447 "\xC2\xB0\xC2\xB1\xC2\xB2\xC2\xB3"
1448 "\xC2\xB4\xC2\xB5\xC2\xB6\xC2\xB7"
1449 "\xC2\xB8\xC2\xB9\xC2\xBA\xC2\xBB"
1450 "\xC2\xBC\xC2\xBD\xC2\xBE\xC2\xBF"
1451 "\xC3\x80\xC3\x81\xC3\x82\xC3\x83"
1452 "\xC3\x84\xC3\x85\xC3\x86\xC3\x87"
1453 "\xC3\x88\xC3\x89\xC3\x8A\xC3\x8B"
1454 "\xC3\x8C\xC3\x8D\xC3\x8E\xC3\x8F"
1455 "\xC3\x90\xC3\x91\xC3\x92\xC3\x93"
1456 "\xC3\x94\xC3\x95\xC3\x96\xC3\x97"
1457 "\xC3\x98\xC3\x99\xC3\x9A\xC3\x9B"
1458 "\xC3\x9C\xC3\x9D\xC3\x9E\xC3\x9F"
1459 "\xC3\xA0\xC3\xA1\xC3\xA2\xC3\xA3"
1460 "\xC3\xA4\xC3\xA5\xC3\xA6\xC3\xA7"
1461 "\xC3\xA8\xC3\xA9\xC3\xAA\xC3\xAB"
1462 "\xC3\xAC\xC3\xAD\xC3\xAE\xC3\xAF"
1463 "\xC3\xB0\xC3\xB1\xC3\xB2\xC3\xB3"
1464 "\xC3\xB4\xC3\xB5\xC3\xB6\xC3\xB7"
1465 "\xC3\xB8\xC3\xB9\xC3\xBA\xC3\xBB"
1466 "\xC3\xBC\xC3\xBD\xC3\xBE\xC3\xBF";
1467 const uint8_t expected[] = {
1468 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB,
1469 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
1470 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3,
1471 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
1472 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB,
1473 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
1474 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3,
1475 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
1476 };
1477 const String& str = String::Handle(String::New(src));
1478 EXPECT(str.IsOneByteString());
1479 intptr_t expected_length = sizeof(expected);
1480 EXPECT_EQ(expected_length, str.Length());
1481 for (int i = 0; i < str.Length(); ++i) {
1482 EXPECT_EQ(expected[i], str.CharAt(i));
1483 }
1484 }
1485
1486 // Create a 2-byte string from a UTF-8 encoded string literal.
1487 {
1488 const char* src =
1489 "\xD7\x92\xD7\x9C\xD7\xA2\xD7\x93"
1490 "\xD7\x91\xD7\xA8\xD7\x9B\xD7\x94";
1491 const uint16_t expected[] = {0x5D2, 0x5DC, 0x5E2, 0x5D3,
1492 0x5D1, 0x5E8, 0x5DB, 0x5D4};
1493 const String& str = String::Handle(String::New(src));
1494 EXPECT(str.IsTwoByteString());
1495 intptr_t expected_size = sizeof(expected) / sizeof(expected[0]);
1496 EXPECT_EQ(expected_size, str.Length());
1497 for (int i = 0; i < str.Length(); ++i) {
1498 EXPECT_EQ(expected[i], str.CharAt(i));
1499 }
1500 }
1501
1502 // Create a BMP 2-byte string from UTF-8 encoded 1- and 2-byte
1503 // characters.
1504 {
1505 const char* src =
1506 "\x0A\x0B\x0D\x0C\x0E\x0F\xC2\xA0"
1507 "\xC2\xB0\xC3\x80\xC3\x90\xC3\xA0"
1508 "\xC3\xB0\xE0\xA8\x80\xE0\xAC\x80"
1509 "\xE0\xB0\x80\xE0\xB4\x80\xE0\xB8"
1510 "\x80\xE0\xBC\x80\xEA\x80\x80\xEB"
1511 "\x80\x80\xEC\x80\x80\xED\x80\x80"
1512 "\xEE\x80\x80\xEF\x80\x80";
1513 const intptr_t expected[] = {
1514 0x000A, 0x000B, 0x000D, 0x000C, 0x000E, 0x000F, 0x00A0, 0x00B0,
1515 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0A00, 0x0B00, 0x0C00, 0x0D00,
1516 0x0E00, 0x0F00, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000};
1517 const String& str = String::Handle(String::New(src));
1518 EXPECT(str.IsTwoByteString());
1519 intptr_t expected_size = sizeof(expected) / sizeof(expected[0]);
1520 EXPECT_EQ(expected_size, str.Length());
1521 for (int i = 0; i < str.Length(); ++i) {
1522 EXPECT_EQ(expected[i], str.CharAt(i));
1523 }
1524 }
1525
1526 // Create a 2-byte string with supplementary characters from a UTF-8
1527 // string literal.
1528 {
1529 const char* src =
1530 "\xF0\x9D\x91\xA0\xF0\x9D\x91\xA1"
1531 "\xF0\x9D\x91\xA2\xF0\x9D\x91\xA3";
1532 const intptr_t expected[] = {0xd835, 0xdc60, 0xd835, 0xdc61,
1533 0xd835, 0xdc62, 0xd835, 0xdc63};
1534 const String& str = String::Handle(String::New(src));
1535 EXPECT(str.IsTwoByteString());
1536 intptr_t expected_size = (sizeof(expected) / sizeof(expected[0]));
1537 EXPECT_EQ(expected_size, str.Length());
1538 for (int i = 0; i < str.Length(); ++i) {
1539 EXPECT_EQ(expected[i], str.CharAt(i));
1540 }
1541 }
1542
1543 // Create a 2-byte string from UTF-8 encoded 2- and 4-byte
1544 // characters.
1545 {
1546 const char* src =
1547 "\xE0\xA8\x80\xE0\xAC\x80\xE0\xB0"
1548 "\x80\xE0\xB4\x80\xE0\xB8\x80\xE0"
1549 "\xBC\x80\xEA\x80\x80\xEB\x80\x80"
1550 "\xEC\x80\x80\xED\x80\x80\xEE\x80"
1551 "\x80\xEF\x80\x80\xF0\x9A\x80\x80"
1552 "\xF0\x9B\x80\x80\xF0\x9D\x80\x80"
1553 "\xF0\x9E\x80\x80\xF0\x9F\x80\x80";
1554 const intptr_t expected[] = {
1555 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, 0x0F00, 0xA000, 0xB000,
1556 0xC000, 0xD000, 0xE000, 0xF000, 0xD828, 0xDC00, 0xD82c, 0xDC00,
1557 0xD834, 0xDC00, 0xD838, 0xDC00, 0xD83c, 0xDC00,
1558 };
1559 const String& str = String::Handle(String::New(src));
1560 EXPECT(str.IsTwoByteString());
1561 intptr_t expected_size = sizeof(expected) / sizeof(expected[0]);
1562 EXPECT_EQ(expected_size, str.Length());
1563 for (int i = 0; i < str.Length(); ++i) {
1564 EXPECT_EQ(expected[i], str.CharAt(i));
1565 }
1566 }
1567
1568 // Create a 2-byte string from UTF-8 encoded 1-, 2- and 4-byte
1569 // characters.
1570 {
1571 const char* src =
1572 "\x0A\x0B\x0D\x0C\x0E\x0F\xC2\xA0"
1573 "\xC2\xB0\xC3\x80\xC3\x90\xC3\xA0"
1574 "\xC3\xB0\xE0\xA8\x80\xE0\xAC\x80"
1575 "\xE0\xB0\x80\xE0\xB4\x80\xE0\xB8"
1576 "\x80\xE0\xBC\x80\xEA\x80\x80\xEB"
1577 "\x80\x80\xEC\x80\x80\xED\x80\x80"
1578 "\xEE\x80\x80\xEF\x80\x80\xF0\x9A"
1579 "\x80\x80\xF0\x9B\x80\x80\xF0\x9D"
1580 "\x80\x80\xF0\x9E\x80\x80\xF0\x9F"
1581 "\x80\x80";
1582 const intptr_t expected[] = {
1583 0x000A, 0x000B, 0x000D, 0x000C, 0x000E, 0x000F, 0x00A0, 0x00B0, 0x00C0,
1584 0x00D0, 0x00E0, 0x00F0, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, 0x0F00,
1585 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0xD828, 0xDC00, 0xD82c,
1586 0xDC00, 0xD834, 0xDC00, 0xD838, 0xDC00, 0xD83c, 0xDC00,
1587 };
1588 const String& str = String::Handle(String::New(src));
1589 EXPECT(str.IsTwoByteString());
1590 intptr_t expected_size = sizeof(expected) / sizeof(expected[0]);
1591 EXPECT_EQ(expected_size, str.Length());
1592 for (int i = 0; i < str.Length(); ++i) {
1593 EXPECT_EQ(expected[i], str.CharAt(i));
1594 }
1595 }
1596}
1597
1598ISOLATE_UNIT_TEST_CASE(StringEqualsUtf8) {
1599 const char* onesrc = "abc";
1600 const String& onestr = String::Handle(String::New(onesrc));
1601 EXPECT(onestr.IsOneByteString());
1602 EXPECT(!onestr.Equals(""));
1603 EXPECT(!onestr.Equals("a"));
1604 EXPECT(!onestr.Equals("ab"));
1605 EXPECT(onestr.Equals("abc"));
1606 EXPECT(!onestr.Equals("abcd"));
1607
1608 const char* twosrc = "\xD7\x90\xD7\x91\xD7\x92";
1609 const String& twostr = String::Handle(String::New(twosrc));
1610 EXPECT(twostr.IsTwoByteString());
1611 EXPECT(!twostr.Equals(""));
1612 EXPECT(!twostr.Equals("\xD7\x90"));
1613 EXPECT(!twostr.Equals("\xD7\x90\xD7\x91"));
1614 EXPECT(twostr.Equals("\xD7\x90\xD7\x91\xD7\x92"));
1615 EXPECT(!twostr.Equals("\xD7\x90\xD7\x91\xD7\x92\xD7\x93"));
1616
1617 const char* foursrc = "\xF0\x90\x8E\xA0\xF0\x90\x8E\xA1\xF0\x90\x8E\xA2";
1618 const String& fourstr = String::Handle(String::New(foursrc));
1619 EXPECT(fourstr.IsTwoByteString());
1620 EXPECT(!fourstr.Equals(""));
1621 EXPECT(!fourstr.Equals("\xF0\x90\x8E\xA0"));
1622 EXPECT(!fourstr.Equals("\xF0\x90\x8E\xA0\xF0\x90\x8E\xA1"));
1623 EXPECT(fourstr.Equals("\xF0\x90\x8E\xA0\xF0\x90\x8E\xA1\xF0\x90\x8E\xA2"));
1624 EXPECT(
1625 !fourstr.Equals("\xF0\x90\x8E\xA0\xF0\x90\x8E\xA1"
1626 "\xF0\x90\x8E\xA2\xF0\x90\x8E\xA3"));
1627}
1628
1629ISOLATE_UNIT_TEST_CASE(StringEqualsUTF32) {
1630 const String& empty = String::Handle(String::New(""));
1631 const String& t_str = String::Handle(String::New("t"));
1632 const String& th_str = String::Handle(String::New("th"));
1633 const int32_t chars[] = {'t', 'h', 'i', 's'};
1634 EXPECT(!empty.Equals(chars, -1));
1635 EXPECT(empty.Equals(chars, 0));
1636 EXPECT(!empty.Equals(chars, 1));
1637 EXPECT(!t_str.Equals(chars, 0));
1638 EXPECT(t_str.Equals(chars, 1));
1639 EXPECT(!t_str.Equals(chars, 2));
1640 EXPECT(!th_str.Equals(chars, 1));
1641 EXPECT(th_str.Equals(chars, 2));
1642 EXPECT(!th_str.Equals(chars, 3));
1643}
1644
1645ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersOneByteString) {
1646 uint8_t characters[] = {'a', '\n', '\f', '\b', '\t',
1647 '\v', '\r', '\\', '$', 'z'};
1648 intptr_t len = ARRAY_SIZE(characters);
1649
1650 const String& str =
1651 String::Handle(OneByteString::New(characters, len, Heap::kNew));
1652 EXPECT(str.IsOneByteString());
1653 EXPECT_EQ(str.Length(), len);
1654 EXPECT(str.Equals("a\n\f\b\t\v\r\\$z"));
1655 const String& escaped_str =
1657 EXPECT(escaped_str.Equals("a\\n\\f\\b\\t\\v\\r\\\\\\$z"));
1658
1659 const String& escaped_empty_str =
1661 EXPECT_EQ(escaped_empty_str.Length(), 0);
1662}
1663
1664ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersTwoByteString) {
1665 uint16_t characters[] = {'a', '\n', '\f', '\b', '\t',
1666 '\v', '\r', '\\', '$', 'z'};
1667 intptr_t len = ARRAY_SIZE(characters);
1668
1669 const String& str =
1670 String::Handle(TwoByteString::New(characters, len, Heap::kNew));
1671 EXPECT(str.IsTwoByteString());
1672 EXPECT_EQ(str.Length(), len);
1673 EXPECT(str.Equals("a\n\f\b\t\v\r\\$z"));
1674 const String& escaped_str =
1676 EXPECT(escaped_str.Equals("a\\n\\f\\b\\t\\v\\r\\\\\\$z"));
1677
1678 const String& empty_str =
1679 String::Handle(TwoByteString::New(static_cast<intptr_t>(0), Heap::kNew));
1680 const String& escaped_empty_str =
1682 EXPECT_EQ(empty_str.Length(), 0);
1683 EXPECT_EQ(escaped_empty_str.Length(), 0);
1684}
1685
1687 const String& one = String::Handle(Symbols::New(thread, "Eins"));
1688 EXPECT(one.IsSymbol());
1689 const String& two = String::Handle(Symbols::New(thread, "Zwei"));
1690 const String& three = String::Handle(Symbols::New(thread, "Drei"));
1691 const String& four = String::Handle(Symbols::New(thread, "Vier"));
1692 const String& five = String::Handle(Symbols::New(thread, "Fuenf"));
1693 const String& six = String::Handle(Symbols::New(thread, "Sechs"));
1694 const String& seven = String::Handle(Symbols::New(thread, "Sieben"));
1695 const String& eight = String::Handle(Symbols::New(thread, "Acht"));
1696 const String& nine = String::Handle(Symbols::New(thread, "Neun"));
1697 const String& ten = String::Handle(Symbols::New(thread, "Zehn"));
1698 String& eins = String::Handle(Symbols::New(thread, "Eins"));
1699 EXPECT_EQ(one.ptr(), eins.ptr());
1700 EXPECT(one.ptr() != two.ptr());
1701 EXPECT(two.Equals(String::Handle(String::New("Zwei"))));
1702 EXPECT_EQ(two.ptr(), Symbols::New(thread, "Zwei"));
1703 EXPECT_EQ(three.ptr(), Symbols::New(thread, "Drei"));
1704 EXPECT_EQ(four.ptr(), Symbols::New(thread, "Vier"));
1705 EXPECT_EQ(five.ptr(), Symbols::New(thread, "Fuenf"));
1706 EXPECT_EQ(six.ptr(), Symbols::New(thread, "Sechs"));
1707 EXPECT_EQ(seven.ptr(), Symbols::New(thread, "Sieben"));
1708 EXPECT_EQ(eight.ptr(), Symbols::New(thread, "Acht"));
1709 EXPECT_EQ(nine.ptr(), Symbols::New(thread, "Neun"));
1710 EXPECT_EQ(ten.ptr(), Symbols::New(thread, "Zehn"));
1711
1712 // Make sure to cause symbol table overflow.
1713 for (int i = 0; i < 1024; i++) {
1714 char buf[256];
1715 Utils::SNPrint(buf, sizeof(buf), "%d", i);
1716 Symbols::New(thread, buf);
1717 }
1718 eins = Symbols::New(thread, "Eins");
1719 EXPECT_EQ(one.ptr(), eins.ptr());
1720 EXPECT_EQ(two.ptr(), Symbols::New(thread, "Zwei"));
1721 EXPECT_EQ(three.ptr(), Symbols::New(thread, "Drei"));
1722 EXPECT_EQ(four.ptr(), Symbols::New(thread, "Vier"));
1723 EXPECT_EQ(five.ptr(), Symbols::New(thread, "Fuenf"));
1724 EXPECT_EQ(six.ptr(), Symbols::New(thread, "Sechs"));
1725 EXPECT_EQ(seven.ptr(), Symbols::New(thread, "Sieben"));
1726 EXPECT_EQ(eight.ptr(), Symbols::New(thread, "Acht"));
1727 EXPECT_EQ(nine.ptr(), Symbols::New(thread, "Neun"));
1728 EXPECT_EQ(ten.ptr(), Symbols::New(thread, "Zehn"));
1729
1730 // Symbols from Strings.
1731 eins = String::New("Eins");
1732 EXPECT(!eins.IsSymbol());
1733 String& ein_symbol = String::Handle(Symbols::New(thread, eins));
1734 EXPECT_EQ(one.ptr(), ein_symbol.ptr());
1735 EXPECT(one.ptr() != eins.ptr());
1736
1737 uint16_t char16[] = {'E', 'l', 'f'};
1738 String& elf1 = String::Handle(Symbols::FromUTF16(thread, char16, 3));
1739 int32_t char32[] = {'E', 'l', 'f'};
1740 String& elf2 = String::Handle(
1741 Symbols::New(thread, String::Handle(String::FromUTF32(char32, 3))));
1742 EXPECT(elf1.IsSymbol());
1743 EXPECT(elf2.IsSymbol());
1744 EXPECT_EQ(elf1.ptr(), Symbols::New(thread, "Elf"));
1745 EXPECT_EQ(elf2.ptr(), Symbols::New(thread, "Elf"));
1746}
1747
1749 uint16_t monkey_utf16[] = {0xd83d, 0xdc35}; // Unicode Monkey Face.
1750 String& monkey = String::Handle(Symbols::FromUTF16(thread, monkey_utf16, 2));
1751 EXPECT(monkey.IsSymbol());
1752 const char monkey_utf8[] = {'\xf0', '\x9f', '\x90', '\xb5', 0};
1753 EXPECT_EQ(monkey.ptr(), Symbols::New(thread, monkey_utf8));
1754
1755 int32_t kMonkeyFace = 0x1f435;
1756 String& monkey2 = String::Handle(
1757 Symbols::New(thread, String::Handle(String::FromUTF32(&kMonkeyFace, 1))));
1758 EXPECT_EQ(monkey.ptr(), monkey2.ptr());
1759
1760 // Unicode cat face with tears of joy.
1761 int32_t kCatFaceWithTearsOfJoy = 0x1f639;
1763 thread, String::Handle(String::FromUTF32(&kCatFaceWithTearsOfJoy, 1))));
1764
1765 uint16_t cat_utf16[] = {0xd83d, 0xde39};
1766 String& cat2 = String::Handle(Symbols::FromUTF16(thread, cat_utf16, 2));
1767 EXPECT(cat2.IsSymbol());
1768 EXPECT_EQ(cat2.ptr(), cat.ptr());
1769}
1770
1775
1777 const int kArrayLen = 5;
1778 const Array& array = Array::Handle(Array::New(kArrayLen));
1779 EXPECT_EQ(kArrayLen, array.Length());
1780 Object& element = Object::Handle(array.At(0));
1781 EXPECT(element.IsNull());
1782 element = array.At(kArrayLen - 1);
1783 EXPECT(element.IsNull());
1784 array.SetAt(0, array);
1785 array.SetAt(2, array);
1786 element = array.At(0);
1787 EXPECT_EQ(array.ptr(), element.ptr());
1788 element = array.At(1);
1789 EXPECT(element.IsNull());
1790 element = array.At(2);
1791 EXPECT_EQ(array.ptr(), element.ptr());
1792
1793 Array& other_array = Array::Handle(Array::New(kArrayLen));
1794 other_array.SetAt(0, array);
1795 other_array.SetAt(2, array);
1796
1797 EXPECT(array.CanonicalizeEquals(array));
1798 EXPECT(array.CanonicalizeEquals(other_array));
1799
1800 other_array.SetAt(1, other_array);
1801 EXPECT(!array.CanonicalizeEquals(other_array));
1802
1803 other_array = Array::New(kArrayLen - 1);
1804 other_array.SetAt(0, array);
1805 other_array.SetAt(2, array);
1806 EXPECT(!array.CanonicalizeEquals(other_array));
1807
1808 EXPECT_EQ(0, Object::empty_array().Length());
1809
1810 array.MakeImmutable();
1811 Object& obj = Object::Handle(array.ptr());
1812 EXPECT(obj.IsArray());
1813}
1814
1816 const intptr_t kSmallSize = 100;
1818 const intptr_t kMediumSize = 1000;
1820 const intptr_t kLargeSize = 100000;
1822
1823 const Array& small = Array::Handle(Array::New(kSmallSize));
1824 for (intptr_t i = 0; i < kSmallSize; i++) {
1825 small.SetAt(i, Smi::Handle(Smi::New(i)));
1826 }
1827
1828 const Array& medium = Array::Handle(Array::Grow(small, kMediumSize));
1829 EXPECT_EQ(kMediumSize, medium.Length());
1830 for (intptr_t i = 0; i < kSmallSize; i++) {
1831 EXPECT_EQ(Smi::New(i), medium.At(i));
1832 }
1833 for (intptr_t i = kSmallSize; i < kMediumSize; i++) {
1834 EXPECT_EQ(Object::null(), medium.At(i));
1835 }
1836
1837 const Array& large = Array::Handle(Array::Grow(small, kLargeSize));
1838 EXPECT_EQ(kLargeSize, large.Length());
1839 for (intptr_t i = 0; i < kSmallSize; i++) {
1840 EXPECT_EQ(large.At(i), Smi::New(i));
1841 }
1842 for (intptr_t i = kSmallSize; i < kLargeSize; i++) {
1843 EXPECT_EQ(large.At(i), Object::null());
1844 }
1845}
1846
1847ISOLATE_UNIT_TEST_CASE(EmptyInstantiationsCacheArray) {
1849 thread->isolate_group()->type_arguments_canonicalization_mutex());
1850 const Array& empty_cache = Object::empty_instantiations_cache_array();
1851 DEBUG_ONLY(EXPECT(TypeArguments::Cache::IsValidStorageLocked(empty_cache));)
1852 const TypeArguments::Cache cache(thread->zone(), empty_cache);
1853 EXPECT(cache.IsLinear());
1854 EXPECT(!cache.IsHash());
1855 EXPECT_EQ(0, cache.NumOccupied());
1856 const InstantiationsCacheTable table(empty_cache);
1857 EXPECT_EQ(1, table.Length());
1858 for (const auto& tuple : table) {
1861 }
1862}
1863
1864static void TestIllegalArrayLength(intptr_t length) {
1865 char buffer[1024];
1866 Utils::SNPrint(buffer, sizeof(buffer),
1867 "main() {\n"
1868 " List.filled(%" Pd
1869 ", null);\n"
1870 "}\n",
1871 length);
1873 EXPECT_VALID(lib);
1874 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
1875 Utils::SNPrint(buffer, sizeof(buffer),
1876 "Unhandled exception:\n"
1877 "RangeError (length): Invalid value: "
1878 "Not in inclusive range 0..%" Pd ": %" Pd,
1881}
1882
1883TEST_CASE(ArrayLengthNegativeOne) {
1885}
1886TEST_CASE(ArrayLengthSmiMin) {
1888}
1889
1890TEST_CASE(ArrayLengthOneTooMany) {
1891 const intptr_t kOneTooMany = Array::kMaxElements + 1;
1892 ASSERT(kOneTooMany >= 0);
1893
1894 char buffer[1024];
1895 Utils::SNPrint(buffer, sizeof(buffer),
1896 "main() {\n"
1897 " return List.filled(%" Pd
1898 ", null);\n"
1899 "}\n",
1900 kOneTooMany);
1902 EXPECT_VALID(lib);
1903 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
1904 EXPECT_ERROR(result, "Out of Memory");
1905}
1906
1907TEST_CASE(ArrayLengthMaxElements) {
1908 char buffer[1024];
1909 Utils::SNPrint(buffer, sizeof(buffer),
1910 "main() {\n"
1911 " return List.filled(%" Pd
1912 ", null);\n"
1913 "}\n",
1916 EXPECT_VALID(lib);
1917 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
1918 if (Dart_IsError(result)) {
1919 EXPECT_ERROR(result, "Out of Memory");
1920 } else {
1921 const intptr_t kExpected = Array::kMaxElements;
1922 intptr_t actual = 0;
1924 EXPECT_EQ(kExpected, actual);
1925 }
1926}
1927
1929 intptr_t length) {
1930 char buffer[1024];
1931 Utils::SNPrint(buffer, sizeof(buffer),
1932 "import 'dart:typed_data';\n"
1933 "main() {\n"
1934 " new %s(%" Pd
1935 ");\n"
1936 "}\n",
1939 EXPECT_VALID(lib);
1940 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
1941 Utils::SNPrint(buffer, sizeof(buffer), "%" Pd, length);
1942 EXPECT_ERROR(result, "RangeError (length): Invalid value");
1944}
1945
1946TEST_CASE(Int8ListLengthNegativeOne) {
1947 TestIllegalTypedDataLength("Int8List", -1);
1948}
1949TEST_CASE(Int8ListLengthSmiMin) {
1951}
1952TEST_CASE(Int8ListLengthOneTooMany) {
1953 const intptr_t kOneTooMany =
1954 TypedData::MaxElements(kTypedDataInt8ArrayCid) + 1;
1955 ASSERT(kOneTooMany >= 0);
1956
1957 char buffer[1024];
1958 Utils::SNPrint(buffer, sizeof(buffer),
1959 "import 'dart:typed_data';\n"
1960 "main() {\n"
1961 " return new Int8List(%" Pd
1962 ");\n"
1963 "}\n",
1964 kOneTooMany);
1966 EXPECT_VALID(lib);
1967 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
1968 EXPECT_ERROR(result, "Out of Memory");
1969}
1970
1971TEST_CASE(Int8ListLengthMaxElements) {
1972 const intptr_t max_elements = TypedData::MaxElements(kTypedDataInt8ArrayCid);
1973 char buffer[1024];
1974 Utils::SNPrint(buffer, sizeof(buffer),
1975 "import 'dart:typed_data';\n"
1976 "main() {\n"
1977 " return new Int8List(%" Pd
1978 ");\n"
1979 "}\n",
1980 max_elements);
1982 EXPECT_VALID(lib);
1983 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
1984 if (Dart_IsError(result)) {
1985 EXPECT_ERROR(result, "Out of Memory");
1986 } else {
1987 intptr_t actual = 0;
1989 EXPECT_EQ(max_elements, actual);
1990 }
1991}
1992
1993ISOLATE_UNIT_TEST_CASE(StringCodePointIterator) {
1994 const String& str0 = String::Handle(String::New(""));
1995 String::CodePointIterator it0(str0);
1996 EXPECT(!it0.Next());
1997
1998 const String& str1 = String::Handle(String::New(" \xc3\xa7 "));
1999 String::CodePointIterator it1(str1);
2000 EXPECT(it1.Next());
2001 EXPECT_EQ(' ', it1.Current());
2002 EXPECT(it1.Next());
2003 EXPECT_EQ(0xE7, it1.Current());
2004 EXPECT(it1.Next());
2005 EXPECT_EQ(' ', it1.Current());
2006 EXPECT(!it1.Next());
2007
2008 const String& str2 =
2009 String::Handle(String::New("\xD7\x92\xD7\x9C"
2010 "\xD7\xA2\xD7\x93"
2011 "\xD7\x91\xD7\xA8"
2012 "\xD7\x9B\xD7\x94"));
2013 String::CodePointIterator it2(str2);
2014 EXPECT(it2.Next());
2015 EXPECT_EQ(0x5D2, it2.Current());
2016 EXPECT(it2.Next());
2017 EXPECT_EQ(0x5DC, it2.Current());
2018 EXPECT(it2.Next());
2019 EXPECT_EQ(0x5E2, it2.Current());
2020 EXPECT(it2.Next());
2021 EXPECT_EQ(0x5D3, it2.Current());
2022 EXPECT(it2.Next());
2023 EXPECT_EQ(0x5D1, it2.Current());
2024 EXPECT(it2.Next());
2025 EXPECT_EQ(0x5E8, it2.Current());
2026 EXPECT(it2.Next());
2027 EXPECT_EQ(0x5DB, it2.Current());
2028 EXPECT(it2.Next());
2029 EXPECT_EQ(0x5D4, it2.Current());
2030 EXPECT(!it2.Next());
2031
2032 const String& str3 =
2033 String::Handle(String::New("\xF0\x9D\x91\xA0"
2034 "\xF0\x9D\x91\xA1"
2035 "\xF0\x9D\x91\xA2"
2036 "\xF0\x9D\x91\xA3"));
2037 String::CodePointIterator it3(str3);
2038 EXPECT(it3.Next());
2039 EXPECT_EQ(0x1D460, it3.Current());
2040 EXPECT(it3.Next());
2041 EXPECT_EQ(0x1D461, it3.Current());
2042 EXPECT(it3.Next());
2043 EXPECT_EQ(0x1D462, it3.Current());
2044 EXPECT(it3.Next());
2045 EXPECT_EQ(0x1D463, it3.Current());
2046 EXPECT(!it3.Next());
2047}
2048
2049ISOLATE_UNIT_TEST_CASE(StringCodePointIteratorRange) {
2050 const String& str = String::Handle(String::New("foo bar baz"));
2051
2052 String::CodePointIterator it0(str, 3, 0);
2053 EXPECT(!it0.Next());
2054
2055 String::CodePointIterator it1(str, 4, 3);
2056 EXPECT(it1.Next());
2057 EXPECT_EQ('b', it1.Current());
2058 EXPECT(it1.Next());
2059 EXPECT_EQ('a', it1.Current());
2060 EXPECT(it1.Next());
2061 EXPECT_EQ('r', it1.Current());
2062 EXPECT(!it1.Next());
2063}
2064
2066 const int kArrayLen = 5;
2067 Smi& value = Smi::Handle();
2070
2071 // Test basic growing functionality.
2072 array = GrowableObjectArray::New(kArrayLen);
2073 EXPECT_EQ(kArrayLen, array.Capacity());
2074 EXPECT_EQ(0, array.Length());
2075 for (intptr_t i = 0; i < 10; i++) {
2076 value = Smi::New(i);
2077 array.Add(value);
2078 }
2079 EXPECT_EQ(10, array.Length());
2080 for (intptr_t i = 0; i < 10; i++) {
2082 value ^= array.At(i);
2083 EXPECT(value.Equals(expected_value));
2084 }
2085 for (intptr_t i = 0; i < 10; i++) {
2086 value = Smi::New(i * 10);
2087 array.SetAt(i, value);
2088 }
2089 EXPECT_EQ(10, array.Length());
2090 for (intptr_t i = 0; i < 10; i++) {
2091 expected_value = Smi::New(i * 10);
2092 value ^= array.At(i);
2093 EXPECT(value.Equals(expected_value));
2094 }
2095
2096 // Test the MakeFixedLength functionality to make sure the resulting array
2097 // object is properly setup.
2098 // 1. Should produce an array of length 2 and a left over int8 array.
2099 Array& new_array = Array::Handle();
2100 TypedData& left_over_array = TypedData::Handle();
2101 Object& obj = Object::Handle();
2102 uword addr = 0;
2103 intptr_t used_size = 0;
2104
2105 array = GrowableObjectArray::New(kArrayLen + 1);
2106 EXPECT_EQ(kArrayLen + 1, array.Capacity());
2107 EXPECT_EQ(0, array.Length());
2108 for (intptr_t i = 0; i < 2; i++) {
2109 value = Smi::New(i);
2110 array.Add(value);
2111 }
2112 used_size = Array::InstanceSize(array.Length());
2113 new_array = Array::MakeFixedLength(array);
2114 addr = UntaggedObject::ToAddr(new_array.ptr());
2115 obj = UntaggedObject::FromAddr(addr);
2116 EXPECT(obj.IsArray());
2117 new_array ^= obj.ptr();
2118 EXPECT_EQ(2, new_array.Length());
2119 addr += used_size;
2120 obj = UntaggedObject::FromAddr(addr);
2121#if defined(DART_COMPRESSED_POINTERS)
2122 // In compressed pointer mode, the TypedData doesn't fit.
2123 EXPECT(obj.IsInstance());
2124#else
2125 EXPECT(obj.IsTypedData());
2126 left_over_array ^= obj.ptr();
2127 EXPECT_EQ(4 * kWordSize - TypedData::InstanceSize(0),
2128 left_over_array.Length());
2129#endif
2130
2131 // 2. Should produce an array of length 3 and a left over int8 array or
2132 // instance.
2133 array = GrowableObjectArray::New(kArrayLen);
2134 EXPECT_EQ(kArrayLen, array.Capacity());
2135 EXPECT_EQ(0, array.Length());
2136 for (intptr_t i = 0; i < 3; i++) {
2137 value = Smi::New(i);
2138 array.Add(value);
2139 }
2140 used_size = Array::InstanceSize(array.Length());
2141 new_array = Array::MakeFixedLength(array);
2142 addr = UntaggedObject::ToAddr(new_array.ptr());
2143 obj = UntaggedObject::FromAddr(addr);
2144 EXPECT(obj.IsArray());
2145 new_array ^= obj.ptr();
2146 EXPECT_EQ(3, new_array.Length());
2147 addr += used_size;
2148 obj = UntaggedObject::FromAddr(addr);
2150 EXPECT(obj.IsTypedData());
2151 left_over_array ^= obj.ptr();
2153 left_over_array.Length());
2154 } else {
2155 EXPECT(obj.IsInstance());
2156 }
2157
2158 // 3. Should produce an array of length 1 and a left over int8 array.
2159 array = GrowableObjectArray::New(kArrayLen + 3);
2160 EXPECT_EQ((kArrayLen + 3), array.Capacity());
2161 EXPECT_EQ(0, array.Length());
2162 for (intptr_t i = 0; i < 1; i++) {
2163 value = Smi::New(i);
2164 array.Add(value);
2165 }
2166 used_size = Array::InstanceSize(array.Length());
2167 new_array = Array::MakeFixedLength(array);
2168 addr = UntaggedObject::ToAddr(new_array.ptr());
2169 obj = UntaggedObject::FromAddr(addr);
2170 EXPECT(obj.IsArray());
2171 new_array ^= obj.ptr();
2172 EXPECT_EQ(1, new_array.Length());
2173 addr += used_size;
2174 obj = UntaggedObject::FromAddr(addr);
2175#if defined(DART_COMPRESSED_POINTERS)
2176 // In compressed pointer mode, the TypedData doesn't fit.
2177 EXPECT(obj.IsInstance());
2178#else
2179 EXPECT(obj.IsTypedData());
2180 left_over_array ^= obj.ptr();
2181 EXPECT_EQ(8 * kWordSize - TypedData::InstanceSize(0),
2182 left_over_array.Length());
2183#endif
2184
2185 // 4. Verify that GC can handle the filler object for a large array.
2186 array = GrowableObjectArray::New((1 * MB) >> kWordSizeLog2);
2187 EXPECT_EQ(0, array.Length());
2188 for (intptr_t i = 0; i < 1; i++) {
2189 value = Smi::New(i);
2190 array.Add(value);
2191 }
2192 Heap* heap = IsolateGroup::Current()->heap();
2193 GCTestHelper::CollectAllGarbage();
2194 GCTestHelper::WaitForGCTasks(); // Sweeper must finish for accurate capacity.
2195 intptr_t capacity_before = heap->CapacityInWords(Heap::kOld);
2196 new_array = Array::MakeFixedLength(array);
2197 EXPECT_EQ(1, new_array.Length());
2198 GCTestHelper::CollectAllGarbage();
2199 GCTestHelper::WaitForGCTasks(); // Sweeper must finish for accurate capacity.
2200 intptr_t capacity_after = heap->CapacityInWords(Heap::kOld);
2201 // Page should shrink.
2202 EXPECT_LT(capacity_after, capacity_before);
2203 EXPECT_EQ(1, new_array.Length());
2204}
2205
2206ISOLATE_UNIT_TEST_CASE(TypedData_Grow) {
2207 const intptr_t kSmallSize = 42;
2208 const intptr_t kLargeSize = 1000;
2209
2210 Random random(42);
2211
2215
2216 const auto& small = TypedData::Handle(TypedData::New(cid, kSmallSize));
2217 EXPECT_EQ(small.LengthInBytes(), kSmallSize * small.ElementSizeInBytes());
2218
2219 for (intptr_t i = 0; i < TypedData::ElementSizeFor(cid) * kSmallSize; i++) {
2220 small.SetUint8(i, static_cast<uint8_t>(random.NextUInt64() & 0xff));
2221 }
2222
2223 const auto& big = TypedData::Handle(TypedData::Grow(small, kLargeSize));
2224 EXPECT_EQ(small.GetClassId(), big.GetClassId());
2225 EXPECT_EQ(big.LengthInBytes(), kLargeSize * big.ElementSizeInBytes());
2226
2227 for (intptr_t i = 0; i < TypedData::ElementSizeFor(cid) * kSmallSize; i++) {
2228 EXPECT_EQ(small.GetUint8(i), big.GetUint8(i));
2229 }
2230 for (intptr_t i = TypedData::ElementSizeFor(cid) * kSmallSize;
2231 i < TypedData::ElementSizeFor(cid) * kLargeSize; i++) {
2232 EXPECT_EQ(0, big.GetUint8(i));
2233 }
2234 }
2235}
2236
2237ISOLATE_UNIT_TEST_CASE(InternalTypedData) {
2238 uint8_t data[] = {253, 254, 255, 0, 1, 2, 3, 4};
2239 intptr_t data_length = ARRAY_SIZE(data);
2240
2241 const TypedData& int8_array =
2242 TypedData::Handle(TypedData::New(kTypedDataInt8ArrayCid, data_length));
2243 EXPECT(!int8_array.IsNull());
2244 EXPECT_EQ(data_length, int8_array.Length());
2245 for (intptr_t i = 0; i < data_length; ++i) {
2246 int8_array.SetInt8(i, data[i]);
2247 }
2248
2249 EXPECT_EQ(-3, int8_array.GetInt8(0));
2250 EXPECT_EQ(253, int8_array.GetUint8(0));
2251
2252 EXPECT_EQ(-2, int8_array.GetInt8(1));
2253 EXPECT_EQ(254, int8_array.GetUint8(1));
2254
2255 EXPECT_EQ(-1, int8_array.GetInt8(2));
2256 EXPECT_EQ(255, int8_array.GetUint8(2));
2257
2258 EXPECT_EQ(0, int8_array.GetInt8(3));
2259 EXPECT_EQ(0, int8_array.GetUint8(3));
2260
2261 EXPECT_EQ(1, int8_array.GetInt8(4));
2262 EXPECT_EQ(1, int8_array.GetUint8(4));
2263
2264 EXPECT_EQ(2, int8_array.GetInt8(5));
2265 EXPECT_EQ(2, int8_array.GetUint8(5));
2266
2267 EXPECT_EQ(3, int8_array.GetInt8(6));
2268 EXPECT_EQ(3, int8_array.GetUint8(6));
2269
2270 EXPECT_EQ(4, int8_array.GetInt8(7));
2271 EXPECT_EQ(4, int8_array.GetUint8(7));
2272
2273 const TypedData& int8_array2 =
2274 TypedData::Handle(TypedData::New(kTypedDataInt8ArrayCid, data_length));
2275 EXPECT(!int8_array.IsNull());
2276 EXPECT_EQ(data_length, int8_array.Length());
2277 for (intptr_t i = 0; i < data_length; ++i) {
2278 int8_array2.SetInt8(i, data[i]);
2279 }
2280
2281 for (intptr_t i = 0; i < data_length; ++i) {
2282 EXPECT_EQ(int8_array.GetInt8(i), int8_array2.GetInt8(i));
2283 }
2284 for (intptr_t i = 0; i < data_length; ++i) {
2285 int8_array.SetInt8(i, 123 + i);
2286 }
2287 for (intptr_t i = 0; i < data_length; ++i) {
2288 EXPECT(int8_array.GetInt8(i) != int8_array2.GetInt8(i));
2289 }
2290}
2291
2293 uint8_t data[] = {253, 254, 255, 0, 1, 2, 3, 4};
2294 intptr_t data_length = ARRAY_SIZE(data);
2295
2296 const ExternalTypedData& int8_array =
2298 kExternalTypedDataInt8ArrayCid, data, data_length));
2299 EXPECT(!int8_array.IsNull());
2300 EXPECT_EQ(data_length, int8_array.Length());
2301
2302 const ExternalTypedData& uint8_array =
2304 kExternalTypedDataUint8ArrayCid, data, data_length));
2305 EXPECT(!uint8_array.IsNull());
2306 EXPECT_EQ(data_length, uint8_array.Length());
2307
2308 const ExternalTypedData& uint8_clamped_array =
2310 kExternalTypedDataUint8ClampedArrayCid, data, data_length));
2311 EXPECT(!uint8_clamped_array.IsNull());
2312 EXPECT_EQ(data_length, uint8_clamped_array.Length());
2313
2314 EXPECT_EQ(-3, int8_array.GetInt8(0));
2315 EXPECT_EQ(253, uint8_array.GetUint8(0));
2316 EXPECT_EQ(253, uint8_clamped_array.GetUint8(0));
2317
2318 EXPECT_EQ(-2, int8_array.GetInt8(1));
2319 EXPECT_EQ(254, uint8_array.GetUint8(1));
2320 EXPECT_EQ(254, uint8_clamped_array.GetUint8(1));
2321
2322 EXPECT_EQ(-1, int8_array.GetInt8(2));
2323 EXPECT_EQ(255, uint8_array.GetUint8(2));
2324 EXPECT_EQ(255, uint8_clamped_array.GetUint8(2));
2325
2326 EXPECT_EQ(0, int8_array.GetInt8(3));
2327 EXPECT_EQ(0, uint8_array.GetUint8(3));
2328 EXPECT_EQ(0, uint8_clamped_array.GetUint8(3));
2329
2330 EXPECT_EQ(1, int8_array.GetInt8(4));
2331 EXPECT_EQ(1, uint8_array.GetUint8(4));
2332 EXPECT_EQ(1, uint8_clamped_array.GetUint8(4));
2333
2334 EXPECT_EQ(2, int8_array.GetInt8(5));
2335 EXPECT_EQ(2, uint8_array.GetUint8(5));
2336 EXPECT_EQ(2, uint8_clamped_array.GetUint8(5));
2337
2338 for (intptr_t i = 0; i < int8_array.Length(); ++i) {
2339 EXPECT_EQ(int8_array.GetUint8(i), uint8_array.GetUint8(i));
2340 }
2341
2342 int8_array.SetInt8(2, -123);
2343 uint8_array.SetUint8(0, 123);
2344 for (intptr_t i = 0; i < int8_array.Length(); ++i) {
2345 EXPECT_EQ(int8_array.GetInt8(i), uint8_array.GetInt8(i));
2346 }
2347
2348 uint8_clamped_array.SetUint8(0, 123);
2349 for (intptr_t i = 0; i < int8_array.Length(); ++i) {
2350 EXPECT_EQ(int8_array.GetUint8(i), uint8_clamped_array.GetUint8(i));
2351 }
2352}
2353
2355 {
2356 const char* url_chars = "builtin:test-case";
2357 const char* source_chars = "This will not compile.";
2358 const String& url = String::Handle(String::New(url_chars));
2359 const String& source = String::Handle(String::New(source_chars));
2360 const Script& script = Script::Handle(Script::New(url, source));
2361 EXPECT(!script.IsNull());
2362 EXPECT(script.IsScript());
2363 String& str = String::Handle(script.url());
2364 EXPECT_EQ(17, str.Length());
2365 EXPECT_EQ('b', str.CharAt(0));
2366 EXPECT_EQ(':', str.CharAt(7));
2367 EXPECT_EQ('e', str.CharAt(16));
2368 str = script.Source();
2369 EXPECT_EQ(22, str.Length());
2370 EXPECT_EQ('T', str.CharAt(0));
2371 EXPECT_EQ('n', str.CharAt(10));
2372 EXPECT_EQ('.', str.CharAt(21));
2373 }
2374
2375 {
2376 const char* url_chars = "";
2377 // Single line, no terminators.
2378 const char* source_chars = "abc";
2379 const String& url = String::Handle(String::New(url_chars));
2380 const String& source = String::Handle(String::New(source_chars));
2381 const Script& script = Script::Handle(Script::New(url, source));
2382 EXPECT(!script.IsNull());
2383 EXPECT(script.IsScript());
2384 auto& str = String::Handle(Z);
2385 str = script.GetLine(1);
2386 EXPECT_STREQ("abc", str.ToCString());
2387 str = script.GetSnippet(1, 1, 1, 2);
2388 EXPECT_STREQ("a", str.ToCString());
2389 str = script.GetSnippet(1, 2, 1, 4);
2390 EXPECT_STREQ("bc", str.ToCString());
2391 // Lines not in the source should return the empty string.
2392 str = script.GetLine(-500);
2393 EXPECT_STREQ("", str.ToCString());
2394 str = script.GetLine(0);
2395 EXPECT_STREQ("", str.ToCString());
2396 str = script.GetLine(2);
2397 EXPECT_STREQ("", str.ToCString());
2398 str = script.GetLine(10000);
2399 EXPECT_STREQ("", str.ToCString());
2400 // Snippets not contained within the source should be the null string.
2401 str = script.GetSnippet(-1, 1, 1, 2);
2402 EXPECT(str.IsNull());
2403 str = script.GetSnippet(2, 1, 2, 2);
2404 EXPECT(str.IsNull());
2405 str = script.GetSnippet(1, 1, 1, 5);
2406 EXPECT(str.IsNull());
2407 }
2408
2409 TransitionVMToNative transition(thread);
2410 const char* kScript = "main() {}";
2411 Dart_Handle h_lib = TestCase::LoadTestScript(kScript, nullptr);
2412 EXPECT_VALID(h_lib);
2413 Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, nullptr);
2415}
2416
2418 const int kNumVariables = 5;
2419 const Context& parent_context = Context::Handle(Context::New(0));
2420 const Context& context = Context::Handle(Context::New(kNumVariables));
2421 context.set_parent(parent_context);
2422 EXPECT_EQ(kNumVariables, context.num_variables());
2423 EXPECT(Context::Handle(context.parent()).ptr() == parent_context.ptr());
2424 EXPECT_EQ(0, Context::Handle(context.parent()).num_variables());
2425 EXPECT(Context::Handle(Context::Handle(context.parent()).parent()).IsNull());
2426 Object& variable = Object::Handle(context.At(0));
2427 EXPECT(variable.IsNull());
2428 variable = context.At(kNumVariables - 1);
2429 EXPECT(variable.IsNull());
2430 context.SetAt(0, Smi::Handle(Smi::New(2)));
2431 context.SetAt(2, Smi::Handle(Smi::New(3)));
2432 Smi& smi = Smi::Handle();
2433 smi ^= context.At(0);
2434 EXPECT_EQ(2, smi.Value());
2435 smi ^= context.At(2);
2436 EXPECT_EQ(3, smi.Value());
2437}
2438
2440 // We need an active compiler context to manipulate scopes, since local
2441 // variables and slots can be canonicalized in the compiler state.
2442 CompilerState compiler_state(Thread::Current(), /*is_aot=*/false,
2443 /*is_optimizing=*/false);
2444
2445 const intptr_t parent_scope_function_level = 0;
2446 LocalScope* parent_scope =
2447 new LocalScope(nullptr, parent_scope_function_level, 0);
2448
2449 const intptr_t local_scope_function_level = 1;
2450 LocalScope* local_scope =
2451 new LocalScope(parent_scope, local_scope_function_level, 0);
2452
2453 const Type& dynamic_type = Type::ZoneHandle(Type::DynamicType());
2454 const String& ta = Symbols::FunctionTypeArgumentsVar();
2455 LocalVariable* var_ta = new LocalVariable(
2456 TokenPosition::kNoSource, TokenPosition::kNoSource, ta, dynamic_type);
2457 parent_scope->AddVariable(var_ta);
2458
2459 const String& a = String::ZoneHandle(Symbols::New(thread, "a"));
2460 LocalVariable* var_a = new LocalVariable(
2461 TokenPosition::kNoSource, TokenPosition::kNoSource, a, dynamic_type);
2462 parent_scope->AddVariable(var_a);
2463
2464 const String& b = String::ZoneHandle(Symbols::New(thread, "b"));
2465 LocalVariable* var_b = new LocalVariable(
2466 TokenPosition::kNoSource, TokenPosition::kNoSource, b, dynamic_type);
2467 local_scope->AddVariable(var_b);
2468
2469 const String& c = String::ZoneHandle(Symbols::New(thread, "c"));
2470 LocalVariable* var_c = new LocalVariable(
2471 TokenPosition::kNoSource, TokenPosition::kNoSource, c, dynamic_type);
2472 parent_scope->AddVariable(var_c);
2473
2474 bool test_only = false; // Please, insert alias.
2475 var_ta = local_scope->LookupVariable(ta, LocalVariable::kNoKernelOffset,
2476 test_only);
2477 EXPECT(var_ta->is_captured());
2478 EXPECT_EQ(parent_scope_function_level, var_ta->owner()->function_level());
2480 var_ta); // Alias.
2481
2482 var_a =
2483 local_scope->LookupVariable(a, LocalVariable::kNoKernelOffset, test_only);
2484 EXPECT(var_a->is_captured());
2485 EXPECT_EQ(parent_scope_function_level, var_a->owner()->function_level());
2487 var_a); // Alias.
2488
2489 var_b =
2490 local_scope->LookupVariable(b, LocalVariable::kNoKernelOffset, test_only);
2491 EXPECT(!var_b->is_captured());
2492 EXPECT_EQ(local_scope_function_level, var_b->owner()->function_level());
2494 var_b);
2495
2496 test_only = true; // Please, do not insert alias.
2497 var_c =
2498 local_scope->LookupVariable(c, LocalVariable::kNoKernelOffset, test_only);
2499 EXPECT(!var_c->is_captured());
2500 EXPECT_EQ(parent_scope_function_level, var_c->owner()->function_level());
2501 // c is not in local_scope.
2503 nullptr);
2504
2505 test_only = false; // Please, insert alias.
2506 var_c =
2507 local_scope->LookupVariable(c, LocalVariable::kNoKernelOffset, test_only);
2508 EXPECT(var_c->is_captured());
2509
2510 EXPECT_EQ(4, local_scope->num_variables()); // ta, a, b, c.
2511 EXPECT_EQ(3, local_scope->NumCapturedVariables()); // ta, a, c.
2512
2513 const VariableIndex first_parameter_index(0);
2514 const int num_parameters = 0;
2515 const VariableIndex first_local_index(-1);
2516 bool found_captured_vars = false;
2517 VariableIndex next_index = parent_scope->AllocateVariables(
2518 Function::null_function(), first_parameter_index, num_parameters,
2519 first_local_index, nullptr, &found_captured_vars);
2520 // Variables a, c and var_ta are captured, therefore are not allocated in
2521 // frame.
2522 EXPECT_EQ(0, next_index.value() -
2523 first_local_index.value()); // Indices in frame < 0.
2524 const intptr_t parent_scope_context_level = 1;
2525 EXPECT_EQ(parent_scope_context_level, parent_scope->context_level());
2526 EXPECT(found_captured_vars);
2527
2528 const intptr_t local_scope_context_level = 5;
2529 const ContextScope& context_scope =
2531 Function::null_function(), local_scope_context_level));
2532 LocalScope* outer_scope = LocalScope::RestoreOuterScope(context_scope);
2533 EXPECT_EQ(3, outer_scope->num_variables());
2534
2535 var_ta = outer_scope->LocalLookupVariable(ta, LocalVariable::kNoKernelOffset);
2536 EXPECT(var_ta->is_captured());
2537 EXPECT_EQ(0, var_ta->index().value()); // First index.
2538 EXPECT_EQ(parent_scope_context_level - local_scope_context_level,
2539 var_ta->owner()->context_level()); // Adjusted context level.
2540
2542 EXPECT(var_a->is_captured());
2543 EXPECT_EQ(1, var_a->index().value()); // First index.
2544 EXPECT_EQ(parent_scope_context_level - local_scope_context_level,
2545 var_a->owner()->context_level()); // Adjusted context level.
2546
2547 // var b was not captured.
2549 nullptr);
2550
2551 var_c = outer_scope->LocalLookupVariable(c, LocalVariable::kNoKernelOffset);
2552 EXPECT(var_c->is_captured());
2553 EXPECT_EQ(2, var_c->index().value());
2554 EXPECT_EQ(parent_scope_context_level - local_scope_context_level,
2555 var_c->owner()->context_level()); // Adjusted context level.
2556}
2557
2559 // Allocate the class first.
2560 const String& class_name = String::Handle(Symbols::New(thread, "MyClass"));
2561 const Script& script = Script::Handle();
2562 const Class& cls = Class::Handle(CreateDummyClass(class_name, script));
2563 const Array& functions = Array::Handle(Array::New(1));
2564
2565 const Context& context = Context::Handle(Context::New(0));
2566 Function& parent = Function::Handle();
2567 const String& parent_name = String::Handle(Symbols::New(thread, "foo_papa"));
2569 parent = Function::New(signature, parent_name,
2570 UntaggedFunction::kRegularFunction, false, false,
2571 false, false, false, cls, TokenPosition::kMinSource);
2572 functions.SetAt(0, parent);
2573 {
2574 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
2575 cls.SetFunctions(functions);
2576 cls.Finalize();
2577 }
2578
2580 const String& function_name = String::Handle(Symbols::New(thread, "foo"));
2583 signature = function.signature();
2584 signature.set_result_type(Object::dynamic_type());
2585 signature ^= ClassFinalizer::FinalizeType(signature);
2586 function.SetSignature(signature);
2587 const Closure& closure = Closure::Handle(
2588 Closure::New(Object::null_type_arguments(), Object::null_type_arguments(),
2589 function, context));
2590 const Class& closure_class = Class::Handle(closure.clazz());
2591 EXPECT_EQ(closure_class.id(), kClosureCid);
2592 const Function& closure_function = Function::Handle(closure.function());
2593 EXPECT_EQ(closure_function.ptr(), function.ptr());
2594 const Context& closure_context = Context::Handle(closure.GetContext());
2595 EXPECT_EQ(closure_context.ptr(), context.ptr());
2596}
2597
2598ISOLATE_UNIT_TEST_CASE(ObjectPrinting) {
2599 // Simple Smis.
2600 EXPECT_STREQ("2", Smi::Handle(Smi::New(2)).ToCString());
2601 EXPECT_STREQ("-15", Smi::Handle(Smi::New(-15)).ToCString());
2602
2603 // bool class and true/false values.
2604 ObjectStore* object_store = IsolateGroup::Current()->object_store();
2605 const Class& bool_class = Class::Handle(object_store->bool_class());
2606 EXPECT_STREQ("Library:'dart:core' Class: bool", bool_class.ToCString());
2607 EXPECT_STREQ("true", Bool::True().ToCString());
2608 EXPECT_STREQ("false", Bool::False().ToCString());
2609
2610 // Strings.
2611 EXPECT_STREQ("Sugarbowl",
2612 String::Handle(String::New("Sugarbowl")).ToCString());
2613}
2614
2616 // Ensure that null handles have the correct C++ vtable setup.
2617 Zone* zone = Thread::Current()->zone();
2618 const String& str1 = String::Handle(zone);
2619 EXPECT(str1.IsString());
2620 EXPECT(str1.IsNull());
2621 const String& str2 = String::CheckedHandle(zone, Object::null());
2622 EXPECT(str2.IsString());
2623 EXPECT(str2.IsNull());
2624 String& str3 = String::Handle(zone);
2625 str3 ^= Object::null();
2626 EXPECT(str3.IsString());
2627 EXPECT(str3.IsNull());
2628 EXPECT(!str3.IsOneByteString());
2629 str3 = String::New("Steep and Deep!");
2630 EXPECT(str3.IsString());
2631 EXPECT(str3.IsOneByteString());
2632 str3 = OneByteString::null();
2633 EXPECT(str3.IsString());
2634 EXPECT(!str3.IsOneByteString());
2635}
2636
2637static LibraryPtr CreateDummyLibrary(const String& library_name) {
2638 return Library::New(library_name);
2639}
2640
2641static FunctionPtr CreateFunction(const char* name) {
2642 Thread* thread = Thread::Current();
2643 const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
2644 const String& lib_name = String::Handle(Symbols::New(thread, "ownerLibrary"));
2645 const Script& script = Script::Handle();
2646 const Class& owner_class =
2648 const Library& owner_library = Library::Handle(CreateDummyLibrary(lib_name));
2649 owner_class.set_library(owner_library);
2652 return Function::New(signature, function_name,
2653 UntaggedFunction::kRegularFunction, true, false, false,
2654 false, false, owner_class, TokenPosition::kMinSource);
2655}
2656
2657// Test for Code and Instruction object creation.
2659 extern void GenerateIncrement(compiler::Assembler * assembler);
2660 compiler::ObjectPoolBuilder object_pool_builder;
2661 compiler::Assembler _assembler_(&object_pool_builder);
2662 GenerateIncrement(&_assembler_);
2663 const Function& function = Function::Handle(CreateFunction("Test_Code"));
2664 SafepointWriteRwLocker locker(thread,
2665 thread->isolate_group()->program_lock());
2667 function, nullptr, &_assembler_, Code::PoolAttachment::kAttachPool));
2668 function.AttachCode(code);
2669 const Instructions& instructions = Instructions::Handle(code.instructions());
2670 uword payload_start = instructions.PayloadStart();
2671 EXPECT_EQ(instructions.ptr(), Instructions::FromPayloadStart(payload_start));
2672 const Object& result =
2673 Object::Handle(DartEntry::InvokeFunction(function, Array::empty_array()));
2674 EXPECT_EQ(1, Smi::Cast(result).Value());
2675}
2676
2677// Test for immutability of generated instructions. The test crashes with a
2678// segmentation fault when writing into it.
2680 extern void GenerateIncrement(compiler::Assembler * assembler);
2681 compiler::ObjectPoolBuilder object_pool_builder;
2682 compiler::Assembler _assembler_(&object_pool_builder);
2683 GenerateIncrement(&_assembler_);
2684 const Function& function = Function::Handle(CreateFunction("Test_Code"));
2685 SafepointWriteRwLocker locker(thread,
2686 thread->isolate_group()->program_lock());
2688 function, nullptr, &_assembler_, Code::PoolAttachment::kAttachPool));
2689 function.AttachCode(code);
2690 Instructions& instructions = Instructions::Handle(code.instructions());
2691 uword payload_start = instructions.PayloadStart();
2692 EXPECT_EQ(instructions.ptr(), Instructions::FromPayloadStart(payload_start));
2693 // Try writing into the generated code, expected to crash.
2694 *(reinterpret_cast<char*>(payload_start) + 1) = 1;
2695 if (!FLAG_write_protect_code) {
2696 // Since this test is expected to crash, crash if write protection of code
2697 // is switched off.
2698 FATAL("Test requires --write-protect-code; skip by forcing expected crash");
2699 }
2700}
2701
2703 public:
2704 static void SetInstructions(const Code& code,
2705 const Instructions& instructions,
2706 uword unchecked_offset) {
2707 code.SetActiveInstructions(instructions, unchecked_offset);
2708 code.set_instructions(instructions);
2709 }
2710};
2711
2712// Test for Embedded String object in the instructions.
2713ISOLATE_UNIT_TEST_CASE(EmbedStringInCode) {
2714 extern void GenerateEmbedStringInCode(compiler::Assembler * assembler,
2715 const char* str);
2716 const char* kHello = "Hello World!";
2717 word expected_length = static_cast<word>(strlen(kHello));
2718 compiler::ObjectPoolBuilder object_pool_builder;
2719 compiler::Assembler _assembler_(&object_pool_builder);
2720 GenerateEmbedStringInCode(&_assembler_, kHello);
2721 const Function& function =
2722 Function::Handle(CreateFunction("Test_EmbedStringInCode"));
2723 SafepointWriteRwLocker locker(thread,
2724 thread->isolate_group()->program_lock());
2726 function, nullptr, &_assembler_, Code::PoolAttachment::kAttachPool));
2727 function.AttachCode(code);
2728 const Object& result =
2729 Object::Handle(DartEntry::InvokeFunction(function, Array::empty_array()));
2730 EXPECT(result.ptr()->IsHeapObject());
2731 String& string_object = String::Handle();
2732 string_object ^= result.ptr();
2733 EXPECT(string_object.Length() == expected_length);
2734 for (int i = 0; i < expected_length; i++) {
2735 EXPECT(string_object.CharAt(i) == kHello[i]);
2736 }
2737}
2738
2739// Test for Embedded Smi object in the instructions.
2740ISOLATE_UNIT_TEST_CASE(EmbedSmiInCode) {
2741 extern void GenerateEmbedSmiInCode(compiler::Assembler * assembler,
2742 intptr_t value);
2743 const intptr_t kSmiTestValue = 5;
2744 compiler::ObjectPoolBuilder object_pool_builder;
2745 compiler::Assembler _assembler_(&object_pool_builder);
2746 GenerateEmbedSmiInCode(&_assembler_, kSmiTestValue);
2747 const Function& function =
2748 Function::Handle(CreateFunction("Test_EmbedSmiInCode"));
2749 SafepointWriteRwLocker locker(thread,
2750 thread->isolate_group()->program_lock());
2752 function, nullptr, &_assembler_, Code::PoolAttachment::kAttachPool));
2753 function.AttachCode(code);
2754 const Object& result =
2755 Object::Handle(DartEntry::InvokeFunction(function, Array::empty_array()));
2756 EXPECT(Smi::Cast(result).Value() == kSmiTestValue);
2757}
2758
2759#if defined(ARCH_IS_64_BIT) && !defined(DART_COMPRESSED_POINTERS)
2760// Test for Embedded Smi object in the instructions.
2761ISOLATE_UNIT_TEST_CASE(EmbedSmiIn64BitCode) {
2762 extern void GenerateEmbedSmiInCode(compiler::Assembler * assembler,
2763 intptr_t value);
2764 const intptr_t kSmiTestValue = DART_INT64_C(5) << 32;
2765 compiler::ObjectPoolBuilder object_pool_builder;
2766 compiler::Assembler _assembler_(&object_pool_builder);
2767 GenerateEmbedSmiInCode(&_assembler_, kSmiTestValue);
2768 const Function& function =
2769 Function::Handle(CreateFunction("Test_EmbedSmiIn64BitCode"));
2770 SafepointWriteRwLocker locker(thread,
2771 thread->isolate_group()->program_lock());
2772 const Code& code = Code::Handle(Code::FinalizeCodeAndNotify(
2773 function, nullptr, &_assembler_, Code::PoolAttachment::kAttachPool));
2774 function.AttachCode(code);
2775 const Object& result =
2776 Object::Handle(DartEntry::InvokeFunction(function, Array::empty_array()));
2777 EXPECT(Smi::Cast(result).Value() == kSmiTestValue);
2778}
2779#endif // ARCH_IS_64_BIT && !DART_COMPRESSED_POINTERS
2780
2782 const int kNumEntries = 4;
2783 // Add an exception handler table to the code.
2784 ExceptionHandlers& exception_handlers = ExceptionHandlers::Handle();
2785 exception_handlers ^= ExceptionHandlers::New(kNumEntries);
2786 const bool kNeedsStackTrace = true;
2787 const bool kNoStackTrace = false;
2788 exception_handlers.SetHandlerInfo(0, -1, 20u, kNeedsStackTrace, false, true);
2789 exception_handlers.SetHandlerInfo(1, 0, 30u, kNeedsStackTrace, false, true);
2790 exception_handlers.SetHandlerInfo(2, -1, 40u, kNoStackTrace, true, true);
2791 exception_handlers.SetHandlerInfo(3, 1, 150u, kNoStackTrace, true, true);
2792
2793 extern void GenerateIncrement(compiler::Assembler * assembler);
2794 compiler::ObjectPoolBuilder object_pool_builder;
2795 compiler::Assembler _assembler_(&object_pool_builder);
2796 GenerateIncrement(&_assembler_);
2797 SafepointWriteRwLocker locker(thread,
2798 thread->isolate_group()->program_lock());
2800 Function::Handle(CreateFunction("Test_Code")), nullptr, &_assembler_,
2802 code.set_exception_handlers(exception_handlers);
2803
2804 // Verify the exception handler table entries by accessing them.
2805 const ExceptionHandlers& handlers =
2806 ExceptionHandlers::Handle(code.exception_handlers());
2807 EXPECT_EQ(kNumEntries, handlers.num_entries());
2809 handlers.GetHandlerInfo(0, &info);
2810 EXPECT_EQ(-1, handlers.OuterTryIndex(0));
2811 EXPECT_EQ(-1, info.outer_try_index);
2812 EXPECT_EQ(20u, handlers.HandlerPCOffset(0));
2813 EXPECT(handlers.NeedsStackTrace(0));
2814 EXPECT(!handlers.HasCatchAll(0));
2815 EXPECT_EQ(20u, info.handler_pc_offset);
2816 EXPECT_EQ(1, handlers.OuterTryIndex(3));
2817 EXPECT_EQ(150u, handlers.HandlerPCOffset(3));
2818 EXPECT(!handlers.NeedsStackTrace(3));
2819 EXPECT(handlers.HasCatchAll(3));
2820}
2821
2823 DescriptorList* builder = new DescriptorList(thread->zone());
2824
2825 // kind, pc_offset, deopt_id, token_pos, try_index, yield_index
2826 builder->AddDescriptor(UntaggedPcDescriptors::kOther, 10, 1,
2827 TokenPosition::Deserialize(20), 1, 1);
2828 builder->AddDescriptor(UntaggedPcDescriptors::kDeopt, 20, 2,
2829 TokenPosition::Deserialize(30), 0, -1);
2830 builder->AddDescriptor(UntaggedPcDescriptors::kOther, 30, 3,
2831 TokenPosition::Deserialize(40), 1, 10);
2832 builder->AddDescriptor(UntaggedPcDescriptors::kOther, 10, 4,
2833 TokenPosition::Deserialize(40), 2, 20);
2834 builder->AddDescriptor(UntaggedPcDescriptors::kOther, 10, 5,
2835 TokenPosition::Deserialize(80), 3, 30);
2836 builder->AddDescriptor(UntaggedPcDescriptors::kOther, 80, 6,
2837 TokenPosition::Deserialize(150), 3, 30);
2838
2839 PcDescriptors& descriptors = PcDescriptors::Handle();
2840 descriptors ^= builder->FinalizePcDescriptors(0);
2841
2842 extern void GenerateIncrement(compiler::Assembler * assembler);
2843 compiler::ObjectPoolBuilder object_pool_builder;
2844 compiler::Assembler _assembler_(&object_pool_builder);
2845 GenerateIncrement(&_assembler_);
2846 SafepointWriteRwLocker locker(thread,
2847 thread->isolate_group()->program_lock());
2849 Function::Handle(CreateFunction("Test_Code")), nullptr, &_assembler_,
2851 code.set_pc_descriptors(descriptors);
2852
2853 // Verify the PcDescriptor entries by accessing them.
2854 const PcDescriptors& pc_descs = PcDescriptors::Handle(code.pc_descriptors());
2855 PcDescriptors::Iterator iter(pc_descs, UntaggedPcDescriptors::kAnyKind);
2856
2857 EXPECT_EQ(true, iter.MoveNext());
2858 EXPECT_EQ(1, iter.YieldIndex());
2859 EXPECT_EQ(20, iter.TokenPos().Pos());
2860 EXPECT_EQ(1, iter.TryIndex());
2861 EXPECT_EQ(static_cast<uword>(10), iter.PcOffset());
2862 EXPECT_EQ(1, iter.DeoptId());
2863 EXPECT_EQ(UntaggedPcDescriptors::kOther, iter.Kind());
2864
2865 EXPECT_EQ(true, iter.MoveNext());
2866 EXPECT_EQ(-1, iter.YieldIndex());
2867 EXPECT_EQ(30, iter.TokenPos().Pos());
2868 EXPECT_EQ(UntaggedPcDescriptors::kDeopt, iter.Kind());
2869
2870 EXPECT_EQ(true, iter.MoveNext());
2871 EXPECT_EQ(10, iter.YieldIndex());
2872 EXPECT_EQ(40, iter.TokenPos().Pos());
2873
2874 EXPECT_EQ(true, iter.MoveNext());
2875 EXPECT_EQ(20, iter.YieldIndex());
2876 EXPECT_EQ(40, iter.TokenPos().Pos());
2877
2878 EXPECT_EQ(true, iter.MoveNext());
2879 EXPECT_EQ(30, iter.YieldIndex());
2880 EXPECT_EQ(80, iter.TokenPos().Pos());
2881
2882 EXPECT_EQ(true, iter.MoveNext());
2883 EXPECT_EQ(30, iter.YieldIndex());
2884 EXPECT_EQ(150, iter.TokenPos().Pos());
2885
2886 EXPECT_EQ(3, iter.TryIndex());
2887 EXPECT_EQ(static_cast<uword>(80), iter.PcOffset());
2888 EXPECT_EQ(150, iter.TokenPos().Pos());
2889 EXPECT_EQ(UntaggedPcDescriptors::kOther, iter.Kind());
2890
2891 EXPECT_EQ(false, iter.MoveNext());
2892}
2893
2894ISOLATE_UNIT_TEST_CASE(PcDescriptorsLargeDeltas) {
2895 DescriptorList* builder = new DescriptorList(thread->zone());
2896
2897 // kind, pc_offset, deopt_id, token_pos, try_index
2898 builder->AddDescriptor(UntaggedPcDescriptors::kOther, 100, 1,
2899 TokenPosition::Deserialize(200), 1, 10);
2900 builder->AddDescriptor(UntaggedPcDescriptors::kDeopt, 200, 2,
2901 TokenPosition::Deserialize(300), 0, -1);
2902 builder->AddDescriptor(UntaggedPcDescriptors::kOther, 300, 3,
2903 TokenPosition::Deserialize(400), 1, 10);
2904 builder->AddDescriptor(UntaggedPcDescriptors::kOther, 100, 4,
2905 TokenPosition::Deserialize(0), 2, 20);
2906 builder->AddDescriptor(UntaggedPcDescriptors::kOther, 100, 5,
2907 TokenPosition::Deserialize(800), 3, 30);
2908 builder->AddDescriptor(UntaggedPcDescriptors::kOther, 800, 6,
2909 TokenPosition::Deserialize(150), 3, 30);
2910
2911 PcDescriptors& descriptors = PcDescriptors::Handle();
2912 descriptors ^= builder->FinalizePcDescriptors(0);
2913
2914 extern void GenerateIncrement(compiler::Assembler * assembler);
2915 compiler::ObjectPoolBuilder object_pool_builder;
2916 compiler::Assembler _assembler_(&object_pool_builder);
2917 GenerateIncrement(&_assembler_);
2918 SafepointWriteRwLocker locker(thread,
2919 thread->isolate_group()->program_lock());
2921 Function::Handle(CreateFunction("Test_Code")), nullptr, &_assembler_,
2923 code.set_pc_descriptors(descriptors);
2924
2925 // Verify the PcDescriptor entries by accessing them.
2926 const PcDescriptors& pc_descs = PcDescriptors::Handle(code.pc_descriptors());
2927 PcDescriptors::Iterator iter(pc_descs, UntaggedPcDescriptors::kAnyKind);
2928
2929 EXPECT_EQ(true, iter.MoveNext());
2930 EXPECT_EQ(10, iter.YieldIndex());
2931 EXPECT_EQ(200, iter.TokenPos().Pos());
2932 EXPECT_EQ(1, iter.TryIndex());
2933 EXPECT_EQ(static_cast<uword>(100), iter.PcOffset());
2934 EXPECT_EQ(1, iter.DeoptId());
2935 EXPECT_EQ(UntaggedPcDescriptors::kOther, iter.Kind());
2936
2937 EXPECT_EQ(true, iter.MoveNext());
2938 EXPECT_EQ(-1, iter.YieldIndex());
2939 EXPECT_EQ(300, iter.TokenPos().Pos());
2940 EXPECT_EQ(UntaggedPcDescriptors::kDeopt, iter.Kind());
2941
2942 EXPECT_EQ(true, iter.MoveNext());
2943 EXPECT_EQ(10, iter.YieldIndex());
2944 EXPECT_EQ(400, iter.TokenPos().Pos());
2945
2946 EXPECT_EQ(true, iter.MoveNext());
2947 EXPECT_EQ(20, iter.YieldIndex());
2948 EXPECT_EQ(0, iter.TokenPos().Pos());
2949
2950 EXPECT_EQ(true, iter.MoveNext());
2951 EXPECT_EQ(30, iter.YieldIndex());
2952 EXPECT_EQ(800, iter.TokenPos().Pos());
2953
2954 EXPECT_EQ(true, iter.MoveNext());
2955 EXPECT_EQ(30, iter.YieldIndex());
2956 EXPECT_EQ(150, iter.TokenPos().Pos());
2957
2958 EXPECT_EQ(3, iter.TryIndex());
2959 EXPECT_EQ(static_cast<uword>(800), iter.PcOffset());
2960 EXPECT_EQ(150, iter.TokenPos().Pos());
2961 EXPECT_EQ(UntaggedPcDescriptors::kOther, iter.Kind());
2962
2963 EXPECT_EQ(false, iter.MoveNext());
2964}
2965
2966static ClassPtr CreateTestClass(const char* name) {
2967 const String& class_name =
2969 const Class& cls =
2971 return cls.ptr();
2972}
2973
2974static FieldPtr CreateTestField(const char* name) {
2975 auto thread = Thread::Current();
2976 const Class& cls = Class::Handle(CreateTestClass("global:"));
2977 const String& field_name = String::Handle(Symbols::New(thread, name));
2978 const Field& field = Field::Handle(Field::New(
2979 field_name, true, false, false, true, false, cls, Object::dynamic_type(),
2981 {
2982 SafepointWriteRwLocker locker(thread,
2983 thread->isolate_group()->program_lock());
2984 thread->isolate_group()->RegisterStaticField(field, Object::sentinel());
2985 }
2986 return field.ptr();
2987}
2988
2990 Class& ae66 = Class::ZoneHandle(CreateTestClass("Ae6/6"));
2991 Class& re44 = Class::ZoneHandle(CreateTestClass("Re4/4"));
2992 Field& ce68 = Field::ZoneHandle(CreateTestField("Ce6/8"));
2994 String& url = String::ZoneHandle(String::New("SBB"));
2995 Library& lib = Library::Handle(Library::New(url));
2996 lib.AddClass(ae66);
2997 lib.AddObject(ce68, String::ZoneHandle(ce68.name()));
2998 lib.AddClass(re44);
2999 lib.AddObject(tee, String::ZoneHandle(tee.name()));
3000 ClassDictionaryIterator iterator(lib);
3001 int count = 0;
3002 Class& cls = Class::Handle();
3003 while (iterator.HasNext()) {
3004 cls = iterator.GetNextClass();
3005 EXPECT((cls.ptr() == ae66.ptr()) || (cls.ptr() == re44.ptr()));
3006 count++;
3007 }
3008 EXPECT(count == 2);
3009}
3010
3011static FunctionPtr GetDummyTarget(const char* name) {
3012 const String& function_name =
3014 const Class& cls =
3016 const bool is_static = false;
3017 const bool is_const = false;
3018 const bool is_abstract = false;
3019 const bool is_external = false;
3020 const bool is_native = false;
3022 return Function::New(signature, function_name,
3023 UntaggedFunction::kRegularFunction, is_static, is_const,
3024 is_abstract, is_external, is_native, cls,
3026}
3027
3030 const intptr_t id = 12;
3031 const intptr_t num_args_tested = 1;
3032 const String& target_name = String::Handle(Symbols::New(thread, "Thun"));
3033 const intptr_t kTypeArgsLen = 0;
3034 const intptr_t kNumArgs = 1;
3035 const Array& args_descriptor = Array::Handle(ArgumentsDescriptor::NewBoxed(
3036 kTypeArgsLen, kNumArgs, Object::null_array()));
3037 ICData& o1 = ICData::Handle();
3038 o1 = ICData::New(function, target_name, args_descriptor, id, num_args_tested,
3039 ICData::kInstance);
3040 EXPECT_EQ(1, o1.NumArgsTested());
3041 EXPECT_EQ(id, o1.deopt_id());
3042 EXPECT_EQ(function.ptr(), o1.Owner());
3043 EXPECT_EQ(0, o1.NumberOfChecks());
3044 EXPECT_EQ(target_name.ptr(), o1.target_name());
3045 EXPECT_EQ(args_descriptor.ptr(), o1.arguments_descriptor());
3046
3047 const Function& target1 = Function::Handle(GetDummyTarget("Thun"));
3048 o1.AddReceiverCheck(kSmiCid, target1);
3049 EXPECT_EQ(1, o1.NumberOfChecks());
3050 EXPECT_EQ(1, o1.NumberOfUsedChecks());
3051 intptr_t test_class_id = -1;
3052 Function& test_target = Function::Handle();
3053 o1.GetOneClassCheckAt(0, &test_class_id, &test_target);
3054 EXPECT_EQ(kSmiCid, test_class_id);
3055 EXPECT_EQ(target1.ptr(), test_target.ptr());
3056 EXPECT_EQ(kSmiCid, o1.GetCidAt(0));
3057 GrowableArray<intptr_t> test_class_ids;
3058 o1.GetCheckAt(0, &test_class_ids, &test_target);
3059 EXPECT_EQ(1, test_class_ids.length());
3060 EXPECT_EQ(kSmiCid, test_class_ids[0]);
3061 EXPECT_EQ(target1.ptr(), test_target.ptr());
3062
3063 const Function& target2 = Function::Handle(GetDummyTarget("Thun"));
3064 o1.AddReceiverCheck(kDoubleCid, target2);
3065 EXPECT_EQ(2, o1.NumberOfChecks());
3066 EXPECT_EQ(2, o1.NumberOfUsedChecks());
3067 o1.GetOneClassCheckAt(1, &test_class_id, &test_target);
3068 EXPECT_EQ(kDoubleCid, test_class_id);
3069 EXPECT_EQ(target2.ptr(), test_target.ptr());
3070 EXPECT_EQ(kDoubleCid, o1.GetCidAt(1));
3071
3072 o1.AddReceiverCheck(kMintCid, target2);
3073 EXPECT_EQ(3, o1.NumberOfUsedChecks());
3074 o1.SetCountAt(o1.NumberOfChecks() - 1, 0);
3075 EXPECT_EQ(2, o1.NumberOfUsedChecks());
3076
3077 ICData& o2 = ICData::Handle();
3078 o2 = ICData::New(function, target_name, args_descriptor, 57, 2,
3079 ICData::kInstance);
3080 EXPECT_EQ(2, o2.NumArgsTested());
3081 EXPECT_EQ(57, o2.deopt_id());
3082 EXPECT_EQ(function.ptr(), o2.Owner());
3083 EXPECT_EQ(0, o2.NumberOfChecks());
3085 classes.Add(kSmiCid);
3086 classes.Add(kSmiCid);
3087 o2.AddCheck(classes, target1);
3088 EXPECT_EQ(1, o2.NumberOfChecks());
3089 o2.GetCheckAt(0, &test_class_ids, &test_target);
3090 EXPECT_EQ(2, test_class_ids.length());
3091 EXPECT_EQ(kSmiCid, test_class_ids[0]);
3092 EXPECT_EQ(kSmiCid, test_class_ids[1]);
3093 EXPECT_EQ(target1.ptr(), test_target.ptr());
3094
3095 // Check ICData for unoptimized static calls.
3096 const intptr_t kNumArgsChecked = 0;
3097 const ICData& scall_icdata = ICData::Handle(
3098 ICData::NewForStaticCall(function, target1, args_descriptor, 57,
3099 kNumArgsChecked, ICData::kInstance));
3100 EXPECT_EQ(target1.ptr(), scall_icdata.GetTargetAt(0));
3101}
3102
3104 SafepointMutexLocker ml(thread->isolate_group()->subtype_test_cache_mutex());
3105
3106 String& class1_name = String::Handle(Symbols::New(thread, "EmptyClass1"));
3107 Script& script = Script::Handle();
3108 const Class& empty_class1 =
3109 Class::Handle(CreateDummyClass(class1_name, script));
3110 String& class2_name = String::Handle(Symbols::New(thread, "EmptyClass2"));
3111 const Class& empty_class2 =
3112 Class::Handle(CreateDummyClass(class2_name, script));
3115 EXPECT(!cache.IsNull());
3116 EXPECT_EQ(0, cache.NumberOfChecks());
3117 const Object& class_id_or_fun = Object::Handle(Smi::New(empty_class1.id()));
3118 const AbstractType& dest_type =
3125 cache.AddCheck(class_id_or_fun, dest_type, targ_0, targ_1, targ_2, targ_3,
3126 targ_4, Bool::True());
3127 EXPECT_EQ(1, cache.NumberOfChecks());
3128 Object& test_class_id_or_fun = Object::Handle();
3129 AbstractType& test_dest_type = AbstractType::Handle();
3130 TypeArguments& test_targ_0 = TypeArguments::Handle();
3131 TypeArguments& test_targ_1 = TypeArguments::Handle();
3132 TypeArguments& test_targ_2 = TypeArguments::Handle();
3133 TypeArguments& test_targ_3 = TypeArguments::Handle();
3134 TypeArguments& test_targ_4 = TypeArguments::Handle();
3135 Bool& test_result = Bool::Handle();
3136 cache.GetCheck(0, &test_class_id_or_fun, &test_dest_type, &test_targ_0,
3137 &test_targ_1, &test_targ_2, &test_targ_3, &test_targ_4,
3138 &test_result);
3139 EXPECT_EQ(class_id_or_fun.ptr(), test_class_id_or_fun.ptr());
3140 EXPECT_EQ(dest_type.ptr(), test_dest_type.ptr());
3141 EXPECT_EQ(targ_0.ptr(), test_targ_0.ptr());
3142 EXPECT_EQ(targ_1.ptr(), test_targ_1.ptr());
3143 EXPECT_EQ(targ_2.ptr(), test_targ_2.ptr());
3144 EXPECT_EQ(targ_3.ptr(), test_targ_3.ptr());
3145 EXPECT_EQ(targ_4.ptr(), test_targ_4.ptr());
3146 EXPECT_EQ(Bool::True().ptr(), test_result.ptr());
3147}
3148
3150 const auto& name = String::Handle(Symbols::New(thread, "name"));
3151 const auto& args_descriptor =
3152 Array::Handle(ArgumentsDescriptor::NewBoxed(1, 1, Object::null_array()));
3153
3154 const auto& cidA = Smi::Handle(Smi::New(1));
3155 const auto& cidB = Smi::Handle(Smi::New(2));
3156
3157 const auto& valueA = Smi::Handle(Smi::New(42));
3158 const auto& valueB = Smi::Handle(Smi::New(43));
3159
3160 // Test normal insert/lookup methods.
3161 {
3162 const auto& cache =
3163 MegamorphicCache::Handle(MegamorphicCache::New(name, args_descriptor));
3164
3165 EXPECT(cache.Lookup(cidA) == Object::null());
3166 cache.EnsureContains(cidA, valueA);
3167 EXPECT(cache.Lookup(cidA) == valueA.ptr());
3168
3169 EXPECT(cache.Lookup(cidB) == Object::null());
3170 cache.EnsureContains(cidB, valueB);
3171 EXPECT(cache.Lookup(cidB) == valueB.ptr());
3172 }
3173
3174 // Try to insert many keys to hit collisions & growth.
3175 {
3176 const auto& cache =
3177 MegamorphicCache::Handle(MegamorphicCache::New(name, args_descriptor));
3178
3179 auto& cid = Smi::Handle();
3180 auto& value = Object::Handle();
3181 for (intptr_t i = 0; i < 100; ++i) {
3182 cid = Smi::New(100 * i);
3183 if (cid.Value() == kIllegalCid) continue;
3184
3185 value = Smi::New(i);
3186 cache.EnsureContains(cid, value);
3187 }
3188 auto& expected = Object::Handle();
3189 for (intptr_t i = 0; i < 100; ++i) {
3190 cid = Smi::New(100 * i);
3191 if (cid.Value() == kIllegalCid) continue;
3192
3193 expected = Smi::New(i);
3194 value = cache.Lookup(cid);
3195 EXPECT(Smi::Cast(value).Equals(Smi::Cast(expected)));
3196 }
3197 }
3198}
3199
3201 const String& f = String::Handle(String::New("oneField"));
3202 const String& getter_f = String::Handle(Field::GetterName(f));
3203 const String& setter_f = String::Handle(Field::SetterName(f));
3206 EXPECT(Field::IsGetterName(getter_f));
3207 EXPECT(!Field::IsSetterName(getter_f));
3208 EXPECT(!Field::IsGetterName(setter_f));
3209 EXPECT(Field::IsSetterName(setter_f));
3210 EXPECT_STREQ(f.ToCString(),
3212 EXPECT_STREQ(f.ToCString(),
3214}
3215
3216// Expose helper function from object.cc for testing.
3217bool EqualsIgnoringPrivate(const String& name, const String& private_name);
3218
3220 String& mangled_name = String::Handle();
3221 String& bare_name = String::Handle();
3222
3223 // Simple matches.
3224 mangled_name = OneByteString::New("foo");
3225 bare_name = OneByteString::New("foo");
3226 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3227
3228 mangled_name = OneByteString::New("foo.");
3229 bare_name = OneByteString::New("foo.");
3230 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3231
3232 mangled_name = OneByteString::New("foo.named");
3233 bare_name = OneByteString::New("foo.named");
3234 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3235
3236 // Simple mismatches.
3237 mangled_name = OneByteString::New("bar");
3238 bare_name = OneByteString::New("foo");
3239 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3240
3241 mangled_name = OneByteString::New("foo.");
3242 bare_name = OneByteString::New("foo");
3243 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3244
3245 mangled_name = OneByteString::New("foo");
3246 bare_name = OneByteString::New("foo.");
3247 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3248
3249 mangled_name = OneByteString::New("foo.name");
3250 bare_name = OneByteString::New("foo.named");
3251 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3252
3253 mangled_name = OneByteString::New("foo.named");
3254 bare_name = OneByteString::New("foo.name");
3255 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3256
3257 // Private match.
3258 mangled_name = OneByteString::New("foo@12345");
3259 bare_name = OneByteString::New("foo");
3260 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3261
3262 // Private mismatch.
3263 mangled_name = OneByteString::New("food@12345");
3264 bare_name = OneByteString::New("foo");
3265 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3266
3267 // Private mismatch 2.
3268 mangled_name = OneByteString::New("foo@12345");
3269 bare_name = OneByteString::New("food");
3270 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3271
3272 // Private mixin application match.
3273 mangled_name = OneByteString::New("_M1@12345&_M2@12345&_M3@12345");
3274 bare_name = OneByteString::New("_M1&_M2&_M3");
3275 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3276
3277 // Private mixin application mismatch.
3278 mangled_name = OneByteString::New("_M1@12345&_M2@12345&_M3@12345");
3279 bare_name = OneByteString::New("_M1&_M2&_M4");
3280 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3281
3282 // Private constructor match.
3283 mangled_name = OneByteString::New("foo@12345.");
3284 bare_name = OneByteString::New("foo.");
3285 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3286
3287 // Private constructor mismatch.
3288 mangled_name = OneByteString::New("foo@12345.");
3289 bare_name = OneByteString::New("foo");
3290 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3291
3292 // Private constructor mismatch 2.
3293 mangled_name = OneByteString::New("foo@12345");
3294 bare_name = OneByteString::New("foo.");
3295 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3296
3297 // Named private constructor match.
3298 mangled_name = OneByteString::New("foo@12345.named");
3299 bare_name = OneByteString::New("foo.named");
3300 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3301
3302 // Named private constructor mismatch.
3303 mangled_name = OneByteString::New("foo@12345.name");
3304 bare_name = OneByteString::New("foo.named");
3305 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3306
3307 // Named private constructor mismatch 2.
3308 mangled_name = OneByteString::New("foo@12345.named");
3309 bare_name = OneByteString::New("foo.name");
3310 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3311
3312 // Named double-private constructor match. Yes, this happens.
3313 mangled_name = OneByteString::New("foo@12345.named@12345");
3314 bare_name = OneByteString::New("foo.named");
3315 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3316
3317 // Named double-private constructor match where the caller knows the private
3318 // key. Yes, this also happens.
3319 mangled_name = OneByteString::New("foo@12345.named@12345");
3320 bare_name = OneByteString::New("foo@12345.named");
3321 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3322
3323 // Named double-private constructor mismatch.
3324 mangled_name = OneByteString::New("foo@12345.name@12345");
3325 bare_name = OneByteString::New("foo.named");
3326 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3327
3328 // Named double-private constructor mismatch.
3329 mangled_name = OneByteString::New("foo@12345.named@12345");
3330 bare_name = OneByteString::New("foo.name");
3331 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3332}
3333
3334ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION(ArrayNew_Overflow_Crash, "Crash") {
3336}
3337
3338TEST_CASE(StackTraceFormat) {
3339 const char* kScriptChars =
3340 "void baz() {\n"
3341 " throw 'MyException';\n"
3342 "}\n"
3343 "\n"
3344 "class _OtherClass {\n"
3345 " _OtherClass._named() {\n"
3346 " baz();\n"
3347 " }\n"
3348 "}\n"
3349 "\n"
3350 "set globalVar(var value) {\n"
3351 " new _OtherClass._named();\n"
3352 "}\n"
3353 "\n"
3354 "void _bar() {\n"
3355 " globalVar = null;\n"
3356 "}\n"
3357 "\n"
3358 "class MyClass {\n"
3359 " MyClass() {\n"
3360 " (() => foo())();\n"
3361 " }\n"
3362 "\n"
3363 " static get field {\n"
3364 " _bar();\n"
3365 " }\n"
3366 "\n"
3367 " static foo() {\n"
3368 " fooHelper() {\n"
3369 " field;\n"
3370 " }\n"
3371 " fooHelper();\n"
3372 " }\n"
3373 "}\n"
3374 "\n"
3375 "main() {\n"
3376 " (() => new MyClass())();\n"
3377 "}\n";
3378 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
3379 EXPECT_VALID(lib);
3380 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, nullptr);
3381
3382 const char* lib_url = "file:///test-lib";
3383 const size_t kBufferSize = 1024;
3384 char expected[kBufferSize];
3385 snprintf(expected, kBufferSize,
3386 "Unhandled exception:\n"
3387 "MyException\n"
3388 "#0 baz (%1$s:2:3)\n"
3389 "#1 new _OtherClass._named (%1$s:7:5)\n"
3390 "#2 globalVar= (%1$s:12:7)\n"
3391 "#3 _bar (%1$s:16:3)\n"
3392 "#4 MyClass.field (%1$s:25:5)\n"
3393 "#5 MyClass.foo.fooHelper (%1$s:30:7)\n"
3394 "#6 MyClass.foo (%1$s:32:5)\n"
3395 "#7 new MyClass.<anonymous closure> (%1$s:21:12)\n"
3396 "#8 new MyClass (%1$s:21:18)\n"
3397 "#9 main.<anonymous closure> (%1$s:37:14)\n"
3398 "#10 main (%1$s:37:24)",
3399 lib_url);
3400
3401 EXPECT_ERROR(result, expected);
3402}
3403
3404ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveRecurse) {
3405 // This used to end in an infinite recursion. Caused by scavenging the weak
3406 // property before scavenging the key.
3408 Array& arr = Array::Handle(Array::New(1));
3409 {
3410 HANDLESCOPE(thread);
3412 key ^= OneByteString::New("key");
3413 arr.SetAt(0, key);
3415 value ^= OneByteString::New("value");
3416 weak ^= WeakProperty::New();
3417 weak.set_key(key);
3418 weak.set_value(value);
3419 }
3420 GCTestHelper::CollectAllGarbage();
3421 EXPECT(weak.key() != Object::null());
3422 EXPECT(weak.value() != Object::null());
3423}
3424
3425ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveOne_NewSpace) {
3428 key ^= OneByteString::New("key");
3429 {
3430 HANDLESCOPE(thread);
3432 value ^= OneByteString::New("value");
3433 weak ^= WeakProperty::New();
3434 weak.set_key(key);
3435 weak.set_value(value);
3436 }
3437 GCTestHelper::CollectNewSpace();
3438 EXPECT(weak.key() != Object::null());
3439 EXPECT(weak.value() != Object::null());
3440}
3441
3442ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwo_NewSpace) {
3444 String& key1 = String::Handle();
3445 key1 ^= OneByteString::New("key1");
3447 String& key2 = String::Handle();
3448 key2 ^= OneByteString::New("key2");
3449 {
3450 HANDLESCOPE(thread);
3451 String& value1 = String::Handle();
3452 value1 ^= OneByteString::New("value1");
3454 weak1.set_key(key1);
3455 weak1.set_value(value1);
3456 String& value2 = String::Handle();
3457 value2 ^= OneByteString::New("value2");
3459 weak2.set_key(key2);
3460 weak2.set_value(value2);
3461 }
3462 GCTestHelper::CollectNewSpace();
3463 EXPECT(weak1.key() != Object::null());
3464 EXPECT(weak1.value() != Object::null());
3465 EXPECT(weak2.key() != Object::null());
3466 EXPECT(weak2.value() != Object::null());
3467}
3468
3469ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwoShared_NewSpace) {
3473 key ^= OneByteString::New("key");
3474 {
3475 HANDLESCOPE(thread);
3476 String& value1 = String::Handle();
3477 value1 ^= OneByteString::New("value1");
3479 weak1.set_key(key);
3480 weak1.set_value(value1);
3481 String& value2 = String::Handle();
3482 value2 ^= OneByteString::New("value2");
3484 weak2.set_key(key);
3485 weak2.set_value(value2);
3486 }
3487 GCTestHelper::CollectNewSpace();
3488 EXPECT(weak1.key() != Object::null());
3489 EXPECT(weak1.value() != Object::null());
3490 EXPECT(weak2.key() != Object::null());
3491 EXPECT(weak2.value() != Object::null());
3492}
3493
3494ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveOne_OldSpace) {
3498 {
3499 HANDLESCOPE(thread);
3501 value ^= OneByteString::New("value", Heap::kOld);
3503 weak.set_key(key);
3504 weak.set_value(value);
3505 }
3506 GCTestHelper::CollectAllGarbage();
3507 EXPECT(weak.key() != Object::null());
3508 EXPECT(weak.value() != Object::null());
3509}
3510
3511ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwo_OldSpace) {
3513 String& key1 = String::Handle();
3514 key1 ^= OneByteString::New("key1", Heap::kOld);
3516 String& key2 = String::Handle();
3517 key2 ^= OneByteString::New("key2", Heap::kOld);
3518 {
3519 HANDLESCOPE(thread);
3520 String& value1 = String::Handle();
3521 value1 ^= OneByteString::New("value1", Heap::kOld);
3523 weak1.set_key(key1);
3524 weak1.set_value(value1);
3525 String& value2 = String::Handle();
3526 value2 ^= OneByteString::New("value2", Heap::kOld);
3528 weak2.set_key(key2);
3529 weak2.set_value(value2);
3530 }
3531 GCTestHelper::CollectAllGarbage();
3532 EXPECT(weak1.key() != Object::null());
3533 EXPECT(weak1.value() != Object::null());
3534 EXPECT(weak2.key() != Object::null());
3535 EXPECT(weak2.value() != Object::null());
3536}
3537
3538ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwoShared_OldSpace) {
3543 {
3544 HANDLESCOPE(thread);
3545 String& value1 = String::Handle();
3546 value1 ^= OneByteString::New("value1", Heap::kOld);
3548 weak1.set_key(key);
3549 weak1.set_value(value1);
3550 String& value2 = String::Handle();
3551 value2 ^= OneByteString::New("value2", Heap::kOld);
3553 weak2.set_key(key);
3554 weak2.set_value(value2);
3555 }
3556 GCTestHelper::CollectAllGarbage();
3557 EXPECT(weak1.key() != Object::null());
3558 EXPECT(weak1.value() != Object::null());
3559 EXPECT(weak2.key() != Object::null());
3560 EXPECT(weak2.value() != Object::null());
3561}
3562
3563ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearOne_NewSpace) {
3565 {
3566 HANDLESCOPE(thread);
3568 key ^= OneByteString::New("key");
3570 value ^= OneByteString::New("value");
3571 weak ^= WeakProperty::New();
3572 weak.set_key(key);
3573 weak.set_value(value);
3576 }
3577 GCTestHelper::CollectNewSpace();
3578 EXPECT(weak.key() == Object::null());
3579 EXPECT(weak.value() == Object::null());
3580}
3581
3582ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearTwoShared_NewSpace) {
3585 {
3586 HANDLESCOPE(thread);
3588 key ^= OneByteString::New("key");
3589 String& value1 = String::Handle();
3590 value1 ^= OneByteString::New("value1");
3592 weak1.set_key(key);
3593 weak1.set_value(value1);
3594 String& value2 = String::Handle();
3595 value2 ^= OneByteString::New("value2");
3597 weak2.set_key(key);
3598 weak2.set_value(value2);
3599 }
3600 GCTestHelper::CollectNewSpace();
3601 EXPECT(weak1.key() == Object::null());
3602 EXPECT(weak1.value() == Object::null());
3603 EXPECT(weak2.key() == Object::null());
3604 EXPECT(weak2.value() == Object::null());
3605}
3606
3607ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearOne_OldSpace) {
3609 {
3610 HANDLESCOPE(thread);
3614 value ^= OneByteString::New("value", Heap::kOld);
3616 weak.set_key(key);
3617 weak.set_value(value);
3620 }
3621 GCTestHelper::CollectAllGarbage();
3622 EXPECT(weak.key() == Object::null());
3623 EXPECT(weak.value() == Object::null());
3624}
3625
3626ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearTwoShared_OldSpace) {
3629 {
3630 HANDLESCOPE(thread);
3633 String& value1 = String::Handle();
3634 value1 ^= OneByteString::New("value1");
3636 weak1.set_key(key);
3637 weak1.set_value(value1);
3638 String& value2 = String::Handle();
3639 value2 ^= OneByteString::New("value2", Heap::kOld);
3641 weak2.set_key(key);
3642 weak2.set_value(value2);
3643 }
3644 GCTestHelper::CollectAllGarbage();
3645 EXPECT(weak1.key() == Object::null());
3646 EXPECT(weak1.value() == Object::null());
3647 EXPECT(weak2.key() == Object::null());
3648 EXPECT(weak2.value() == Object::null());
3649}
3650
3651static void WeakReference_PreserveOne(Thread* thread, Heap::Space space) {
3652 auto& weak = WeakReference::Handle();
3653 const auto& target = String::Handle(OneByteString::New("target", space));
3654 {
3655 HANDLESCOPE(thread);
3656 ObjectStore* object_store = thread->isolate_group()->object_store();
3657 const auto& type_arguments =
3658 TypeArguments::Handle(object_store->type_argument_double());
3659 weak ^= WeakReference::New(space);
3660 weak.set_target(target);
3661 weak.SetTypeArguments(type_arguments);
3662 }
3663
3664 if (space == Heap::kNew) {
3665 GCTestHelper::CollectNewSpace();
3666 } else {
3667 GCTestHelper::CollectAllGarbage();
3668 }
3669
3670 EXPECT(weak.target() != Object::null());
3671 EXPECT(weak.GetTypeArguments() != Object::null());
3672}
3673
3674ISOLATE_UNIT_TEST_CASE(WeakReference_PreserveOne_NewSpace) {
3676}
3677
3678ISOLATE_UNIT_TEST_CASE(WeakReference_PreserveOne_OldSpace) {
3680}
3681
3682static void WeakReference_ClearOne(Thread* thread, Heap::Space space) {
3683 auto& weak = WeakReference::Handle();
3684 {
3685 HANDLESCOPE(thread);
3686 const auto& target = String::Handle(OneByteString::New("target", space));
3687 ObjectStore* object_store = thread->isolate_group()->object_store();
3688 const auto& type_arguments =
3689 TypeArguments::Handle(object_store->type_argument_double());
3690 weak ^= WeakReference::New(space);
3691 weak.set_target(target);
3692 weak.SetTypeArguments(type_arguments);
3693 }
3694
3695 if (space == Heap::kNew) {
3696 GCTestHelper::CollectNewSpace();
3697 } else {
3698 GCTestHelper::CollectAllGarbage();
3699 }
3700
3701 EXPECT(weak.target() == Object::null());
3702 EXPECT(weak.GetTypeArguments() != Object::null());
3703}
3704
3705ISOLATE_UNIT_TEST_CASE(WeakReference_ClearOne_NewSpace) {
3707}
3708
3709ISOLATE_UNIT_TEST_CASE(WeakReference_ClearOne_OldSpace) {
3711}
3712
3714 Thread* thread,
3715 Heap::Space space) {
3716 auto& weak_property = WeakProperty::Handle();
3717 const auto& key = String::Handle(OneByteString::New("key", space));
3718 {
3719 HANDLESCOPE(thread);
3720 ObjectStore* object_store = thread->isolate_group()->object_store();
3721 const auto& type_arguments =
3722 TypeArguments::Handle(object_store->type_argument_double());
3723 const auto& weak_reference =
3725 const auto& target = String::Handle(OneByteString::New("target", space));
3726 weak_reference.set_target(target);
3727 weak_reference.SetTypeArguments(type_arguments);
3728
3729 weak_property ^= WeakProperty::New(space);
3730 weak_property.set_key(key);
3731 weak_property.set_value(weak_reference);
3732 }
3733
3734 if (space == Heap::kNew) {
3735 GCTestHelper::CollectNewSpace();
3736 } else {
3737 GCTestHelper::CollectAllGarbage();
3738 }
3739
3740 const auto& weak_reference =
3741 WeakReference::CheckedHandle(Z, weak_property.value());
3742 EXPECT(weak_reference.target() == Object::null());
3743 EXPECT(weak_reference.GetTypeArguments() != Object::null());
3744}
3745
3747 WeakReference_Clear_ReachableThroughWeakProperty_NewSpace) {
3749}
3750
3752 WeakReference_Clear_ReachableThroughWeakProperty_OldSpace) {
3754}
3755
3757 Thread* thread,
3758 Heap::Space space) {
3759 auto& weak_property = WeakProperty::Handle();
3760 const auto& key = String::Handle(OneByteString::New("key", space));
3761 const auto& target = String::Handle(OneByteString::New("target", space));
3762 {
3763 HANDLESCOPE(thread);
3764 ObjectStore* object_store = thread->isolate_group()->object_store();
3765 const auto& type_arguments =
3766 TypeArguments::Handle(object_store->type_argument_double());
3767 const auto& weak_reference =
3769 weak_reference.set_target(target);
3770 weak_reference.SetTypeArguments(type_arguments);
3771
3772 weak_property ^= WeakProperty::New(space);
3773 weak_property.set_key(key);
3774 weak_property.set_value(weak_reference);
3775 }
3776
3777 if (space == Heap::kNew) {
3778 GCTestHelper::CollectNewSpace();
3779 } else {
3780 GCTestHelper::CollectAllGarbage();
3781 }
3782
3783 const auto& weak_reference =
3784 WeakReference::CheckedHandle(Z, weak_property.value());
3785 EXPECT(weak_reference.target() != Object::null());
3786 EXPECT(weak_reference.GetTypeArguments() != Object::null());
3787}
3788
3790 WeakReference_Preserve_ReachableThroughWeakProperty_NewSpace) {
3792}
3793
3795 WeakReference_Preserve_ReachableThroughWeakProperty_OldSpace) {
3797}
3798
3801 Object& target0 = Object::Handle();
3802 {
3803 HANDLESCOPE(thread);
3804 target0 = String::New("0", Heap::kNew);
3805 Object& target1 = Object::Handle(String::New("1", Heap::kNew));
3806 array.SetAt(0, target0);
3807 array.SetAt(1, target1);
3808 }
3809
3810 EXPECT(array.Length() == 2);
3811 EXPECT(array.At(0) != Object::null());
3812 EXPECT(array.At(1) != Object::null());
3813
3814 GCTestHelper::CollectNewSpace();
3815
3816 EXPECT(array.Length() == 2);
3817 EXPECT(array.At(0) != Object::null()); // Survives
3818 EXPECT(array.At(1) == Object::null()); // Cleared
3819}
3820
3823 Object& target0 = Object::Handle();
3824 {
3825 HANDLESCOPE(thread);
3826 target0 = String::New("0", Heap::kOld);
3827 Object& target1 = Object::Handle(String::New("1", Heap::kOld));
3828 array.SetAt(0, target0);
3829 array.SetAt(1, target1);
3830 }
3831
3832 EXPECT(array.Length() == 2);
3833 EXPECT(array.At(0) != Object::null());
3834 EXPECT(array.At(1) != Object::null());
3835
3836 GCTestHelper::CollectAllGarbage();
3837
3838 EXPECT(array.Length() == 2);
3839 EXPECT(array.At(0) != Object::null()); // Survives
3840 EXPECT(array.At(1) == Object::null()); // Cleared
3841}
3842
3843static int NumEntries(const FinalizerEntry& entry, intptr_t acc = 0) {
3844 if (entry.IsNull()) {
3845 return acc;
3846 }
3847 return NumEntries(FinalizerEntry::Handle(entry.next()), acc + 1);
3848}
3849
3850static void Finalizer_PreserveOne(Thread* thread,
3851 Heap::Space space,
3852 bool with_detach) {
3853#ifdef DEBUG
3854 SetFlagScope<bool> sfs(&FLAG_trace_finalizers, true);
3855#endif
3856
3857 MessageHandler* handler = thread->isolate()->message_handler();
3858 {
3860 EXPECT_EQ(0, aq.queue()->Length());
3861 }
3862
3863 const auto& finalizer = Finalizer::Handle(Finalizer::New(space));
3864 finalizer.set_isolate(thread->isolate());
3865 const auto& entry =
3867 const auto& value = String::Handle(OneByteString::New("value", space));
3868 entry.set_value(value);
3869 auto& detach = Object::Handle();
3870 if (with_detach) {
3871 detach = OneByteString::New("detach", space);
3872 } else {
3873 detach = Object::null();
3874 }
3875 entry.set_detach(detach);
3876 const auto& token = String::Handle(OneByteString::New("token", space));
3877 entry.set_token(token);
3878
3879 if (space == Heap::kNew) {
3880 GCTestHelper::CollectNewSpace();
3881 } else {
3882 GCTestHelper::CollectAllGarbage();
3883 }
3884
3885 // Nothing in the entry should have been collected.
3886 EXPECT_NE(Object::null(), entry.value());
3887 EXPECT((entry.detach() == Object::null()) ^ with_detach);
3888 EXPECT_NE(Object::null(), entry.token());
3889
3890 // The entry should not have moved to the collected list.
3891 EXPECT_EQ(0,
3892 NumEntries(FinalizerEntry::Handle(finalizer.entries_collected())));
3893
3894 // We should have no messages.
3895 {
3896 // Acquire ownership of message handler queues.
3898 EXPECT_EQ(0, aq.queue()->Length());
3899 }
3900}
3901
3902ISOLATE_UNIT_TEST_CASE(Finalizer_PreserveNoDetachOne_NewSpace) {
3903 Finalizer_PreserveOne(thread, Heap::kNew, false);
3904}
3905
3906ISOLATE_UNIT_TEST_CASE(Finalizer_PreserveNoDetachOne_OldSpace) {
3907 Finalizer_PreserveOne(thread, Heap::kOld, false);
3908}
3909
3910ISOLATE_UNIT_TEST_CASE(Finalizer_PreserveWithDetachOne_NewSpace) {
3911 Finalizer_PreserveOne(thread, Heap::kNew, true);
3912}
3913
3914ISOLATE_UNIT_TEST_CASE(Finalizer_PreserveWithDetachOne_OldSpace) {
3915 Finalizer_PreserveOne(thread, Heap::kOld, true);
3916}
3917
3918static void Finalizer_ClearDetachOne(Thread* thread, Heap::Space space) {
3919#ifdef DEBUG
3920 SetFlagScope<bool> sfs(&FLAG_trace_finalizers, true);
3921#endif
3922
3923 MessageHandler* handler = thread->isolate()->message_handler();
3924 {
3926 EXPECT_EQ(0, aq.queue()->Length());
3927 }
3928
3929 const auto& finalizer = Finalizer::Handle(Finalizer::New(space));
3930 finalizer.set_isolate(thread->isolate());
3931 const auto& entry =
3933 const auto& value = String::Handle(OneByteString::New("value", space));
3934 entry.set_value(value);
3935 const auto& token = String::Handle(OneByteString::New("token", space));
3936 entry.set_token(token);
3937
3938 {
3939 HANDLESCOPE(thread);
3940 const auto& detach = String::Handle(OneByteString::New("detach", space));
3941 entry.set_detach(detach);
3942 }
3943
3944 if (space == Heap::kNew) {
3945 GCTestHelper::CollectNewSpace();
3946 } else {
3947 GCTestHelper::CollectAllGarbage();
3948 }
3949
3950 // Detach should have been collected.
3951 EXPECT_NE(Object::null(), entry.value());
3952 EXPECT_EQ(Object::null(), entry.detach());
3953 EXPECT_NE(Object::null(), entry.token());
3954
3955 // The entry should not have moved to the collected list.
3956 EXPECT_EQ(0,
3957 NumEntries(FinalizerEntry::Handle(finalizer.entries_collected())));
3958
3959 // We should have no messages.
3960 {
3961 // Acquire ownership of message handler queues.
3963 EXPECT_EQ(0, aq.queue()->Length());
3964 }
3965}
3966
3967ISOLATE_UNIT_TEST_CASE(Finalizer_ClearDetachOne_NewSpace) {
3969}
3970
3971ISOLATE_UNIT_TEST_CASE(Finalizer_ClearDetachOne_OldSpace) {
3973}
3974
3976 Heap::Space space,
3977 bool null_token) {
3978#ifdef DEBUG
3979 SetFlagScope<bool> sfs(&FLAG_trace_finalizers, true);
3980#endif
3981
3982 MessageHandler* handler = thread->isolate()->message_handler();
3983 {
3985 EXPECT_EQ(0, aq.queue()->Length());
3986 }
3987
3988 const auto& finalizer = Finalizer::Handle(Finalizer::New(space));
3989 finalizer.set_isolate(thread->isolate());
3990 const auto& entry =
3992 const auto& detach = String::Handle(OneByteString::New("detach", space));
3993 auto& token = Object::Handle();
3994 if (null_token) {
3995 // Null is a valid token in Dart finalizers.
3996 token = Object::null();
3997 } else {
3998 token = OneByteString::New("token", space);
3999 }
4000 entry.set_token(token);
4001 entry.set_detach(detach);
4002
4003 {
4004 HANDLESCOPE(thread);
4005 const auto& value = String::Handle(OneByteString::New("value", space));
4006 entry.set_value(value);
4007 }
4008
4009 if (space == Heap::kNew) {
4010 GCTestHelper::CollectNewSpace();
4011 } else {
4012 GCTestHelper::CollectAllGarbage();
4013 }
4014
4015 // Value should have been collected.
4016 EXPECT_EQ(Object::null(), entry.value());
4017 EXPECT_NE(Object::null(), entry.detach());
4018
4019 // The entry should have moved to the collected list.
4020 EXPECT_EQ(1,
4021 NumEntries(FinalizerEntry::Handle(finalizer.entries_collected())));
4022
4023 // We should have 1 message.
4024 {
4025 // Acquire ownership of message handler queues.
4027 EXPECT_EQ(1, aq.queue()->Length());
4028 }
4029}
4030
4031ISOLATE_UNIT_TEST_CASE(Finalizer_ClearValueOne_NewSpace) {
4032 Finalizer_ClearValueOne(thread, Heap::kNew, false);
4033}
4034
4035ISOLATE_UNIT_TEST_CASE(Finalizer_ClearValueOne_OldSpace) {
4036 Finalizer_ClearValueOne(thread, Heap::kOld, false);
4037}
4038
4039ISOLATE_UNIT_TEST_CASE(Finalizer_ClearValueNullTokenOne_NewSpace) {
4040 Finalizer_ClearValueOne(thread, Heap::kNew, true);
4041}
4042
4043ISOLATE_UNIT_TEST_CASE(Finalizer_ClearValueNullTokenOne_OldSpace) {
4044 Finalizer_ClearValueOne(thread, Heap::kOld, true);
4045}
4046
4047static void Finalizer_DetachOne(Thread* thread,
4048 Heap::Space space,
4049 bool clear_value) {
4050#ifdef DEBUG
4051 SetFlagScope<bool> sfs(&FLAG_trace_finalizers, true);
4052#endif
4053
4054 MessageHandler* handler = thread->isolate()->message_handler();
4055 {
4057 EXPECT_EQ(0, aq.queue()->Length());
4058 }
4059
4060 const auto& finalizer = Finalizer::Handle(Finalizer::New(space));
4061 finalizer.set_isolate(thread->isolate());
4062 const auto& entry =
4064 const auto& detach = String::Handle(OneByteString::New("detach", space));
4065 entry.set_detach(detach);
4066
4067 // Simulate calling detach, setting the token of the entry to the entry.
4068 entry.set_token(entry);
4069
4070 auto& value = String::Handle();
4071 {
4072 HANDLESCOPE(thread);
4073
4074 const auto& object = String::Handle(OneByteString::New("value", space));
4075 entry.set_value(object);
4076 if (!clear_value) {
4077 value = object.ptr();
4078 }
4079 }
4080
4081 if (space == Heap::kNew) {
4082 GCTestHelper::CollectNewSpace();
4083 } else {
4084 GCTestHelper::CollectAllGarbage();
4085 }
4086
4087 EXPECT((entry.value() == Object::null()) ^ !clear_value);
4088 EXPECT_NE(Object::null(), entry.detach());
4089 EXPECT_EQ(entry.ptr(), entry.token());
4090
4091 // The entry should have been removed entirely
4092 EXPECT_EQ(0,
4093 NumEntries(FinalizerEntry::Handle(finalizer.entries_collected())));
4094
4095 // We should have no message.
4096 {
4097 // Acquire ownership of message handler queues.
4099 EXPECT_EQ(0, aq.queue()->Length());
4100 }
4101}
4102
4103ISOLATE_UNIT_TEST_CASE(Finalizer_DetachOne_NewSpace) {
4104 Finalizer_DetachOne(thread, Heap::kNew, false);
4105}
4106
4107ISOLATE_UNIT_TEST_CASE(Finalizer_DetachOne_OldSpace) {
4108 Finalizer_DetachOne(thread, Heap::kOld, false);
4109}
4110
4111ISOLATE_UNIT_TEST_CASE(Finalizer_DetachAndClearValueOne_NewSpace) {
4112 Finalizer_DetachOne(thread, Heap::kNew, true);
4113}
4114
4115ISOLATE_UNIT_TEST_CASE(Finalizer_DetachAndClearValueOne_OldSpace) {
4116 Finalizer_DetachOne(thread, Heap::kOld, true);
4117}
4118
4119static void Finalizer_GcFinalizer(Thread* thread, Heap::Space space) {
4120#ifdef DEBUG
4121 SetFlagScope<bool> sfs(&FLAG_trace_finalizers, true);
4122#endif
4123
4124 MessageHandler* handler = thread->isolate()->message_handler();
4125 {
4127 EXPECT_EQ(0, aq.queue()->Length());
4128 }
4129
4130 const auto& detach = String::Handle(OneByteString::New("detach", space));
4131 const auto& token = String::Handle(OneByteString::New("token", space));
4132
4133 {
4134 HANDLESCOPE(thread);
4135 const auto& finalizer = Finalizer::Handle(Finalizer::New(space));
4136 finalizer.set_isolate(thread->isolate());
4137 const auto& entry =
4139 entry.set_detach(detach);
4140 entry.set_token(token);
4141 const auto& value = String::Handle(OneByteString::New("value", space));
4142 entry.set_value(value);
4143 }
4144
4145 if (space == Heap::kNew) {
4146 GCTestHelper::CollectNewSpace();
4147 } else {
4148 GCTestHelper::CollectAllGarbage();
4149 }
4150
4151 // We should have no message, the Finalizer itself has been GCed.
4152 {
4153 // Acquire ownership of message handler queues.
4155 EXPECT_EQ(0, aq.queue()->Length());
4156 }
4157}
4158
4159ISOLATE_UNIT_TEST_CASE(Finalizer_GcFinalizer_NewSpace) {
4161}
4162
4163ISOLATE_UNIT_TEST_CASE(Finalizer_GcFinalizer_OldSpace) {
4165}
4166
4168 Thread* thread,
4169 Heap::Space* spaces,
4170 bool collect_old_space,
4171 bool collect_new_space,
4172 bool evacuate_new_space_and_collect_old_space,
4173 bool clear_value_1,
4174 bool clear_value_2,
4175 bool clear_detach_1,
4176 bool clear_detach_2) {
4177#ifdef DEBUG
4178 SetFlagScope<bool> sfs(&FLAG_trace_finalizers, true);
4179#endif
4180
4181 MessageHandler* handler = thread->isolate()->message_handler();
4182 // We're reusing the isolate in a loop, so there are messages from previous
4183 // runs of this test.
4184 intptr_t queue_length_start = 0;
4185 {
4187 queue_length_start = aq.queue()->Length();
4188 }
4189
4190 const auto& finalizer = Finalizer::Handle(Finalizer::New(spaces[0]));
4191 finalizer.set_isolate(thread->isolate());
4192 const auto& entry1 =
4193 FinalizerEntry::Handle(FinalizerEntry::New(finalizer, spaces[1]));
4194 const auto& entry2 =
4195 FinalizerEntry::Handle(FinalizerEntry::New(finalizer, spaces[2]));
4196
4197 auto& value1 = String::Handle();
4198 auto& detach1 = String::Handle();
4199 const auto& token1 = String::Handle(OneByteString::New("token1", spaces[3]));
4200 entry1.set_token(token1);
4201
4202 auto& value2 = String::Handle();
4203 auto& detach2 = String::Handle();
4204 const auto& token2 = String::Handle(OneByteString::New("token2", spaces[4]));
4205 entry2.set_token(token2);
4206 entry2.set_detach(detach2);
4207
4208 {
4209 HANDLESCOPE(thread);
4210 auto& object = String::Handle();
4211
4212 object ^= OneByteString::New("value1", spaces[5]);
4213 entry1.set_value(object);
4214 if (!clear_value_1) {
4215 value1 = object.ptr();
4216 }
4217
4218 object ^= OneByteString::New("detach", spaces[6]);
4219 entry1.set_detach(object);
4220 if (!clear_detach_1) {
4221 detach1 = object.ptr();
4222 }
4223
4224 object ^= OneByteString::New("value2", spaces[7]);
4225 entry2.set_value(object);
4226 if (!clear_value_2) {
4227 value2 = object.ptr();
4228 }
4229
4230 object ^= OneByteString::New("detach", spaces[8]);
4231 entry2.set_detach(object);
4232 if (!clear_detach_2) {
4233 detach2 = object.ptr();
4234 }
4235 }
4236
4237 if (collect_old_space) {
4238 GCTestHelper::CollectOldSpace();
4239 }
4240 if (collect_new_space) {
4241 GCTestHelper::CollectNewSpace();
4242 }
4243 if (evacuate_new_space_and_collect_old_space) {
4244 GCTestHelper::CollectAllGarbage();
4245 }
4246
4247 EXPECT((entry1.value() == Object::null()) ^ !clear_value_1);
4248 EXPECT((entry2.value() == Object::null()) ^ !clear_value_2);
4249 EXPECT((entry1.detach() == Object::null()) ^ !clear_detach_1);
4250 EXPECT((entry2.detach() == Object::null()) ^ !clear_detach_2);
4251 EXPECT_NE(Object::null(), entry1.token());
4252 EXPECT_NE(Object::null(), entry2.token());
4253
4254 const intptr_t expect_num_cleared =
4255 (clear_value_1 ? 1 : 0) + (clear_value_2 ? 1 : 0);
4256 EXPECT_EQ(expect_num_cleared,
4257 NumEntries(FinalizerEntry::Handle(finalizer.entries_collected())));
4258
4259 const intptr_t expect_num_messages = expect_num_cleared == 0 ? 0 : 1;
4260 {
4261 // Acquire ownership of message handler queues.
4263 EXPECT_EQ(expect_num_messages + queue_length_start, aq.queue()->Length());
4264 }
4265}
4266
4268
4269static void Finalizer_TwoEntries(Thread* thread,
4270 Heap::Space space,
4271 bool clear_value_1,
4272 bool clear_value_2,
4273 bool clear_detach_1,
4274 bool clear_detach_2) {
4275 const bool collect_old_space = true;
4276 const bool collect_new_space = space == Heap::kNew;
4277 const bool evacuate_new_space_and_collect_old_space = !collect_new_space;
4278
4280 for (intptr_t i = 0; i < kFinalizerTwoEntriesNumObjects; i++) {
4281 spaces[i] = space;
4282 }
4284 thread, spaces, collect_old_space, collect_new_space,
4285 evacuate_new_space_and_collect_old_space, clear_value_1, clear_value_2,
4286 clear_detach_1, clear_detach_2);
4287}
4288
4289ISOLATE_UNIT_TEST_CASE(Finalizer_ClearValueTwo_NewSpace) {
4290 Finalizer_TwoEntries(thread, Heap::kNew, true, true, false, false);
4291}
4292
4293ISOLATE_UNIT_TEST_CASE(Finalizer_ClearValueTwo_OldSpace) {
4294 Finalizer_TwoEntries(thread, Heap::kOld, true, true, false, false);
4295}
4296
4297ISOLATE_UNIT_TEST_CASE(Finalizer_ClearFirstValue_NewSpace) {
4298 Finalizer_TwoEntries(thread, Heap::kNew, true, false, false, false);
4299}
4300
4301ISOLATE_UNIT_TEST_CASE(Finalizer_ClearFirstValue_OldSpace) {
4302 Finalizer_TwoEntries(thread, Heap::kOld, true, false, false, false);
4303}
4304
4305ISOLATE_UNIT_TEST_CASE(Finalizer_ClearSecondValue_NewSpace) {
4306 Finalizer_TwoEntries(thread, Heap::kNew, false, true, false, false);
4307}
4308
4309ISOLATE_UNIT_TEST_CASE(Finalizer_ClearSecondValue_OldSpace) {
4310 Finalizer_TwoEntries(thread, Heap::kOld, false, true, false, false);
4311}
4312
4313ISOLATE_UNIT_TEST_CASE(Finalizer_PreserveTwo_NewSpace) {
4314 Finalizer_TwoEntries(thread, Heap::kNew, false, false, false, false);
4315}
4316
4317ISOLATE_UNIT_TEST_CASE(Finalizer_PreserveTwo_OldSpace) {
4318 Finalizer_TwoEntries(thread, Heap::kOld, false, false, false, false);
4319}
4320
4321ISOLATE_UNIT_TEST_CASE(Finalizer_ClearDetachTwo_NewSpace) {
4322 Finalizer_TwoEntries(thread, Heap::kNew, false, false, true, true);
4323}
4324
4325ISOLATE_UNIT_TEST_CASE(Finalizer_ClearDetachTwo_OldSpace) {
4326 Finalizer_TwoEntries(thread, Heap::kOld, false, false, true, true);
4327}
4328
4329static void Finalizer_TwoEntriesCrossGen(Thread* thread, intptr_t test_i) {
4330 ASSERT(test_i < (1 << kFinalizerTwoEntriesNumObjects));
4332 for (intptr_t i = 0; i < kFinalizerTwoEntriesNumObjects; i++) {
4333 spaces[i] = ((test_i >> i) & 0x1) == 0x1 ? Heap::kOld : Heap::kNew;
4334 }
4335 // Either collect or evacuate new space.
4336 for (const bool collect_new_space : {false, true}) {
4337 // Always run old space collection first.
4338 const bool collect_old_space = true;
4339 // Always run old space collection after new space.
4340 const bool evacuate_new_space_and_collect_old_space = true;
4341 for (intptr_t test_j = 0; test_j < 16; test_j++) {
4342 const bool clear_value_1 = (test_j >> 0 & 0x1) == 0x1;
4343 const bool clear_value_2 = (test_j >> 1 & 0x1) == 0x1;
4344 const bool clear_detach_1 = (test_j >> 2 & 0x1) == 0x1;
4345 const bool clear_detach_2 = (test_j >> 3 & 0x1) == 0x1;
4347 thread, spaces, collect_old_space, collect_new_space,
4348 evacuate_new_space_and_collect_old_space, clear_value_1,
4349 clear_value_2, clear_detach_1, clear_detach_2);
4350 }
4351 }
4352}
4353#define FINALIZER_CROSS_GEN_TEST_CASE(n) \
4354 ISOLATE_UNIT_TEST_CASE(Finalizer_CrossGen_##n) { \
4355 Finalizer_TwoEntriesCrossGen(thread, n); \
4356 }
4357
4358#define REPEAT_512(V) \
4359 V(0) \
4360 V(1) \
4361 V(2) \
4362 V(3) \
4363 V(4) \
4364 V(5) \
4365 V(6) \
4366 V(7) \
4367 V(8) \
4368 V(9) \
4369 V(10) \
4370 V(11) \
4371 V(12) \
4372 V(13) \
4373 V(14) \
4374 V(15) \
4375 V(16) \
4376 V(17) \
4377 V(18) \
4378 V(19) \
4379 V(20) \
4380 V(21) \
4381 V(22) \
4382 V(23) \
4383 V(24) \
4384 V(25) \
4385 V(26) \
4386 V(27) \
4387 V(28) \
4388 V(29) \
4389 V(30) \
4390 V(31) \
4391 V(32) \
4392 V(33) \
4393 V(34) \
4394 V(35) \
4395 V(36) \
4396 V(37) \
4397 V(38) \
4398 V(39) \
4399 V(40) \
4400 V(41) \
4401 V(42) \
4402 V(43) \
4403 V(44) \
4404 V(45) \
4405 V(46) \
4406 V(47) \
4407 V(48) \
4408 V(49) \
4409 V(50) \
4410 V(51) \
4411 V(52) \
4412 V(53) \
4413 V(54) \
4414 V(55) \
4415 V(56) \
4416 V(57) \
4417 V(58) \
4418 V(59) \
4419 V(60) \
4420 V(61) \
4421 V(62) \
4422 V(63) \
4423 V(64) \
4424 V(65) \
4425 V(66) \
4426 V(67) \
4427 V(68) \
4428 V(69) \
4429 V(70) \
4430 V(71) \
4431 V(72) \
4432 V(73) \
4433 V(74) \
4434 V(75) \
4435 V(76) \
4436 V(77) \
4437 V(78) \
4438 V(79) \
4439 V(80) \
4440 V(81) \
4441 V(82) \
4442 V(83) \
4443 V(84) \
4444 V(85) \
4445 V(86) \
4446 V(87) \
4447 V(88) \
4448 V(89) \
4449 V(90) \
4450 V(91) \
4451 V(92) \
4452 V(93) \
4453 V(94) \
4454 V(95) \
4455 V(96) \
4456 V(97) \
4457 V(98) \
4458 V(99) \
4459 V(100) \
4460 V(101) \
4461 V(102) \
4462 V(103) \
4463 V(104) \
4464 V(105) \
4465 V(106) \
4466 V(107) \
4467 V(108) \
4468 V(109) \
4469 V(110) \
4470 V(111) \
4471 V(112) \
4472 V(113) \
4473 V(114) \
4474 V(115) \
4475 V(116) \
4476 V(117) \
4477 V(118) \
4478 V(119) \
4479 V(120) \
4480 V(121) \
4481 V(122) \
4482 V(123) \
4483 V(124) \
4484 V(125) \
4485 V(126) \
4486 V(127) \
4487 V(128) \
4488 V(129) \
4489 V(130) \
4490 V(131) \
4491 V(132) \
4492 V(133) \
4493 V(134) \
4494 V(135) \
4495 V(136) \
4496 V(137) \
4497 V(138) \
4498 V(139) \
4499 V(140) \
4500 V(141) \
4501 V(142) \
4502 V(143) \
4503 V(144) \
4504 V(145) \
4505 V(146) \
4506 V(147) \
4507 V(148) \
4508 V(149) \
4509 V(150) \
4510 V(151) \
4511 V(152) \
4512 V(153) \
4513 V(154) \
4514 V(155) \
4515 V(156) \
4516 V(157) \
4517 V(158) \
4518 V(159) \
4519 V(160) \
4520 V(161) \
4521 V(162) \
4522 V(163) \
4523 V(164) \
4524 V(165) \
4525 V(166) \
4526 V(167) \
4527 V(168) \
4528 V(169) \
4529 V(170) \
4530 V(171) \
4531 V(172) \
4532 V(173) \
4533 V(174) \
4534 V(175) \
4535 V(176) \
4536 V(177) \
4537 V(178) \
4538 V(179) \
4539 V(180) \
4540 V(181) \
4541 V(182) \
4542 V(183) \
4543 V(184) \
4544 V(185) \
4545 V(186) \
4546 V(187) \
4547 V(188) \
4548 V(189) \
4549 V(190) \
4550 V(191) \
4551 V(192) \
4552 V(193) \
4553 V(194) \
4554 V(195) \
4555 V(196) \
4556 V(197) \
4557 V(198) \
4558 V(199) \
4559 V(200) \
4560 V(201) \
4561 V(202) \
4562 V(203) \
4563 V(204) \
4564 V(205) \
4565 V(206) \
4566 V(207) \
4567 V(208) \
4568 V(209) \
4569 V(210) \
4570 V(211) \
4571 V(212) \
4572 V(213) \
4573 V(214) \
4574 V(215) \
4575 V(216) \
4576 V(217) \
4577 V(218) \
4578 V(219) \
4579 V(220) \
4580 V(221) \
4581 V(222) \
4582 V(223) \
4583 V(224) \
4584 V(225) \
4585 V(226) \
4586 V(227) \
4587 V(228) \
4588 V(229) \
4589 V(230) \
4590 V(231) \
4591 V(232) \
4592 V(233) \
4593 V(234) \
4594 V(235) \
4595 V(236) \
4596 V(237) \
4597 V(238) \
4598 V(239) \
4599 V(240) \
4600 V(241) \
4601 V(242) \
4602 V(243) \
4603 V(244) \
4604 V(245) \
4605 V(246) \
4606 V(247) \
4607 V(248) \
4608 V(249) \
4609 V(250) \
4610 V(251) \
4611 V(252) \
4612 V(253) \
4613 V(254) \
4614 V(255) \
4615 V(256) \
4616 V(257) \
4617 V(258) \
4618 V(259) \
4619 V(260) \
4620 V(261) \
4621 V(262) \
4622 V(263) \
4623 V(264) \
4624 V(265) \
4625 V(266) \
4626 V(267) \
4627 V(268) \
4628 V(269) \
4629 V(270) \
4630 V(271) \
4631 V(272) \
4632 V(273) \
4633 V(274) \
4634 V(275) \
4635 V(276) \
4636 V(277) \
4637 V(278) \
4638 V(279) \
4639 V(280) \
4640 V(281) \
4641 V(282) \
4642 V(283) \
4643 V(284) \
4644 V(285) \
4645 V(286) \
4646 V(287) \
4647 V(288) \
4648 V(289) \
4649 V(290) \
4650 V(291) \
4651 V(292) \
4652 V(293) \
4653 V(294) \
4654 V(295) \
4655 V(296) \
4656 V(297) \
4657 V(298) \
4658 V(299) \
4659 V(300) \
4660 V(301) \
4661 V(302) \
4662 V(303) \
4663 V(304) \
4664 V(305) \
4665 V(306) \
4666 V(307) \
4667 V(308) \
4668 V(309) \
4669 V(310) \
4670 V(311) \
4671 V(312) \
4672 V(313) \
4673 V(314) \
4674 V(315) \
4675 V(316) \
4676 V(317) \
4677 V(318) \
4678 V(319) \
4679 V(320) \
4680 V(321) \
4681 V(322) \
4682 V(323) \
4683 V(324) \
4684 V(325) \
4685 V(326) \
4686 V(327) \
4687 V(328) \
4688 V(329) \
4689 V(330) \
4690 V(331) \
4691 V(332) \
4692 V(333) \
4693 V(334) \
4694 V(335) \
4695 V(336) \
4696 V(337) \
4697 V(338) \
4698 V(339) \
4699 V(340) \
4700 V(341) \
4701 V(342) \
4702 V(343) \
4703 V(344) \
4704 V(345) \
4705 V(346) \
4706 V(347) \
4707 V(348) \
4708 V(349) \
4709 V(350) \
4710 V(351) \
4711 V(352) \
4712 V(353) \
4713 V(354) \
4714 V(355) \
4715 V(356) \
4716 V(357) \
4717 V(358) \
4718 V(359) \
4719 V(360) \
4720 V(361) \
4721 V(362) \
4722 V(363) \
4723 V(364) \
4724 V(365) \
4725 V(366) \
4726 V(367) \
4727 V(368) \
4728 V(369) \
4729 V(370) \
4730 V(371) \
4731 V(372) \
4732 V(373) \
4733 V(374) \
4734 V(375) \
4735 V(376) \
4736 V(377) \
4737 V(378) \
4738 V(379) \
4739 V(380) \
4740 V(381) \
4741 V(382) \
4742 V(383) \
4743 V(384) \
4744 V(385) \
4745 V(386) \
4746 V(387) \
4747 V(388) \
4748 V(389) \
4749 V(390) \
4750 V(391) \
4751 V(392) \
4752 V(393) \
4753 V(394) \
4754 V(395) \
4755 V(396) \
4756 V(397) \
4757 V(398) \
4758 V(399) \
4759 V(400) \
4760 V(401) \
4761 V(402) \
4762 V(403) \
4763 V(404) \
4764 V(405) \
4765 V(406) \
4766 V(407) \
4767 V(408) \
4768 V(409) \
4769 V(410) \
4770 V(411) \
4771 V(412) \
4772 V(413) \
4773 V(414) \
4774 V(415) \
4775 V(416) \
4776 V(417) \
4777 V(418) \
4778 V(419) \
4779 V(420) \
4780 V(421) \
4781 V(422) \
4782 V(423) \
4783 V(424) \
4784 V(425) \
4785 V(426) \
4786 V(427) \
4787 V(428) \
4788 V(429) \
4789 V(430) \
4790 V(431) \
4791 V(432) \
4792 V(433) \
4793 V(434) \
4794 V(435) \
4795 V(436) \
4796 V(437) \
4797 V(438) \
4798 V(439) \
4799 V(440) \
4800 V(441) \
4801 V(442) \
4802 V(443) \
4803 V(444) \
4804 V(445) \
4805 V(446) \
4806 V(447) \
4807 V(448) \
4808 V(449) \
4809 V(450) \
4810 V(451) \
4811 V(452) \
4812 V(453) \
4813 V(454) \
4814 V(455) \
4815 V(456) \
4816 V(457) \
4817 V(458) \
4818 V(459) \
4819 V(460) \
4820 V(461) \
4821 V(462) \
4822 V(463) \
4823 V(464) \
4824 V(465) \
4825 V(466) \
4826 V(467) \
4827 V(468) \
4828 V(469) \
4829 V(470) \
4830 V(471) \
4831 V(472) \
4832 V(473) \
4833 V(474) \
4834 V(475) \
4835 V(476) \
4836 V(477) \
4837 V(478) \
4838 V(479) \
4839 V(480) \
4840 V(481) \
4841 V(482) \
4842 V(483) \
4843 V(484) \
4844 V(485) \
4845 V(486) \
4846 V(487) \
4847 V(488) \
4848 V(489) \
4849 V(490) \
4850 V(491) \
4851 V(492) \
4852 V(493) \
4853 V(494) \
4854 V(495) \
4855 V(496) \
4856 V(497) \
4857 V(498) \
4858 V(499) \
4859 V(500) \
4860 V(501) \
4861 V(502) \
4862 V(503) \
4863 V(504) \
4864 V(505) \
4865 V(506) \
4866 V(507) \
4867 V(508) \
4868 V(509) \
4869 V(510) \
4870 V(511)
4871
4873
4874#undef FINALIZER_CROSS_GEN_TEST_CASE
4875
4876// Force the marker to add a FinalizerEntry to the store buffer during marking.
4877//
4878// This test requires two entries, one in new space, one in old space.
4879// The scavenger should run first, adding the entry to collected_entries.
4880// The marker runs right after, swapping the collected_entries with the entry
4881// in old space, _and_ setting the next field to the entry in new space.
4882// This forces the entry to be added to the store-buffer _during_ marking.
4883//
4884// Then, the compacter needs to be used. Which will move the entry in old
4885// space.
4886//
4887// If the thread's store buffer block is not released after that, the compactor
4888// will not update it, causing an outdated address to be released to the store
4889// buffer later.
4890//
4891// This causes two types of errors to trigger with --verify-store-buffer:
4892// 1. We see the address in the store buffer but the object is no entry there.
4893// Also can cause segfaults on reading garbage or unallocated memory.
4894// 2. We see the entry has a marked bit, but can't find it in the store buffer.
4895ISOLATE_UNIT_TEST_CASE(Finalizer_Regress_48843) {
4896#ifdef DEBUG
4897 SetFlagScope<bool> sfs(&FLAG_trace_finalizers, true);
4898 SetFlagScope<bool> sfs2(&FLAG_verify_store_buffer, true);
4899#endif
4900 SetFlagScope<bool> sfs3(&FLAG_use_compactor, true);
4901
4902 const auto& finalizer = Finalizer::Handle(Finalizer::New(Heap::kOld));
4903 finalizer.set_isolate(thread->isolate());
4904
4905 const auto& detach1 =
4907 const auto& token1 = String::Handle(OneByteString::New("token1", Heap::kNew));
4908 const auto& detach2 =
4910 const auto& token2 = String::Handle(OneByteString::New("token2", Heap::kOld));
4911
4912 {
4913 HANDLESCOPE(thread);
4914 const auto& entry1 =
4916 entry1.set_detach(detach1);
4917 entry1.set_token(token1);
4918
4919 const auto& entry2 =
4921 entry2.set_detach(detach2);
4922 entry2.set_token(token2);
4923
4924 {
4925 HANDLESCOPE(thread);
4926 const auto& value1 =
4928 entry1.set_value(value1);
4929 const auto& value2 =
4931 entry2.set_value(value2);
4932 // Lose both values.
4933 }
4934
4935 // First collect new space.
4936 GCTestHelper::CollectNewSpace();
4937 // Then old space, this will make the old space entry point to the new
4938 // space entry.
4939 // Also, this must be a mark compact, not a mark sweep, to move the entry.
4940 GCTestHelper::CollectOldSpace();
4941 }
4942
4943 // Imagine callbacks running.
4944 // Entries themselves become unreachable.
4945 finalizer.set_entries_collected(
4947
4948 // There should be a single entry in the store buffer.
4949 // And it should crash when seeing the address in the buffer.
4950 GCTestHelper::CollectNewSpace();
4951
4952 // We should no longer be processing the entries.
4953 GCTestHelper::CollectOldSpace();
4954 GCTestHelper::CollectNewSpace();
4955}
4956
4958 intptr_t* token = reinterpret_cast<intptr_t*>(peer);
4959 (*token)++;
4960}
4961
4963 Thread* thread,
4964 Heap::Space* spaces,
4965 bool collect_new_space,
4966 bool evacuate_new_space_and_collect_old_space,
4967 bool clear_value_1,
4968 bool clear_value_2,
4969 bool clear_detach_1,
4970 bool clear_detach_2) {
4971#ifdef DEBUG
4972 SetFlagScope<bool> sfs(&FLAG_trace_finalizers, true);
4973#endif
4974
4975 intptr_t token1_memory = 0;
4976 intptr_t token2_memory = 0;
4977
4978 MessageHandler* handler = thread->isolate()->message_handler();
4979 // We're reusing the isolate in a loop, so there are messages from previous
4980 // runs of this test.
4981 intptr_t queue_length_start = 0;
4982 {
4984 queue_length_start = aq.queue()->Length();
4985 }
4986
4989 spaces[3]));
4990
4991 const auto& finalizer =
4993 finalizer.set_callback(callback);
4994 finalizer.set_isolate(thread->isolate());
4995
4996 const auto& isolate_finalizers =
4999 weak1.set_target(finalizer);
5000 isolate_finalizers.Add(weak1);
5001 thread->isolate()->set_finalizers(isolate_finalizers);
5002
5003 const auto& all_entries = Set::Handle(Set::NewDefault());
5004 finalizer.set_all_entries(all_entries);
5005 const auto& all_entries_data = Array::Handle(all_entries.data());
5006 THR_Print("entry1 space: %s\n", spaces[1] == Heap::kNew ? "new" : "old");
5007 const auto& entry1 =
5008 FinalizerEntry::Handle(FinalizerEntry::New(finalizer, spaces[1]));
5009 all_entries_data.SetAt(0, entry1);
5010 THR_Print("entry2 space: %s\n", spaces[2] == Heap::kNew ? "new" : "old");
5011 const auto& entry2 =
5012 FinalizerEntry::Handle(FinalizerEntry::New(finalizer, spaces[2]));
5013 all_entries_data.SetAt(1, entry2);
5014 all_entries.set_used_data(2); // Don't bother setting the index.
5015
5016 const intptr_t external_size1 = 1024;
5017 const intptr_t external_size2 = 2048;
5018 entry1.set_external_size(external_size1);
5019 entry2.set_external_size(external_size2);
5020 IsolateGroup::Current()->heap()->AllocatedExternal(external_size1, spaces[5]);
5021 IsolateGroup::Current()->heap()->AllocatedExternal(external_size2, spaces[7]);
5022
5023 auto& value1 = String::Handle();
5024 auto& detach1 = String::Handle();
5025 const auto& token1 = Pointer::Handle(
5026 Pointer::New(reinterpret_cast<uword>(&token1_memory), spaces[3]));
5027 entry1.set_token(token1);
5028
5029 auto& value2 = String::Handle();
5030 auto& detach2 = String::Handle();
5031 const auto& token2 = Pointer::Handle(
5032 Pointer::New(reinterpret_cast<uword>(&token2_memory), spaces[4]));
5033 entry2.set_token(token2);
5034 entry2.set_detach(detach2);
5035
5036 {
5037 HANDLESCOPE(thread);
5038 auto& object = String::Handle();
5039
5040 THR_Print("value1 space: %s\n", spaces[5] == Heap::kNew ? "new" : "old");
5041 object ^= OneByteString::New("value1", spaces[5]);
5042 entry1.set_value(object);
5043 if (!clear_value_1) {
5044 value1 = object.ptr();
5045 }
5046
5047 object ^= OneByteString::New("detach", spaces[6]);
5048 entry1.set_detach(object);
5049 if (!clear_detach_1) {
5050 detach1 = object.ptr();
5051 }
5052
5053 THR_Print("value2 space: %s\n", spaces[7] == Heap::kNew ? "new" : "old");
5054 object ^= OneByteString::New("value2", spaces[7]);
5055 entry2.set_value(object);
5056 if (!clear_value_2) {
5057 value2 = object.ptr();
5058 }
5059
5060 object ^= OneByteString::New("detach", spaces[8]);
5061 entry2.set_detach(object);
5062 if (!clear_detach_2) {
5063 detach2 = object.ptr();
5064 }
5065 }
5066
5067 THR_Print("CollectOldSpace\n");
5068 GCTestHelper::CollectOldSpace();
5069 if (collect_new_space) {
5070 THR_Print("CollectNewSpace\n");
5071 GCTestHelper::CollectNewSpace();
5072 }
5073 if (evacuate_new_space_and_collect_old_space) {
5074 THR_Print("CollectAllGarbage\n");
5075 GCTestHelper::CollectAllGarbage();
5076 }
5077
5078 EXPECT((entry1.value() == Object::null()) ^ !clear_value_1);
5079 EXPECT((entry2.value() == Object::null()) ^ !clear_value_2);
5080 EXPECT((entry1.detach() == Object::null()) ^ !clear_detach_1);
5081 EXPECT((entry2.detach() == Object::null()) ^ !clear_detach_2);
5082 EXPECT_NE(Object::null(), entry1.token());
5083 EXPECT_NE(Object::null(), entry2.token());
5084
5085 const intptr_t expect_num_cleared =
5086 (clear_value_1 ? 1 : 0) + (clear_value_2 ? 1 : 0);
5087 EXPECT_EQ(expect_num_cleared,
5088 NumEntries(FinalizerEntry::Handle(finalizer.entries_collected())));
5089
5090 EXPECT_EQ(clear_value_1 ? 1 : 0, token1_memory);
5091 EXPECT_EQ(clear_value_2 ? 1 : 0, token2_memory);
5092
5093 const intptr_t expect_num_messages = expect_num_cleared == 0 ? 0 : 1;
5094 {
5095 // Acquire ownership of message handler queues.
5097 EXPECT_EQ(expect_num_messages + queue_length_start, aq.queue()->Length());
5098 }
5099
5100 // Simulate detachments.
5101 entry1.set_token(entry1);
5102 entry2.set_token(entry2);
5103 all_entries_data.SetAt(0, Object::Handle(Object::null()));
5104 all_entries_data.SetAt(1, Object::Handle(Object::null()));
5105 all_entries.set_used_data(0);
5106}
5107
5109 intptr_t test_i) {
5110 ASSERT(test_i < (1 << kFinalizerTwoEntriesNumObjects));
5112 for (intptr_t i = 0; i < kFinalizerTwoEntriesNumObjects; i++) {
5113 spaces[i] = ((test_i >> i) & 0x1) == 0x1 ? Heap::kOld : Heap::kNew;
5114 }
5115 // Either collect or evacuate new space.
5116 for (const bool collect_new_space : {true, false}) {
5117 // Always run old space collection after new space.
5118 const bool evacuate_new_space_and_collect_old_space = true;
5119 const bool clear_value_1 = true;
5120 const bool clear_value_2 = true;
5121 const bool clear_detach_1 = false;
5122 const bool clear_detach_2 = false;
5123 THR_Print(
5124 "collect_new_space: %s evacuate_new_space_and_collect_old_space: %s\n",
5125 collect_new_space ? "true" : "false",
5126 evacuate_new_space_and_collect_old_space ? "true" : "false");
5127 NativeFinalizer_TwoEntriesCrossGen(thread, spaces, collect_new_space,
5128 evacuate_new_space_and_collect_old_space,
5129 clear_value_1, clear_value_2,
5130 clear_detach_1, clear_detach_2);
5131 }
5132}
5133
5134#define FINALIZER_NATIVE_CROSS_GEN_TEST_CASE(n) \
5135 ISOLATE_UNIT_TEST_CASE(NativeFinalizer_CrossGen_##n) { \
5136 NativeFinalizer_TwoEntriesCrossGen(thread, n); \
5137 }
5138
5140
5141#undef FINALIZER_NATIVE_CROSS_GEN_TEST_CASE
5142
5143#undef REPEAT_512
5144
5145TEST_CASE(IsIsolateUnsendable) {
5146 Zone* const zone = Thread::Current()->zone();
5147
5148 const char* kScript = R"(
5149import 'dart:ffi';
5150
5151class AImpl implements A {}
5152class ASub extends A {}
5153// Wonky class order and non-alphabetic naming on purpose.
5154class C extends Z {}
5155class E extends D {}
5156class A implements Finalizable {}
5157class Z implements A {}
5158class D implements C {}
5159class X extends E {}
5160)";
5161 Dart_Handle h_lib = TestCase::LoadTestScript(kScript, nullptr);
5162 EXPECT_VALID(h_lib);
5163
5164 TransitionNativeToVM transition(thread);
5165 const Library& lib = Library::CheckedHandle(zone, Api::UnwrapHandle(h_lib));
5166 EXPECT(!lib.IsNull());
5167
5168 const auto& class_x = Class::Handle(zone, GetClass(lib, "X"));
5169 class_x.EnsureIsFinalized(thread);
5170 EXPECT(class_x.is_isolate_unsendable());
5171
5172 const auto& class_a_impl = Class::Handle(zone, GetClass(lib, "AImpl"));
5173 class_a_impl.EnsureIsFinalized(thread);
5174 EXPECT(class_a_impl.is_isolate_unsendable());
5175
5176 const auto& class_a_sub = Class::Handle(zone, GetClass(lib, "ASub"));
5177 class_a_sub.EnsureIsFinalized(thread);
5178 EXPECT(class_a_sub.is_isolate_unsendable());
5179}
5180
5181TEST_CASE(ImplementorCid) {
5182 const char* kScriptChars = R"(
5183abstract class AInterface {}
5184
5185abstract class BInterface {}
5186class BImplementation implements BInterface {}
5187
5188abstract class CInterface {}
5189class CImplementation1 implements CInterface {}
5190class CImplementation2 implements CInterface {}
5191
5192abstract class DInterface {}
5193abstract class DSubinterface implements DInterface {}
5194
5195abstract class EInterface {}
5196abstract class ESubinterface implements EInterface {}
5197class EImplementation implements ESubinterface {}
5198
5199abstract class FInterface {}
5200abstract class FSubinterface implements FInterface {}
5201class FImplementation1 implements FSubinterface {}
5202class FImplementation2 implements FSubinterface {}
5203
5204main() {
5205 new BImplementation();
5206 new CImplementation1();
5207 new CImplementation2();
5208 new EImplementation();
5209 new FImplementation1();
5210 new FImplementation2();
5211}
5212)";
5213 Dart_Handle h_lib = TestCase::LoadTestScript(kScriptChars, nullptr);
5214 EXPECT_VALID(h_lib);
5215 Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, nullptr);
5217
5218 TransitionNativeToVM transition(thread);
5219 const Library& lib =
5220 Library::CheckedHandle(thread->zone(), Api::UnwrapHandle(h_lib));
5221 EXPECT(!lib.IsNull());
5222
5223 const Class& AInterface = Class::Handle(GetClass(lib, "AInterface"));
5224 EXPECT_EQ(AInterface.implementor_cid(), kIllegalCid);
5225
5226 const Class& BInterface = Class::Handle(GetClass(lib, "BInterface"));
5227 const Class& BImplementation =
5228 Class::Handle(GetClass(lib, "BImplementation"));
5229 EXPECT_EQ(BInterface.implementor_cid(), BImplementation.id());
5230 EXPECT_EQ(BImplementation.implementor_cid(), BImplementation.id());
5231
5232 const Class& CInterface = Class::Handle(GetClass(lib, "CInterface"));
5233 const Class& CImplementation1 =
5234 Class::Handle(GetClass(lib, "CImplementation1"));
5235 const Class& CImplementation2 =
5236 Class::Handle(GetClass(lib, "CImplementation2"));
5237 EXPECT_EQ(CInterface.implementor_cid(), kDynamicCid);
5238 EXPECT_EQ(CImplementation1.implementor_cid(), CImplementation1.id());
5239 EXPECT_EQ(CImplementation2.implementor_cid(), CImplementation2.id());
5240
5241 const Class& DInterface = Class::Handle(GetClass(lib, "DInterface"));
5242 const Class& DSubinterface = Class::Handle(GetClass(lib, "DSubinterface"));
5243 EXPECT_EQ(DInterface.implementor_cid(), kIllegalCid);
5244 EXPECT_EQ(DSubinterface.implementor_cid(), kIllegalCid);
5245
5246 const Class& EInterface = Class::Handle(GetClass(lib, "EInterface"));
5247 const Class& ESubinterface = Class::Handle(GetClass(lib, "ESubinterface"));
5248 const Class& EImplementation =
5249 Class::Handle(GetClass(lib, "EImplementation"));
5250 EXPECT_EQ(EInterface.implementor_cid(), EImplementation.id());
5251 EXPECT_EQ(ESubinterface.implementor_cid(), EImplementation.id());
5252 EXPECT_EQ(EImplementation.implementor_cid(), EImplementation.id());
5253
5254 const Class& FInterface = Class::Handle(GetClass(lib, "FInterface"));
5255 const Class& FSubinterface = Class::Handle(GetClass(lib, "FSubinterface"));
5256 const Class& FImplementation1 =
5257 Class::Handle(GetClass(lib, "FImplementation1"));
5258 const Class& FImplementation2 =
5259 Class::Handle(GetClass(lib, "FImplementation2"));
5260 EXPECT_EQ(FInterface.implementor_cid(), kDynamicCid);
5261 EXPECT_EQ(FSubinterface.implementor_cid(), kDynamicCid);
5262 EXPECT_EQ(FImplementation1.implementor_cid(), FImplementation1.id());
5263 EXPECT_EQ(FImplementation2.implementor_cid(), FImplementation2.id());
5264}
5265
5267 const MirrorReference& reference =
5269 Object& initial_referent = Object::Handle(reference.referent());
5270 EXPECT(initial_referent.IsNull());
5271
5273 EXPECT(!library.IsNull());
5274 EXPECT(library.IsLibrary());
5275 reference.set_referent(library);
5276 const Object& returned_referent = Object::Handle(reference.referent());
5277 EXPECT(returned_referent.IsLibrary());
5278 EXPECT_EQ(returned_referent.ptr(), library.ptr());
5279
5280 const MirrorReference& other_reference =
5282 EXPECT_NE(reference.ptr(), other_reference.ptr());
5283 other_reference.set_referent(library);
5284 EXPECT_NE(reference.ptr(), other_reference.ptr());
5285 EXPECT_EQ(reference.referent(), other_reference.referent());
5286
5287 Object& obj = Object::Handle(reference.ptr());
5288 EXPECT(obj.IsMirrorReference());
5289}
5290
5291static FunctionPtr GetFunction(const Class& cls, const char* name) {
5292 Thread* thread = Thread::Current();
5293 const auto& error = cls.EnsureIsFinalized(thread);
5294 EXPECT(error == Error::null());
5296 Z, cls, String::Handle(String::New(name))));
5297 EXPECT(!result.IsNull());
5298 return result.ptr();
5299}
5300
5301static FunctionPtr GetStaticFunction(const Class& cls, const char* name) {
5302 const auto& error = cls.EnsureIsFinalized(Thread::Current());
5303 EXPECT(error == Error::null());
5306 EXPECT(!result.IsNull());
5307 return result.ptr();
5308}
5309
5310static FieldPtr GetField(const Class& cls, const char* name) {
5311 const Field& field =
5313 EXPECT(!field.IsNull());
5314 return field.ptr();
5315}
5316
5317ISOLATE_UNIT_TEST_CASE(FindClosureIndex) {
5318 // Allocate the class first.
5319 const String& class_name = String::Handle(Symbols::New(thread, "MyClass"));
5320 const Script& script = Script::Handle();
5321 const Class& cls = Class::Handle(CreateDummyClass(class_name, script));
5322 const Array& functions = Array::Handle(Array::New(1));
5323
5324 Function& parent = Function::Handle();
5325 const String& parent_name = String::Handle(Symbols::New(thread, "foo_papa"));
5327 parent = Function::New(signature, parent_name,
5328 UntaggedFunction::kRegularFunction, false, false,
5329 false, false, false, cls, TokenPosition::kMinSource);
5330 functions.SetAt(0, parent);
5331 {
5332 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
5333 cls.SetFunctions(functions);
5334 }
5335
5337 const String& function_name = String::Handle(Symbols::New(thread, "foo"));
5340 function.set_kernel_offset(42);
5341 // Add closure function to class.
5342 {
5343 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
5345 }
5346
5347 // The closure should return a valid index.
5348 intptr_t good_closure_index =
5350 EXPECT_GE(good_closure_index, 0);
5351 // The parent function should return an invalid index.
5352 intptr_t bad_closure_index = ClosureFunctionsCache::FindClosureIndex(parent);
5353 EXPECT_EQ(bad_closure_index, -1);
5354
5355 // Retrieve closure function via index.
5356 Function& func_from_index = Function::Handle();
5357 func_from_index ^=
5359 // Same closure function.
5360 EXPECT_EQ(func_from_index.ptr(), function.ptr());
5361}
5362
5363ISOLATE_UNIT_TEST_CASE(FindInvocationDispatcherFunctionIndex) {
5364 const String& class_name = String::Handle(Symbols::New(thread, "MyClass"));
5365 const Script& script = Script::Handle();
5366 const Class& cls = Class::Handle(CreateDummyClass(class_name, script));
5368
5369 const Array& functions = Array::Handle(Array::New(1));
5370 Function& parent = Function::Handle();
5371 const String& parent_name = String::Handle(Symbols::New(thread, "foo_papa"));
5373 parent = Function::New(signature, parent_name,
5374 UntaggedFunction::kRegularFunction, false, false,
5375 false, false, false, cls, TokenPosition::kMinSource);
5376 functions.SetAt(0, parent);
5377 {
5378 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
5379 cls.SetFunctions(functions);
5380 cls.Finalize();
5381 }
5382
5383 // Add invocation dispatcher.
5384 const String& invocation_dispatcher_name =
5385 String::Handle(Symbols::New(thread, "myMethod"));
5386 const Array& args_desc = Array::Handle(ArgumentsDescriptor::NewBoxed(0, 1));
5387 Function& invocation_dispatcher = Function::Handle();
5388 invocation_dispatcher ^= cls.GetInvocationDispatcher(
5389 invocation_dispatcher_name, args_desc,
5390 UntaggedFunction::kNoSuchMethodDispatcher, true /* create_if_absent */);
5391 EXPECT(!invocation_dispatcher.IsNull());
5392 // Get index to function.
5393 intptr_t invocation_dispatcher_index =
5394 cls.FindInvocationDispatcherFunctionIndex(invocation_dispatcher);
5395 // Expect a valid index.
5396 EXPECT_GE(invocation_dispatcher_index, 0);
5397 // Retrieve function through index.
5398 Function& invocation_dispatcher_from_index = Function::Handle();
5399 invocation_dispatcher_from_index ^=
5400 cls.InvocationDispatcherFunctionFromIndex(invocation_dispatcher_index);
5401 // Same function.
5402 EXPECT_EQ(invocation_dispatcher.ptr(),
5403 invocation_dispatcher_from_index.ptr());
5404 // Test function not found case.
5405 const Function& bad_function = Function::Handle(Function::null());
5406 intptr_t bad_invocation_dispatcher_index =
5407 cls.FindInvocationDispatcherFunctionIndex(bad_function);
5408 EXPECT_EQ(bad_invocation_dispatcher_index, -1);
5409}
5410
5411static void PrintMetadata(const char* name, const Object& data) {
5412 if (data.IsError()) {
5413 OS::PrintErr("Error in metadata evaluation for %s: '%s'\n", name,
5414 Error::Cast(data).ToErrorCString());
5415 }
5416 EXPECT(data.IsArray());
5417 const Array& metadata = Array::Cast(data);
5418 OS::PrintErr("Metadata for %s has %" Pd " values:\n", name,
5419 metadata.Length());
5420 Object& elem = Object::Handle();
5421 for (int i = 0; i < metadata.Length(); i++) {
5422 elem = metadata.At(i);
5423 OS::PrintErr(" %d: %s\n", i, elem.ToCString());
5424 }
5425}
5426
5427TEST_CASE(Metadata) {
5428 // clang-format off
5429 auto kScriptChars =
5431 "@metafoo \n"
5432 "class Meta { \n"
5433 " final m; \n"
5434 " const Meta(this.m); \n"
5435 "} \n"
5436 " \n"
5437 "const metafoo = 'metafoo'; \n"
5438 "const metabar = 'meta' 'bar'; \n"
5439 " \n"
5440 "@metafoo \n"
5441 "@Meta(0) String%s gVar; \n"
5442 " \n"
5443 "@metafoo \n"
5444 "get tlGetter => gVar; \n"
5445 " \n"
5446 "@metabar \n"
5447 "class A { \n"
5448 " @metafoo \n"
5449 " @metabar \n"
5450 " @Meta('baz') \n"
5451 " var aField; \n"
5452 " \n"
5453 " @metabar @Meta('baa') \n"
5454 " int aFunc(a,b) => a + b; \n"
5455 "} \n"
5456 " \n"
5457 "@Meta('main') \n"
5458 "A main() { \n"
5459 " return A(); \n"
5460 "} \n",
5461 TestCase::NullableTag()), std::free);
5462 // clang-format on
5463
5464 Dart_Handle h_lib = TestCase::LoadTestScript(kScriptChars.get(), nullptr);
5465 EXPECT_VALID(h_lib);
5466 Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, nullptr);
5468 TransitionNativeToVM transition(thread);
5469 Library& lib = Library::Handle();
5470 lib ^= Api::UnwrapHandle(h_lib);
5471 EXPECT(!lib.IsNull());
5472 const Class& class_a = Class::Handle(GetClass(lib, "A"));
5473 Object& res = Object::Handle(lib.GetMetadata(class_a));
5474 PrintMetadata("A", res);
5475
5476 const Class& class_meta = Class::Handle(GetClass(lib, "Meta"));
5477 res = lib.GetMetadata(class_meta);
5478 PrintMetadata("Meta", res);
5479
5480 Field& field = Field::Handle(GetField(class_a, "aField"));
5481 res = lib.GetMetadata(field);
5482 PrintMetadata("A.aField", res);
5483
5484 Function& func = Function::Handle(GetFunction(class_a, "aFunc"));
5485 res = lib.GetMetadata(func);
5486 PrintMetadata("A.aFunc", res);
5487
5488 func = lib.LookupFunctionAllowPrivate(
5489 String::Handle(Symbols::New(thread, "main")));
5490 EXPECT(!func.IsNull());
5491 res = lib.GetMetadata(func);
5492 PrintMetadata("main", res);
5493
5494 func = lib.LookupFunctionAllowPrivate(
5495 String::Handle(Symbols::New(thread, "get:tlGetter")));
5496 EXPECT(!func.IsNull());
5497 res = lib.GetMetadata(func);
5498 PrintMetadata("tlGetter", res);
5499
5500 field =
5502 EXPECT(!field.IsNull());
5503 res = lib.GetMetadata(field);
5504 PrintMetadata("gVar", res);
5505}
5506
5507TEST_CASE(FunctionSourceFingerprint) {
5508 const char* kScriptChars =
5509 "class A {\n"
5510 " static test1(int a) {\n"
5511 " return a > 1 ? a + 1 : a;\n"
5512 " }\n"
5513 " static test2(a) {\n"
5514 " return a > 1 ? a + 1 : a;\n"
5515 " }\n"
5516 " static test3(b) {\n"
5517 " return b > 1 ? b + 1 : b;\n"
5518 " }\n"
5519 " static test4(b) {\n"
5520 " return b > 1 ? b - 1 : b;\n"
5521 " }\n"
5522 " static test5(b) {\n"
5523 " return b > 1 ? b - 2 : b;\n"
5524 " }\n"
5525 " test6(int a) {\n"
5526 " return a > 1 ? a + 1 : a;\n"
5527 " }\n"
5528 "}\n"
5529 "class B {\n"
5530 " static /* Different declaration style. */\n"
5531 " test1(int a) {\n"
5532 " /* Returns a + 1 for a > 1, a otherwise. */\n"
5533 " return a > 1 ?\n"
5534 " a + 1 :\n"
5535 " a;\n"
5536 " }\n"
5537 " static test5(b) {\n"
5538 " return b > 1 ?\n"
5539 " b - 2 : b;\n"
5540 " }\n"
5541 " test6(int a) {\n"
5542 " return a > 1 ? a + 1 : a;\n"
5543 " }\n"
5544 "}";
5545 TestCase::LoadTestScript(kScriptChars, nullptr);
5546 TransitionNativeToVM transition(thread);
5549 const Library& lib = Library::Handle(Library::LookupLibrary(thread, name));
5550 EXPECT(!lib.IsNull());
5551
5552 const Class& class_a =
5554 const Class& class_b =
5556 const Function& a_test1 =
5557 Function::Handle(GetStaticFunction(class_a, "test1"));
5558 const Function& b_test1 =
5559 Function::Handle(GetStaticFunction(class_b, "test1"));
5560 const Function& a_test2 =
5561 Function::Handle(GetStaticFunction(class_a, "test2"));
5562 const Function& a_test3 =
5563 Function::Handle(GetStaticFunction(class_a, "test3"));
5564 const Function& a_test4 =
5565 Function::Handle(GetStaticFunction(class_a, "test4"));
5566 const Function& a_test5 =
5567 Function::Handle(GetStaticFunction(class_a, "test5"));
5568 const Function& b_test5 =
5569 Function::Handle(GetStaticFunction(class_b, "test5"));
5570 const Function& a_test6 = Function::Handle(GetFunction(class_a, "test6"));
5571 const Function& b_test6 = Function::Handle(GetFunction(class_b, "test6"));
5572
5573 EXPECT_EQ(a_test1.SourceFingerprint(), b_test1.SourceFingerprint());
5574 EXPECT_NE(a_test1.SourceFingerprint(), a_test2.SourceFingerprint());
5575 EXPECT_NE(a_test2.SourceFingerprint(), a_test3.SourceFingerprint());
5576 EXPECT_NE(a_test3.SourceFingerprint(), a_test4.SourceFingerprint());
5577 EXPECT_NE(a_test4.SourceFingerprint(), a_test5.SourceFingerprint());
5578 EXPECT_EQ(a_test5.SourceFingerprint(), b_test5.SourceFingerprint());
5579 // Although a_test6's receiver type is different than b_test6's receiver type,
5580 // the fingerprints are identical. The token stream does not reflect the
5581 // receiver's type. This is not a problem, since we recognize functions
5582 // of a given class and of a given name.
5583 EXPECT_EQ(a_test6.SourceFingerprint(), b_test6.SourceFingerprint());
5584}
5585
5586#ifndef PRODUCT
5587
5588TEST_CASE(FunctionWithBreakpointNotInlined) {
5589 const char* kScriptChars =
5590 "class A {\n"
5591 " a() {\n"
5592 " }\n"
5593 " b() {\n"
5594 " a();\n" // This is line 5.
5595 " }\n"
5596 "}\n"
5597 "test() {\n"
5598 " new A().b();\n"
5599 "}";
5600 const int kBreakpointLine = 5;
5601 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
5602 EXPECT_VALID(lib);
5603
5604 // Run function A.b one time.
5605 Dart_Handle result = Dart_Invoke(lib, NewString("test"), 0, nullptr);
5607
5608 // With no breakpoint, function A.b is inlineable.
5609 {
5610 TransitionNativeToVM transition(thread);
5612 const Library& vmlib =
5614 EXPECT(!vmlib.IsNull());
5615 const Class& class_a = Class::Handle(
5616 vmlib.LookupClass(String::Handle(Symbols::New(thread, "A"))));
5617 Function& func_b = Function::Handle(GetFunction(class_a, "b"));
5618 EXPECT(func_b.CanBeInlined());
5619 }
5620
5621 result = Dart_SetBreakpoint(NewString(TestCase::url()), kBreakpointLine);
5623
5624 // After setting a breakpoint in a function A.b, it is no longer inlineable.
5625 {
5626 TransitionNativeToVM transition(thread);
5628 const Library& vmlib =
5630 EXPECT(!vmlib.IsNull());
5631 const Class& class_a = Class::Handle(
5632 vmlib.LookupClass(String::Handle(Symbols::New(thread, "A"))));
5633 Function& func_b = Function::Handle(GetFunction(class_a, "b"));
5634 EXPECT(!func_b.CanBeInlined());
5635 }
5636}
5637
5639 // Refers to the DeoptimizeFramesWhenSettingBreakpoint function below.
5640 const int kBreakpointLine = 8;
5641
5642 // This will force deoptimization of functions on stack.
5643 // Function on stack has to be optimized, since we want to trigger debuggers
5644 // on-stack deoptimization flow when we set a breakpoint.
5646 Dart_SetBreakpoint(NewString(TestCase::url()), kBreakpointLine);
5648}
5649
5651 int argument_count,
5652 bool* auto_setup_scope) {
5653 ASSERT(auto_setup_scope != nullptr);
5654 *auto_setup_scope = true;
5655 const char* cstr = nullptr;
5658 EXPECT_STREQ(cstr, "setBreakpoint");
5659 return &SetBreakpoint;
5660}
5661
5662TEST_CASE(DeoptimizeFramesWhenSettingBreakpoint) {
5663 const char* kOriginalScript = "test() {}";
5664
5665 Dart_Handle lib = TestCase::LoadTestScript(kOriginalScript, nullptr);
5666 EXPECT_VALID(lib);
5668
5669 // Get unoptimized code for functions so they can be optimized.
5670 Dart_Handle result = Dart_Invoke(lib, NewString("test"), 0, nullptr);
5672
5673 // Launch second isolate so that running with stopped mutators during
5674 // deoptimizattion requests a safepoint.
5677 char* error = nullptr;
5678 Dart_Isolate child = Dart_CreateIsolateInGroup(parent, "child",
5679 /*shutdown_callback=*/nullptr,
5680 /*cleanup_callback=*/nullptr,
5681 /*peer=*/nullptr, &error);
5682 EXPECT_NE(nullptr, child);
5683 EXPECT_EQ(nullptr, error);
5685 Dart_EnterIsolate(parent);
5686
5687 const char* kReloadScript =
5688 R"(
5689 @pragma("vm:external-name", "setBreakpoint")
5690 external setBreakpoint();
5691 baz() {}
5692 test() {
5693 if (true) {
5694 setBreakpoint();
5695 } else {
5696 baz(); // this line gets a breakpoint
5697 }
5698 }
5699 )";
5700 lib = TestCase::ReloadTestScript(kReloadScript);
5701 EXPECT_VALID(lib);
5702
5703 {
5704 TransitionNativeToVM transition(thread);
5706 const Library& vmlib =
5708 EXPECT(!vmlib.IsNull());
5709 Function& func_test = Function::Handle(GetFunction(vmlib, "test"));
5710 Compiler::EnsureUnoptimizedCode(thread, func_test);
5711 Compiler::CompileOptimizedFunction(thread, func_test);
5713 }
5714
5715 result = Dart_Invoke(lib, NewString("test"), 0, nullptr);
5717
5718 // Make sure child isolate finishes.
5721 {
5722 bool result =
5723 Dart_RunLoopAsync(/*errors_are_fatal=*/true,
5724 /*on_error_port=*/0, /*on_exit_port=*/0, &error);
5725 EXPECT_EQ(true, result);
5727 EXPECT_EQ(nullptr, error);
5728 Dart_EnterIsolate(parent);
5729}
5730
5731class ToggleBreakpointTask : public ThreadPool::Task {
5732 public:
5733 ToggleBreakpointTask(IsolateGroup* isolate_group,
5734 Dart_Isolate isolate,
5735 std::atomic<bool>* done)
5736 : isolate_group_(isolate_group), isolate_(isolate), done_(done) {}
5737 virtual void Run() {
5738 Dart_EnterIsolate(isolate_);
5740 const int kBreakpointLine = 5; // in the dart script below
5741 Thread* t = Thread::Current();
5742 for (intptr_t i = 0; i < 1000; i++) {
5744 Dart_SetBreakpoint(NewString(TestCase::url()), kBreakpointLine);
5746 int64_t breakpoint_id;
5747 {
5748 TransitionNativeToVM transition(t);
5749 Integer& breakpoint_id_handle = Integer::Handle();
5750 breakpoint_id_handle ^= Api::UnwrapHandle(result);
5751 breakpoint_id = breakpoint_id_handle.AsInt64Value();
5752 }
5755 }
5758 *done_ = true;
5759 }
5760
5761 private:
5762 IsolateGroup* isolate_group_;
5763 Dart_Isolate isolate_;
5764 std::atomic<bool>* done_;
5765};
5766
5767TEST_CASE(DartAPI_BreakpointLockRace) {
5768 const char* kScriptChars =
5769 "class A {\n"
5770 " a() {\n"
5771 " }\n"
5772 " b() {\n"
5773 " a();\n" // This is line 5.
5774 " }\n"
5775 "}\n"
5776 "test() {\n"
5777 " new A().b();\n"
5778 "}";
5779 // Create a test library and Load up a test script in it.
5780 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, nullptr);
5781 EXPECT_VALID(lib);
5782
5783 // Run function A.b one time.
5784 Dart_Handle result = Dart_Invoke(lib, NewString("test"), 0, nullptr);
5786
5787 // Launch second isolate so that running with stopped mutators during
5788 // deoptimizattion requests a safepoint.
5791 char* error = nullptr;
5792 Dart_Isolate child = Dart_CreateIsolateInGroup(parent, "child",
5793 /*shutdown_callback=*/nullptr,
5794 /*cleanup_callback=*/nullptr,
5795 /*peer=*/nullptr, &error);
5796 EXPECT_NE(nullptr, child);
5797 EXPECT_EQ(nullptr, error);
5799 Dart_EnterIsolate(parent);
5800
5801 // Run function A.b one time.
5802 std::atomic<bool> done = false;
5803 Dart::thread_pool()->Run<ToggleBreakpointTask>(IsolateGroup::Current(), child,
5804 &done);
5805
5806 while (!done) {
5807 ReloadParticipationScope allow_reload(thread);
5808 {
5809 TransitionNativeToVM transition(thread);
5810 const String& name = String::Handle(String::New(TestCase::url()));
5811 const Library& vmlib =
5813 EXPECT(!vmlib.IsNull());
5814 const Class& class_a = Class::Handle(
5815 vmlib.LookupClass(String::Handle(Symbols::New(thread, "A"))));
5816 Function& func_b = Function::Handle(GetFunction(class_a, "b"));
5817 func_b.CanBeInlined();
5818 }
5819 }
5820
5821 // Make sure child isolate finishes.
5824 {
5825 bool result =
5826 Dart_RunLoopAsync(/*errors_are_fatal=*/true,
5827 /*on_error_port=*/0, /*on_exit_port=*/0, &error);
5828 EXPECT_EQ(true, result);
5829 }
5830 EXPECT_EQ(nullptr, error);
5831 Dart_EnterIsolate(parent);
5832}
5833
5834ISOLATE_UNIT_TEST_CASE(SpecialClassesHaveEmptyArrays) {
5835 ObjectStore* object_store = IsolateGroup::Current()->object_store();
5836 Class& cls = Class::Handle();
5837 Object& array = Object::Handle();
5838
5839 cls = object_store->null_class();
5840 array = cls.fields();
5841 EXPECT(!array.IsNull());
5842 EXPECT(array.IsArray());
5843 array = cls.current_functions();
5844 EXPECT(!array.IsNull());
5845 EXPECT(array.IsArray());
5846
5847 cls = Object::void_class();
5848 array = cls.fields();
5849 EXPECT(!array.IsNull());
5850 EXPECT(array.IsArray());
5851 array = cls.current_functions();
5852 EXPECT(!array.IsNull());
5853 EXPECT(array.IsArray());
5854
5856 array = cls.fields();
5857 EXPECT(!array.IsNull());
5858 EXPECT(array.IsArray());
5859 array = cls.current_functions();
5860 EXPECT(!array.IsNull());
5861 EXPECT(array.IsArray());
5862}
5863
5864class ObjectAccumulator : public ObjectVisitor {
5865 public:
5866 explicit ObjectAccumulator(GrowableArray<Object*>* objects)
5867 : objects_(objects) {}
5868 virtual ~ObjectAccumulator() {}
5869 virtual void VisitObject(ObjectPtr obj) {
5870 if (obj->IsPseudoObject()) {
5871 return; // Cannot be wrapped in handles.
5872 }
5873 Object& handle = Object::Handle(obj);
5874 // Skip some common simple objects to run in reasonable time.
5875 if (handle.IsString() || handle.IsArray()) {
5876 return;
5877 }
5878 objects_->Add(&handle);
5879 }
5880
5881 private:
5882 GrowableArray<Object*>* objects_;
5883};
5884
5885ISOLATE_UNIT_TEST_CASE(ToCString) {
5886 // Set native resolvers in case we need to read native methods.
5887 {
5888 TransitionVMToNative transition(thread);
5893 }
5894
5895 GCTestHelper::CollectAllGarbage();
5896 GrowableArray<Object*> objects;
5897 {
5898 HeapIterationScope iteration(Thread::Current());
5899 ObjectAccumulator acc(&objects);
5900 iteration.IterateObjects(&acc);
5901 }
5902 for (intptr_t i = 0; i < objects.length(); ++i) {
5903 StackZone zone(thread);
5904 HANDLESCOPE(thread);
5905
5906 // All ToCString implementations should not allocate on the Dart heap so
5907 // they remain useful in all parts of the VM.
5908 NoSafepointScope no_safepoint;
5909 objects[i]->ToCString();
5910 }
5911}
5912
5913ISOLATE_UNIT_TEST_CASE(PrintJSON) {
5914 // Set native resolvers in case we need to read native methods.
5915 {
5916 TransitionVMToNative transition(thread);
5921 }
5922
5923 GCTestHelper::CollectAllGarbage();
5924 GrowableArray<Object*> objects;
5925 {
5927 ObjectAccumulator acc(&objects);
5928 iteration.IterateObjects(&acc);
5929 }
5930 for (intptr_t i = 0; i < objects.length(); ++i) {
5931 JSONStream js;
5932 objects[i]->PrintJSON(&js, false);
5933 EXPECT_SUBSTRING("\"type\":", js.ToCString());
5934 }
5935}
5936
5937ISOLATE_UNIT_TEST_CASE(PrintJSONPrimitives) {
5938 // WARNING: This MUST be big enough for the serialized JSON string.
5939 const int kBufferSize = 4096;
5940 char buffer[kBufferSize];
5941 Isolate* isolate = Isolate::Current();
5942
5943 // Class reference
5944 {
5945 JSONStream js;
5946 Class& cls = Class::Handle(isolate->group()->object_store()->bool_class());
5947 cls.PrintJSON(&js, true);
5948 const char* json_str = js.ToCString();
5949 ASSERT(strlen(json_str) < kBufferSize);
5950 ElideJSONSubstring("classes", json_str, buffer);
5951 ElideJSONSubstring("libraries", buffer, buffer);
5953
5954 EXPECT_STREQ(
5955 "{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"bool\","
5956 "\"location\":{\"type\":\"SourceLocation\",\"script\":{\"type\":\"@"
5957 "Script\","
5958 "\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:core\\/bool.dart\","
5959 "\"_kind\":\"kernel\"}},"
5960 "\"library\":{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
5961 "\"name\":\"dart.core\",\"uri\":\"dart:core\"}}",
5962 buffer);
5963 }
5964 // Function reference
5965 {
5966 Thread* thread = Thread::Current();
5967 JSONStream js;
5968 Class& cls = Class::Handle(isolate->group()->object_store()->bool_class());
5969 const String& func_name = String::Handle(String::New("toString"));
5970 Function& func =
5972 ASSERT(!func.IsNull());
5973 func.PrintJSON(&js, true);
5974 const char* json_str = js.ToCString();
5975 ASSERT(strlen(json_str) < kBufferSize);
5976 ElideJSONSubstring("classes", json_str, buffer);
5977 ElideJSONSubstring("libraries", buffer, buffer);
5979 EXPECT_STREQ(
5980 "{\"type\":\"@Function\",\"fixedId\":true,\"id\":\"\","
5981 "\"name\":\"toString\",\"owner\":{\"type\":\"@Class\","
5982 "\"fixedId\":true,\"id\":\"\",\"name\":\"bool\","
5983 "\"location\":{\"type\":\"SourceLocation\","
5984 "\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
5985 "\"id\":\"\",\"uri\":\"dart:core\\/bool.dart\","
5986 "\"_kind\":\"kernel\"}},"
5987 "\"library\":{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
5988 "\"name\":\"dart.core\",\"uri\":\"dart:core\"}},"
5989 "\"_kind\":\"RegularFunction\",\"static\":false,\"const\":false,"
5990 "\"implicit\":false,\"abstract\":false,"
5991 "\"_intrinsic\":false,\"_native\":false,\"isGetter\":false,"
5992 "\"isSetter\":false,\"location\":{\"type\":\"SourceLocation\","
5993 "\"script\":{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\","
5994 "\"uri\":\"dart:core\\/bool.dart\",\"_kind\":\"kernel\"}}}",
5995 buffer);
5996 }
5997 // Library reference
5998 {
5999 JSONStream js;
6000 Library& lib =
6001 Library::Handle(isolate->group()->object_store()->core_library());
6002 lib.PrintJSON(&js, true);
6003 const char* json_str = js.ToCString();
6004 ASSERT(strlen(json_str) < kBufferSize);
6005 ElideJSONSubstring("libraries", json_str, buffer);
6006 EXPECT_STREQ(
6007 "{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
6008 "\"name\":\"dart.core\",\"uri\":\"dart:core\"}",
6009 buffer);
6010 }
6011 // Bool reference
6012 {
6013 JSONStream js;
6014 Bool::True().PrintJSON(&js, true);
6015 const char* json_str = js.ToCString();
6016 ASSERT(strlen(json_str) < kBufferSize);
6017 ElideJSONSubstring("classes", json_str, buffer);
6018 ElideJSONSubstring("libraries", buffer, buffer);
6020 EXPECT_STREQ(
6021 "{\"type\":\"@Instance\",\"_vmType\":\"Bool\",\"class\":{\"type\":\"@"
6022 "Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"bool\",\"location\":{"
6023 "\"type\":\"SourceLocation\",\"script\":{\"type\":\"@Script\","
6024 "\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:core\\/bool.dart\",\"_"
6025 "kind\":\"kernel\"}},\"library\":"
6026 "{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\",\"name\":\"dart."
6027 "core\",\"uri\":\"dart:core\"}},\"identityHashCode\":0,\"kind\":"
6028 "\"Bool\",\"fixedId\":true,\"id\":\"objects\\/bool-true\","
6029 "\"valueAsString\":\"true\"}",
6030 buffer);
6031 }
6032 // Smi reference
6033 {
6034 JSONStream js;
6035 const Integer& smi = Integer::Handle(Integer::New(7));
6036 smi.PrintJSON(&js, true);
6037 const char* json_str = js.ToCString();
6038 ASSERT(strlen(json_str) < kBufferSize);
6039 ElideJSONSubstring("classes", json_str, buffer);
6040 ElideJSONSubstring("_Smi@", buffer, buffer);
6041 ElideJSONSubstring("libraries", buffer, buffer);
6043 EXPECT_STREQ(
6044 "{\"type\":\"@Instance\",\"_vmType\":\"Smi\",\"class\":{\"type\":\"@"
6045 "Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"_Smi\",\"_vmName\":"
6046 "\"\",\"location\":{\"type\":\"SourceLocation\",\"script\":{\"type\":"
6047 "\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:core-"
6048 "patch\\/integers.dart\",\"_kind\":\"kernel\"}"
6049 "},\"library\":{\"type\":\"@Library\",\"fixedId\":"
6050 "true,\"id\":\"\",\"name\":\"dart.core\",\"uri\":\"dart:core\"}},"
6051 "\"identityHashCode\":0,\"kind\":\"Int\",\"fixedId\":true,\"id\":"
6052 "\"objects\\/int-7\",\"valueAsString\":\"7\"}",
6053 buffer);
6054 }
6055 // Mint reference
6056 {
6057 JSONStream js;
6058 const Integer& smi = Integer::Handle(Integer::New(Mint::kMinValue));
6059 smi.PrintJSON(&js, true);
6060 const char* json_str = js.ToCString();
6061 ASSERT(strlen(json_str) < kBufferSize);
6062 ElideJSONSubstring("classes", json_str, buffer);
6063 ElideJSONSubstring("objects", buffer, buffer);
6064 ElideJSONSubstring("libraries", buffer, buffer);
6065 ElideJSONSubstring("_Mint@", buffer, buffer);
6067 EXPECT_STREQ(
6068 "{\"type\":\"@Instance\",\"_vmType\":\"Mint\",\"class\":{\"type\":\"@"
6069 "Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"_Mint\",\"_vmName\":"
6070 "\"\",\"location\":{\"type\":\"SourceLocation\",\"script\":{\"type\":"
6071 "\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:core-"
6072 "patch\\/integers.dart\",\"_kind\":\"kernel\"}"
6073 "},\"library\":{\"type\":\"@Library\",\"fixedId\":"
6074 "true,\"id\":\"\",\"name\":\"dart.core\",\"uri\":\"dart:core\"}},"
6075 "\"identityHashCode\":0,\"id\":\"\",\"kind\":\"Int\",\"valueAsString\":"
6076 "\"-9223372036854775808\"}",
6077 buffer);
6078 }
6079 // Double reference
6080 {
6081 JSONStream js;
6082 const Double& dub = Double::Handle(Double::New(0.1234));
6083 dub.PrintJSON(&js, true);
6084 const char* json_str = js.ToCString();
6085 ASSERT(strlen(json_str) < kBufferSize);
6086 ElideJSONSubstring("classes", json_str, buffer);
6087 ElideJSONSubstring("objects", buffer, buffer);
6088 ElideJSONSubstring("libraries", buffer, buffer);
6089 ElideJSONSubstring("_Double@", buffer, buffer);
6091 EXPECT_STREQ(
6092 "{\"type\":\"@Instance\",\"_vmType\":\"Double\",\"class\":{\"type\":\"@"
6093 "Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"_Double\",\"_vmName\":"
6094 "\"\",\"location\":{\"type\":\"SourceLocation\",\"script\":{\"type\":"
6095 "\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:core-"
6096 "patch\\/double.dart\",\"_kind\":\"kernel\"}"
6097 "},\"library\":{\"type\":\"@Library\",\"fixedId\":"
6098 "true,\"id\":\"\",\"name\":\"dart.core\",\"uri\":\"dart:core\"}},"
6099 "\"identityHashCode\":0,\"id\":\"\",\"kind\":\"Double\","
6100 "\"valueAsString\":\"0.1234\"}",
6101 buffer);
6102 }
6103 // String reference
6104 {
6105 JSONStream js;
6106 const String& str = String::Handle(String::New("dw"));
6107 str.PrintJSON(&js, true);
6108 const char* json_str = js.ToCString();
6109 ASSERT(strlen(json_str) < kBufferSize);
6110 ElideJSONSubstring("classes", json_str, buffer);
6111 ElideJSONSubstring("objects", buffer, buffer);
6112 ElideJSONSubstring("libraries", buffer, buffer);
6113 ElideJSONSubstring("_OneByteString@", buffer, buffer);
6115 EXPECT_STREQ(
6116 "{\"type\":\"@Instance\",\"_vmType\":\"String\",\"class\":{\"type\":\"@"
6117 "Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"_OneByteString\",\"_"
6118 "vmName\":\"\",\"location\":{\"type\":\"SourceLocation\",\"script\":{"
6119 "\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:core-"
6120 "patch\\/string_patch.dart\",\"_kind\":\"kernel\"}"
6121 "},\"library\":{\"type\":\"@Library\",\"fixedId\":"
6122 "true,\"id\":\"\",\"name\":\"dart.core\",\"uri\":\"dart:core\"}},"
6123 "\"identityHashCode\":0,\"id\":\"\",\"kind\":\"String\",\"length\":2,"
6124 "\"valueAsString\":\"dw\"}",
6125 buffer);
6126 }
6127 // Array reference
6128 {
6129 JSONStream js;
6130 const Array& array = Array::Handle(Array::New(0));
6131 array.PrintJSON(&js, true);
6132 const char* json_str = js.ToCString();
6133 ASSERT(strlen(json_str) < kBufferSize);
6134 ElideJSONSubstring("classes", json_str, buffer);
6135 ElideJSONSubstring("objects", buffer, buffer);
6136 ElideJSONSubstring("libraries", buffer, buffer);
6137 ElideJSONSubstring("_List@", buffer, buffer);
6138 ElideJSONSubstring("_TypeParameter@", buffer, buffer);
6140 EXPECT_SUBSTRING(
6141 "{\"type\":\"@Instance\",\"_vmType\":\"Array\",\"class\":{\"type\":\"@"
6142 "Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"_List\",\"_vmName\":"
6143 "\"\",\"location\":{\"type\":\"SourceLocation\",\"script\":{\"type\":"
6144 "\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:core-patch\\/"
6145 "array.dart\",\"_kind\":\"kernel\"}},"
6146 "\"library\":{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
6147 "\"name\":\"dart.core\",\"uri\":\"dart:core\"},\"typeParameters\":[{"
6148 "\"type\":\"@"
6149 "Instance\",\"_vmType\":\"TypeParameter\",\"class\":{\"type\":\"@"
6150 "Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"_TypeParameter\",\"_"
6151 "vmName\":\"\",\"location\":{\"type\":"
6152 "\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
6153 "\"id\":\"\",\"uri\":\"dart:core-patch\\/"
6154 "type_patch.dart\",\"_kind\":\"kernel\"}},"
6155 "\"library\":{\"type\":\"@Library\",\"fixedId\":"
6156 "true,\"id\":\"\",\"name\":\"dart.core\",\"uri\":\"dart:core\"}},"
6157 "\"identityHashCode\":",
6158 buffer);
6159
6160 EXPECT_SUBSTRING(
6161 "\"id\":\"\",\"kind\":\"TypeParameter\",\"name\":\"X0\","
6162 "\"parameterizedClass\":{\"type\":\"@Instance\",\"_vmType\":\"Class\","
6163 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\",\"name\":"
6164 "\"Null\",\"location\":{\"type\":\"SourceLocation\",\"script\":{"
6165 "\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:"
6166 "core\\/"
6167 "null.dart\",\"_kind\":\"kernel\"}},"
6168 "\"library\":{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
6169 "\"name\":\"dart.core\",\"uri\":\"dart:core\"}},\"kind\":\"Null\","
6170 "\"fixedId\":true,\"id\":\"\",\"valueAsString\":\"null\"}}]},"
6171 "\"identityHashCode\":0,\"id\":\"\",\"kind\":\"List\",\"length\":0}",
6172 buffer);
6173 }
6174 OS::PrintErr("\n\n\n");
6175 // GrowableObjectArray reference
6176 {
6177 JSONStream js;
6178 const GrowableObjectArray& array =
6180 array.PrintJSON(&js, true);
6181 const char* json_str = js.ToCString();
6182 ASSERT(strlen(json_str) < kBufferSize);
6183 ElideJSONSubstring("classes", json_str, buffer);
6184 ElideJSONSubstring("objects", buffer, buffer);
6185 ElideJSONSubstring("libraries", buffer, buffer);
6186 ElideJSONSubstring("_GrowableList@", buffer, buffer);
6188 ElideJSONSubstring("_TypeParameter@", buffer, buffer);
6189 EXPECT_SUBSTRING(
6190 "{\"type\":\"@Instance\",\"_vmType\":\"GrowableObjectArray\",\"class\":"
6191 "{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"_"
6192 "GrowableList\",\"_vmName\":\"\",\"location\":{\"type\":"
6193 "\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
6194 "\"id\":\"\",\"uri\":\"dart:core-patch\\/"
6195 "growable_array.dart\",\"_kind\":\"kernel\"}"
6196 "},\"library\":{\"type\":\"@Library\",\"fixedId\":"
6197 "true,\"id\":\"\",\"name\":\"dart.core\",\"uri\":\"dart:core\"},"
6198 "\"typeParameters\":[{\"type\":\"@Instance\",\"_vmType\":"
6199 "\"TypeParameter\",\"class\":{\"type\":\"@Class\",\"fixedId\":true,"
6200 "\"id\":\"\",\"name\":\"_TypeParameter\",\"_vmName\":\""
6201 "\",\"location\":{\"type\":\"SourceLocation\",\"script\":{"
6202 "\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:core-"
6203 "patch\\/"
6204 "type_patch.dart\",\"_kind\":\"kernel\"}"
6205 "},\"library\":{\"type\":\"@Library\",\"fixedId\":"
6206 "true,\"id\":\"\",\"name\":\"dart.core\",\"uri\":\"dart:core\"}},"
6207 "\"identityHashCode\":",
6208 buffer);
6209
6210 EXPECT_SUBSTRING(
6211 "\"id\":\"\",\"kind\":\"TypeParameter\",\"name\":\"X0\","
6212 "\"parameterizedClass\":{\"type\":\"@Instance\","
6213 "\"_vmType\":\"Class\",\"class\":{\"type\":\"@Class\",\"fixedId\":true,"
6214 "\"id\":\"\",\"name\":\"Null\",\"location\":{\"type\":"
6215 "\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
6216 "\"id\":\"\",\"uri\":\"dart:core\\/"
6217 "null.dart\",\"_kind\":\"kernel\"}"
6218 "},\"library\":{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
6219 "\"name\":\"dart.core\",\"uri\":\"dart:core\"}},\"kind\":\"Null\","
6220 "\"fixedId\":true,\"id\":\"\",\"valueAsString\":\"null\"}}]},"
6221 "\"identityHashCode\":0,\"id\":\"\",\"kind\":\"List\",\"length\":0}",
6222 buffer);
6223 }
6224 // Map reference
6225 {
6226 JSONStream js;
6227 const Map& array = Map::Handle(Map::NewDefault());
6228 array.PrintJSON(&js, true);
6229 const char* json_str = js.ToCString();
6230 ASSERT(strlen(json_str) < kBufferSize);
6231 ElideJSONSubstring("classes", json_str, buffer);
6232 ElideJSONSubstring("objects", buffer, buffer);
6233 ElideJSONSubstring("libraries", buffer, buffer);
6234 ElideJSONSubstring("_Map@", buffer, buffer);
6236 ElideJSONSubstring("_TypeParameter@", buffer, buffer);
6237 EXPECT_SUBSTRING(
6238 "{\"type\":\"@Instance\",\"_vmType\":\"Map\",\"class\":{"
6239 "\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"_"
6240 "Map\",\"_vmName\":\"\",\"location\":{\"type\":"
6241 "\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
6242 "\"id\":\"\",\"uri\":\"dart:collection-patch\\/"
6243 "compact_hash.dart\",\"_kind\":\"kernel\"}"
6244 "},\"library\":{\"type\":\"@Library\",\"fixedId\":"
6245 "true,\"id\":\"\",\"name\":\"dart.collection\",\"uri\":\"dart:"
6246 "collection\"},\"typeParameters\":[{\"type\":\"@Instance\",\"_vmType\":"
6247 "\"TypeParameter\",\"class\":{\"type\":\"@Class\",\"fixedId\":true,"
6248 "\"id\":\"\",\"name\":\"_TypeParameter\",\"_vmName\":\""
6249 "\",\"location\":{\"type\":\"SourceLocation\",\"script\":{"
6250 "\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:core-"
6251 "patch\\/"
6252 "type_patch.dart\",\"_kind\":\"kernel\"}"
6253 "},\"library\":{\"type\":\"@Library\",\"fixedId\":"
6254 "true,\"id\":\"\",\"name\":\"dart.core\",\"uri\":\"dart:core\"}},"
6255 "\"identityHashCode\":",
6256 buffer);
6257
6258 EXPECT_SUBSTRING(
6259 "\"id\":\"\",\"kind\":\"TypeParameter\",\"name\":\"X0\","
6260 "\"parameterizedClass\":{\"type\":\"@Instance\","
6261 "\"_vmType\":\"Class\",\"class\":{\"type\":\"@Class\",\"fixedId\":true,"
6262 "\"id\":\"\",\"name\":\"Null\",\"location\":{\"type\":"
6263 "\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
6264 "\"id\":\"\",\"uri\":\"dart:core\\/"
6265 "null.dart\",\"_kind\":\"kernel\"}"
6266 "},\"library\":{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
6267 "\"name\":\"dart.core\",\"uri\":\"dart:core\"}},\"kind\":\"Null\","
6268 "\"fixedId\":true,\"id\":\"\",\"valueAsString\":\"null\"}},{\"type\":"
6269 "\"@Instance\",\"_vmType\":\"TypeParameter\",\"class\":{\"type\":\"@"
6270 "Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"_TypeParameter\",\"_"
6271 "vmName\":\"\",\"location\":{\"type\":"
6272 "\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
6273 "\"id\":\"\",\"uri\":\"dart:core-patch\\/"
6274 "type_patch.dart\",\"_kind\":\"kernel\"}"
6275 "},\"library\":{\"type\":\"@Library\",\"fixedId\":"
6276 "true,\"id\":\"\",\"name\":\"dart.core\",\"uri\":\"dart:core\"}},"
6277 "\"identityHashCode\":",
6278 buffer);
6279
6280 EXPECT_SUBSTRING(
6281 "\"id\":\"\",\"kind\":\"TypeParameter\",\"name\":\"X1\","
6282 "\"parameterizedClass\":{\"type\":\"@Instance\","
6283 "\"_vmType\":\"Class\",\"class\":{\"type\":\"@Class\",\"fixedId\":true,"
6284 "\"id\":\"\",\"name\":\"Null\",\"location\":{\"type\":"
6285 "\"SourceLocation\",\"script\":{\"type\":\"@Script\",\"fixedId\":true,"
6286 "\"id\":\"\",\"uri\":\"dart:core\\/"
6287 "null.dart\",\"_kind\":\"kernel\"}"
6288 "},\"library\":{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
6289 "\"name\":\"dart.core\",\"uri\":\"dart:core\"}},\"kind\":\"Null\","
6290 "\"fixedId\":true,\"id\":\"\",\"valueAsString\":\"null\"}}]},"
6291 "\"identityHashCode\":0,\"id\":\"\",\"kind\":\"Map\",\"length\":0}",
6292 buffer);
6293 }
6294 // UserTag reference
6295 {
6296 JSONStream js;
6297 Instance& tag = Instance::Handle(isolate->default_tag());
6298 tag.PrintJSON(&js, true);
6299 const char* json_str = js.ToCString();
6300 ASSERT(strlen(json_str) < kBufferSize);
6301 ElideJSONSubstring("classes", json_str, buffer);
6302 ElideJSONSubstring("objects", buffer, buffer);
6303 ElideJSONSubstring("libraries", buffer, buffer);
6304 ElideJSONSubstring("_UserTag@", buffer, buffer);
6306 EXPECT_SUBSTRING(
6307 "\"type\":\"@Instance\",\"_vmType\":\"UserTag\",\"class\":{\"type\":\"@"
6308 "Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"_UserTag\",\"_"
6309 "vmName\":\"\",\"location\":{\"type\":\"SourceLocation\",\"script\":{"
6310 "\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:"
6311 "developer-patch\\/"
6312 "profiler.dart\",\"_kind\":\"kernel\"}},\"library\":{\"type\":\"@"
6313 "Library\","
6314 "\"fixedId\":true,\"id\":\"\",\"name\":\"dart.developer\",\"uri\":"
6315 "\"dart:developer\"}},"
6316 // Handle non-zero identity hash.
6317 "\"identityHashCode\":",
6318 buffer);
6319 EXPECT_SUBSTRING(
6320 "\"id\":\"\","
6321 "\"kind\":\"UserTag\",\"label\":\"Default\"}",
6322 buffer);
6323 }
6324 // Type reference
6325 // TODO(turnidge): Add in all of the other Type siblings.
6326 {
6327 JSONStream js;
6328 Instance& type =
6329 Instance::Handle(isolate->group()->object_store()->bool_type());
6330 type.PrintJSON(&js, true);
6331 const char* json_str = js.ToCString();
6332 ASSERT(strlen(json_str) < kBufferSize);
6333 ElideJSONSubstring("classes", json_str, buffer);
6334 ElideJSONSubstring("objects", buffer, buffer);
6335 ElideJSONSubstring("libraries", buffer, buffer);
6336 ElideJSONSubstring("_Type@", buffer, buffer);
6338 EXPECT_SUBSTRING(
6339 "{\"type\":\"@Instance\",\"_vmType\":\"Type\",\"class\":{\"type\":\"@"
6340 "Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"_Type\",\"_vmName\":"
6341 "\"\",\"location\":{\"type\":\"SourceLocation\",\"script\":{\"type\":"
6342 "\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:core-"
6343 "patch\\/type_patch.dart\",\"_kind\":\"kernel\"}"
6344 "},\"library\":{\"type\":\"@Library\",\"fixedId\":"
6345 "true,\"id\":\"\",\"name\":\"dart.core\",\"uri\":\"dart:core\"}},"
6346 // Handle non-zero identity hash.
6347 "\"identityHashCode\":",
6348 buffer);
6349 EXPECT_SUBSTRING(
6350 "\"kind\":\"Type\","
6351 "\"fixedId\":true,\"id\":\"\","
6352 "\"typeClass\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
6353 "\"name\":\"bool\",\"location\":{\"type\":\"SourceLocation\","
6354 "\"script\":{\"type\":\"@Script\",\"fixedId\":true,\"id\":\"\",\"uri\":"
6355 "\"dart:core\\/bool.dart\",\"_kind\":\"kernel\"}"
6356 "},\"library\":{\"type\":\"@Library\",\"fixedId\":"
6357 "true,\"id\":\"\",\"name\":\"dart.core\",\"uri\":\"dart:core\"}},"
6358 "\"name\":\"bool\"}",
6359 buffer);
6360 }
6361 // Null reference
6362 {
6363 JSONStream js;
6364 Object::null_object().PrintJSON(&js, true);
6365 const char* json_str = js.ToCString();
6366 ASSERT(strlen(json_str) < kBufferSize);
6367 ElideJSONSubstring("classes", json_str, buffer);
6368 ElideJSONSubstring("libraries", buffer, buffer);
6370 EXPECT_STREQ(
6371 "{\"type\":\"@Instance\",\"_vmType\":\"null\",\"class\":{\"type\":\"@"
6372 "Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"Null\",\"location\":{"
6373 "\"type\":\"SourceLocation\",\"script\":{\"type\":\"@Script\","
6374 "\"fixedId\":true,\"id\":\"\",\"uri\":\"dart:core\\/null.dart\",\"_"
6375 "kind\":\"kernel\"}},\"library\":"
6376 "{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\",\"name\":\"dart."
6377 "core\",\"uri\":\"dart:core\"}},\"kind\":\"Null\",\"fixedId\":true,"
6378 "\"id\":\"objects\\/null\",\"valueAsString\":\"null\"}",
6379 buffer);
6380 }
6381 // Sentinel reference
6382 {
6383 JSONStream js;
6384 Object::sentinel().PrintJSON(&js, true);
6385 EXPECT_STREQ(
6386 "{\"type\":\"Sentinel\","
6387 "\"kind\":\"NotInitialized\","
6388 "\"valueAsString\":\"<not initialized>\"}",
6389 js.ToCString());
6390 }
6391 // Transition sentinel reference
6392 {
6393 JSONStream js;
6394 Object::transition_sentinel().PrintJSON(&js, true);
6395 EXPECT_STREQ(
6396 "{\"type\":\"Sentinel\","
6397 "\"kind\":\"BeingInitialized\","
6398 "\"valueAsString\":\"<being initialized>\"}",
6399 js.ToCString());
6400 }
6401}
6402
6403#endif // !PRODUCT
6404
6405TEST_CASE(InstanceEquality) {
6406 // Test that Instance::OperatorEquals can call a user-defined operator==.
6407 const char* kScript =
6408 "class A {\n"
6409 " bool operator==(covariant A other) { return true; }\n"
6410 "}\n"
6411 "main() {\n"
6412 " A a = new A();\n"
6413 "}";
6414
6415 Dart_Handle h_lib = TestCase::LoadTestScript(kScript, nullptr);
6416 EXPECT_VALID(h_lib);
6417 Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, nullptr);
6419
6420 TransitionNativeToVM transition(thread);
6421 Library& lib = Library::Handle();
6422 lib ^= Api::UnwrapHandle(h_lib);
6423 const Class& clazz = Class::Handle(GetClass(lib, "A"));
6424 EXPECT(!clazz.IsNull());
6425 const Instance& a0 = Instance::Handle(Instance::New(clazz));
6426 const Instance& a1 = Instance::Handle(Instance::New(clazz));
6427 EXPECT(a0.ptr() != a1.ptr());
6428 EXPECT(a0.OperatorEquals(a0));
6429 EXPECT(a0.OperatorEquals(a1));
6430 EXPECT(a0.IsIdenticalTo(a0));
6431 EXPECT(!a0.IsIdenticalTo(a1));
6432}
6433
6434TEST_CASE(HashCode) {
6435 // Ensure C++ overrides of Instance::HashCode match the Dart implementations.
6436 const char* kScript =
6437 "foo() {\n"
6438 " return \"foo\".hashCode;\n"
6439 "}";
6440
6441 Dart_Handle h_lib = TestCase::LoadTestScript(kScript, nullptr);
6442 EXPECT_VALID(h_lib);
6443 Dart_Handle h_result = Dart_Invoke(h_lib, NewString("foo"), 0, nullptr);
6444 EXPECT_VALID(h_result);
6445
6446 TransitionNativeToVM transition(thread);
6448 result ^= Api::UnwrapHandle(h_result);
6449 String& foo = String::Handle(String::New("foo"));
6450 Integer& expected = Integer::Handle();
6451 expected ^= foo.HashCode();
6452 EXPECT(result.IsIdenticalTo(expected));
6454
6455const uint32_t kCalculateCanonicalizeHash = 0;
6456
6457// Checks that the .hashCode equals the VM CanonicalizeHash() for keys in
6458// constant maps.
6459//
6460// Expects a script with a method named `value`.
6461//
6462// If `hashcode_canonicalize_vm` is non-zero, the VM CanonicalizeHash()
6463// is not executed but the provided value is used.
6465 const char* value_script,
6466 uint32_t hashcode_canonicalize_vm = kCalculateCanonicalizeHash,
6467 bool check_identity = true,
6468 bool check_hashcode = true) {
6469 auto kScriptChars = Utils::CStringUniquePtr(
6470 OS::SCreate(nullptr,
6471 "%s"
6472 "\n"
6473 "valueHashCode() {\n"
6474 " return value().hashCode;\n"
6475 "}\n"
6476 "\n"
6477 "valueIdentityHashCode() {\n"
6478 " return identityHashCode(value());\n"
6479 "}\n",
6480 value_script),
6481 std::free);
6482
6483 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars.get(), nullptr);
6484 EXPECT_VALID(lib);
6485 Dart_Handle value_result = Dart_Invoke(lib, NewString("value"), 0, nullptr);
6486 EXPECT_VALID(value_result);
6487 Dart_Handle hashcode_result;
6488 if (check_hashcode) {
6489 hashcode_result = Dart_Invoke(lib, NewString("valueHashCode"), 0, nullptr);
6490 EXPECT_VALID(hashcode_result);
6491 }
6492 Dart_Handle identity_hashcode_result =
6493 Dart_Invoke(lib, NewString("valueIdentityHashCode"), 0, nullptr);
6494 EXPECT_VALID(identity_hashcode_result);
6495
6496 TransitionNativeToVM transition(Thread::Current());
6497
6498 const auto& value_dart = Instance::CheckedHandle(
6499 Thread::Current()->zone(), Api::UnwrapHandle(value_result));
6500 int64_t hashcode_dart;
6501 if (check_hashcode) {
6502 hashcode_dart =
6503 Integer::Cast(Object::Handle(Api::UnwrapHandle(hashcode_result)))
6504 .AsInt64Value();
6505 }
6506 const int64_t identity_hashcode_dart =
6507 Integer::Cast(Object::Handle(Api::UnwrapHandle(identity_hashcode_result)))
6508 .AsInt64Value();
6509 if (hashcode_canonicalize_vm == 0) {
6510 hashcode_canonicalize_vm = Instance::Cast(value_dart).CanonicalizeHash();
6511 }
6512
6513 bool success = true;
6514
6515 if (check_hashcode) {
6516 success &= hashcode_dart == hashcode_canonicalize_vm;
6517 }
6518 if (check_identity) {
6519 success &= identity_hashcode_dart == hashcode_canonicalize_vm;
6520 }
6521
6522 if (!success) {
6523 LogBlock lb;
6524 THR_Print(
6525 "Dart hashCode or Dart identityHashCode does not equal VM "
6526 "CanonicalizeHash for %s\n",
6527 value_dart.ToCString());
6528 THR_Print("Dart hashCode %" Px64 " %" Pd64 "\n", hashcode_dart,
6529 hashcode_dart);
6530 THR_Print("Dart identityHashCode %" Px64 " %" Pd64 "\n",
6531 identity_hashcode_dart, identity_hashcode_dart);
6532 THR_Print("VM CanonicalizeHash %" Px32 " %" Pd32 "\n",
6533 hashcode_canonicalize_vm, hashcode_canonicalize_vm);
6534 }
6535
6536 return success;
6537}
6538
6539TEST_CASE(HashCode_Double) {
6540 const char* kScript =
6541 "value() {\n"
6542 " return 1.0;\n"
6543 "}\n";
6544 // Double VM CanonicalizeHash is not equal to hashCode, because doubles
6545 // cannot be used as keys in constant sets and maps. However, doubles
6546 // _can_ be used for lookups in which case they are equal to their integer
6547 // value.
6548 uint32_t kInt1HashCode = 0;
6549 {
6550 TransitionNativeToVM transition(thread);
6551 kInt1HashCode = Integer::Handle(Integer::New(1)).CanonicalizeHash();
6552 }
6553 EXPECT(HashCodeEqualsCanonicalizeHash(kScript, kInt1HashCode));
6554}
6555
6556TEST_CASE(HashCode_Mint) {
6557 const char* kScript =
6558 "value() {\n"
6559 " return 0x8000000;\n"
6560 "}\n";
6562}
6563
6564TEST_CASE(HashCode_Null) {
6565 const char* kScript =
6566 "value() {\n"
6567 " return null;\n"
6568 "}\n";
6570}
6571
6572TEST_CASE(HashCode_Smi) {
6573 const char* kScript =
6574 "value() {\n"
6575 " return 123;\n"
6576 "}\n";
6578}
6579
6580TEST_CASE(HashCode_String) {
6581 const char* kScript =
6582 "value() {\n"
6583 " return 'asdf';\n"
6584 "}\n";
6587
6588TEST_CASE(HashCode_Symbol) {
6589 const char* kScript =
6590 "value() {\n"
6591 " return #A;\n"
6592 "}\n";
6594 /*check_identity=*/false));
6595}
6596
6597TEST_CASE(HashCode_True) {
6598 const char* kScript =
6599 "value() {\n"
6600 " return true;\n"
6601 "}\n";
6603}
6604
6605TEST_CASE(HashCode_Type_Dynamic) {
6606 const char* kScript =
6607 "const type = dynamic;\n"
6608 "\n"
6609 "value() {\n"
6610 " return type;\n"
6611 "}\n";
6613 /*check_identity=*/false));
6614}
6615
6616TEST_CASE(HashCode_Type_Int) {
6617 const char* kScript =
6618 "const type = int;\n"
6619 "\n"
6620 "value() {\n"
6621 " return type;\n"
6622 "}\n";
6624 /*check_identity=*/false));
6625}
6626
6627TEST_CASE(Map_iteration) {
6628 const char* kScript =
6629 "makeMap() {\n"
6630 " var map = {'x': 3, 'y': 4, 'z': 5, 'w': 6};\n"
6631 " map.remove('y');\n"
6632 " map.remove('w');\n"
6633 " return map;\n"
6634 "}";
6635 Dart_Handle h_lib = TestCase::LoadTestScript(kScript, nullptr);
6636 EXPECT_VALID(h_lib);
6637 Dart_Handle h_result = Dart_Invoke(h_lib, NewString("makeMap"), 0, nullptr);
6638 EXPECT_VALID(h_result);
6639
6640 TransitionNativeToVM transition(thread);
6641 Instance& dart_map = Instance::Handle();
6642 dart_map ^= Api::UnwrapHandle(h_result);
6643 ASSERT(dart_map.IsMap());
6644 const Map& cc_map = Map::Cast(dart_map);
6645
6646 EXPECT_EQ(2, cc_map.Length());
6647
6648 Map::Iterator iterator(cc_map);
6649 Object& object = Object::Handle();
6650
6651 EXPECT(iterator.MoveNext());
6652 object = iterator.CurrentKey();
6653 EXPECT_STREQ("x", object.ToCString());
6654 object = iterator.CurrentValue();
6655 EXPECT_STREQ("3", object.ToCString());
6657 EXPECT(iterator.MoveNext());
6658 object = iterator.CurrentKey();
6659 EXPECT_STREQ("z", object.ToCString());
6660 object = iterator.CurrentValue();
6661 EXPECT_STREQ("5", object.ToCString());
6662
6663 EXPECT(!iterator.MoveNext());
6664}
6665
6666template <class LinkedHashBase>
6667static bool LinkedHashBaseEqual(const LinkedHashBase& map1,
6668 const LinkedHashBase& map2,
6669 bool print_diff,
6670 bool check_data = true) {
6671 if (check_data) {
6672 // Check data, only for non-nested.
6673 const auto& data1 = Array::Handle(map1.data());
6674 const auto& data2 = Array::Handle(map2.data());
6675 const intptr_t data1_length = Smi::Value(map1.used_data());
6676 const intptr_t data2_length = Smi::Value(map2.used_data());
6677 const bool data_length_equal = data1_length == data2_length;
6678 bool data_equal = data_length_equal;
6679 if (data_length_equal) {
6680 auto& object1 = Instance::Handle();
6681 auto& object2 = Instance::Handle();
6682 for (intptr_t i = 0; i < data1_length; i++) {
6683 object1 ^= data1.At(i);
6684 object2 ^= data2.At(i);
6685 data_equal &= object1.CanonicalizeEquals(object2);
6686 }
6687 }
6688 if (!data_equal) {
6689 if (print_diff) {
6690 THR_Print("LinkedHashBaseEqual Data not equal.\n");
6691 THR_Print("LinkedHashBaseEqual data1.length %" Pd " data1.length %" Pd
6692 " \n",
6693 data1_length, data2_length);
6694 auto& object1 = Instance::Handle();
6695 for (intptr_t i = 0; i < data1_length; i++) {
6696 object1 ^= data1.At(i);
6697 THR_Print("LinkedHashBaseEqual data1[%" Pd "] %s\n", i,
6698 object1.ToCString());
6699 }
6700 for (intptr_t i = 0; i < data2_length; i++) {
6701 object1 ^= data2.At(i);
6702 THR_Print("LinkedHashBaseEqual data2[%" Pd "] %s\n", i,
6703 object1.ToCString());
6704 }
6705 }
6706 return false;
6707 }
6708 }
6709
6710 // Check hashing.
6711 intptr_t hash_mask1 = Smi::Value(map1.hash_mask());
6712 EXPECT(!Integer::Handle(map2.hash_mask()).IsNull());
6713 intptr_t hash_mask2 = Smi::Value(map2.hash_mask());
6714 const bool hash_masks_equal = hash_mask1 == hash_mask2;
6715 if (!hash_masks_equal) {
6716 if (print_diff) {
6717 THR_Print("LinkedHashBaseEqual Hash masks not equal.\n");
6718 THR_Print("LinkedHashBaseEqual hash_mask1 %" Px " hash_mask2 %" Px " \n",
6719 hash_mask1, hash_mask2);
6720 }
6721 }
6722
6723 // Check indices.
6724 const auto& index1 = TypedData::Handle(map1.index());
6725 const auto& index2 = TypedData::Handle(map2.index());
6726 EXPECT(!index2.IsNull());
6727 ASSERT(index1.ElementType() == kUint32ArrayElement);
6728 ASSERT(index2.ElementType() == kUint32ArrayElement);
6729 const intptr_t kElementSize = 4;
6730 ASSERT(kElementSize == index1.ElementSizeInBytes());
6731 const bool index_length_equal = index1.Length() == index2.Length();
6732 bool index_equal = index_length_equal;
6733 if (index_length_equal) {
6734 for (intptr_t i = 0; i < index1.Length(); i++) {
6735 const uint32_t index1_val = index1.GetUint32(i * kElementSize);
6736 const uint32_t index2_val = index2.GetUint32(i * kElementSize);
6737 index_equal &= index1_val == index2_val;
6738 }
6739 }
6740 if (!index_equal && print_diff) {
6741 THR_Print("LinkedHashBaseEqual Indices not equal.\n");
6742 THR_Print("LinkedHashBaseEqual index1.length %" Pd " index2.length %" Pd
6743 " \n",
6744 index1.Length(), index2.Length());
6745 for (intptr_t i = 0; i < index1.Length(); i++) {
6746 const uint32_t index_val = index1.GetUint32(i * kElementSize);
6747 THR_Print("LinkedHashBaseEqual index1[%" Pd "] %" Px32 "\n", i,
6748 index_val);
6750 for (intptr_t i = 0; i < index2.Length(); i++) {
6751 const uint32_t index_val = index2.GetUint32(i * kElementSize);
6752 THR_Print("LinkedHashBaseEqual index2[%" Pd "] %" Px32 "\n", i,
6753 index_val);
6754 }
6755 }
6756 return index_equal;
6757}
6758
6759// Copies elements from data.
6760static MapPtr ConstructImmutableMap(const Array& input_data,
6761 intptr_t used_data,
6762 const TypeArguments& type_arguments) {
6764
6765 const auto& data = Array::Handle(Array::New(used_data));
6766 for (intptr_t i = 0; i < used_data; i++) {
6767 data.SetAt(i, Object::Handle(input_data.At(i)));
6768 }
6769 map.set_data(data);
6770 map.set_used_data(used_data);
6771 map.SetTypeArguments(type_arguments);
6772 map.set_deleted_keys(0);
6773 map.ComputeAndSetHashMask();
6774 map ^= map.Canonicalize(Thread::Current());
6775
6776 return map.ptr();
6777}
6778
6779// Constructs an immutable hashmap from a mutable one in this test.
6780TEST_CASE(ConstMap_vm) {
6781 const char* kScript = R"(
6782enum ExperimentalFlag {
6783 alternativeInvalidationStrategy,
6784 constFunctions,
6785 constantUpdate2018,
6786 constructorTearoffs,
6787 controlFlowCollections,
6788 extensionMethods,
6789 extensionTypes,
6790 genericMetadata,
6791 nonNullable,
6792 nonfunctionTypeAliases,
6793 setLiterals,
6794 spreadCollections,
6795 testExperiment,
6796 tripleShift,
6797 valueClass,
6798 variance,
6799}
6800
6801final Map<ExperimentalFlag?, bool> expiredExperimentalFlagsNonConst = {
6802 ExperimentalFlag.alternativeInvalidationStrategy: false,
6803 ExperimentalFlag.constFunctions: false,
6804 ExperimentalFlag.constantUpdate2018: true,
6805 ExperimentalFlag.constructorTearoffs: false,
6806 ExperimentalFlag.controlFlowCollections: true,
6807 ExperimentalFlag.extensionMethods: false,
6808 ExperimentalFlag.extensionTypes: false,
6809 ExperimentalFlag.genericMetadata: false,
6810 ExperimentalFlag.nonNullable: false,
6811 ExperimentalFlag.nonfunctionTypeAliases: false,
6812 ExperimentalFlag.setLiterals: true,
6813 ExperimentalFlag.spreadCollections: true,
6814 ExperimentalFlag.testExperiment: false,
6815 ExperimentalFlag.tripleShift: false,
6816 ExperimentalFlag.valueClass: false,
6817 ExperimentalFlag.variance: false,
6818};
6819
6820makeNonConstMap() {
6821 return expiredExperimentalFlagsNonConst;
6822}
6823
6824firstKey() {
6825 return ExperimentalFlag.alternativeInvalidationStrategy;
6826}
6827
6828firstKeyHashCode() {
6829 return firstKey().hashCode;
6830}
6831
6832firstKeyIdentityHashCode() {
6833 return identityHashCode(firstKey());
6834}
6835
6836bool lookupSpreadCollections(Map map) =>
6837 map[ExperimentalFlag.spreadCollections];
6838
6839bool? lookupNull(Map map) => map[null];
6840)";
6841 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
6842 EXPECT_VALID(lib);
6843 Dart_Handle non_const_result =
6844 Dart_Invoke(lib, NewString("makeNonConstMap"), 0, nullptr);
6845 EXPECT_VALID(non_const_result);
6846 Dart_Handle first_key_result =
6847 Dart_Invoke(lib, NewString("firstKey"), 0, nullptr);
6848 EXPECT_VALID(first_key_result);
6849 Dart_Handle first_key_hashcode_result =
6850 Dart_Invoke(lib, NewString("firstKeyHashCode"), 0, nullptr);
6851 EXPECT_VALID(first_key_hashcode_result);
6852 Dart_Handle first_key_identity_hashcode_result =
6853 Dart_Invoke(lib, NewString("firstKeyIdentityHashCode"), 0, nullptr);
6854 EXPECT_VALID(first_key_identity_hashcode_result);
6855
6856 Dart_Handle const_argument;
6857
6858 {
6859 TransitionNativeToVM transition(thread);
6860 const auto& non_const_map =
6861 Map::Cast(Object::Handle(Api::UnwrapHandle(non_const_result)));
6862 const auto& non_const_type_args =
6863 TypeArguments::Handle(non_const_map.GetTypeArguments());
6864 const auto& non_const_data = Array::Handle(non_const_map.data());
6865 const auto& const_map = Map::Handle(ConstructImmutableMap(
6866 non_const_data, Smi::Value(non_const_map.used_data()),
6867 non_const_type_args));
6868 ASSERT(non_const_map.GetClassId() == kMapCid);
6869 ASSERT(const_map.GetClassId() == kConstMapCid);
6870 ASSERT(!non_const_map.IsCanonical());
6871 ASSERT(const_map.IsCanonical());
6872
6873 const_argument = Api::NewHandle(thread, const_map.ptr());
6874 }
6875
6876 Dart_Handle lookup_result = Dart_Invoke(
6877 lib, NewString("lookupSpreadCollections"), 1, &const_argument);
6878 EXPECT_VALID(lookup_result);
6879 EXPECT_TRUE(lookup_result);
6880
6881 Dart_Handle lookup_null_result =
6882 Dart_Invoke(lib, NewString("lookupNull"), 1, &const_argument);
6883 EXPECT_VALID(lookup_null_result);
6884 EXPECT_NULL(lookup_null_result);
6885
6886 {
6887 TransitionNativeToVM transition(thread);
6888 const auto& non_const_object =
6889 Object::Handle(Api::UnwrapHandle(non_const_result));
6890 const auto& non_const_map = Map::Cast(non_const_object);
6891 const auto& const_object =
6893 const auto& const_map = Map::Cast(const_object);
6894
6895 EXPECT(non_const_map.GetClassId() != const_map.GetClassId());
6896
6897 // Check that the index is identical.
6898 EXPECT(LinkedHashBaseEqual(non_const_map, const_map,
6899 /*print_diff=*/true));
6900 }
6902
6903static bool IsLinkedHashBase(const Object& object) {
6904 return object.IsMap() || object.IsSet();
6905}
6906
6907// Checks that the non-constant and constant HashMap and HashSets are equal.
6908//
6909// Expects a script with a methods named `nonConstValue`, `constValue`, and
6910// `init`.
6911template <class LinkedHashBase, int kMutableCid, int kImmutableCid>
6912static void HashBaseNonConstEqualsConst(const char* script,
6913 bool check_data = true) {
6914 Dart_Handle lib = TestCase::LoadTestScript(script, nullptr);
6915 EXPECT_VALID(lib);
6916 Dart_Handle init_result = Dart_Invoke(lib, NewString("init"), 0, nullptr);
6917 EXPECT_VALID(init_result);
6918 Dart_Handle non_const_result =
6919 Dart_Invoke(lib, NewString("nonConstValue"), 0, nullptr);
6920 EXPECT_VALID(non_const_result);
6921 Dart_Handle const_result =
6922 Dart_Invoke(lib, NewString("constValue"), 0, nullptr);
6923 EXPECT_VALID(const_result);
6924
6925 TransitionNativeToVM transition(Thread::Current());
6926 const auto& non_const_object =
6927 Object::Handle(Api::UnwrapHandle(non_const_result));
6928 const auto& const_object = Object::Handle(Api::UnwrapHandle(const_result));
6929 non_const_object.IsMap();
6930 EXPECT(IsLinkedHashBase(non_const_object));
6931 if (!IsLinkedHashBase(non_const_object)) return;
6932 const auto& non_const_value = LinkedHashBase::Cast(non_const_object);
6933 EXPECT(IsLinkedHashBase(const_object));
6934 if (!IsLinkedHashBase(const_object)) return;
6935 const auto& const_value = LinkedHashBase::Cast(const_object);
6936 EXPECT_EQ(non_const_value.GetClassId(), kMutableCid);
6937 EXPECT_EQ(const_value.GetClassId(), kImmutableCid);
6938 EXPECT(!non_const_value.IsCanonical());
6939 EXPECT(const_value.IsCanonical());
6940 EXPECT(LinkedHashBaseEqual(non_const_value, const_value,
6941 /*print_diff=*/true, check_data));
6942}
6944static void HashMapNonConstEqualsConst(const char* script,
6945 bool check_data = true) {
6946 HashBaseNonConstEqualsConst<Map, kMapCid, kConstMapCid>(script, check_data);
6947}
6948
6949static void HashSetNonConstEqualsConst(const char* script,
6950 bool check_data = true) {
6951 HashBaseNonConstEqualsConst<Set, kSetCid, kConstSetCid>(script, check_data);
6952}
6953
6954TEST_CASE(ConstMap_small) {
6955 const char* kScript = R"(
6956constValue() => const {1: 42, 'foo': 499, 2: 'bar'};
6957
6958nonConstValue() => {1: 42, 'foo': 499, 2: 'bar'};
6959
6960void init() {
6961 constValue()[null];
6962}
6963)";
6965}
6966
6967TEST_CASE(ConstMap_null) {
6968 const char* kScript = R"(
6969constValue() => const {1: 42, 'foo': 499, null: 'bar'};
6970
6971nonConstValue() => {1: 42, 'foo': 499, null: 'bar'};
6972
6973void init() {
6974 constValue()[null];
6975}
6976)";
6978}
6979
6980TEST_CASE(ConstMap_larger) {
6981 const char* kScript = R"(
6982enum ExperimentalFlag {
6983 alternativeInvalidationStrategy,
6984 constFunctions,
6985 constantUpdate2018,
6986 constructorTearoffs,
6987 controlFlowCollections,
6988 extensionMethods,
6989 extensionTypes,
6990 genericMetadata,
6991 nonNullable,
6992 nonfunctionTypeAliases,
6993 setLiterals,
6994 spreadCollections,
6995 testExperiment,
6996 tripleShift,
6997 valueClass,
6998 variance,
6999}
7000
7001const Map<ExperimentalFlag, bool> expiredExperimentalFlags = {
7002 ExperimentalFlag.alternativeInvalidationStrategy: false,
7003 ExperimentalFlag.constFunctions: false,
7004 ExperimentalFlag.constantUpdate2018: true,
7005 ExperimentalFlag.constructorTearoffs: false,
7006 ExperimentalFlag.controlFlowCollections: true,
7007 ExperimentalFlag.extensionMethods: false,
7008 ExperimentalFlag.extensionTypes: false,
7009 ExperimentalFlag.genericMetadata: false,
7010 ExperimentalFlag.nonNullable: false,
7011 ExperimentalFlag.nonfunctionTypeAliases: false,
7012 ExperimentalFlag.setLiterals: true,
7013 ExperimentalFlag.spreadCollections: true,
7014 ExperimentalFlag.testExperiment: false,
7015 ExperimentalFlag.tripleShift: false,
7016 ExperimentalFlag.valueClass: false,
7017 ExperimentalFlag.variance: false,
7018};
7019
7020final Map<ExperimentalFlag, bool> expiredExperimentalFlagsNonConst = {
7021 ExperimentalFlag.alternativeInvalidationStrategy: false,
7022 ExperimentalFlag.constFunctions: false,
7023 ExperimentalFlag.constantUpdate2018: true,
7024 ExperimentalFlag.constructorTearoffs: false,
7025 ExperimentalFlag.controlFlowCollections: true,
7026 ExperimentalFlag.extensionMethods: false,
7027 ExperimentalFlag.extensionTypes: false,
7028 ExperimentalFlag.genericMetadata: false,
7029 ExperimentalFlag.nonNullable: false,
7030 ExperimentalFlag.nonfunctionTypeAliases: false,
7031 ExperimentalFlag.setLiterals: true,
7032 ExperimentalFlag.spreadCollections: true,
7033 ExperimentalFlag.testExperiment: false,
7034 ExperimentalFlag.tripleShift: false,
7035 ExperimentalFlag.valueClass: false,
7036 ExperimentalFlag.variance: false,
7037};
7038
7039constValue() => expiredExperimentalFlags;
7040
7041nonConstValue() => expiredExperimentalFlagsNonConst;
7042
7043void init() {
7044 constValue()[null];
7045}
7046)";
7048}
7049
7050TEST_CASE(ConstMap_nested) {
7051 const char* kScript = R"(
7052enum Abi {
7053 wordSize64,
7054 wordSize32Align32,
7055 wordSize32Align64,
7056}
7057
7058enum NativeType {
7059 kNativeType,
7060 kNativeInteger,
7061 kNativeDouble,
7062 kPointer,
7063 kNativeFunction,
7064 kInt8,
7065 kInt16,
7066 kInt32,
7067 kInt64,
7068 kUint8,
7069 kUint16,
7070 kUint32,
7071 kUint64,
7072 kIntptr,
7073 kFloat,
7074 kDouble,
7075 kVoid,
7076 kOpaque,
7077 kStruct,
7078 kHandle,
7079}
7080
7081const nonSizeAlignment = <Abi, Map<NativeType, int>>{
7082 Abi.wordSize64: {},
7083 Abi.wordSize32Align32: {
7084 NativeType.kDouble: 4,
7085 NativeType.kInt64: 4,
7086 NativeType.kUint64: 4
7087 },
7088 Abi.wordSize32Align64: {},
7089};
7090
7091final nonSizeAlignmentNonConst = <Abi, Map<NativeType, int>>{
7092 Abi.wordSize64: {},
7093 Abi.wordSize32Align32: {
7094 NativeType.kDouble: 4,
7095 NativeType.kInt64: 4,
7096 NativeType.kUint64: 4
7097 },
7098 Abi.wordSize32Align64: {},
7099};
7100
7101constValue() => nonSizeAlignment;
7102
7103nonConstValue() => nonSizeAlignmentNonConst;
7104
7105void init() {
7106 constValue()[null];
7107}
7108)";
7109 HashMapNonConstEqualsConst(kScript, false);
7110}
7111
7112TEST_CASE(Set_iteration) {
7113 const char* kScript = R"(
7114makeSet() {
7115 var set = {'x', 'y', 'z', 'w'};
7116 set.remove('y');
7117 set.remove('w');
7118 return set;
7119}
7120)";
7121 Dart_Handle h_lib = TestCase::LoadTestScript(kScript, nullptr);
7122 EXPECT_VALID(h_lib);
7123 Dart_Handle h_result = Dart_Invoke(h_lib, NewString("makeSet"), 0, nullptr);
7124 EXPECT_VALID(h_result);
7125
7126 TransitionNativeToVM transition(thread);
7127 Instance& dart_set = Instance::Handle();
7128 dart_set ^= Api::UnwrapHandle(h_result);
7129 ASSERT(dart_set.IsSet());
7130 const Set& cc_set = Set::Cast(dart_set);
7131
7132 EXPECT_EQ(2, cc_set.Length());
7133
7134 Set::Iterator iterator(cc_set);
7135 Object& object = Object::Handle();
7136
7137 EXPECT(iterator.MoveNext());
7138 object = iterator.CurrentKey();
7139 EXPECT_STREQ("x", object.ToCString());
7140
7141 EXPECT(iterator.MoveNext());
7142 object = iterator.CurrentKey();
7143 EXPECT_STREQ("z", object.ToCString());
7144
7145 EXPECT(!iterator.MoveNext());
7146}
7147
7148// Copies elements from data.
7149static SetPtr ConstructImmutableSet(const Array& input_data,
7150 intptr_t used_data,
7151 const TypeArguments& type_arguments) {
7153
7154 const auto& data = Array::Handle(Array::New(used_data));
7155 for (intptr_t i = 0; i < used_data; i++) {
7156 data.SetAt(i, Object::Handle(input_data.At(i)));
7158 set.set_data(data);
7159 set.set_used_data(used_data);
7160 set.SetTypeArguments(type_arguments);
7161 set.set_deleted_keys(0);
7162 set.ComputeAndSetHashMask();
7163 set ^= set.Canonicalize(Thread::Current());
7164
7165 return set.ptr();
7166}
7167
7168TEST_CASE(ConstSet_vm) {
7169 const char* kScript = R"(
7170makeNonConstSet() {
7171 return {1, 2, 3, 5, 8, 13};
7172}
7173
7174bool containsFive(Set set) => set.contains(5);
7175)";
7176 Dart_Handle lib = TestCase::LoadTestScript(kScript, nullptr);
7177 EXPECT_VALID(lib);
7178 Dart_Handle non_const_result =
7179 Dart_Invoke(lib, NewString("makeNonConstSet"), 0, nullptr);
7180 EXPECT_VALID(non_const_result);
7181
7182 Dart_Handle const_argument;
7183
7184 {
7185 TransitionNativeToVM transition(thread);
7186 const auto& non_const_object =
7187 Object::Handle(Api::UnwrapHandle(non_const_result));
7188 const auto& non_const_set = Set::Cast(non_const_object);
7189 ASSERT(non_const_set.GetClassId() == kSetCid);
7190 ASSERT(!non_const_set.IsCanonical());
7191
7192 const auto& non_const_data = Array::Handle(non_const_set.data());
7193 const auto& non_const_type_args =
7194 TypeArguments::Handle(non_const_set.GetTypeArguments());
7195 const auto& const_set = Set::Handle(ConstructImmutableSet(
7196 non_const_data, Smi::Value(non_const_set.used_data()),
7197 non_const_type_args));
7198 ASSERT(const_set.GetClassId() == kConstSetCid);
7199 ASSERT(const_set.IsCanonical());
7200
7201 const_argument = Api::NewHandle(thread, const_set.ptr());
7202 }
7203
7204 Dart_Handle contains_5_result =
7205 Dart_Invoke(lib, NewString("containsFive"), 1, &const_argument);
7206 EXPECT_VALID(contains_5_result);
7207 EXPECT_TRUE(contains_5_result);
7208
7209 {
7210 TransitionNativeToVM transition(thread);
7211 const auto& non_const_object =
7212 Object::Handle(Api::UnwrapHandle(non_const_result));
7213 const auto& non_const_set = Set::Cast(non_const_object);
7214 const auto& const_object =
7216 const auto& const_set = Set::Cast(const_object);
7217
7218 EXPECT(non_const_set.GetClassId() != const_set.GetClassId());
7219
7220 // Check that the index is identical.
7221 EXPECT(LinkedHashBaseEqual(non_const_set, const_set,
7222 /*print_diff=*/true));
7223 }
7224}
7225
7226TEST_CASE(ConstSet_small) {
7227 const char* kScript = R"(
7228constValue() => const {1, 2, 3, 5, 8, 13};
7229
7230nonConstValue() => {1, 2, 3, 5, 8, 13};
7231
7232void init() {
7233 constValue().contains(null);
7234}
7235)";
7237}
7238
7239TEST_CASE(ConstSet_larger) {
7240 const char* kScript = R"(
7241const Set<String> tokensThatMayFollowTypeArg = {
7242 '(',
7243 ')',
7244 ']',
7245 '}',
7246 ':',
7247 ';',
7248 ',',
7249 '.',
7250 '?',
7251 '==',
7252 '!=',
7253 '..',
7254 '?.',
7255 '\?\?',
7256 '?..',
7257 '&',
7258 '|',
7259 '^',
7260 '+',
7261 '*',
7262 '%',
7263 '/',
7264 '~/'
7265};
7266
7267final Set<String> tokensThatMayFollowTypeArgNonConst = {
7268 '(',
7269 ')',
7270 ']',
7271 '}',
7272 ':',
7273 ';',
7274 ',',
7275 '.',
7276 '?',
7277 '==',
7278 '!=',
7279 '..',
7280 '?.',
7281 '\?\?',
7282 '?..',
7283 '&',
7284 '|',
7285 '^',
7286 '+',
7287 '*',
7288 '%',
7289 '/',
7290 '~/'
7291};
7292
7293constValue() => tokensThatMayFollowTypeArg;
7294
7295nonConstValue() => tokensThatMayFollowTypeArgNonConst;
7296
7297void init() {
7298 constValue().contains(null);
7299}
7300)";
7302}
7303
7304static void CheckConcatAll(const String* data[], intptr_t n) {
7305 Thread* thread = Thread::Current();
7306 Zone* zone = thread->zone();
7307 GrowableHandlePtrArray<const String> pieces(zone, n);
7308 const Array& array = Array::Handle(zone, Array::New(n));
7309 for (int i = 0; i < n; i++) {
7310 pieces.Add(*data[i]);
7311 array.SetAt(i, *data[i]);
7312 }
7313 const String& res1 =
7314 String::Handle(zone, Symbols::FromConcatAll(thread, pieces));
7315 const String& res2 = String::Handle(zone, String::ConcatAll(array));
7316 EXPECT(res1.Equals(res2));
7317}
7318
7319ISOLATE_UNIT_TEST_CASE(Symbols_FromConcatAll) {
7320 {
7321 const String* data[3] = {&Symbols::TypeError(), &Symbols::Dot(),
7322 &Symbols::isPaused()};
7323 CheckConcatAll(data, 3);
7324 }
7325
7326 {
7327 const intptr_t kWideCharsLen = 7;
7328 uint16_t wide_chars[kWideCharsLen] = {'H', 'e', 'l', 'l', 'o', 256, '!'};
7329 const String& two_str =
7330 String::Handle(String::FromUTF16(wide_chars, kWideCharsLen));
7331
7332 const String* data[3] = {&two_str, &Symbols::Dot(), &two_str};
7337 const String& empty = String::Handle(String::New(""));
7338 const String* data[3] = {&Symbols::TypeError(), &empty,
7339 &Symbols::isPaused()};
7340 CheckConcatAll(data, 3);
7341 }
7342}
7343
7344struct TestResult {
7345 const char* in;
7346 const char* out;
7347};
7348
7349ISOLATE_UNIT_TEST_CASE(String_ScrubName) {
7350 TestResult tests[] = {
7351 {"(dynamic, dynamic) => void", "(dynamic, dynamic) => void"},
7352 {"_List@915557746", "_List"},
7353 {"_HashMap@600006304<K, V>(dynamic) => V",
7354 "_HashMap<K, V>(dynamic) => V"},
7355 {"set:foo", "foo="},
7356 {"get:foo", "foo"},
7357 {"_ReceivePortImpl@709387912", "_ReceivePortImpl"},
7358 {"_ReceivePortImpl@709387912._internal@709387912",
7359 "_ReceivePortImpl._internal"},
7360 {"_C@6328321&_E@6328321&_F@6328321", "_C&_E&_F"},
7361 {"List.", "List"},
7362 {"get:foo@6328321", "foo"},
7363 {"_MyClass@6328321.", "_MyClass"},
7364 {"_MyClass@6328321.named", "_MyClass.named"},
7365 };
7366 String& test = String::Handle();
7367 const char* result;
7368 for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
7369 test = String::New(tests[i].in);
7371 EXPECT_STREQ(tests[i].out, result);
7372 }
7373}
7374
7375ISOLATE_UNIT_TEST_CASE(String_EqualsUTF32) {
7376 // Regression test for Issue 27433. Checks that comparisons between Strings
7377 // and utf32 arrays happens after conversion to utf16 instead of utf32, as
7378 // required for proper canonicalization of string literals with a lossy
7379 // utf32->utf16 conversion.
7380 int32_t char_codes[] = {0, 0x0a, 0x0d, 0x7f, 0xff,
7381 0xffff, 0xd800, 0xdc00, 0xdbff, 0xdfff};
7382
7383 const String& str =
7384 String::Handle(String::FromUTF32(char_codes, ARRAY_SIZE(char_codes)));
7385 EXPECT(str.Equals(char_codes, ARRAY_SIZE(char_codes)));
7386}
7387
7388TEST_CASE(TypeParameterTypeRef) {
7389 // Regression test for issue 82890.
7390 const char* kScriptChars =
7391 "void foo<T extends C<T>>(T x) {}\n"
7392 "void bar<M extends U<M>>(M x) {}\n"
7393 "abstract class C<T> {}\n"
7394 "abstract class U<T> extends C<T> {}\n";
7395 TestCase::LoadTestScript(kScriptChars, nullptr);
7396 TransitionNativeToVM transition(thread);
7402 const Function& foo = Function::Handle(GetFunction(lib, "foo"));
7403 const Function& bar = Function::Handle(GetFunction(lib, "bar"));
7406 EXPECT(!m.IsSubtypeOf(t, Heap::kNew));
7407}
7408
7409static void FinalizeAndCanonicalize(AbstractType* type) {
7411 ASSERT(type->IsCanonical());
7412}
7413
7414static void CheckSubtypeRelation(const Expect& expect,
7415 const AbstractType& sub,
7416 const AbstractType& super,
7417 bool is_subtype) {
7418 if (sub.IsSubtypeOf(super, Heap::kNew) != is_subtype) {
7419 TextBuffer buffer(128);
7420 buffer.AddString("Expected ");
7421 sub.PrintName(Object::kScrubbedName, &buffer);
7422 buffer.Printf(" to %s a subtype of ", is_subtype ? "be" : "not be");
7423 super.PrintName(Object::kScrubbedName, &buffer);
7424 expect.Fail("%s", buffer.buffer());
7425 }
7426}
7427
7428#define EXPECT_SUBTYPE(sub, super) \
7429 CheckSubtypeRelation(Expect(__FILE__, __LINE__), sub, super, true);
7430#define EXPECT_NOT_SUBTYPE(sub, super) \
7431 CheckSubtypeRelation(Expect(__FILE__, __LINE__), sub, super, false);
7432
7433ISOLATE_UNIT_TEST_CASE(ClosureType_SubtypeOfFunctionType) {
7434 const auto& closure_class =
7435 Class::Handle(IsolateGroup::Current()->object_store()->closure_class());
7436 const auto& closure_type = Type::Handle(closure_class.DeclarationType());
7437 auto& closure_type_nullable = Type::Handle(
7438 closure_type.ToNullability(Nullability::kNullable, Heap::kNew));
7439 FinalizeAndCanonicalize(&closure_type_nullable);
7440 auto& closure_type_legacy = Type::Handle(
7441 closure_type.ToNullability(Nullability::kLegacy, Heap::kNew));
7442 FinalizeAndCanonicalize(&closure_type_legacy);
7443 auto& closure_type_nonnullable = Type::Handle(
7444 closure_type.ToNullability(Nullability::kNonNullable, Heap::kNew));
7445 FinalizeAndCanonicalize(&closure_type_nonnullable);
7446
7447 const auto& function_type =
7448 Type::Handle(IsolateGroup::Current()->object_store()->function_type());
7449 auto& function_type_nullable = Type::Handle(
7450 function_type.ToNullability(Nullability::kNullable, Heap::kNew));
7451 FinalizeAndCanonicalize(&function_type_nullable);
7452 auto& function_type_legacy = Type::Handle(
7453 function_type.ToNullability(Nullability::kLegacy, Heap::kNew));
7454 FinalizeAndCanonicalize(&function_type_legacy);
7455 auto& function_type_nonnullable = Type::Handle(
7456 function_type.ToNullability(Nullability::kNonNullable, Heap::kNew));
7457 FinalizeAndCanonicalize(&function_type_nonnullable);
7458
7459 EXPECT_SUBTYPE(closure_type_nonnullable, function_type_nullable);
7460 EXPECT_SUBTYPE(closure_type_nonnullable, function_type_legacy);
7461 EXPECT_SUBTYPE(closure_type_nonnullable, function_type_nonnullable);
7462 EXPECT_SUBTYPE(closure_type_legacy, function_type_nullable);
7463 EXPECT_SUBTYPE(closure_type_legacy, function_type_legacy);
7464 EXPECT_SUBTYPE(closure_type_legacy, function_type_nonnullable);
7465 EXPECT_SUBTYPE(closure_type_nullable, function_type_nullable);
7466 EXPECT_SUBTYPE(closure_type_nullable, function_type_legacy);
7467 EXPECT_NOT_SUBTYPE(closure_type_nullable, function_type_nonnullable);
7468
7469 const auto& async_lib = Library::Handle(Library::AsyncLibrary());
7470 const auto& future_or_class =
7471 Class::Handle(async_lib.LookupClass(Symbols::FutureOr()));
7472 auto& tav_function_nullable = TypeArguments::Handle(TypeArguments::New(1));
7473 tav_function_nullable.SetTypeAt(0, function_type_nullable);
7474 tav_function_nullable = tav_function_nullable.Canonicalize(thread);
7475 auto& tav_function_legacy = TypeArguments::Handle(TypeArguments::New(1));
7476 tav_function_legacy.SetTypeAt(0, function_type_legacy);
7477 tav_function_legacy = tav_function_legacy.Canonicalize(thread);
7478 auto& tav_function_nonnullable = TypeArguments::Handle(TypeArguments::New(1));
7479 tav_function_nonnullable.SetTypeAt(0, function_type_nonnullable);
7480 tav_function_nonnullable = tav_function_nonnullable.Canonicalize(thread);
7481
7482 auto& future_or_function_type_nullable =
7483 Type::Handle(Type::New(future_or_class, tav_function_nullable));
7484 FinalizeAndCanonicalize(&future_or_function_type_nullable);
7485 auto& future_or_function_type_legacy =
7486 Type::Handle(Type::New(future_or_class, tav_function_legacy));
7487 FinalizeAndCanonicalize(&future_or_function_type_legacy);
7488 auto& future_or_function_type_nonnullable =
7489 Type::Handle(Type::New(future_or_class, tav_function_nonnullable));
7490 FinalizeAndCanonicalize(&future_or_function_type_nonnullable);
7491
7492 EXPECT_SUBTYPE(closure_type_nonnullable, future_or_function_type_nullable);
7493 EXPECT_SUBTYPE(closure_type_nonnullable, future_or_function_type_legacy);
7494 EXPECT_SUBTYPE(closure_type_nonnullable, future_or_function_type_nonnullable);
7495 EXPECT_SUBTYPE(closure_type_legacy, future_or_function_type_nullable);
7496 EXPECT_SUBTYPE(closure_type_legacy, future_or_function_type_legacy);
7497 EXPECT_SUBTYPE(closure_type_legacy, future_or_function_type_nonnullable);
7498 EXPECT_SUBTYPE(closure_type_nullable, future_or_function_type_nullable);
7499 EXPECT_SUBTYPE(closure_type_nullable, future_or_function_type_legacy);
7500 EXPECT_NOT_SUBTYPE(closure_type_nullable,
7501 future_or_function_type_nonnullable);
7502}
7503
7504ISOLATE_UNIT_TEST_CASE(FunctionType_IsSubtypeOfNonNullableObject) {
7505 const auto& type_object = Type::Handle(
7506 IsolateGroup::Current()->object_store()->non_nullable_object_type());
7507
7508 auto& type_function_int_nullary =
7510 type_function_int_nullary.set_result_type(Type::Handle(Type::IntType()));
7511 FinalizeAndCanonicalize(&type_function_int_nullary);
7512
7513 auto& type_nullable_function_int_nullary =
7514 FunctionType::Handle(type_function_int_nullary.ToNullability(
7516 FinalizeAndCanonicalize(&type_nullable_function_int_nullary);
7517
7518 EXPECT_SUBTYPE(type_function_int_nullary, type_object);
7519 EXPECT_NOT_SUBTYPE(type_nullable_function_int_nullary, type_object);
7520}
7521
7522#undef EXPECT_NOT_SUBTYPE
7523#undef EXPECT_SUBTYPE
7524
7525static void ExpectTypesEquivalent(const Expect& expect,
7526 const AbstractType& expected,
7527 const AbstractType& got,
7528 TypeEquality kind) {
7529 if (got.IsEquivalent(expected, kind)) return;
7530 TextBuffer buffer(128);
7531 buffer.AddString("Expected type ");
7532 expected.PrintName(Object::kScrubbedName, &buffer);
7533 buffer.AddString(", got ");
7534 got.PrintName(Object::kScrubbedName, &buffer);
7535 expect.Fail("%s", buffer.buffer());
7536}
7537
7538#define EXPECT_TYPES_EQUAL(expected, got) \
7539 ExpectTypesEquivalent(Expect(__FILE__, __LINE__), expected, got, \
7540 TypeEquality::kCanonical);
7541
7542TEST_CASE(Class_GetInstantiationOf) {
7543 const char* kScript = R"(
7544 class B<T> {}
7545 class A1<X, Y> implements B<List<Y>> {}
7546 class A2<X, Y> extends A1<Y, X> {}
7547 )";
7548 Dart_Handle api_lib = TestCase::LoadTestScript(kScript, nullptr);
7549 EXPECT_VALID(api_lib);
7550 TransitionNativeToVM transition(thread);
7551 Zone* const zone = thread->zone();
7552
7553 const auto& root_lib =
7554 Library::CheckedHandle(zone, Api::UnwrapHandle(api_lib));
7555 EXPECT(!root_lib.IsNull());
7556 const auto& class_b = Class::Handle(zone, GetClass(root_lib, "B"));
7557 const auto& class_a1 = Class::Handle(zone, GetClass(root_lib, "A1"));
7558 const auto& class_a2 = Class::Handle(zone, GetClass(root_lib, "A2"));
7559
7560 const auto& core_lib = Library::Handle(zone, Library::CoreLibrary());
7561 const auto& class_list = Class::Handle(zone, GetClass(core_lib, "List"));
7562
7563 const auto& decl_type_b = Type::Handle(zone, class_b.DeclarationType());
7564 const auto& decl_type_list = Type::Handle(zone, class_list.DeclarationType());
7565 const auto& null_tav = Object::null_type_arguments();
7566
7567 // Test that A1.GetInstantiationOf(B) returns B<List<A1::Y>>.
7568 {
7569 const auto& decl_type_a1 = Type::Handle(zone, class_a1.DeclarationType());
7570 const auto& decl_type_args_a1 =
7571 TypeArguments::Handle(zone, decl_type_a1.arguments());
7572 const auto& type_arg_a1_y =
7573 TypeParameter::CheckedHandle(zone, decl_type_args_a1.TypeAt(1));
7574 auto& tav_a1_y = TypeArguments::Handle(TypeArguments::New(1));
7575 tav_a1_y.SetTypeAt(0, type_arg_a1_y);
7576 tav_a1_y = tav_a1_y.Canonicalize(thread);
7577 auto& type_list_a1_y = Type::CheckedHandle(
7578 zone, decl_type_list.InstantiateFrom(tav_a1_y, null_tav, kAllFree,
7579 Heap::kNew));
7580 type_list_a1_y ^= type_list_a1_y.Canonicalize(thread);
7581 auto& tav_list_a1_y = TypeArguments::Handle(TypeArguments::New(1));
7582 tav_list_a1_y.SetTypeAt(0, type_list_a1_y);
7583 tav_list_a1_y = tav_list_a1_y.Canonicalize(thread);
7584 auto& type_b_list_a1_y = Type::CheckedHandle(
7585 zone, decl_type_b.InstantiateFrom(tav_list_a1_y, null_tav, kAllFree,
7586 Heap::kNew));
7587 type_b_list_a1_y ^= type_b_list_a1_y.Canonicalize(thread);
7588
7589 const auto& inst_b_a1 =
7590 Type::Handle(zone, class_a1.GetInstantiationOf(zone, class_b));
7591 EXPECT(!inst_b_a1.IsNull());
7592 EXPECT_TYPES_EQUAL(type_b_list_a1_y, inst_b_a1);
7593 }
7594
7595 // Test that A2.GetInstantiationOf(B) returns B<List<A2::X>>.
7596 {
7597 const auto& decl_type_a2 = Type::Handle(zone, class_a2.DeclarationType());
7598 const auto& decl_type_args_a2 =
7599 TypeArguments::Handle(zone, decl_type_a2.arguments());
7600 const auto& type_arg_a2_x =
7601 TypeParameter::CheckedHandle(zone, decl_type_args_a2.TypeAt(0));
7602 auto& tav_a2_x = TypeArguments::Handle(TypeArguments::New(1));
7603 tav_a2_x.SetTypeAt(0, type_arg_a2_x);
7604 tav_a2_x = tav_a2_x.Canonicalize(thread);
7605 auto& type_list_a2_x = Type::CheckedHandle(
7606 zone, decl_type_list.InstantiateFrom(tav_a2_x, null_tav, kAllFree,
7607 Heap::kNew));
7608 type_list_a2_x ^= type_list_a2_x.Canonicalize(thread);
7609 auto& tav_list_a2_x = TypeArguments::Handle(TypeArguments::New(1));
7610 tav_list_a2_x.SetTypeAt(0, type_list_a2_x);
7611 tav_list_a2_x = tav_list_a2_x.Canonicalize(thread);
7612 auto& type_b_list_a2_x = Type::CheckedHandle(
7613 zone, decl_type_b.InstantiateFrom(tav_list_a2_x, null_tav, kAllFree,
7614 Heap::kNew));
7615 type_b_list_a2_x ^= type_b_list_a2_x.Canonicalize(thread);
7616
7617 const auto& inst_b_a2 =
7618 Type::Handle(zone, class_a2.GetInstantiationOf(zone, class_b));
7619 EXPECT(!inst_b_a2.IsNull());
7620 EXPECT_TYPES_EQUAL(type_b_list_a2_x, inst_b_a2);
7621 }
7622}
7623
7624#undef EXPECT_TYPES_EQUAL
7625
7626#define EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(expected, got) \
7627 ExpectTypesEquivalent(Expect(__FILE__, __LINE__), expected, got, \
7628 TypeEquality::kSyntactical);
7629
7630static TypePtr CreateFutureOrType(const AbstractType& param,
7631 Nullability nullability) {
7632 const auto& async_lib = Library::Handle(Library::AsyncLibrary());
7633 const auto& future_or_class =
7634 Class::Handle(async_lib.LookupClass(Symbols::FutureOr()));
7635 const auto& tav = TypeArguments::Handle(TypeArguments::New(1));
7636 tav.SetTypeAt(0, param);
7637 const auto& type =
7638 AbstractType::Handle(Type::New(future_or_class, tav, nullability));
7639 return Type::RawCast(
7641}
7642
7643static TypePtr CreateFutureType(const AbstractType& param,
7644 Nullability nullability) {
7645 ObjectStore* const object_store = IsolateGroup::Current()->object_store();
7646 const auto& future_class = Class::Handle(object_store->future_class());
7647 const auto& tav = TypeArguments::Handle(TypeArguments::New(1));
7648 tav.SetTypeAt(0, param);
7649 const auto& type = Type::Handle(Type::New(future_class, tav, nullability));
7650 return Type::RawCast(
7652}
7653
7654ISOLATE_UNIT_TEST_CASE(AbstractType_NormalizeFutureOrType) {
7655 // This should be kept up to date with any changes in
7656 // https://github.com/dart-lang/language/blob/master/resources/type-system/normalization.md
7657
7658 ObjectStore* const object_store = IsolateGroup::Current()->object_store();
7659
7660 auto normalized_future_or = [&](const AbstractType& param,
7661 Nullability nullability) -> AbstractTypePtr {
7662 const auto& type = Type::Handle(CreateFutureOrType(param, nullability));
7663 return type.NormalizeFutureOrType(Heap::kNew);
7664 };
7665
7666 // NORM(FutureOr<T>) =
7667 // let S be NORM(T)
7668 // if S is a top type then S
7669 {
7670 const auto& type = AbstractType::Handle(normalized_future_or(
7671 Object::dynamic_type(), Nullability::kNonNullable));
7672 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(Object::dynamic_type(), type);
7673 }
7674
7675 {
7676 const auto& type = AbstractType::Handle(
7677 normalized_future_or(Object::void_type(), Nullability::kNonNullable));
7678 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(Object::void_type(), type);
7679 }
7680
7681 {
7682 const auto& type_nullable_object =
7683 Type::Handle(object_store->nullable_object_type());
7684 const auto& type = AbstractType::Handle(
7685 normalized_future_or(type_nullable_object, Nullability::kNonNullable));
7686 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, type);
7687 }
7688
7689 // if S is Object then S
7690
7691 {
7692 const auto& type_non_nullable_object =
7693 Type::Handle(object_store->non_nullable_object_type());
7694 const auto& type = AbstractType::Handle(normalized_future_or(
7695 type_non_nullable_object, Nullability::kNonNullable));
7696 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_non_nullable_object, type);
7697 }
7698
7699 // if S is Object* then S
7700
7701 {
7702 const auto& type_legacy_object =
7703 Type::Handle(object_store->legacy_object_type());
7704 const auto& type = AbstractType::Handle(
7705 normalized_future_or(type_legacy_object, Nullability::kNonNullable));
7706 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_legacy_object, type);
7707 }
7708
7709 // if S is Never then Future<Never>
7710
7711 {
7712 const auto& type_never = Type::Handle(object_store->never_type());
7713 const auto& expected =
7715 const auto& got = AbstractType::Handle(
7716 normalized_future_or(type_never, Nullability::kNonNullable));
7718 }
7719
7720 // if S is Null then Future<Null>?
7721
7722 {
7723 const auto& type_null = Type::Handle(object_store->null_type());
7724 const auto& expected =
7726 const auto& got = AbstractType::Handle(
7727 normalized_future_or(type_null, Nullability::kNonNullable));
7729 }
7730
7731 // else FutureOr<S>
7732
7733 // NORM(T?) =
7734 // let S be NORM(T)
7735 // ...
7736 // if S is FutureOr<R> and R is nullable then S
7737
7739 const auto& type_nullable_int =
7740 Type::Handle(object_store->nullable_int_type());
7741 const auto& expected = Type::Handle(
7742 CreateFutureOrType(type_nullable_int, Nullability::kNonNullable));
7743 const auto& got = AbstractType::Handle(
7744 normalized_future_or(type_nullable_int, Nullability::kNullable));
7746 }
7747}
7748
7749TEST_CASE(AbstractType_InstantiatedFutureOrIsNormalized) {
7750 const char* kScript = R"(
7751import 'dart:async';
7752
7753FutureOr<T>? foo<T>() { return null; }
7754FutureOr<T?> bar<T>() { return null; }
7755)";
7756
7757 Dart_Handle api_lib = TestCase::LoadTestScript(kScript, nullptr);
7758 EXPECT_VALID(api_lib);
7759 TransitionNativeToVM transition(thread);
7760 Zone* const zone = thread->zone();
7761 ObjectStore* const object_store = IsolateGroup::Current()->object_store();
7762
7763 const auto& null_tav = Object::null_type_arguments();
7764 auto instantiate_future_or =
7765 [&](const AbstractType& generic,
7766 const AbstractType& param) -> AbstractTypePtr {
7767 const auto& tav = TypeArguments::Handle(TypeArguments::New(1));
7768 tav.SetTypeAt(0, param);
7769 return generic.InstantiateFrom(null_tav, tav, kCurrentAndEnclosingFree,
7770 Heap::kNew);
7771 };
7772
7773 const auto& root_lib =
7774 Library::CheckedHandle(zone, Api::UnwrapHandle(api_lib));
7775 EXPECT(!root_lib.IsNull());
7776 const auto& foo = Function::Handle(zone, GetFunction(root_lib, "foo"));
7777 const auto& bar = Function::Handle(zone, GetFunction(root_lib, "bar"));
7778 const auto& foo_sig = FunctionType::Handle(zone, foo.signature());
7779 const auto& bar_sig = FunctionType::Handle(zone, bar.signature());
7780
7781 const auto& nullable_future_or_T =
7782 AbstractType::Handle(zone, foo_sig.result_type());
7783 const auto& future_or_nullable_T =
7784 AbstractType::Handle(zone, bar_sig.result_type());
7785
7786 const auto& type_nullable_object =
7787 Type::Handle(object_store->nullable_object_type());
7788 const auto& type_non_nullable_object =
7789 Type::Handle(object_store->non_nullable_object_type());
7790 const auto& type_legacy_object =
7791 Type::Handle(object_store->legacy_object_type());
7792
7793 // Testing same cases as AbstractType_NormalizeFutureOrType.
7794
7795 // FutureOr<T>?[top type] = top type
7796
7797 {
7798 const auto& got = AbstractType::Handle(
7799 instantiate_future_or(nullable_future_or_T, Object::dynamic_type()));
7800 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(Object::dynamic_type(), got);
7801 }
7802
7803 {
7804 const auto& got = AbstractType::Handle(
7805 instantiate_future_or(nullable_future_or_T, Object::void_type()));
7806 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(Object::void_type(), got);
7807 }
7808
7809 {
7810 const auto& got = AbstractType::Handle(
7811 instantiate_future_or(nullable_future_or_T, type_nullable_object));
7812 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, got);
7813 }
7814
7815 // FutureOr<T?>[top type] = top type
7816
7817 {
7818 const auto& got = AbstractType::Handle(
7819 instantiate_future_or(future_or_nullable_T, Object::dynamic_type()));
7820 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(Object::dynamic_type(), got);
7821 }
7822
7823 {
7824 const auto& got = AbstractType::Handle(
7825 instantiate_future_or(future_or_nullable_T, Object::void_type()));
7826 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(Object::void_type(), got);
7827 }
7828
7829 {
7830 const auto& got = AbstractType::Handle(
7831 instantiate_future_or(future_or_nullable_T, type_nullable_object));
7832 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, got);
7833 }
7834
7835 // FutureOr<T?>[Object] = Object?
7836
7837 {
7838 const auto& got = AbstractType::Handle(
7839 instantiate_future_or(future_or_nullable_T, type_non_nullable_object));
7840 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, got);
7841 }
7842
7843 // FutureOr<T?>[Object*] = Object?
7844
7845 {
7846 const auto& got = AbstractType::Handle(
7847 instantiate_future_or(future_or_nullable_T, type_legacy_object));
7848 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, got);
7849 }
7850
7851 // FutureOr<T>?[Object] = Object?
7852
7853 {
7854 const auto& got = AbstractType::Handle(
7855 instantiate_future_or(nullable_future_or_T, type_non_nullable_object));
7856 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, got);
7857 }
7858
7859 // FutureOr<T>?[Object*] = Object?
7860
7861 {
7862 const auto& got = AbstractType::Handle(
7863 instantiate_future_or(nullable_future_or_T, type_legacy_object));
7864 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(type_nullable_object, got);
7865 }
7866
7867 const auto& type_never = Type::Handle(object_store->never_type());
7868 const auto& type_null = Type::Handle(object_store->null_type());
7869
7870 // FutureOr<T?>[Never] = Future<Null>?
7871
7872 {
7873 const auto& expected =
7875 const auto& got = AbstractType::Handle(
7876 instantiate_future_or(future_or_nullable_T, type_never));
7878 }
7879
7880 // FutureOr<T>?[Never] = Future<Never>?
7881
7882 {
7883 const auto& expected =
7885 const auto& got = AbstractType::Handle(
7886 instantiate_future_or(nullable_future_or_T, type_never));
7888 }
7889
7890 // FutureOr<T?>[Null] = Future<Null>?
7891
7892 {
7893 const auto& expected =
7895 const auto& got = AbstractType::Handle(
7896 instantiate_future_or(future_or_nullable_T, type_null));
7898 }
7899
7900 // FutureOr<T>?[Null] = Future<Null>?
7901
7902 {
7903 const auto& expected =
7905 const auto& got = AbstractType::Handle(
7906 instantiate_future_or(nullable_future_or_T, type_null));
7908 }
7909
7910 const auto& type_nullable_int =
7911 Type::Handle(object_store->nullable_int_type());
7912 const auto& type_non_nullable_int =
7913 Type::Handle(object_store->non_nullable_int_type());
7914
7915 // FutureOr<T?>[int] = FutureOr<int?>
7916
7917 {
7918 const auto& expected = Type::Handle(
7919 CreateFutureOrType(type_nullable_int, Nullability::kNonNullable));
7920 const auto& got = AbstractType::Handle(
7921 instantiate_future_or(future_or_nullable_T, type_non_nullable_int));
7923 }
7924
7925 // FutureOr<T?>[int?] = FutureOr<int?>
7926
7927 {
7928 const auto& expected = Type::Handle(
7929 CreateFutureOrType(type_nullable_int, Nullability::kNonNullable));
7930 const auto& got = AbstractType::Handle(
7931 instantiate_future_or(future_or_nullable_T, type_nullable_int));
7933 }
7934
7935 // FutureOr<T>?[int?] = FutureOr<int?>
7936
7937 {
7938 const auto& expected = Type::Handle(
7939 CreateFutureOrType(type_nullable_int, Nullability::kNonNullable));
7940 const auto& got = AbstractType::Handle(
7941 instantiate_future_or(nullable_future_or_T, type_nullable_int));
7943 }
7944
7945 // FutureOr<T>?[int] = FutureOr<int>?
7946
7948 const auto& expected = Type::Handle(
7949 CreateFutureOrType(type_non_nullable_int, Nullability::kNullable));
7950 const auto& got = AbstractType::Handle(
7951 instantiate_future_or(nullable_future_or_T, type_non_nullable_int));
7953 }
7954}
7955
7956#define __ assembler->
7957
7958static void GenerateInvokeInstantiateTAVStub(compiler::Assembler* assembler) {
7959 __ EnterDartFrame(0);
7960
7961 // Load the arguments into the right stub calling convention registers.
7962 const intptr_t uninstantiated_offset =
7963 (kCallerSpSlotFromFp + 2) * compiler::target::kWordSize;
7964 const intptr_t inst_type_args_offset =
7965 (kCallerSpSlotFromFp + 1) * compiler::target::kWordSize;
7966 const intptr_t fun_type_args_offset =
7967 (kCallerSpSlotFromFp + 0) * compiler::target::kWordSize;
7968
7970 uninstantiated_offset);
7972 inst_type_args_offset);
7974 fun_type_args_offset);
7975
7976 __ Call(StubCode::InstantiateTypeArguments());
7977
7978 // Set the return from the stub.
7981 __ LeaveDartFrame();
7982 __ Ret();
7983}
7984
7985#undef __
7986
7987static CodePtr CreateInvokeInstantiateTypeArgumentsStub(Thread* thread) {
7988 Zone* const zone = thread->zone();
7989 const auto& klass = Class::Handle(
7990 zone, thread->isolate_group()->class_table()->At(kInstanceCid));
7991 const auto& symbol = String::Handle(
7992 zone, Symbols::New(thread, OS::SCreate(zone, "InstantiateTAVTest")));
7993 const auto& signature = FunctionType::Handle(zone, FunctionType::New());
7994 const auto& function = Function::Handle(
7995 zone, Function::New(signature, symbol, UntaggedFunction::kRegularFunction,
7996 false, false, false, false, false, klass,
7997 TokenPosition::kNoSource));
7998
7999 compiler::ObjectPoolBuilder pool_builder;
8000 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
8001 compiler::Assembler assembler(&pool_builder);
8003 const Code& invoke_instantiate_tav = Code::Handle(
8004 Code::FinalizeCodeAndNotify("InstantiateTAV", nullptr, &assembler,
8006 /*optimized=*/false));
8007
8008 const auto& pool =
8010 invoke_instantiate_tav.set_object_pool(pool.ptr());
8011 invoke_instantiate_tav.set_owner(function);
8012 invoke_instantiate_tav.set_exception_handlers(
8014#if defined(TARGET_ARCH_IA32)
8015 EXPECT_EQ(0, pool.Length());
8016#else
8017 EXPECT_EQ(1, pool.Length()); // The InstantiateTypeArguments stub.
8018#endif
8019 return invoke_instantiate_tav.ptr();
8020}
8021
8022#if !defined(PRODUCT)
8023// Defined before TypeArguments::InstantiateAndCanonicalizeFrom in object.cc.
8025#endif
8026
8027static void TypeArgumentsHashCacheTest(Thread* thread, intptr_t num_classes) {
8028 TextBuffer buffer(MB);
8029 buffer.AddString("class D<T> {}\n");
8030 for (intptr_t i = 0; i < num_classes; i++) {
8031 buffer.Printf("class C%" Pd " { String toString() => 'C%" Pd "'; }\n", i,
8032 i);
8033 }
8034 buffer.AddString("main() {\n");
8035 for (intptr_t i = 0; i < num_classes; i++) {
8036 buffer.Printf(" C%" Pd "().toString();\n", i);
8037 }
8038 buffer.AddString("}\n");
8039
8040 Dart_Handle api_lib = TestCase::LoadTestScript(buffer.buffer(), nullptr);
8041 EXPECT_VALID(api_lib);
8042 Dart_Handle result = Dart_Invoke(api_lib, NewString("main"), 0, nullptr);
8044
8045 // D + C0...CN, where N = kNumClasses - 1
8046 EXPECT(IsolateGroup::Current()->class_table()->NumCids() > num_classes);
8047
8048 TransitionNativeToVM transition(thread);
8049 Zone* const zone = thread->zone();
8050
8051 const auto& root_lib =
8052 Library::CheckedHandle(zone, Api::UnwrapHandle(api_lib));
8053 EXPECT(!root_lib.IsNull());
8054
8055 const auto& class_d = Class::Handle(zone, GetClass(root_lib, "D"));
8056 ASSERT(!class_d.IsNull());
8057 const auto& decl_type_d = Type::Handle(zone, class_d.DeclarationType());
8058 const auto& decl_type_d_type_args =
8059 TypeArguments::Handle(zone, decl_type_d.arguments());
8060
8061 EXPECT(!decl_type_d_type_args.HasInstantiations());
8062
8063 auto& class_c = Class::Handle(zone);
8064 auto& decl_type_c = Type::Handle(zone);
8065 auto& instantiator_type_args = TypeArguments::Handle(zone);
8066 const auto& function_type_args = Object::null_type_arguments();
8067 auto& result_type_args = TypeArguments::Handle(zone);
8068 auto& result_type = AbstractType::Handle(zone);
8069 // Cache the first computed set of instantiator type arguments to check that
8070 // no entries from the cache have been lost when the cache grows.
8071 auto& first_instantiator_type_args = TypeArguments::Handle(zone);
8072 // Used for the cache hit in stub check.
8073 const auto& invoke_instantiate_tav =
8075 const auto& invoke_instantiate_tav_arguments =
8076 Array::Handle(zone, Array::New(3));
8077 const auto& invoke_instantiate_tav_args_descriptor =
8079 for (intptr_t i = 0; i < num_classes; ++i) {
8080 const bool updated_cache_is_linear =
8082 auto const name = OS::SCreate(zone, "C%" Pd "", i);
8083 class_c = GetClass(root_lib, name);
8084 ASSERT(!class_c.IsNull());
8085 decl_type_c = class_c.DeclarationType();
8086 instantiator_type_args = TypeArguments::New(1);
8087 instantiator_type_args.SetTypeAt(0, decl_type_c);
8088 instantiator_type_args = instantiator_type_args.Canonicalize(thread);
8089
8090#if !defined(PRODUCT)
8091 // The first call to InstantiateAndCanonicalizeFrom shouldn't have a cache
8092 // hit since the instantiator type arguments should be unique for each
8093 // iteration, and after that we do a check that the InstantiateTypeArguments
8094 // stub finds the entry (unless the cache is hash-based on IA32).
8096#endif
8097
8098 // Check that the key does not currently exist in the cache.
8099 intptr_t old_capacity;
8100 {
8101 SafepointMutexLocker ml(
8102 thread->isolate_group()->type_arguments_canonicalization_mutex());
8103 TypeArguments::Cache cache(zone, decl_type_d_type_args);
8104 EXPECT_EQ(i, cache.NumOccupied());
8105 auto loc =
8106 cache.FindKeyOrUnused(instantiator_type_args, function_type_args);
8107 EXPECT(!loc.present);
8108 old_capacity = cache.NumEntries();
8109 }
8110
8111 decl_type_d_type_args.InstantiateAndCanonicalizeFrom(instantiator_type_args,
8112 function_type_args);
8113
8114 // Check that the key now does exist in the cache.
8115 TypeArguments::Cache::KeyLocation loc;
8116 bool storage_changed;
8117 {
8118 SafepointMutexLocker ml(
8119 thread->isolate_group()->type_arguments_canonicalization_mutex());
8120 TypeArguments::Cache cache(zone, decl_type_d_type_args);
8121 EXPECT_EQ(i + 1, cache.NumOccupied());
8122 // Double-check that we got the expected type of cache.
8123 EXPECT(updated_cache_is_linear ? cache.IsLinear() : cache.IsHash());
8124 loc = cache.FindKeyOrUnused(instantiator_type_args, function_type_args);
8125 EXPECT(loc.present);
8126 storage_changed = cache.NumEntries() != old_capacity;
8127 }
8128
8129#if defined(TARGET_ARCH_IA32)
8130 const bool stub_checks_hash_caches = false;
8131#else
8132 const bool stub_checks_hash_caches = true;
8133#endif
8134 // Now check that we get the expected result from calling the stub if it
8135 // checks the cache (e.g., in all cases but hash-based caches on IA32).
8136 if (updated_cache_is_linear || stub_checks_hash_caches) {
8137 invoke_instantiate_tav_arguments.SetAt(0, decl_type_d_type_args);
8138 invoke_instantiate_tav_arguments.SetAt(1, instantiator_type_args);
8139 invoke_instantiate_tav_arguments.SetAt(2, function_type_args);
8140 result_type_args ^= DartEntry::InvokeCode(
8141 invoke_instantiate_tav, invoke_instantiate_tav_args_descriptor,
8142 invoke_instantiate_tav_arguments, thread);
8143 EXPECT_EQ(1, result_type_args.Length());
8144 result_type = result_type_args.TypeAt(0);
8145 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(decl_type_c, result_type);
8146 }
8147
8148#if !defined(PRODUCT)
8149 // Setting to false prior to re-calling InstantiateAndCanonicalizeFrom with
8150 // the same keys, as now we want a runtime check of an existing cache entry.
8152#endif
8153
8154 result_type_args = decl_type_d_type_args.InstantiateAndCanonicalizeFrom(
8155 instantiator_type_args, function_type_args);
8156 result_type = result_type_args.TypeAt(0);
8157 EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(decl_type_c, result_type);
8158
8159 // Check that no new entries were added to the cache.
8160 {
8161 SafepointMutexLocker ml(
8162 thread->isolate_group()->type_arguments_canonicalization_mutex());
8163 TypeArguments::Cache cache(zone, decl_type_d_type_args);
8164 EXPECT_EQ(i + 1, cache.NumOccupied());
8165 auto const loc2 =
8166 cache.FindKeyOrUnused(instantiator_type_args, function_type_args);
8167 EXPECT(loc2.present);
8168 EXPECT_EQ(loc.entry, loc2.entry);
8169 }
8170
8171 if (i == 0) {
8172 first_instantiator_type_args = instantiator_type_args.ptr();
8173 } else if (storage_changed) {
8174 // Check that the first instantiator TAV still exists in the new cache.
8175 SafepointMutexLocker ml(
8176 thread->isolate_group()->type_arguments_canonicalization_mutex());
8177 TypeArguments::Cache cache(zone, decl_type_d_type_args);
8178 EXPECT_EQ(i + 1, cache.NumOccupied());
8179 // Double-check that we got the expected type of cache.
8181 : cache.IsHash());
8182 auto const loc =
8183 cache.FindKeyOrUnused(instantiator_type_args, function_type_args);
8184 EXPECT(loc.present);
8185 }
8186 }
8187}
8188
8189// A smaller version of the following test case, just to ensure some coverage
8190// on slower builds.
8191TEST_CASE(TypeArguments_Cache_SomeInstantiations) {
8194}
8195
8196// Too slow in debug mode. Also avoid the sanitizers and simulators for similar
8197// reasons. Any core issues will likely be found by SomeInstantiations.
8198#if !defined(DEBUG) && !defined(USING_MEMORY_SANITIZER) && \
8199 !defined(USING_THREAD_SANITIZER) && !defined(USING_LEAK_SANITIZER) && \
8200 !defined(USING_UNDEFINED_BEHAVIOR_SANITIZER) && !defined(USING_SIMULATOR)
8201TEST_CASE(TypeArguments_Cache_ManyInstantiations) {
8202 const intptr_t kNumClasses = 100000;
8203 static_assert(kNumClasses > TypeArguments::Cache::kMaxLinearCacheEntries,
8204 "too few classes to trigger change to a hash-based cache");
8205 TypeArgumentsHashCacheTest(thread, kNumClasses);
8206}
8207#endif
8208
8209#undef EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT
8210
8211static void SubtypeTestCacheCheckContents(Zone* zone,
8212 const SubtypeTestCache& cache) {
8213 const intptr_t used_inputs = cache.num_inputs();
8214 if (used_inputs < 1 || used_inputs > SubtypeTestCache::kMaxInputs) {
8215 FAIL("Invalid number of used inputs: %" Pd "", used_inputs);
8216 return;
8217 }
8218 const auto& array = Array::Handle(zone, cache.cache());
8219 for (intptr_t i = 0; i < cache.NumEntries(); i++) {
8220 if (!cache.IsOccupied(i)) continue;
8221 const intptr_t entry_start = i * SubtypeTestCache::kTestEntryLength;
8222 {
8223 const intptr_t cid =
8224 array.At(entry_start + SubtypeTestCache::kTestResult)
8226 EXPECT(cid == kNullCid || cid == kBoolCid);
8227 }
8228
8229 // Used to make sure all the cases are in the correct order below.
8230 int check_ordering = used_inputs;
8231 // Input: the value of SubtypeTestCache::Entries for this input
8232 // ExpectedCids is an expression where [cid] is bound to the contents cid.
8233#define USED_INPUT_CASE(Input, ExpectedCids) \
8234 case (Input) + 1: { \
8235 RELEASE_ASSERT((Input) + 1 == check_ordering); \
8236 const intptr_t cid = \
8237 array.At(entry_start + (Input))->GetClassIdMayBeSmi(); \
8238 if (!(ExpectedCids)) { \
8239 FAIL("expected: " #ExpectedCids ", got: cid %" Pd "", cid); \
8240 } \
8241 --check_ordering; \
8242 }
8243
8244 switch (used_inputs) {
8249 cid == kNullCid || cid == kTypeArgumentsCid);
8252 cid == kNullCid || cid == kTypeArgumentsCid);
8255 cid == kNullCid || cid == kTypeArgumentsCid);
8258 cid == kNullCid || cid == kTypeArgumentsCid);
8261 cid == kNullCid || cid == kTypeArgumentsCid);
8264 cid == kSmiCid || cid == kFunctionTypeCid);
8265 break;
8266 default:
8267 UNREACHABLE();
8268 }
8269
8270#undef USED_INPUT_CASE
8271 RELEASE_ASSERT(0 == check_ordering);
8272
8273 // Check that unused inputs have never been set.
8274 for (intptr_t i = used_inputs; i < SubtypeTestCache::kMaxInputs; i++) {
8275 // Since we sometimes use Array::NewUninitialized() for allocations of
8276 // STCs and never set unused inputs, the only thing we know is that the
8277 // entry is GC-safe. Since we don't expect valid values for unused inputs,
8278 // we just check if it's either a Smi or null.
8279 const intptr_t cid = array.At(entry_start + i)->GetClassIdMayBeSmi();
8280 EXPECT(cid == kSmiCid || cid == kNullCid);
8281 }
8282 }
8283}
8284
8285static void SubtypeTestCacheEntryTest(
8286 Thread* thread,
8287 const SubtypeTestCache& cache,
8288 const Object& instance_class_id_or_signature,
8289 const AbstractType& destination_type,
8290 const TypeArguments& instance_type_arguments,
8291 const TypeArguments& instantiator_type_arguments,
8292 const TypeArguments& function_type_arguments,
8293 const TypeArguments& parent_function_type_arguments,
8294 const TypeArguments& delayed_type_arguments,
8295 const Bool& expected_result,
8296 Bool* got_result) {
8297 const auto& tav_null = TypeArguments::null_type_arguments();
8298 const intptr_t num_inputs = cache.num_inputs();
8299 const bool was_hash = cache.IsHash();
8300 const intptr_t old_count = cache.NumberOfChecks();
8301 intptr_t expected_index, got_index;
8302
8303 EXPECT(!cache.HasCheck(
8304 instance_class_id_or_signature, destination_type, instance_type_arguments,
8305 instantiator_type_arguments, function_type_arguments,
8306 parent_function_type_arguments, delayed_type_arguments, /*index=*/nullptr,
8307 /*result=*/nullptr));
8308 {
8309 SafepointMutexLocker ml(
8310 thread->isolate_group()->subtype_test_cache_mutex());
8311 expected_index =
8312 cache.AddCheck(instance_class_id_or_signature, destination_type,
8313 instance_type_arguments, instantiator_type_arguments,
8314 function_type_arguments, parent_function_type_arguments,
8315 delayed_type_arguments, expected_result);
8316 EXPECT(expected_index >= 0);
8317 }
8318 EXPECT_EQ(old_count + 1, cache.NumberOfChecks());
8319 EXPECT(cache.HasCheck(instance_class_id_or_signature, destination_type,
8320 instance_type_arguments, instantiator_type_arguments,
8321 function_type_arguments, parent_function_type_arguments,
8322 delayed_type_arguments, &got_index, got_result));
8323 EXPECT_EQ(expected_index, got_index);
8324 EXPECT(got_result->ptr() == expected_result.ptr());
8325 if (num_inputs < (SubtypeTestCache::kInstanceTypeArguments + 1)) {
8326 // Match replacing unused instance type arguments with null.
8327 EXPECT(cache.HasCheck(instance_class_id_or_signature, destination_type,
8328 tav_null, instantiator_type_arguments,
8329 function_type_arguments,
8330 parent_function_type_arguments,
8331 delayed_type_arguments, &got_index, got_result));
8332 EXPECT_EQ(expected_index, got_index);
8333 EXPECT(got_result->ptr() == expected_result.ptr());
8334 } else {
8335 // No match replacing used instance type arguments with null.
8336 EXPECT(!cache.HasCheck(
8337 instance_class_id_or_signature, destination_type, tav_null,
8338 instantiator_type_arguments, function_type_arguments,
8339 parent_function_type_arguments, delayed_type_arguments,
8340 /*index=*/nullptr, /*result=*/nullptr));
8341 }
8342 if (num_inputs < (SubtypeTestCache::kInstantiatorTypeArguments + 1)) {
8343 // Match replacing unused instantiator type arguments with null.
8344 EXPECT(cache.HasCheck(instance_class_id_or_signature, destination_type,
8345 instance_type_arguments, tav_null,
8346 function_type_arguments,
8347 parent_function_type_arguments,
8348 delayed_type_arguments, &got_index, got_result));
8349 EXPECT_EQ(expected_index, got_index);
8350 EXPECT(got_result->ptr() == expected_result.ptr());
8351 } else {
8352 // No match replacing used instantiator type arguments with null.
8353 EXPECT(!cache.HasCheck(
8354 instance_class_id_or_signature, destination_type,
8355 instance_type_arguments, tav_null, function_type_arguments,
8356 parent_function_type_arguments, delayed_type_arguments,
8357 /*index=*/nullptr, /*result=*/nullptr));
8358 }
8359 if (num_inputs < (SubtypeTestCache::kFunctionTypeArguments + 1)) {
8360 // Match replacing unused function type arguments with null.
8361 EXPECT(cache.HasCheck(instance_class_id_or_signature, destination_type,
8362 instance_type_arguments, instantiator_type_arguments,
8363 tav_null, parent_function_type_arguments,
8364 delayed_type_arguments, &got_index, got_result));
8365 EXPECT_EQ(expected_index, got_index);
8366 EXPECT(got_result->ptr() == expected_result.ptr());
8367 } else {
8368 // No match replacing used function type arguments with null.
8369 EXPECT(!cache.HasCheck(instance_class_id_or_signature, destination_type,
8370 instance_type_arguments, instantiator_type_arguments,
8371 tav_null, parent_function_type_arguments,
8372 delayed_type_arguments,
8373 /*index=*/nullptr, /*result=*/nullptr));
8374 }
8375 if (num_inputs <
8377 // Match replacing unused parent function type arguments with null.
8378 EXPECT(cache.HasCheck(instance_class_id_or_signature, destination_type,
8379 instance_type_arguments, instantiator_type_arguments,
8380 function_type_arguments, tav_null,
8381 delayed_type_arguments, &got_index, got_result));
8382 EXPECT_EQ(expected_index, got_index);
8383 EXPECT(got_result->ptr() == expected_result.ptr());
8384 } else {
8385 // No match replacing used parent function type arguments with null.
8386 EXPECT(!cache.HasCheck(instance_class_id_or_signature, destination_type,
8387 instance_type_arguments, instantiator_type_arguments,
8388 function_type_arguments, tav_null,
8389 delayed_type_arguments, /*index=*/nullptr,
8390 /*result=*/nullptr));
8391 }
8392 if (num_inputs <
8394 // Match replacing unused delayed type arguments with null.
8395 EXPECT(cache.HasCheck(instance_class_id_or_signature, destination_type,
8396 instance_type_arguments, instantiator_type_arguments,
8397 function_type_arguments,
8398 parent_function_type_arguments, tav_null, &got_index,
8399 got_result));
8400 EXPECT_EQ(expected_index, got_index);
8401 EXPECT(got_result->ptr() == expected_result.ptr());
8402 } else {
8403 // No match replacing used delayed type arguments with null.
8404 EXPECT(!cache.HasCheck(instance_class_id_or_signature, destination_type,
8405 instance_type_arguments, instantiator_type_arguments,
8406 function_type_arguments,
8407 parent_function_type_arguments, tav_null,
8408 /*index=*/nullptr, /*result=*/nullptr));
8409 }
8410 // Make sure we're not accidentally using the same type as the input below.
8411 RELEASE_ASSERT(destination_type.ptr() != Type::VoidType());
8412 if (num_inputs < (SubtypeTestCache::kDestinationType + 1)) {
8413 // Match replacing unused destination type argument with the null type.
8414 EXPECT(cache.HasCheck(instance_class_id_or_signature, Object::void_type(),
8415 instance_type_arguments, instantiator_type_arguments,
8416 function_type_arguments,
8417 parent_function_type_arguments,
8418 delayed_type_arguments, &got_index, got_result));
8419 EXPECT_EQ(expected_index, got_index);
8420 EXPECT(got_result->ptr() == expected_result.ptr());
8421 } else {
8422 // No match replacing used destination type argument with the null type.
8423 EXPECT(!cache.HasCheck(instance_class_id_or_signature, Object::void_type(),
8424 instance_type_arguments, instantiator_type_arguments,
8425 function_type_arguments,
8426 parent_function_type_arguments,
8427 delayed_type_arguments,
8428 /*index=*/nullptr, /*result=*/nullptr));
8429 }
8430 // Once hash-based, should stay a hash-based cache.
8431 EXPECT(!was_hash || cache.IsHash());
8432}
8433
8434static void SubtypeTestCacheTest(Thread* thread,
8435 intptr_t num_classes,
8436 bool expect_hash) {
8437 TextBuffer buffer(MB);
8438 buffer.AddString("class D {}\n");
8439 buffer.AddString("D createInstanceD() => D();");
8440 buffer.AddString("D Function() createClosureD() => () => D();\n");
8441 for (intptr_t i = 0; i < num_classes; i++) {
8442 buffer.Printf(R"(class C%)" Pd R"( extends D {}
8443)"
8444 R"(C%)" Pd R"( createInstanceC%)" Pd R"(() => C%)" Pd
8445 R"(();
8446)"
8447 R"(C%)" Pd R"( Function() createClosureC%)" Pd
8448 R"(() => () => C%)" Pd
8449 R"(();
8450)",
8451 i, i, i, i, i, i, i);
8452 }
8453
8454 Dart_Handle api_lib = TestCase::LoadTestScript(buffer.buffer(), nullptr);
8455 EXPECT_VALID(api_lib);
8456
8457 // D + C0...CN, where N = kNumClasses - 1
8458 EXPECT(IsolateGroup::Current()->class_table()->NumCids() > num_classes);
8459
8460 TransitionNativeToVM transition(thread);
8461 Zone* const zone = thread->zone();
8462
8463 const auto& root_lib =
8464 Library::CheckedHandle(zone, Api::UnwrapHandle(api_lib));
8465 EXPECT(!root_lib.IsNull());
8466
8467 const auto& class_d = Class::Handle(zone, GetClass(root_lib, "D"));
8468 ASSERT(!class_d.IsNull());
8469 {
8470 SafepointWriteRwLocker ml(thread, thread->isolate_group()->program_lock());
8472 }
8473 const auto& instance_d =
8474 Instance::CheckedHandle(zone, Invoke(root_lib, "createInstanceD"));
8475 auto& type_instance_d_int =
8476 Type::CheckedHandle(zone, instance_d.GetType(Heap::kNew));
8477 const auto& closure_d =
8478 Instance::CheckedHandle(zone, Invoke(root_lib, "createClosureD"));
8479 ASSERT(!closure_d.IsNull());
8480 auto& type_closure_d_int =
8481 FunctionType::CheckedHandle(zone, closure_d.GetType(Heap::kNew));
8482
8483 // Test all the possible input values.
8484 const SubtypeTestCache* stcs[SubtypeTestCache::kMaxInputs];
8485 for (intptr_t i = 0; i < SubtypeTestCache::kMaxInputs; i++) {
8486 stcs[i] = &SubtypeTestCache::Handle(zone, SubtypeTestCache::New(i + 1));
8487 }
8488
8489 auto& class_c = Class::Handle(zone);
8490 auto& instance_c = Instance::Handle(zone);
8491 auto& closure_c = Closure::Handle(zone);
8492 auto& instance_class_id_or_signature = Object::Handle(zone);
8493 // Set up unique tavs for each of the TAV inputs.
8494 auto& instance_type_arguments =
8496 instance_type_arguments.SetTypeAt(0, Type::Handle(zone, Type::SmiType()));
8497 instance_type_arguments = instance_type_arguments.Canonicalize(thread);
8498 auto& instantiator_type_arguments =
8500 instantiator_type_arguments.SetTypeAt(0, Type::Handle(zone, Type::IntType()));
8501 instantiator_type_arguments =
8502 instantiator_type_arguments.Canonicalize(thread);
8503 auto& function_type_arguments =
8505 function_type_arguments.SetTypeAt(0, Type::Handle(zone, Type::Double()));
8506 function_type_arguments = function_type_arguments.Canonicalize(thread);
8507 auto& parent_function_type_arguments =
8509 parent_function_type_arguments.SetTypeAt(
8510 0, Type::Handle(zone, Type::StringType()));
8511 parent_function_type_arguments =
8512 parent_function_type_arguments.Canonicalize(thread);
8513 auto& delayed_type_arguments =
8515 delayed_type_arguments.SetTypeAt(0, Type::Handle(zone, Type::BoolType()));
8516 delayed_type_arguments = delayed_type_arguments.Canonicalize(thread);
8517 auto& got_result = Bool::Handle(zone);
8518 for (intptr_t i = 0; i < num_classes; ++i) {
8519 // Just so we're testing both true and false values, as we're not actually
8520 // using the results to determine subtype/assignability.
8521 const auto& expected_result = (i % 2 == 0) ? Bool::True() : Bool::False();
8522
8523 auto const class_name = OS::SCreate(zone, "C%" Pd "", i);
8524 class_c = GetClass(root_lib, class_name);
8525 ASSERT(!class_c.IsNull());
8526 {
8527 SafepointWriteRwLocker ml(thread,
8528 thread->isolate_group()->program_lock());
8530 }
8531 auto const instance_name = OS::SCreate(zone, "createInstanceC%" Pd "", i);
8532 instance_c ^= Invoke(root_lib, instance_name);
8533 EXPECT(!instance_c.IsClosure());
8534 instance_class_id_or_signature = Smi::New(instance_c.GetClassId());
8535
8536 for (intptr_t i = 0; i < 5; i++) {
8538 thread, *stcs[i], instance_class_id_or_signature, type_instance_d_int,
8539 instance_type_arguments, instantiator_type_arguments,
8540 function_type_arguments, parent_function_type_arguments,
8541 delayed_type_arguments, expected_result, &got_result);
8542 }
8543
8544 auto const function_name = OS::SCreate(zone, "createClosureC%" Pd "", i);
8545 closure_c ^= Invoke(root_lib, function_name);
8546
8547 instance_class_id_or_signature = closure_c.function();
8548 instance_class_id_or_signature =
8549 Function::Cast(instance_class_id_or_signature).signature();
8550
8551 for (intptr_t i = 5; i < SubtypeTestCache::kMaxInputs; i++) {
8553 thread, *stcs[i], instance_class_id_or_signature, type_closure_d_int,
8554 instance_type_arguments, instantiator_type_arguments,
8555 function_type_arguments, parent_function_type_arguments,
8556 delayed_type_arguments, expected_result, &got_result);
8558 }
8559 for (intptr_t i = 0; i < SubtypeTestCache::kMaxInputs; i++) {
8560 SubtypeTestCacheCheckContents(zone, *stcs[i]);
8561 EXPECT_EQ(expect_hash, stcs[i]->IsHash());
8562 }
8563}
8564
8565TEST_CASE(STC_LinearLookup) {
8567 /*expect_hash=*/false);
8568}
8569
8570TEST_CASE(STC_HashLookup) {
8572 /*expect_hash=*/true);
8573}
8574
8575} // namespace dart
AutoreleasePool pool
static BlurTest tests[]
Definition BlurTest.cpp:84
static void check_data(skiatest::Reporter *reporter, SkCachedData *data, int refcnt, CachedState cacheState, LockedState lockedState)
static void done(const char *config, const char *src, const char *srcOptions, const char *name)
Definition DM.cpp:263
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
int count
static const size_t kBufferSize
Definition SkString.cpp:27
SI F table(const skcms_Curve *curve, F v)
#define EXPECT(type, expectedAlignment, expectedSize)
#define __
#define UNREACHABLE()
Definition assert.h:248
#define RELEASE_ASSERT(cond)
Definition assert.h:327
#define Z
static Dart_Handle NewHandle(Thread *thread, ObjectPtr raw)
static ObjectPtr UnwrapHandle(Dart_Handle object)
static ArrayPtr NewBoxed(intptr_t type_args_len, intptr_t num_arguments, const Array &optional_arguments_names, Heap::Space space=Heap::kOld)
Definition dart_entry.h:83
static intptr_t InstanceSize()
Definition object.h:10910
static constexpr intptr_t kMaxElements
Definition object.h:10898
static ArrayPtr New(intptr_t len, Heap::Space space=Heap::kNew)
Definition object.h:10933
virtual bool CanonicalizeEquals(const Instance &other) const
Definition object.cc:24781
void MakeImmutable() const
Definition object.cc:24916
static constexpr bool UseCardMarkingForAllocation(const intptr_t array_length)
Definition object.h:10797
ObjectPtr At(intptr_t index) const
Definition object.h:10854
intptr_t Length() const
Definition object.h:10808
static ArrayPtr MakeFixedLength(const GrowableObjectArray &growable_array, bool unique=false)
Definition object.cc:25014
void SetAt(intptr_t index, const Object &value) const
Definition object.h:10858
static ArrayPtr Grow(const Array &source, intptr_t new_length, Heap::Space space=Heap::kNew)
Definition object.cc:24932
void Add(const T &value)
intptr_t length() const
static const Bool & False()
Definition object.h:10778
static const Bool & True()
Definition object.h:10776
StringPtr target_name() const
Definition object.h:2352
ArrayPtr arguments_descriptor() const
Definition object.h:2353
static constexpr Register kReturnReg
static AbstractTypePtr FinalizeType(const AbstractType &type, FinalizationKind finalization=kCanonicalize)
static bool ProcessPendingClasses()
static void FinalizeTypesInClass(const Class &cls)
static void FinalizeClass(const Class &cls)
void set_is_implemented_unsafe() const
Definition object.cc:5673
FunctionPtr InvocationDispatcherFunctionFromIndex(intptr_t idx) const
Definition object.cc:3469
void Finalize() const
Definition object.cc:4362
void SetFields(const Array &value) const
Definition object.cc:5039
TypePtr super_type() const
Definition object.h:1433
FunctionPtr GetInvocationDispatcher(const String &target_name, const Array &args_desc, UntaggedFunction::Kind kind, bool create_if_absent) const
Definition object.cc:3897
FunctionPtr LookupStaticFunction(const String &name) const
Definition object.cc:6192
intptr_t id() const
Definition object.h:1235
void set_interfaces(const Array &value) const
Definition object.cc:5794
ArrayPtr fields() const
Definition object.h:1617
void set_is_declaration_loaded_unsafe() const
Definition object.cc:5687
intptr_t implementor_cid() const
Definition object.h:1247
intptr_t host_instance_size() const
Definition object.h:1145
StringPtr Name() const
Definition object.cc:3038
ErrorPtr EnsureIsFinalized(Thread *thread) const
Definition object.cc:4979
void set_is_synthesized_class_unsafe() const
Definition object.cc:5706
static ClassPtr New(IsolateGroup *isolate_group, bool register_class=true)
Definition object.cc:3114
TokenPosition end_token_pos() const
Definition object.h:1293
FieldPtr LookupField(const String &name) const
Definition object.cc:6407
void set_library(const Library &value) const
Definition object.cc:3488
bool is_implemented() const
Definition object.h:1694
void SetFunctions(const Array &value) const
Definition object.cc:3314
intptr_t FindInvocationDispatcherFunctionIndex(const Function &needle) const
Definition object.cc:3442
ArrayPtr current_functions() const
Definition object.h:1643
ScriptPtr script() const
Definition object.h:1274
static intptr_t FindClosureIndex(const Function &needle)
static void AddClosureFunctionLocked(const Function &function, bool allow_implicit_closure_functions=false)
static FunctionPtr ClosureFunctionFromIndex(intptr_t idx)
static ClosurePtr New(const TypeArguments &instantiator_type_arguments, const TypeArguments &function_type_arguments, const Function &function, const Object &context, Heap::Space space=Heap::kNew)
Definition object.cc:26021
static void SetInstructions(const Code &code, const Instructions &instructions, uword unchecked_offset)
static CodePtr FinalizeCodeAndNotify(const Function &function, FlowGraphCompiler *compiler, compiler::Assembler *assembler, PoolAttachment pool_attachment, bool optimized=false, CodeStatistics *stats=nullptr)
Definition object.cc:18033
static ErrorPtr EnsureUnoptimizedCode(Thread *thread, const Function &function)
Definition compiler.cc:855
static ObjectPtr CompileOptimizedFunction(Thread *thread, const Function &function, intptr_t osr_id=kNoOSRDeoptId)
Definition compiler.cc:887
static ConstMapPtr NewUninitialized(Heap::Space space=Heap::kNew)
Definition object.cc:25320
static ConstSetPtr NewUninitialized(Heap::Space space=Heap::kNew)
Definition object.cc:25368
static ContextPtr New(intptr_t num_variables, Heap::Space space=Heap::kNew)
Definition object.cc:18561
void set_parent(const Context &parent) const
Definition object.h:7378
void SetAt(intptr_t context_index, const Object &value) const
Definition object.h:13277
ObjectPtr At(intptr_t context_index) const
Definition object.h:7393
intptr_t num_variables() const
Definition object.h:7385
ContextPtr parent() const
Definition object.h:7377
static ObjectPtr InvokeFunction(const Function &function, const Array &arguments)
Definition dart_entry.cc:31
static ThreadPool * thread_pool()
Definition dart.h:73
virtual bool OperatorEquals(const Instance &other) const
Definition object.cc:23457
virtual bool CanonicalizeEquals(const Instance &other) const
Definition object.cc:23467
static DoublePtr New(double d, Heap::Space space=Heap::kNew)
Definition object.cc:23481
double value() const
Definition object.h:10094
static DoublePtr NewCanonical(double d)
Definition object.cc:23497
intptr_t OuterTryIndex(intptr_t try_index) const
Definition object.cc:16248
bool HasCatchAll(intptr_t try_index) const
Definition object.cc:16263
void GetHandlerInfo(intptr_t try_index, ExceptionHandlerInfo *info) const
Definition object.cc:16236
uword HandlerPCOffset(intptr_t try_index) const
Definition object.cc:16243
bool NeedsStackTrace(intptr_t try_index) const
Definition object.cc:16253
void SetHandlerInfo(intptr_t try_index, intptr_t outer_try_index, uword handler_pc_offset, bool needs_stacktrace, bool has_catch_all, bool is_generated) const
Definition object.cc:16215
intptr_t num_entries() const
Definition object.cc:16200
static ExceptionHandlersPtr New(intptr_t num_handlers)
Definition object.cc:16288
static ExternalTypedDataPtr New(intptr_t class_id, uint8_t *data, intptr_t len, Heap::Space space=Heap::kNew, bool perform_eager_msan_initialization_check=true)
Definition object.cc:25705
static StringPtr NameFromSetter(const String &setter_name)
Definition object.cc:11872
static bool IsGetterName(const String &function_name)
Definition object.cc:11882
static bool IsSetterName(const String &function_name)
Definition object.cc:11886
StringPtr name() const
Definition object.h:4408
intptr_t HostOffset() const
Definition object.h:13215
static StringPtr GetterName(const String &field_name)
Definition object.cc:11843
static StringPtr SetterName(const String &field_name)
Definition object.cc:11855
static StringPtr NameFromGetter(const String &getter_name)
Definition object.cc:11867
FinalizerEntryPtr next() const
Definition object.h:12970
static FinalizerEntryPtr New(const FinalizerBase &finalizer, Heap::Space space=Heap::kNew)
Definition object.cc:26941
static FinalizerPtr New(Heap::Space space=Heap::kNew)
Definition object.cc:26861
void set_result_type(const AbstractType &value) const
Definition object.cc:8633
void set_num_fixed_parameters(intptr_t value) const
Definition object.cc:11659
void SetNumOptionalParameters(intptr_t num_optional_parameters, bool are_optional_positional) const
Definition object.cc:11668
static FunctionTypePtr New(intptr_t num_parent_type_arguments=0, Nullability nullability=Nullability::kLegacy, Heap::Space space=Heap::kOld)
Definition object.cc:11682
bool CanBeInlined() const
Definition object.cc:9257
static FunctionPtr New(const FunctionType &signature, const String &name, UntaggedFunction::Kind kind, bool is_static, bool is_const, bool is_abstract, bool is_external, bool is_native, const Object &owner, TokenPosition token_pos, Heap::Space space=Heap::kOld)
Definition object.cc:10301
int32_t SourceFingerprint() const
Definition object.cc:11227
void set_unoptimized_code(const Code &value) const
Definition object.cc:8096
static FunctionPtr NewClosureFunction(const String &name, const Function &parent, TokenPosition token_pos)
Definition object.cc:10406
TypeParameterPtr TypeParameterAt(intptr_t index, Nullability nullability=Nullability::kNonNullable) const
Definition object.cc:8939
void Add(const Object &value, Heap::Space space=Heap::kNew) const
Definition object.cc:25070
static GrowableObjectArrayPtr New(Heap::Space space=Heap::kNew)
Definition object.h:11118
intptr_t Length() const
Definition object.h:11046
ObjectPtr At(intptr_t index) const
Definition object.h:11059
void SetAt(intptr_t index, const Object &value) const
Definition object.h:11065
intptr_t Capacity() const
Definition object.h:11041
bool AllocatedExternal(intptr_t size, Space space)
Definition heap.cc:179
@ kNew
Definition heap.h:38
@ kOld
Definition heap.h:39
intptr_t CapacityInWords(Space space) const
Definition heap.cc:795
void AddReceiverCheck(intptr_t receiver_class_id, const Function &target, intptr_t count=1, StaticTypeExactnessState exactness=StaticTypeExactnessState::NotTracking()) const
Definition object.cc:16936
intptr_t deopt_id() const
Definition object.h:2448
intptr_t NumberOfUsedChecks() const
Definition object.cc:16687
void GetOneClassCheckAt(intptr_t index, intptr_t *class_id, Function *target) const
Definition object.cc:17036
intptr_t NumArgsTested() const
Definition object.cc:16518
static ICDataPtr NewForStaticCall(const Function &owner, const Function &target, const Array &arguments_descriptor, intptr_t deopt_id, intptr_t num_args_tested, RebindRule rebind_rule)
Definition object.cc:17448
void AddCheck(const GrowableArray< intptr_t > &class_ids, const Function &target, intptr_t count=1) const
Definition object.cc:16831
FunctionPtr GetTargetAt(intptr_t index) const
Definition object.cc:17076
void GetCheckAt(intptr_t index, GrowableArray< intptr_t > *class_ids, Function *target) const
Definition object.cc:17002
intptr_t GetCidAt(intptr_t index) const
Definition object.cc:17051
intptr_t NumberOfChecks() const
Definition object.cc:16624
FunctionPtr Owner() const
Definition object.cc:16470
void SetCountAt(intptr_t index, intptr_t value) const
Definition object.cc:17097
ObjectPtr GetField(const Field &field) const
Definition object.cc:20516
bool IsIdenticalTo(const Instance &other) const
Definition object.cc:20902
static intptr_t ElementSizeFor(intptr_t cid)
Definition object.cc:21008
virtual bool OperatorEquals(const Instance &other) const
Definition object.cc:20896
static InstancePtr New(const Class &cls, Heap::Space space=Heap::kNew)
Definition object.cc:20976
static InstructionsPtr FromPayloadStart(uword payload_start)
Definition object.h:5817
uword PayloadStart() const
Definition object.h:5716
static IntegerPtr New(const String &str, Heap::Space space=Heap::kNew)
Definition object.cc:23063
static IntegerPtr NewCanonical(const String &str)
Definition object.cc:23078
virtual bool IsNegative() const
Definition object.cc:23125
virtual bool IsZero() const
Definition object.cc:23119
virtual bool Equals(const Instance &other) const
Definition object.cc:23113
Heap * heap() const
Definition isolate.h:295
ObjectStore * object_store() const
Definition isolate.h:505
static IsolateGroup * Current()
Definition isolate.h:534
static Isolate * Current()
Definition isolate.h:939
MessageHandler * message_handler() const
Definition isolate.cc:2380
void set_finalizers(const GrowableObjectArray &value)
Definition isolate.cc:1965
static LibraryPtr CoreLibrary()
Definition object.cc:14834
void AddObject(const Object &obj, const String &name) const
Definition object.cc:13862
ObjectPtr GetMetadata(const Object &declaration) const
Definition object.cc:13701
void AddClass(const Class &cls) const
Definition object.cc:13961
FunctionPtr LookupFunctionAllowPrivate(const String &name) const
Definition object.cc:14131
static LibraryPtr AsyncLibrary()
Definition object.cc:14826
ClassPtr LookupClass(const String &name) const
Definition object.cc:14152
static LibraryPtr LookupLibrary(Thread *thread, const String &url)
Definition object.cc:14646
FieldPtr LookupFieldAllowPrivate(const String &name) const
Definition object.cc:14122
static const LinkedHashBase & Cast(const Object &obj)
Definition object.h:11984
int context_level() const
Definition scopes.h:333
int NumCapturedVariables() const
Definition scopes.cc:409
int function_level() const
Definition scopes.h:322
static LocalScope * RestoreOuterScope(const ContextScope &context_scope)
Definition scopes.cc:518
VariableIndex AllocateVariables(const Function &function, VariableIndex first_parameter_index, int num_parameters, VariableIndex first_local_index, LocalScope *context_owner, bool *found_captured_variables)
Definition scopes.cc:133
intptr_t num_variables() const
Definition scopes.h:397
LocalVariable * LookupVariable(const String &name, intptr_t kernel_offset, bool test_only)
Definition scopes.cc:350
bool AddVariable(LocalVariable *variable)
Definition scopes.cc:57
ContextScopePtr PreserveOuterScope(const Function &function, intptr_t current_context_level) const
Definition scopes.cc:433
LocalVariable * LocalLookupVariable(const String &name, intptr_t kernel_offset) const
Definition scopes.cc:336
VariableIndex index() const
Definition scopes.h:202
LocalScope * owner() const
Definition scopes.h:122
bool is_captured() const
Definition scopes.h:143
static constexpr intptr_t kNoKernelOffset
Definition scopes.h:77
static MapPtr NewDefault(intptr_t class_id=kMapCid, Heap::Space space=Heap::kNew)
Definition object.cc:25169
intptr_t Length() const
Definition message.cc:191
virtual int CompareWith(const Integer &other) const
Definition object.cc:23427
static constexpr int64_t kMinValue
Definition object.h:10049
int64_t value() const
Definition object.h:10052
ObjectPtr referent() const
Definition object.h:13094
void set_referent(const Object &referent) const
Definition object.h:13096
static MirrorReferencePtr New(const Object &referent, Heap::Space space=Heap::kNew)
Definition object.cc:26995
static NativeFinalizerPtr New(Heap::Space space=Heap::kNew)
Definition object.cc:26877
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
static char * SCreate(Zone *zone, const char *format,...) PRINTF_ATTRIBUTE(2
virtual void VisitObject(ObjectPtr obj)
static ObjectPoolPtr NewFromBuilder(const compiler::ObjectPoolBuilder &builder)
Definition object.cc:15723
intptr_t GetClassIdMayBeSmi() const
@ kScrubbedName
Definition object.h:633
void PrintJSON(JSONStream *stream, bool ref=true) const
static ObjectPtr null()
Definition object.h:433
ObjectPtr ptr() const
Definition object.h:332
virtual const char * ToCString() const
Definition object.h:366
bool IsNull() const
Definition object.h:363
static Object & Handle()
Definition object.h:407
static ObjectPtr RawCast(ObjectPtr obj)
Definition object.h:325
static ClassPtr void_class()
Definition object.h:515
static Object & ZoneHandle()
Definition object.h:419
static ClassPtr dynamic_class()
Definition object.h:514
ClassPtr clazz() const
Definition object.h:13192
static OneByteStringPtr New(intptr_t len, Heap::Space space)
Definition object.cc:24447
static OneByteStringPtr null()
Definition object.h:10603
intptr_t YieldIndex() const
Definition object.h:6133
TokenPosition TokenPos() const
Definition object.h:6129
intptr_t DeoptId() const
Definition object.h:6128
intptr_t TryIndex() const
Definition object.h:6132
UntaggedPcDescriptors::Kind Kind() const
Definition object.h:6134
static PointerPtr New(uword native_address, Heap::Space space=Heap::kNew)
Definition object.cc:25805
uint64_t NextUInt64()
Definition random.h:26
static FunctionPtr ResolveDynamicFunction(Zone *zone, const Class &receiver_class, const String &function_name)
Definition resolver.cc:189
static FunctionPtr ResolveFunction(Zone *zone, const Class &receiver_class, const String &function_name)
Definition resolver.cc:180
static ScriptPtr New(const String &url, const String &source)
Definition object.cc:13498
bool GetTokenLocation(const TokenPosition &token_pos, intptr_t *line, intptr_t *column=nullptr) const
Definition object.cc:13330
static SetPtr NewDefault(intptr_t class_id=kSetCid, Heap::Space space=Heap::kNew)
Definition object.cc:25345
static SmiPtr New(intptr_t value)
Definition object.h:9985
intptr_t Value() const
Definition object.h:9969
virtual bool Equals(const Instance &other) const
Definition object.cc:23330
virtual int64_t AsInt64Value() const
Definition object.cc:23341
virtual int CompareWith(const Integer &other) const
Definition object.cc:23349
static bool IsValid(int64_t value)
Definition object.h:10005
virtual double AsDoubleValue() const
Definition object.cc:23337
static StringPtr FromLatin1(const uint8_t *latin1_array, intptr_t array_len, Heap::Space space=Heap::kNew)
Definition object.cc:23812
static StringPtr NewFormatted(const char *format,...) PRINTF_ATTRIBUTE(1
Definition object.cc:24083
bool IsOneByteString() const
Definition object.h:10290
intptr_t Length() const
Definition object.h:10189
virtual ObjectPtr HashCode() const
Definition object.h:10236
static uword HashConcat(const String &str1, const String &str2)
Definition object.cc:23564
static StringPtr ConcatAll(const Array &strings, Heap::Space space=Heap::kNew)
Definition object.cc:24127
static const char * ScrubName(const String &name, bool is_extension=false)
Definition object.cc:287
bool Equals(const String &str) const
Definition object.h:13311
static StringPtr New(const char *cstr, Heap::Space space=Heap::kNew)
Definition object.cc:23777
intptr_t CompareTo(const String &other) const
Definition object.cc:23717
bool IsTwoByteString() const
Definition object.h:10294
uint16_t CharAt(intptr_t index) const
Definition object.h:10238
static StringPtr SubString(const String &str, intptr_t begin_index, Heap::Space space=Heap::kNew)
Definition object.cc:24159
bool StartsWith(const String &other) const
Definition object.h:10277
static StringPtr EscapeSpecialCharacters(const String &str)
Definition object.cc:23940
static StringPtr Concat(const String &str1, const String &str2, Heap::Space space=Heap::kNew)
Definition object.cc:24116
static StringPtr DecodeIRI(const String &str)
Definition object.cc:24027
bool IsSymbol() const
Definition object.h:10288
static StringPtr FromUTF16(const uint16_t *utf16_array, intptr_t array_len, Heap::Space space=Heap::kNew)
Definition object.cc:23818
uword Hash() const
Definition object.h:10195
bool EqualsLatin1(const uint8_t *characters, intptr_t len) const
Definition object.h:10253
static bool EqualsIgnoringPrivateKey(const String &str1, const String &str2)
Definition object.cc:24378
static const char * EncodeIRI(const String &str)
Definition object.cc:23997
static StringPtr FromUTF32(const int32_t *utf32_array, intptr_t array_len, Heap::Space space=Heap::kNew)
Definition object.cc:23834
static StringPtr FromUTF8(const uint8_t *utf8_array, intptr_t array_len, Heap::Space space=Heap::kNew)
Definition object.cc:23784
static SubtypeTestCachePtr New(intptr_t num_inputs)
Definition object.cc:18974
static constexpr intptr_t kMaxInputs
Definition object.h:7676
@ kInstanceDelayedFunctionTypeArguments
Definition object.h:7665
@ kInstanceParentFunctionTypeArguments
Definition object.h:7664
static constexpr intptr_t kMaxLinearCacheEntries
Definition object.h:7801
static StringPtr FromUTF16(Thread *thread, const uint16_t *utf16_array, intptr_t len)
Definition symbols.cc:229
static StringPtr FromConcatAll(Thread *thread, const GrowableHandlePtrArray< const String > &strs)
Definition symbols.cc:262
static const String & Empty()
Definition symbols.h:687
static StringPtr New(Thread *thread, const char *cstr)
Definition symbols.h:722
static const String & Dot()
Definition symbols.h:612
static Dart_Handle LoadTestScript(const char *script, Dart_NativeEntryResolver resolver, const char *lib_uri=RESOLVED_USER_TEST_URI, bool finalize=true, bool allow_compile_errors=false)
Definition unit_test.cc:422
static Dart_Handle ReloadTestScript(const char *script)
Definition unit_test.cc:599
static const char * url()
Definition unit_test.cc:184
static const char * NullableTag()
Definition unit_test.h:421
bool Run(Args &&... args)
Definition thread_pool.h:45
Zone * zone() const
static Thread * Current()
Definition thread.h:361
Isolate * isolate() const
Definition thread.h:533
IsolateGroup * isolate_group() const
Definition thread.h:540
intptr_t Pos() const
static TokenPosition Deserialize(int32_t value)
static const TokenPosition kMinSource
static TwoByteStringPtr New(intptr_t len, Heap::Space space)
Definition object.cc:24641
static SmiPtr Sentinel()
Definition object.cc:7231
static constexpr intptr_t kMaxLinearCacheEntries
Definition object.h:8907
bool Equals(const TypeArguments &other) const
Definition object.h:8660
void SetTypeAt(intptr_t index, const AbstractType &value) const
Definition object.cc:7381
TypeArgumentsPtr Canonicalize(Thread *thread) const
Definition object.cc:7761
static TypeArgumentsPtr New(intptr_t len, Heap::Space space=Heap::kOld)
Definition object.cc:7733
static TypePtr VoidType()
Definition object.cc:21870
static TypePtr SmiType()
Definition object.cc:21894
static TypePtr BoolType()
Definition object.cc:21882
static TypePtr New(const Class &clazz, const TypeArguments &arguments, Nullability nullability=Nullability::kLegacy, Heap::Space space=Heap::kOld)
Definition object.cc:22492
static TypePtr Double()
Definition object.cc:21902
static TypePtr DynamicType()
Definition object.cc:21866
static TypePtr StringType()
Definition object.cc:21930
static TypePtr IntType()
Definition object.cc:21886
static TypePtr NewNonParameterizedType(const Class &type_class)
Definition object.cc:21946
intptr_t Length() const
Definition object.h:11492
static TypedDataPtr Grow(const TypedData &current, intptr_t len, Heap::Space space=Heap::kNew)
Definition object.cc:25680
static intptr_t MaxElements(intptr_t class_id)
Definition object.h:11658
static TypedDataPtr New(intptr_t class_id, intptr_t len, Heap::Space space=Heap::kNew)
Definition object.cc:25666
static intptr_t InstanceSize()
Definition object.h:11647
static ObjectPtr FromAddr(uword addr)
Definition raw_object.h:495
static uword ToAddr(const UntaggedObject *raw_obj)
Definition raw_object.h:501
static int SNPrint(char *str, size_t size, const char *format,...) PRINTF_ATTRIBUTE(3
std::unique_ptr< char, decltype(std::free) * > CStringUniquePtr
Definition utils.h:644
static constexpr T RoundUp(T x, uintptr_t alignment, uintptr_t offset=0)
Definition utils.h:105
int value() const
Definition scopes.h:69
void SetAt(intptr_t index, const Object &value) const
Definition object.h:6696
intptr_t Length() const
Definition object.h:6670
ObjectPtr At(intptr_t index) const
Definition object.h:6695
static WeakArrayPtr New(intptr_t length, Heap::Space space=Heap::kNew)
Definition object.cc:17583
ObjectPtr value() const
Definition object.h:12898
static WeakPropertyPtr New(Heap::Space space=Heap::kNew)
Definition object.cc:26835
void set_key(const Object &key) const
Definition object.h:12895
ObjectPtr key() const
Definition object.h:12894
void set_value(const Object &value) const
Definition object.h:12899
static WeakReferencePtr New(Heap::Space space=Heap::kNew)
Definition object.cc:26845
static void SetNativeResolver(BuiltinLibraryId id)
Definition builtin.cc:28
static void SetNativeResolver()
#define THR_Print(format,...)
Definition log.h:20
struct _Dart_Handle * Dart_Handle
Definition dart_api.h:258
struct _Dart_Isolate * Dart_Isolate
Definition dart_api.h:88
struct _Dart_NativeArguments * Dart_NativeArguments
Definition dart_api.h:3010
void(* Dart_NativeFunction)(Dart_NativeArguments arguments)
Definition dart_api.h:3198
#define FAIL(name, result)
#define ASSERT(E)
VkInstance instance
Definition main.cc:48
SkBitmap source
Definition examples.cpp:28
static bool b
struct MyStruct a[10]
EMSCRIPTEN_KEEPALIVE void empty()
#define FATAL(error)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
static const char * expected_value
static const uint8_t buffer[]
const uint8_t uint32_t uint32_t GError ** error
uint8_t value
GAsyncResult * result
uint32_t * target
#define DECLARE_FLAG(type, name)
Definition flags.h:14
Dart_NativeFunction function
Definition fuchsia.cc:51
int argument_count
Definition fuchsia.cc:52
#define HANDLESCOPE(thread)
Definition handles.h:321
size_t length
constexpr int64_t kMaxInt64
Definition globals.h:486
const int kNumTypedDataCidRemainders
Definition class_id.h:265
static bool Equals(const Object &expected, const Object &actual)
static const ClassId kLastTypedDataCid
Definition class_id.h:378
static CodePtr CreateInvokeInstantiateTypeArgumentsStub(Thread *thread)
constexpr intptr_t MB
Definition globals.h:530
static void GenerateInvokeInstantiateTAVStub(compiler::Assembler *assembler)
bool IsTypedDataClassId(intptr_t index)
Definition class_id.h:433
void ElideJSONSubstring(const char *prefix, const char *in, char *out, const char *postfix)
Definition unit_test.cc:776
static MapPtr ConstructImmutableMap(const Array &input_data, intptr_t used_data, const TypeArguments &type_arguments)
static void WeakReference_Preserve_ReachableThroughWeakProperty(Thread *thread, Heap::Space space)
static void Finalizer_GcFinalizer(Thread *thread, Heap::Space space)
static void SubtypeTestCacheEntryTest(Thread *thread, const SubtypeTestCache &cache, const Object &instance_class_id_or_signature, const AbstractType &destination_type, const TypeArguments &instance_type_arguments, const TypeArguments &instantiator_type_arguments, const TypeArguments &function_type_arguments, const TypeArguments &parent_function_type_arguments, const TypeArguments &delayed_type_arguments, const Bool &expected_result, Bool *got_result)
void SetBreakpoint(Dart_NativeArguments args)
DART_EXPORT void Dart_EnterScope()
static void CheckSubtypeRelation(const Expect &expect, const AbstractType &sub, const AbstractType &super, bool is_subtype)
const char *const name
static void ExpectTypesEquivalent(const Expect &expect, const AbstractType &expected, const AbstractType &got, TypeEquality kind)
bool IsConcreteTypeClassId(intptr_t index)
Definition class_id.h:325
const intptr_t kFinalizerTwoEntriesNumObjects
DART_EXPORT void Dart_EnterIsolate(Dart_Isolate isolate)
static void Finalizer_ClearDetachOne(Thread *thread, Heap::Space space)
DART_EXPORT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
static void HashMapNonConstEqualsConst(const char *script, bool check_data=true)
Nullability
Definition object.h:1112
static Dart_WeakPersistentHandle weak1
static void TestIllegalTypedDataLength(const char *class_name, intptr_t length)
static void Finalizer_ClearValueOne(Thread *thread, Heap::Space space, bool null_token)
static void Finalizer_PreserveOne(Thread *thread, Heap::Space space, bool with_detach)
static FieldPtr GetField(const Class &cls, const char *name)
static void FinalizeAndCanonicalize(AbstractType *type)
static void PrintMetadata(const char *name, const Object &data)
const char *const class_name
Dart_Handle Dart_RemoveBreakpoint(Dart_Handle breakpoint_id_in)
DART_EXPORT Dart_Handle Dart_NewInteger(int64_t value)
int32_t classid_t
Definition globals.h:524
static void Finalizer_TwoEntriesCrossGen(Thread *thread, Heap::Space *spaces, bool collect_old_space, bool collect_new_space, bool evacuate_new_space_and_collect_old_space, bool clear_value_1, bool clear_value_2, bool clear_detach_1, bool clear_detach_2)
constexpr uint64_t kMaxUint64
Definition globals.h:487
@ kIllegalCid
Definition class_id.h:214
@ kNullCid
Definition class_id.h:252
@ kDynamicCid
Definition class_id.h:253
ObjectPtr Invoke(const Library &lib, const char *name)
constexpr intptr_t kWordSizeLog2
Definition globals.h:507
FunctionPtr GetFunction(const Library &lib, const char *name)
static bool HashCodeEqualsCanonicalizeHash(const char *value_script, uint32_t hashcode_canonicalize_vm=kCalculateCanonicalizeHash, bool check_identity=true, bool check_hashcode=true)
static FunctionPtr GetDummyTarget(const char *name)
static void CheckConcatAll(const String *data[], intptr_t n)
bool EqualsIgnoringPrivate(const String &name, const String &private_name)
uintptr_t uword
Definition globals.h:501
intptr_t word
Definition globals.h:500
DART_EXPORT Dart_Isolate Dart_CurrentIsolate()
static void TypeArgumentsHashCacheTest(Thread *thread, intptr_t num_classes)
TypeEquality
Definition object.h:1120
DART_EXPORT bool Dart_IsError(Dart_Handle handle)
static void SubtypeTestCacheTest(Thread *thread, intptr_t num_classes, bool expect_hash)
static void SubtypeTestCacheCheckContents(Zone *zone, const SubtypeTestCache &cache)
AsThreadStackResource< RawReloadParticipationScope > ReloadParticipationScope
Definition thread.h:1612
static ClassPtr CreateDummyClass(const String &class_name, const Script &script)
static const ClassId kFirstTypedDataCid
Definition class_id.h:377
static constexpr int kCallerSpSlotFromFp
DART_EXPORT Dart_Isolate Dart_CreateIsolateInGroup(Dart_Isolate group_member, const char *name, Dart_IsolateShutdownCallback shutdown_callback, Dart_IsolateCleanupCallback cleanup_callback, void *child_isolate_data, char **error)
DART_EXPORT bool Dart_RunLoopAsync(bool errors_are_fatal, Dart_Port on_error_port, Dart_Port on_exit_port, char **error)
static void HashSetNonConstEqualsConst(const char *script, bool check_data=true)
@ kCurrentAndEnclosingFree
Definition object.h:2917
@ kAllFree
Definition object.h:2920
DART_EXPORT Dart_Handle Dart_SetNativeResolver(Dart_Handle library, Dart_NativeEntryResolver resolver, Dart_NativeEntrySymbol symbol)
DART_EXPORT void Dart_ExitIsolate()
const Register FPREG
ClassPtr GetClass(const Library &lib, const char *name)
const intptr_t cid
const uint32_t kCalculateCanonicalizeHash
static void WeakReference_PreserveOne(Thread *thread, Heap::Space space)
static constexpr intptr_t kCompressedWordSize
Definition globals.h:42
Dart_Handle NewString(const char *str)
static void WeakReference_ClearOne(Thread *thread, Heap::Space space)
static void NativeFinalizer_TwoEntriesCrossGen(Thread *thread, Heap::Space *spaces, bool collect_new_space, bool evacuate_new_space_and_collect_old_space, bool clear_value_1, bool clear_value_2, bool clear_detach_1, bool clear_detach_2)
static bool IsLinkedHashBase(const Object &object)
static uint32_t Hash(uint32_t key)
bool TESTING_runtime_fail_on_existing_cache_entry
Definition object.cc:7675
DART_EXPORT void Dart_ExitScope()
constexpr int32_t kMaxInt32
Definition globals.h:483
static LibraryPtr CreateDummyLibrary(const String &library_name)
DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t *len)
static FieldPtr CreateTestField(const char *name)
constexpr intptr_t kWordSize
Definition globals.h:509
static SetPtr ConstructImmutableSet(const Array &input_data, intptr_t used_data, const TypeArguments &type_arguments)
static constexpr intptr_t kObjectAlignment
static FunctionPtr CreateFunction(const char *name)
static ClassPtr CreateTestClass(const char *name)
static void HashBaseNonConstEqualsConst(const char *script, bool check_data=true)
static void Finalizer_DetachOne(Thread *thread, Heap::Space space, bool clear_value)
const char *const function_name
static int8_t data[kExtLength]
DART_EXPORT Dart_Handle Dart_StringToCString(Dart_Handle object, const char **cstr)
static void TestIllegalArrayLength(intptr_t length)
static FunctionPtr GetStaticFunction(const Class &cls, const char *name)
Dart_Handle Dart_SetBreakpoint(Dart_Handle script_url_in, intptr_t line_number)
const intptr_t kSmiMin
Definition globals.h:29
void StripTokenPositions(char *buffer)
Definition unit_test.cc:799
static void Finalizer_TwoEntries(Thread *thread, Heap::Space space, bool clear_value_1, bool clear_value_2, bool clear_detach_1, bool clear_detach_2)
static bool LinkedHashBaseEqual(const LinkedHashBase &map1, const LinkedHashBase &map2, bool print_diff, bool check_data=true)
static int NumEntries(const FinalizerEntry &entry, intptr_t acc=0)
void NativeFinalizer_TwoEntriesCrossGen_Finalizer(void *peer)
static Dart_WeakPersistentHandle weak2
static Dart_NativeFunction SetBreakpointResolver(Dart_Handle name, int argument_count, bool *auto_setup_scope)
static void WeakReference_Clear_ReachableThroughWeakProperty(Thread *thread, Heap::Space space)
static TypePtr CreateFutureOrType(const AbstractType &param, Nullability nullability)
static TypePtr CreateFutureType(const AbstractType &param, Nullability nullability)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace Enable an endless trace buffer The default is a ring buffer This is useful when very old events need to viewed For during application launch Memory usage will continue to grow indefinitely however Start app with an specific route defined on the framework flutter assets Path to the Flutter assets directory enable service port Allow the VM service to fallback to automatic port selection if binding to a specified port fails trace Trace early application lifecycle Automatically switches to an endless trace buffer trace skia Filters out all Skia trace event categories except those that are specified in this comma separated list dump skp on shader Automatically dump the skp that triggers new shader compilations This is useful for writing custom ShaderWarmUp to reduce jank By this is not enabled to reduce the overhead purge persistent cache
Definition switches.h:191
SI auto map(std::index_sequence< I... >, Fn &&fn, const Args &... args) -> skvx::Vec< sizeof...(I), decltype(fn(args[0]...))>
Definition SkVx.h:680
#define EXPECT_SUBTYPE(sub, super)
#define USED_INPUT_CASE(Input, ExpectedCids)
#define EXPECT_TYPES_EQUAL(expected, got)
#define FINALIZER_CROSS_GEN_TEST_CASE(n)
#define EXPECT_NOT_SUBTYPE(sub, super)
#define EXPECT_TYPES_SYNTACTICALLY_EQUIVALENT(expected, got)
#define REPEAT_512(V)
#define FINALIZER_NATIVE_CROSS_GEN_TEST_CASE(n)
#define Px32
Definition globals.h:414
#define FALL_THROUGH
Definition globals.h:15
#define Px
Definition globals.h:410
#define DART_2PART_UINT64_C(a, b)
Definition globals.h:472
#define DEBUG_ONLY(code)
Definition globals.h:141
#define Pd64
Definition globals.h:416
#define Px64
Definition globals.h:418
#define Pd
Definition globals.h:408
#define DART_INT64_C(x)
Definition globals.h:433
#define Pd32
Definition globals.h:412
static constexpr Register kInstantiatorTypeArgumentsReg
static constexpr Register kUninstantiatedTypeArgumentsReg
static constexpr Register kResultTypeArgumentsReg
static constexpr Register kFunctionTypeArgumentsReg
const char * out
const char * in
#define EXPECT_ERROR(handle, substring)
Definition unit_test.h:670
#define EXPECT_NULL(handle)
Definition unit_test.h:701
#define EXPECT_TRUE(handle)
Definition unit_test.h:685
#define ISOLATE_UNIT_TEST_CASE(name)
Definition unit_test.h:64
#define ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION(name, expectation)
Definition unit_test.h:51
#define TEST_CASE(name)
Definition unit_test.h:85
#define EXPECT_VALID(handle)
Definition unit_test.h:650
#define ARRAY_SIZE(array)
Definition globals.h:72