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
7#include "include/dart_api.h"
8
9#include "bin/builtin.h"
10#include "bin/vmservice_impl.h"
11
12#include "platform/globals.h"
13
14#include "vm/class_finalizer.h"
15#include "vm/code_descriptors.h"
16#include "vm/compiler/assembler/assembler.h"
17#include "vm/compiler/compiler_state.h"
18#include "vm/dart_api_impl.h"
19#include "vm/dart_entry.h"
20#include "vm/debugger.h"
21#include "vm/debugger_api_impl_test.h"
22#include "vm/isolate.h"
23#include "vm/malloc_hooks.h"
24#include "vm/object.h"
25#include "vm/object_store.h"
26#include "vm/simulator.h"
27#include "vm/symbols.h"
28#include "vm/unit_test.h"
29
30namespace dart {
31
32DECLARE_FLAG(bool, dual_map_code);
33DECLARE_FLAG(bool, write_protect_code);
34
35static ClassPtr CreateDummyClass(const String& class_name,
36 const Script& script) {
37 const Class& cls = Class::Handle(Class::New(
38 Library::Handle(), class_name, script, TokenPosition::kNoSource));
39 cls.set_is_synthesized_class(); // Dummy class for testing.
40 cls.set_is_declaration_loaded();
41 return cls.raw();
42}
43
44ISOLATE_UNIT_TEST_CASE(Class) {
45 // Allocate the class first.
46 const String& class_name = String::Handle(Symbols::New(thread, "MyClass"));
47 const Script& script = Script::Handle();
48 const Class& cls = Class::Handle(CreateDummyClass(class_name, script));
49
50 // Class has no fields and no functions yet.
51 EXPECT_EQ(Array::Handle(cls.fields()).Length(), 0);
52 EXPECT_EQ(Array::Handle(cls.functions()).Length(), 0);
53
54 // Setup the interfaces in the class.
55 // Normally the class finalizer is resolving super types and interfaces
56 // before finalizing the types in a class. A side-effect of this is setting
57 // the is_implemented() bit on a class. We do that manually here.
58 const Array& interfaces = Array::Handle(Array::New(2));
59 Class& interface = Class::Handle();
60 String& interface_name = String::Handle();
61 interface_name = Symbols::New(thread, "Harley");
62 interface = CreateDummyClass(interface_name, script);
63 interfaces.SetAt(0, Type::Handle(Type::NewNonParameterizedType(interface)));
64 interface.set_is_implemented();
65 interface_name = Symbols::New(thread, "Norton");
66 interface = CreateDummyClass(interface_name, script);
67 interfaces.SetAt(1, Type::Handle(Type::NewNonParameterizedType(interface)));
68 interface.set_is_implemented();
69 cls.set_interfaces(interfaces);
70
71 // Finalization of types happens before the fields and functions have been
72 // parsed.
73 ClassFinalizer::FinalizeTypesInClass(cls);
74
75 // Create and populate the function arrays.
76 const Array& functions = Array::Handle(Array::New(6));
77 Function& function = Function::Handle();
78 String& function_name = String::Handle();
79 function_name = Symbols::New(thread, "foo");
80 function =
81 Function::New(function_name, FunctionLayout::kRegularFunction, false,
82 false, false, false, false, cls, TokenPosition::kMinSource);
83 functions.SetAt(0, function);
84 function_name = Symbols::New(thread, "bar");
85 function =
86 Function::New(function_name, FunctionLayout::kRegularFunction, false,
87 false, false, false, false, cls, TokenPosition::kMinSource);
88
89 const int kNumFixedParameters = 2;
90 const int kNumOptionalParameters = 3;
91 const bool kAreOptionalPositional = true;
92 function.set_num_fixed_parameters(kNumFixedParameters);
93 function.SetNumOptionalParameters(kNumOptionalParameters,
94 kAreOptionalPositional);
95 functions.SetAt(1, function);
96
97 function_name = Symbols::New(thread, "baz");
98 function =
99 Function::New(function_name, FunctionLayout::kRegularFunction, false,
100 false, false, false, false, cls, TokenPosition::kMinSource);
101 functions.SetAt(2, function);
102
103 function_name = Symbols::New(thread, "Foo");
104 function =
105 Function::New(function_name, FunctionLayout::kRegularFunction, true,
106 false, false, false, false, cls, TokenPosition::kMinSource);
107
108 functions.SetAt(3, function);
109 function_name = Symbols::New(thread, "Bar");
110 function =
111 Function::New(function_name, FunctionLayout::kRegularFunction, true,
112 false, false, false, false, cls, TokenPosition::kMinSource);
113 functions.SetAt(4, function);
114 function_name = Symbols::New(thread, "BaZ");
115 function =
116 Function::New(function_name, FunctionLayout::kRegularFunction, true,
117 false, false, false, false, cls, TokenPosition::kMinSource);
118 functions.SetAt(5, function);
119
120 // Setup the functions in the class.
121 cls.SetFunctions(functions);
122
123 // The class can now be finalized.
124 cls.Finalize();
125
126 function_name = String::New("Foo");
127 function = cls.LookupDynamicFunction(function_name);
128 EXPECT(function.IsNull());
129 function = cls.LookupStaticFunction(function_name);
130 EXPECT(!function.IsNull());
131 EXPECT(function_name.Equals(String::Handle(function.name())));
132 EXPECT_EQ(cls.raw(), function.Owner());
133 EXPECT(function.is_static());
134 function_name = String::New("baz");
135 function = cls.LookupDynamicFunction(function_name);
136 EXPECT(!function.IsNull());
137 EXPECT(function_name.Equals(String::Handle(function.name())));
138 EXPECT_EQ(cls.raw(), function.Owner());
139 EXPECT(!function.is_static());
140 function = cls.LookupStaticFunction(function_name);
141 EXPECT(function.IsNull());
142
143 function_name = String::New("foo");
144 function = cls.LookupDynamicFunction(function_name);
145 EXPECT(!function.IsNull());
146 EXPECT_EQ(0, function.num_fixed_parameters());
147 EXPECT(!function.HasOptionalParameters());
148
149 function_name = String::New("bar");
150 function = cls.LookupDynamicFunction(function_name);
151 EXPECT(!function.IsNull());
152 EXPECT_EQ(kNumFixedParameters, function.num_fixed_parameters());
153 EXPECT_EQ(kNumOptionalParameters, function.NumOptionalParameters());
154}
155
156ISOLATE_UNIT_TEST_CASE(SixtyThousandDartClasses) {
157 auto zone = thread->zone();
158 auto isolate = thread->isolate();
159 auto class_table = isolate->class_table();
160
161 const intptr_t start_cid = class_table->NumCids();
162 const intptr_t num_classes = std::numeric_limits<uint16_t>::max() - start_cid;
163
164 const Script& script = Script::Handle(zone);
165 String& name = String::Handle(zone);
166 Class& cls = Class::Handle(zone);
167 Field& field = Field::Handle(zone);
168 Array& fields = Array::Handle(zone);
169 Instance& instance = Instance::Handle(zone);
170 Instance& instance2 = Instance::Handle(zone);
171
172 const auto& instances =
173 GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
174
175 // Create many top-level classes - they should not consume 16-bit range.
176 for (intptr_t i = 0; i < (1 << 16); ++i) {
177 cls = CreateDummyClass(Symbols::TopLevel(), script);
178 cls.Finalize();
179 EXPECT(cls.id() > std::numeric_limits<uint16_t>::max());
180 }
181
182 // Create many concrete classes - they should occupy the entire 16-bit space.
183 for (intptr_t i = 0; i < num_classes; ++i) {
184 name = Symbols::New(thread, OS::SCreate(zone, "MyClass%" Pd "", i));
185 cls = CreateDummyClass(name, script);
186 EXPECT_EQ(start_cid + i, cls.id());
187
188 const intptr_t num_fields = (i % 10);
189 fields = Array::New(num_fields);
190 for (intptr_t f = 0; f < num_fields; ++f) {
191 name =
192 Symbols::New(thread, OS::SCreate(zone, "myField_%" Pd "_%" Pd, i, f));
193 field = Field::New(name, false, false, false, true, false, cls,
194 Object::dynamic_type(), TokenPosition::kMinSource,
195 TokenPosition::kMinSource);
196 fields.SetAt(f, field);
197 }
198
199 cls.set_interfaces(Array::empty_array());
200 cls.SetFunctions(Array::empty_array());
201 cls.SetFields(fields);
202 cls.Finalize();
203
204 instance = Instance::New(cls);
205 for (intptr_t f = 0; f < num_fields; ++f) {
206 field ^= fields.At(f);
207 name = Symbols::New(thread,
208 OS::SCreate(zone, "myFieldValue_%" Pd "_%" Pd, i, f));
209 instance.SetField(field, name);
210 }
211 instances.Add(instance);
212 }
213 EXPECT_EQ((1 << 16) - 1, class_table->NumCids());
214
215 // Ensure GC runs and can recognize all those new instances.
216 isolate->heap()->CollectAllGarbage();
217
218 // Ensure the instances are what we expect.
219 for (intptr_t i = 0; i < num_classes; ++i) {
220 instance ^= instances.At(i);
221 cls = instance.clazz();
222 fields = cls.fields();
223
224 name = cls.Name();
225 EXPECT(strstr(name.ToCString(), OS::SCreate(zone, "MyClass%" Pd "", i)) !=
226 0);
227 EXPECT_EQ((i % 10), fields.Length());
228
229 for (intptr_t f = 0; f < fields.Length(); ++f) {
230 field ^= fields.At(f);
231 instance2 ^= instance.GetField(field);
232 EXPECT(strstr(instance2.ToCString(),
233 OS::SCreate(zone, "myFieldValue_%" Pd "_%" Pd, i, f)) != 0);
234 }
235 }
236}
237
238ISOLATE_UNIT_TEST_CASE(TypeArguments) {
239 const Type& type1 = Type::Handle(Type::Double());
240 const Type& type2 = Type::Handle(Type::StringType());
241 const TypeArguments& type_arguments1 =
242 TypeArguments::Handle(TypeArguments::New(2));
243 type_arguments1.SetTypeAt(0, type1);
244 type_arguments1.SetTypeAt(1, type2);
245 const TypeArguments& type_arguments2 =
246 TypeArguments::Handle(TypeArguments::New(2));
247 type_arguments2.SetTypeAt(0, type1);
248 type_arguments2.SetTypeAt(1, type2);
249 EXPECT_NE(type_arguments1.raw(), type_arguments2.raw());
250 OS::PrintErr("1: %s\n", type_arguments1.ToCString());
251 OS::PrintErr("2: %s\n", type_arguments2.ToCString());
252 EXPECT(type_arguments1.Equals(type_arguments2));
253 TypeArguments& type_arguments3 = TypeArguments::Handle();
254 type_arguments1.Canonicalize();
255 type_arguments3 ^= type_arguments2.Canonicalize();
256 EXPECT_EQ(type_arguments1.raw(), type_arguments3.raw());
257}
258
259TEST_CASE(Class_EndTokenPos) {
260 const char* kScript =
261 "\n"
262 "class A {\n"
263 " /**\n"
264 " * Description of foo().\n"
265 " */\n"
266 " foo(a) { return '''\"}'''; }\n"
267 " // }\n"
268 " var bar = '\\'}';\n"
269 "}\n";
270 Dart_Handle lib_h = TestCase::LoadTestScript(kScript, NULL);
271 EXPECT_VALID(lib_h);
272 TransitionNativeToVM transition(thread);
273 Library& lib = Library::Handle();
274 lib ^= Api::UnwrapHandle(lib_h);
275 EXPECT(!lib.IsNull());
276 const Class& cls =
277 Class::Handle(lib.LookupClass(String::Handle(String::New("A"))));
278 EXPECT(!cls.IsNull());
279 const Error& error = Error::Handle(cls.EnsureIsFinalized(thread));
280 EXPECT(error.IsNull());
281 const TokenPosition end_token_pos = cls.end_token_pos();
282 const Script& scr = Script::Handle(cls.script());
283 intptr_t line;
284 intptr_t col;
285 scr.GetTokenLocation(end_token_pos, &line, &col);
286 EXPECT_EQ(9, line);
287 EXPECT_EQ(1, col);
288}
289
290ISOLATE_UNIT_TEST_CASE(InstanceClass) {
291 // Allocate the class first.
292 String& class_name = String::Handle(Symbols::New(thread, "EmptyClass"));
293 Script& script = Script::Handle();
294 const Class& empty_class =
295 Class::Handle(CreateDummyClass(class_name, script));
296
297 // EmptyClass has no fields and no functions.
298 EXPECT_EQ(Array::Handle(empty_class.fields()).Length(), 0);
299 EXPECT_EQ(Array::Handle(empty_class.functions()).Length(), 0);
300
301 ClassFinalizer::FinalizeTypesInClass(empty_class);
302 empty_class.Finalize();
303
304 EXPECT_EQ(kObjectAlignment, empty_class.host_instance_size());
305 Instance& instance = Instance::Handle(Instance::New(empty_class));
306 EXPECT_EQ(empty_class.raw(), instance.clazz());
307
308 class_name = Symbols::New(thread, "OneFieldClass");
309 const Class& one_field_class =
310 Class::Handle(CreateDummyClass(class_name, script));
311
312 // No fields, functions, or super type for the OneFieldClass.
313 EXPECT_EQ(Array::Handle(empty_class.fields()).Length(), 0);
314 EXPECT_EQ(Array::Handle(empty_class.functions()).Length(), 0);
315 EXPECT_EQ(empty_class.super_type(), AbstractType::null());
316 ClassFinalizer::FinalizeTypesInClass(one_field_class);
317
318 const Array& one_fields = Array::Handle(Array::New(1));
319 const String& field_name = String::Handle(Symbols::New(thread, "the_field"));
320 const Field& field = Field::Handle(
321 Field::New(field_name, false, false, false, true, false, one_field_class,
322 Object::dynamic_type(), TokenPosition::kMinSource,
323 TokenPosition::kMinSource));
324 one_fields.SetAt(0, field);
325 one_field_class.SetFields(one_fields);
326 one_field_class.Finalize();
327 intptr_t header_size = sizeof(ObjectLayout);
328 EXPECT_EQ(Utils::RoundUp((header_size + (1 * kWordSize)), kObjectAlignment),
329 one_field_class.host_instance_size());
330 EXPECT_EQ(header_size, field.HostOffset());
331 EXPECT(!one_field_class.is_implemented());
332 one_field_class.set_is_implemented();
333 EXPECT(one_field_class.is_implemented());
334}
335
336ISOLATE_UNIT_TEST_CASE(Smi) {
337 const Smi& smi = Smi::Handle(Smi::New(5));
338 Object& smi_object = Object::Handle(smi.raw());
339 EXPECT(smi.IsSmi());
340 EXPECT(smi_object.IsSmi());
341 EXPECT_EQ(5, smi.Value());
342 const Object& object = Object::Handle();
343 EXPECT(!object.IsSmi());
344 smi_object = Object::null();
345 EXPECT(!smi_object.IsSmi());
346
347 EXPECT(smi.Equals(Smi::Handle(Smi::New(5))));
348 EXPECT(!smi.Equals(Smi::Handle(Smi::New(6))));
349 EXPECT(smi.Equals(smi));
350 EXPECT(!smi.Equals(Smi::Handle()));
351
352 EXPECT(Smi::IsValid(0));
353 EXPECT(Smi::IsValid(-15));
354 EXPECT(Smi::IsValid(0xFFu));
355// Upper two bits must be either 00 or 11.
356#if defined(ARCH_IS_64_BIT)
357 EXPECT(!Smi::IsValid(kMaxInt64));
358 EXPECT(Smi::IsValid(0x3FFFFFFFFFFFFFFF));
359 EXPECT(Smi::IsValid(-1));
360#else
361 EXPECT(!Smi::IsValid(kMaxInt32));
362 EXPECT(Smi::IsValid(0x3FFFFFFF));
363 EXPECT(Smi::IsValid(-1));
364 EXPECT(!Smi::IsValid(0xFFFFFFFFu));
365#endif
366
367 EXPECT_EQ(5, smi.AsInt64Value());
368 EXPECT_EQ(5.0, smi.AsDoubleValue());
369
370 Smi& a = Smi::Handle(Smi::New(5));
371 Smi& b = Smi::Handle(Smi::New(3));
372 EXPECT_EQ(1, a.CompareWith(b));
373 EXPECT_EQ(-1, b.CompareWith(a));
374 EXPECT_EQ(0, a.CompareWith(a));
375
376 Smi& c = Smi::Handle(Smi::New(-1));
377
378 Mint& mint1 = Mint::Handle();
379 mint1 ^= Integer::New(DART_2PART_UINT64_C(0x7FFFFFFF, 100));
380 Mint& mint2 = Mint::Handle();
381 mint2 ^= Integer::New(-DART_2PART_UINT64_C(0x7FFFFFFF, 100));
382 EXPECT_EQ(-1, a.CompareWith(mint1));
383 EXPECT_EQ(1, a.CompareWith(mint2));
384 EXPECT_EQ(-1, c.CompareWith(mint1));
385 EXPECT_EQ(1, c.CompareWith(mint2));
386}
387
388ISOLATE_UNIT_TEST_CASE(StringCompareTo) {
389 const String& abcd = String::Handle(String::New("abcd"));
390 const String& abce = String::Handle(String::New("abce"));
391 EXPECT_EQ(0, abcd.CompareTo(abcd));
392 EXPECT_EQ(0, abce.CompareTo(abce));
393 EXPECT(abcd.CompareTo(abce) < 0);
394 EXPECT(abce.CompareTo(abcd) > 0);
395
396 const int kMonkeyLen = 4;
397 const uint8_t monkey_utf8[kMonkeyLen] = {0xf0, 0x9f, 0x90, 0xb5};
398 const String& monkey_face =
399 String::Handle(String::FromUTF8(monkey_utf8, kMonkeyLen));
400 const int kDogLen = 4;
401 // 0x1f436 DOG FACE.
402 const uint8_t dog_utf8[kDogLen] = {0xf0, 0x9f, 0x90, 0xb6};
403 const String& dog_face = String::Handle(String::FromUTF8(dog_utf8, kDogLen));
404 EXPECT_EQ(0, monkey_face.CompareTo(monkey_face));
405 EXPECT_EQ(0, dog_face.CompareTo(dog_face));
406 EXPECT(monkey_face.CompareTo(dog_face) < 0);
407 EXPECT(dog_face.CompareTo(monkey_face) > 0);
408
409 const int kDominoLen = 4;
410 // 0x1f036 DOMINO TILE HORIZONTAL-00-05.
411 const uint8_t domino_utf8[kDominoLen] = {0xf0, 0x9f, 0x80, 0xb6};
412 const String& domino =
413 String::Handle(String::FromUTF8(domino_utf8, kDominoLen));
414 EXPECT_EQ(0, domino.CompareTo(domino));
415 EXPECT(domino.CompareTo(dog_face) < 0);
416 EXPECT(domino.CompareTo(monkey_face) < 0);
417 EXPECT(dog_face.CompareTo(domino) > 0);
418 EXPECT(monkey_face.CompareTo(domino) > 0);
419
420 EXPECT(abcd.CompareTo(monkey_face) < 0);
421 EXPECT(abce.CompareTo(monkey_face) < 0);
422 EXPECT(abcd.CompareTo(domino) < 0);
423 EXPECT(abce.CompareTo(domino) < 0);
424 EXPECT(domino.CompareTo(abcd) > 0);
425 EXPECT(domino.CompareTo(abcd) > 0);
426 EXPECT(monkey_face.CompareTo(abce) > 0);
427 EXPECT(monkey_face.CompareTo(abce) > 0);
428}
429
430ISOLATE_UNIT_TEST_CASE(StringEncodeIRI) {
431 const char* kInput =
432 "file:///usr/local/johnmccutchan/workspace/dart-repo/dart/test.dart";
433 const char* kOutput =
434 "file%3A%2F%2F%2Fusr%2Flocal%2Fjohnmccutchan%2Fworkspace%2F"
435 "dart-repo%2Fdart%2Ftest.dart";
436 const String& input = String::Handle(String::New(kInput));
437 const char* encoded = String::EncodeIRI(input);
438 EXPECT(strcmp(encoded, kOutput) == 0);
439}
440
441ISOLATE_UNIT_TEST_CASE(StringDecodeIRI) {
442 const char* kOutput =
443 "file:///usr/local/johnmccutchan/workspace/dart-repo/dart/test.dart";
444 const char* kInput =
445 "file%3A%2F%2F%2Fusr%2Flocal%2Fjohnmccutchan%2Fworkspace%2F"
446 "dart-repo%2Fdart%2Ftest.dart";
447 const String& input = String::Handle(String::New(kInput));
448 const String& output = String::Handle(String::New(kOutput));
449 const String& decoded = String::Handle(String::DecodeIRI(input));
450 EXPECT(output.Equals(decoded));
451}
452
453ISOLATE_UNIT_TEST_CASE(StringDecodeIRIInvalid) {
454 String& input = String::Handle();
455 input = String::New("file%");
456 String& decoded = String::Handle();
457 decoded = String::DecodeIRI(input);
458 EXPECT(decoded.IsNull());
459 input = String::New("file%3");
460 decoded = String::DecodeIRI(input);
461 EXPECT(decoded.IsNull());
462 input = String::New("file%3g");
463 decoded = String::DecodeIRI(input);
464 EXPECT(decoded.IsNull());
465}
466
467ISOLATE_UNIT_TEST_CASE(StringIRITwoByte) {
468 const intptr_t kInputLen = 3;
469 const uint16_t kInput[kInputLen] = {'x', '/', 256};
470 const String& input = String::Handle(String::FromUTF16(kInput, kInputLen));
471 const intptr_t kOutputLen = 10;
472 const uint16_t kOutput[kOutputLen] = {'x', '%', '2', 'F', '%',
473 'C', '4', '%', '8', '0'};
474 const String& output = String::Handle(String::FromUTF16(kOutput, kOutputLen));
475 const String& encoded = String::Handle(String::New(String::EncodeIRI(input)));
476 EXPECT(output.Equals(encoded));
477 const String& decoded = String::Handle(String::DecodeIRI(output));
478 EXPECT(input.Equals(decoded));
479}
480
481ISOLATE_UNIT_TEST_CASE(Mint) {
482// On 64-bit architectures a Smi is stored in a 64 bit word. A Midint cannot
483// be allocated if it does fit into a Smi.
484#if !defined(ARCH_IS_64_BIT)
485 {
486 Mint& med = Mint::Handle();
487 EXPECT(med.IsNull());
488 int64_t v = DART_2PART_UINT64_C(1, 0);
489 med ^= Integer::New(v);
490 EXPECT_EQ(v, med.value());
491 const String& smi_str = String::Handle(String::New("1"));
492 const String& mint1_str = String::Handle(String::New("2147419168"));
493 const String& mint2_str = String::Handle(String::New("-2147419168"));
494 Integer& i = Integer::Handle(Integer::NewCanonical(smi_str));
495 EXPECT(i.IsSmi());
496 i = Integer::NewCanonical(mint1_str);
497 EXPECT(i.IsMint());
498 EXPECT(!i.IsZero());
499 EXPECT(!i.IsNegative());
500 i = Integer::NewCanonical(mint2_str);
501 EXPECT(i.IsMint());
502 EXPECT(!i.IsZero());
503 EXPECT(i.IsNegative());
504 }
505 Integer& i = Integer::Handle(Integer::New(DART_2PART_UINT64_C(1, 0)));
506 EXPECT(i.IsMint());
507 EXPECT(!i.IsZero());
508 EXPECT(!i.IsNegative());
509 Integer& i1 = Integer::Handle(Integer::New(DART_2PART_UINT64_C(1010, 0)));
510 Mint& i2 = Mint::Handle();
511 i2 ^= Integer::New(DART_2PART_UINT64_C(1010, 0));
512 EXPECT(i1.Equals(i2));
513 EXPECT(!i.Equals(i1));
514 int64_t test = DART_2PART_UINT64_C(1010, 0);
515 EXPECT_EQ(test, i2.value());
516
517 Mint& a = Mint::Handle();
518 a ^= Integer::New(DART_2PART_UINT64_C(5, 0));
519 Mint& b = Mint::Handle();
520 b ^= Integer::New(DART_2PART_UINT64_C(3, 0));
521 EXPECT_EQ(1, a.CompareWith(b));
522 EXPECT_EQ(-1, b.CompareWith(a));
523 EXPECT_EQ(0, a.CompareWith(a));
524
525 Mint& c = Mint::Handle();
526 c ^= Integer::New(-DART_2PART_UINT64_C(3, 0));
527 Smi& smi1 = Smi::Handle(Smi::New(4));
528 Smi& smi2 = Smi::Handle(Smi::New(-4));
529 EXPECT_EQ(1, a.CompareWith(smi1));
530 EXPECT_EQ(1, a.CompareWith(smi2));
531 EXPECT_EQ(-1, c.CompareWith(smi1));
532 EXPECT_EQ(-1, c.CompareWith(smi2));
533
534 int64_t mint_value = DART_2PART_UINT64_C(0x7FFFFFFF, 64);
535 const String& mint_string = String::Handle(String::New("0x7FFFFFFF00000064"));
536 Mint& mint1 = Mint::Handle();
537 mint1 ^= Integer::NewCanonical(mint_string);
538 Mint& mint2 = Mint::Handle();
539 mint2 ^= Integer::NewCanonical(mint_string);
540 EXPECT_EQ(mint1.value(), mint_value);
541 EXPECT_EQ(mint2.value(), mint_value);
542 EXPECT_EQ(mint1.raw(), mint2.raw());
543#endif
544}
545
546ISOLATE_UNIT_TEST_CASE(Double) {
547 {
548 const double dbl_const = 5.0;
549 const Double& dbl = Double::Handle(Double::New(dbl_const));
550 Object& dbl_object = Object::Handle(dbl.raw());
551 EXPECT(dbl.IsDouble());
552 EXPECT(dbl_object.IsDouble());
553 EXPECT_EQ(dbl_const, dbl.value());
554 }
555
556 {
557 const double dbl_const = -5.0;
558 const Double& dbl = Double::Handle(Double::New(dbl_const));
559 Object& dbl_object = Object::Handle(dbl.raw());
560 EXPECT(dbl.IsDouble());
561 EXPECT(dbl_object.IsDouble());
562 EXPECT_EQ(dbl_const, dbl.value());
563 }
564
565 {
566 const double dbl_const = 0.0;
567 const Double& dbl = Double::Handle(Double::New(dbl_const));
568 Object& dbl_object = Object::Handle(dbl.raw());
569 EXPECT(dbl.IsDouble());
570 EXPECT(dbl_object.IsDouble());
571 EXPECT_EQ(dbl_const, dbl.value());
572 }
573
574 {
575 const double dbl_const = 5.0;
576 const String& dbl_str = String::Handle(String::New("5.0"));
577 const Double& dbl1 = Double::Handle(Double::NewCanonical(dbl_const));
578 const Double& dbl2 = Double::Handle(Double::NewCanonical(dbl_const));
579 const Double& dbl3 = Double::Handle(Double::NewCanonical(dbl_str));
580 EXPECT_EQ(dbl_const, dbl1.value());
581 EXPECT_EQ(dbl_const, dbl2.value());
582 EXPECT_EQ(dbl_const, dbl3.value());
583 EXPECT_EQ(dbl1.raw(), dbl2.raw());
584 EXPECT_EQ(dbl1.raw(), dbl3.raw());
585 }
586
587 {
588 const double dbl_const = 2.0;
589 const Double& dbl1 = Double::Handle(Double::New(dbl_const));
590 const Double& dbl2 = Double::Handle(Double::New(dbl_const));
591 EXPECT(dbl1.OperatorEquals(dbl2));
592 EXPECT(dbl1.IsIdenticalTo(dbl2));
593 EXPECT(dbl1.CanonicalizeEquals(dbl2));
594 const Double& dbl3 = Double::Handle(Double::New(3.3));
595 EXPECT(!dbl1.OperatorEquals(dbl3));
596 EXPECT(!dbl1.OperatorEquals(Smi::Handle(Smi::New(3))));
597 EXPECT(!dbl1.OperatorEquals(Double::Handle()));
598 const Double& nan0 = Double::Handle(Double::New(NAN));
599 EXPECT(isnan(nan0.value()));
600 EXPECT(nan0.IsIdenticalTo(nan0));
601 EXPECT(nan0.CanonicalizeEquals(nan0));
602 EXPECT(!nan0.OperatorEquals(nan0));
603 const Double& nan1 =
604 Double::Handle(Double::New(bit_cast<double>(kMaxUint64 - 0)));
605 const Double& nan2 =
606 Double::Handle(Double::New(bit_cast<double>(kMaxUint64 - 1)));
607 EXPECT(isnan(nan1.value()));
608 EXPECT(isnan(nan2.value()));
609 EXPECT(!nan1.IsIdenticalTo(nan2));
610 EXPECT(!nan1.CanonicalizeEquals(nan2));
611 EXPECT(!nan1.OperatorEquals(nan2));
612 }
613 {
614 const String& dbl_str0 = String::Handle(String::New("bla"));
615 const Double& dbl0 = Double::Handle(Double::New(dbl_str0));
616 EXPECT(dbl0.IsNull());
617
618 const String& dbl_str1 = String::Handle(String::New("2.0"));
619 const Double& dbl1 = Double::Handle(Double::New(dbl_str1));
620 EXPECT_EQ(2.0, dbl1.value());
621
622 // Disallow legacy form.
623 const String& dbl_str2 = String::Handle(String::New("2.0d"));
624 const Double& dbl2 = Double::Handle(Double::New(dbl_str2));
625 EXPECT(dbl2.IsNull());
626 }
627}
628
629ISOLATE_UNIT_TEST_CASE(Integer) {
630 Integer& i = Integer::Handle();
631 i = Integer::NewCanonical(String::Handle(String::New("12")));
632 EXPECT(i.IsSmi());
633 i = Integer::NewCanonical(String::Handle(String::New("-120")));
634 EXPECT(i.IsSmi());
635 i = Integer::NewCanonical(String::Handle(String::New("0")));
636 EXPECT(i.IsSmi());
637 i = Integer::NewCanonical(
638 String::Handle(String::New("12345678901234567890")));
639 EXPECT(i.IsNull());
640 i = Integer::NewCanonical(
641 String::Handle(String::New("-12345678901234567890111222")));
642 EXPECT(i.IsNull());
643}
644
645ISOLATE_UNIT_TEST_CASE(String) {
646 const char* kHello = "Hello World!";
647 int32_t hello_len = strlen(kHello);
648 const String& str = String::Handle(String::New(kHello));
649 EXPECT(str.IsInstance());
650 EXPECT(str.IsString());
651 EXPECT(str.IsOneByteString());
652 EXPECT(!str.IsTwoByteString());
653 EXPECT(!str.IsNumber());
654 EXPECT_EQ(hello_len, str.Length());
655 EXPECT_EQ('H', str.CharAt(0));
656 EXPECT_EQ('e', str.CharAt(1));
657 EXPECT_EQ('l', str.CharAt(2));
658 EXPECT_EQ('l', str.CharAt(3));
659 EXPECT_EQ('o', str.CharAt(4));
660 EXPECT_EQ(' ', str.CharAt(5));
661 EXPECT_EQ('W', str.CharAt(6));
662 EXPECT_EQ('o', str.CharAt(7));
663 EXPECT_EQ('r', str.CharAt(8));
664 EXPECT_EQ('l', str.CharAt(9));
665 EXPECT_EQ('d', str.CharAt(10));
666 EXPECT_EQ('!', str.CharAt(11));
667
668 const uint8_t* motto =
669 reinterpret_cast<const uint8_t*>("Dart's bescht wos je hets gits");
670 const String& str2 = String::Handle(String::FromUTF8(motto + 7, 4));
671 EXPECT_EQ(4, str2.Length());
672 EXPECT_EQ('b', str2.CharAt(0));
673 EXPECT_EQ('e', str2.CharAt(1));
674 EXPECT_EQ('s', str2.CharAt(2));
675 EXPECT_EQ('c', str2.CharAt(3));
676
677 const String& str3 = String::Handle(String::New(kHello));
678 EXPECT(str.Equals(str));
679 EXPECT_EQ(str.Hash(), str.Hash());
680 EXPECT(!str.Equals(str2));
681 EXPECT(str.Equals(str3));
682 EXPECT_EQ(str.Hash(), str3.Hash());
683 EXPECT(str3.Equals(str));
684
685 const String& str4 = String::Handle(String::New("foo"));
686 const String& str5 = String::Handle(String::New("bar"));
687 const String& str6 = String::Handle(String::Concat(str4, str5));
688 const String& str7 = String::Handle(String::New("foobar"));
689 EXPECT(str6.Equals(str7));
690 EXPECT(!str6.Equals(Smi::Handle(Smi::New(4))));
691
692 const String& empty1 = String::Handle(String::New(""));
693 const String& empty2 = String::Handle(String::New(""));
694 EXPECT(empty1.Equals(empty2, 0, 0));
695
696 const intptr_t kCharsLen = 8;
697 const uint8_t chars[kCharsLen] = {1, 2, 127, 64, 92, 0, 55, 55};
698 const String& str8 = String::Handle(String::FromUTF8(chars, kCharsLen));
699 EXPECT_EQ(kCharsLen, str8.Length());
700 EXPECT_EQ(1, str8.CharAt(0));
701 EXPECT_EQ(127, str8.CharAt(2));
702 EXPECT_EQ(64, str8.CharAt(3));
703 EXPECT_EQ(0, str8.CharAt(5));
704 EXPECT_EQ(55, str8.CharAt(6));
705 EXPECT_EQ(55, str8.CharAt(7));
706 const intptr_t kCharsIndex = 3;
707 const String& sub1 = String::Handle(String::SubString(str8, kCharsIndex));
708 EXPECT_EQ((kCharsLen - kCharsIndex), sub1.Length());
709 EXPECT_EQ(64, sub1.CharAt(0));
710 EXPECT_EQ(92, sub1.CharAt(1));
711 EXPECT_EQ(0, sub1.CharAt(2));
712 EXPECT_EQ(55, sub1.CharAt(3));
713 EXPECT_EQ(55, sub1.CharAt(4));
714
715 const intptr_t kWideCharsLen = 7;
716 uint16_t wide_chars[kWideCharsLen] = {'H', 'e', 'l', 'l', 'o', 256, '!'};
717 const String& two_str =
718 String::Handle(String::FromUTF16(wide_chars, kWideCharsLen));
719 EXPECT(two_str.IsInstance());
720 EXPECT(two_str.IsString());
721 EXPECT(two_str.IsTwoByteString());
722 EXPECT(!two_str.IsOneByteString());
723 EXPECT_EQ(kWideCharsLen, two_str.Length());
724 EXPECT_EQ('H', two_str.CharAt(0));
725 EXPECT_EQ(256, two_str.CharAt(5));
726 const intptr_t kWideCharsIndex = 3;
727 const String& sub2 = String::Handle(String::SubString(two_str, kCharsIndex));
728 EXPECT_EQ((kWideCharsLen - kWideCharsIndex), sub2.Length());
729 EXPECT_EQ('l', sub2.CharAt(0));
730 EXPECT_EQ('o', sub2.CharAt(1));
731 EXPECT_EQ(256, sub2.CharAt(2));
732 EXPECT_EQ('!', sub2.CharAt(3));
733
734 {
735 const String& str1 = String::Handle(String::New("My.create"));
736 const String& str2 = String::Handle(String::New("My"));
737 const String& str3 = String::Handle(String::New("create"));
738 EXPECT_EQ(true, str1.StartsWith(str2));
739 EXPECT_EQ(false, str1.StartsWith(str3));
740 }
741
742 const int32_t four_chars[] = {'C', 0xFF, 'h', 0xFFFF, 'a', 0x10FFFF, 'r'};
743 const String& four_str = String::Handle(String::FromUTF32(four_chars, 7));
744 EXPECT_EQ(four_str.Hash(), four_str.Hash());
745 EXPECT(four_str.IsTwoByteString());
746 EXPECT(!four_str.IsOneByteString());
747 EXPECT_EQ(8, four_str.Length());
748 EXPECT_EQ('C', four_str.CharAt(0));
749 EXPECT_EQ(0xFF, four_str.CharAt(1));
750 EXPECT_EQ('h', four_str.CharAt(2));
751 EXPECT_EQ(0xFFFF, four_str.CharAt(3));
752 EXPECT_EQ('a', four_str.CharAt(4));
753 EXPECT_EQ(0xDBFF, four_str.CharAt(5));
754 EXPECT_EQ(0xDFFF, four_str.CharAt(6));
755 EXPECT_EQ('r', four_str.CharAt(7));
756
757 // Create a 1-byte string from an array of 2-byte elements.
758 {
759 const uint16_t char16[] = {0x00, 0x7F, 0xFF};
760 const String& str8 = String::Handle(String::FromUTF16(char16, 3));
761 EXPECT(str8.IsOneByteString());
762 EXPECT(!str8.IsTwoByteString());
763 EXPECT_EQ(0x00, str8.CharAt(0));
764 EXPECT_EQ(0x7F, str8.CharAt(1));
765 EXPECT_EQ(0xFF, str8.CharAt(2));
766 }
767
768 // Create a 1-byte string from an array of 4-byte elements.
769 {
770 const int32_t char32[] = {0x00, 0x1F, 0x7F};
771 const String& str8 = String::Handle(String::FromUTF32(char32, 3));
772 EXPECT(str8.IsOneByteString());
773 EXPECT(!str8.IsTwoByteString());
774 EXPECT_EQ(0x00, str8.CharAt(0));
775 EXPECT_EQ(0x1F, str8.CharAt(1));
776 EXPECT_EQ(0x7F, str8.CharAt(2));
777 }
778
779 // Create a 2-byte string from an array of 4-byte elements.
780 {
781 const int32_t char32[] = {0, 0x7FFF, 0xFFFF};
782 const String& str16 = String::Handle(String::FromUTF32(char32, 3));
783 EXPECT(!str16.IsOneByteString());
784 EXPECT(str16.IsTwoByteString());
785 EXPECT_EQ(0x0000, str16.CharAt(0));
786 EXPECT_EQ(0x7FFF, str16.CharAt(1));
787 EXPECT_EQ(0xFFFF, str16.CharAt(2));
788 }
789}
790
791ISOLATE_UNIT_TEST_CASE(StringFormat) {
792 const char* hello_str = "Hello World!";
793 const String& str =
794 String::Handle(String::NewFormatted("Hello %s!", "World"));
795 EXPECT(str.IsInstance());
796 EXPECT(str.IsString());
797 EXPECT(str.IsOneByteString());
798 EXPECT(!str.IsTwoByteString());
799 EXPECT(!str.IsNumber());
800 EXPECT(str.Equals(hello_str));
801}
802
803ISOLATE_UNIT_TEST_CASE(StringConcat) {
804 // Create strings from concatenated 1-byte empty strings.
805 {
806 const String& empty1 = String::Handle(String::New(""));
807 EXPECT(empty1.IsOneByteString());
808 EXPECT_EQ(0, empty1.Length());
809
810 const String& empty2 = String::Handle(String::New(""));
811 EXPECT(empty2.IsOneByteString());
812 EXPECT_EQ(0, empty2.Length());
813
814 // Concat
815
816 const String& empty3 = String::Handle(String::Concat(empty1, empty2));
817 EXPECT(empty3.IsOneByteString());
818 EXPECT_EQ(0, empty3.Length());
819
820 // ConcatAll
821
822 const Array& array1 = Array::Handle(Array::New(0));
823 EXPECT_EQ(0, array1.Length());
824 const String& empty4 = String::Handle(String::ConcatAll(array1));
825 EXPECT_EQ(0, empty4.Length());
826
827 const Array& array2 = Array::Handle(Array::New(10));
828 EXPECT_EQ(10, array2.Length());
829 for (int i = 0; i < array2.Length(); ++i) {
830 array2.SetAt(i, String::Handle(String::New("")));
831 }
832 const String& empty5 = String::Handle(String::ConcatAll(array2));
833 EXPECT(empty5.IsOneByteString());
834 EXPECT_EQ(0, empty5.Length());
835
836 const Array& array3 = Array::Handle(Array::New(123));
837 EXPECT_EQ(123, array3.Length());
838
839 const String& empty6 = String::Handle(String::New(""));
840 EXPECT(empty6.IsOneByteString());
841 EXPECT_EQ(0, empty6.Length());
842 for (int i = 0; i < array3.Length(); ++i) {
843 array3.SetAt(i, empty6);
844 }
845 const String& empty7 = String::Handle(String::ConcatAll(array3));
846 EXPECT(empty7.IsOneByteString());
847 EXPECT_EQ(0, empty7.Length());
848 }
849
850 // Concatenated empty and non-empty 1-byte strings.
851 {
852 const String& str1 = String::Handle(String::New(""));
853 EXPECT_EQ(0, str1.Length());
854 EXPECT(str1.IsOneByteString());
855
856 const String& str2 = String::Handle(String::New("one"));
857 EXPECT(str2.IsOneByteString());
858 EXPECT_EQ(3, str2.Length());
859
860 // Concat
861
862 const String& str3 = String::Handle(String::Concat(str1, str2));
863 EXPECT(str3.IsOneByteString());
864 EXPECT_EQ(3, str3.Length());
865 EXPECT(str3.Equals(str2));
866
867 const String& str4 = String::Handle(String::Concat(str2, str1));
868 EXPECT(str4.IsOneByteString());
869 EXPECT_EQ(3, str4.Length());
870 EXPECT(str4.Equals(str2));
871
872 // ConcatAll
873
874 const Array& array1 = Array::Handle(Array::New(2));
875 EXPECT_EQ(2, array1.Length());
876 array1.SetAt(0, str1);
877 array1.SetAt(1, str2);
878 const String& str5 = String::Handle(String::ConcatAll(array1));
879 EXPECT(str5.IsOneByteString());
880 EXPECT_EQ(3, str5.Length());
881 EXPECT(str5.Equals(str2));
882
883 const Array& array2 = Array::Handle(Array::New(2));
884 EXPECT_EQ(2, array2.Length());
885 array2.SetAt(0, str1);
886 array2.SetAt(1, str2);
887 const String& str6 = String::Handle(String::ConcatAll(array2));
888 EXPECT(str6.IsOneByteString());
889 EXPECT_EQ(3, str6.Length());
890 EXPECT(str6.Equals(str2));
891
892 const Array& array3 = Array::Handle(Array::New(3));
893 EXPECT_EQ(3, array3.Length());
894 array3.SetAt(0, str2);
895 array3.SetAt(1, str1);
896 array3.SetAt(2, str2);
897 const String& str7 = String::Handle(String::ConcatAll(array3));
898 EXPECT(str7.IsOneByteString());
899 EXPECT_EQ(6, str7.Length());
900 EXPECT(str7.Equals("oneone"));
901 EXPECT(!str7.Equals("oneoneone"));
902 }
903
904 // Create a string by concatenating non-empty 1-byte strings.
905 {
906 const char* one = "one";
907 intptr_t one_len = strlen(one);
908 const String& onestr = String::Handle(String::New(one));
909 EXPECT(onestr.IsOneByteString());
910 EXPECT_EQ(one_len, onestr.Length());
911
912 const char* three = "three";
913 intptr_t three_len = strlen(three);
914 const String& threestr = String::Handle(String::New(three));
915 EXPECT(threestr.IsOneByteString());
916 EXPECT_EQ(three_len, threestr.Length());
917
918 // Concat
919
920 const String& str3 = String::Handle(String::Concat(onestr, threestr));
921 EXPECT(str3.IsOneByteString());
922 const char* one_three = "onethree";
923 EXPECT(str3.Equals(one_three));
924
925 const String& str4 = String::Handle(String::Concat(threestr, onestr));
926 EXPECT(str4.IsOneByteString());
927 const char* three_one = "threeone";
928 intptr_t three_one_len = strlen(three_one);
929 EXPECT_EQ(three_one_len, str4.Length());
930 EXPECT(str4.Equals(three_one));
931
932 // ConcatAll
933
934 const Array& array1 = Array::Handle(Array::New(2));
935 EXPECT_EQ(2, array1.Length());
936 array1.SetAt(0, onestr);
937 array1.SetAt(1, threestr);
938 const String& str5 = String::Handle(String::ConcatAll(array1));
939 EXPECT(str5.IsOneByteString());
940 intptr_t one_three_len = strlen(one_three);
941 EXPECT_EQ(one_three_len, str5.Length());
942 EXPECT(str5.Equals(one_three));
943
944 const Array& array2 = Array::Handle(Array::New(2));
945 EXPECT_EQ(2, array2.Length());
946 array2.SetAt(0, threestr);
947 array2.SetAt(1, onestr);
948 const String& str6 = String::Handle(String::ConcatAll(array2));
949 EXPECT(str6.IsOneByteString());
950 EXPECT_EQ(three_one_len, str6.Length());
951 EXPECT(str6.Equals(three_one));
952
953 const Array& array3 = Array::Handle(Array::New(3));
954 EXPECT_EQ(3, array3.Length());
955 array3.SetAt(0, onestr);
956 array3.SetAt(1, threestr);
957 array3.SetAt(2, onestr);
958 const String& str7 = String::Handle(String::ConcatAll(array3));
959 EXPECT(str7.IsOneByteString());
960 const char* one_three_one = "onethreeone";
961 intptr_t one_three_one_len = strlen(one_three_one);
962 EXPECT_EQ(one_three_one_len, str7.Length());
963 EXPECT(str7.Equals(one_three_one));
964
965 const Array& array4 = Array::Handle(Array::New(3));
966 EXPECT_EQ(3, array4.Length());
967 array4.SetAt(0, threestr);
968 array4.SetAt(1, onestr);
969 array4.SetAt(2, threestr);
970 const String& str8 = String::Handle(String::ConcatAll(array4));
971 EXPECT(str8.IsOneByteString());
972 const char* three_one_three = "threeonethree";
973 intptr_t three_one_three_len = strlen(three_one_three);
974 EXPECT_EQ(three_one_three_len, str8.Length());
975 EXPECT(str8.Equals(three_one_three));
976 }
977
978 // Concatenate empty and non-empty 2-byte strings.
979 {
980 const String& str1 = String::Handle(String::New(""));
981 EXPECT(str1.IsOneByteString());
982 EXPECT_EQ(0, str1.Length());
983
984 uint16_t two[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9};
985 intptr_t two_len = sizeof(two) / sizeof(two[0]);
986 const String& str2 = String::Handle(String::FromUTF16(two, two_len));
987 EXPECT(str2.IsTwoByteString());
988 EXPECT_EQ(two_len, str2.Length());
989
990 // Concat
991
992 const String& str3 = String::Handle(String::Concat(str1, str2));
993 EXPECT(str3.IsTwoByteString());
994 EXPECT_EQ(two_len, str3.Length());
995 EXPECT(str3.Equals(str2));
996
997 const String& str4 = String::Handle(String::Concat(str2, str1));
998 EXPECT(str4.IsTwoByteString());
999 EXPECT_EQ(two_len, str4.Length());
1000 EXPECT(str4.Equals(str2));
1001
1002 // ConcatAll
1003
1004 const Array& array1 = Array::Handle(Array::New(2));
1005 EXPECT_EQ(2, array1.Length());
1006 array1.SetAt(0, str1);
1007 array1.SetAt(1, str2);
1008 const String& str5 = String::Handle(String::ConcatAll(array1));
1009 EXPECT(str5.IsTwoByteString());
1010 EXPECT_EQ(two_len, str5.Length());
1011 EXPECT(str5.Equals(str2));
1012
1013 const Array& array2 = Array::Handle(Array::New(2));
1014 EXPECT_EQ(2, array2.Length());
1015 array2.SetAt(0, str1);
1016 array2.SetAt(1, str2);
1017 const String& str6 = String::Handle(String::ConcatAll(array2));
1018 EXPECT(str6.IsTwoByteString());
1019 EXPECT_EQ(two_len, str6.Length());
1020 EXPECT(str6.Equals(str2));
1021
1022 const Array& array3 = Array::Handle(Array::New(3));
1023 EXPECT_EQ(3, array3.Length());
1024 array3.SetAt(0, str2);
1025 array3.SetAt(1, str1);
1026 array3.SetAt(2, str2);
1027 const String& str7 = String::Handle(String::ConcatAll(array3));
1028 EXPECT(str7.IsTwoByteString());
1029 EXPECT_EQ(two_len * 2, str7.Length());
1030 uint16_t twotwo[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9,
1031 0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1032 intptr_t twotwo_len = sizeof(twotwo) / sizeof(twotwo[0]);
1033 EXPECT(str7.IsTwoByteString());
1034 EXPECT(str7.Equals(twotwo, twotwo_len));
1035 }
1036
1037 // Concatenating non-empty 2-byte strings.
1038 {
1039 const uint16_t one[] = {0x05D0, 0x05D9, 0x05D9, 0x05DF};
1040 intptr_t one_len = sizeof(one) / sizeof(one[0]);
1041 const String& str1 = String::Handle(String::FromUTF16(one, one_len));
1042 EXPECT(str1.IsTwoByteString());
1043 EXPECT_EQ(one_len, str1.Length());
1044
1045 const uint16_t two[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1046 intptr_t two_len = sizeof(two) / sizeof(two[0]);
1047 const String& str2 = String::Handle(String::FromUTF16(two, two_len));
1048 EXPECT(str2.IsTwoByteString());
1049 EXPECT_EQ(two_len, str2.Length());
1050
1051 // Concat
1052
1053 const String& one_two_str = String::Handle(String::Concat(str1, str2));
1054 EXPECT(one_two_str.IsTwoByteString());
1055 const uint16_t one_two[] = {0x05D0, 0x05D9, 0x05D9, 0x05DF, 0x05E6,
1056 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1057 intptr_t one_two_len = sizeof(one_two) / sizeof(one_two[0]);
1058 EXPECT_EQ(one_two_len, one_two_str.Length());
1059 EXPECT(one_two_str.Equals(one_two, one_two_len));
1060
1061 const String& two_one_str = String::Handle(String::Concat(str2, str1));
1062 EXPECT(two_one_str.IsTwoByteString());
1063 const uint16_t two_one[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9,
1064 0x05D0, 0x05D9, 0x05D9, 0x05DF};
1065 intptr_t two_one_len = sizeof(two_one) / sizeof(two_one[0]);
1066 EXPECT_EQ(two_one_len, two_one_str.Length());
1067 EXPECT(two_one_str.Equals(two_one, two_one_len));
1068
1069 // ConcatAll
1070
1071 const Array& array1 = Array::Handle(Array::New(2));
1072 EXPECT_EQ(2, array1.Length());
1073 array1.SetAt(0, str1);
1074 array1.SetAt(1, str2);
1075 const String& str3 = String::Handle(String::ConcatAll(array1));
1076 EXPECT(str3.IsTwoByteString());
1077 EXPECT_EQ(one_two_len, str3.Length());
1078 EXPECT(str3.Equals(one_two, one_two_len));
1079
1080 const Array& array2 = Array::Handle(Array::New(2));
1081 EXPECT_EQ(2, array2.Length());
1082 array2.SetAt(0, str2);
1083 array2.SetAt(1, str1);
1084 const String& str4 = String::Handle(String::ConcatAll(array2));
1085 EXPECT(str4.IsTwoByteString());
1086 EXPECT_EQ(two_one_len, str4.Length());
1087 EXPECT(str4.Equals(two_one, two_one_len));
1088
1089 const Array& array3 = Array::Handle(Array::New(3));
1090 EXPECT_EQ(3, array3.Length());
1091 array3.SetAt(0, str1);
1092 array3.SetAt(1, str2);
1093 array3.SetAt(2, str1);
1094 const String& str5 = String::Handle(String::ConcatAll(array3));
1095 EXPECT(str5.IsTwoByteString());
1096 const uint16_t one_two_one[] = {0x05D0, 0x05D9, 0x05D9, 0x05DF, 0x05E6,
1097 0x05D5, 0x05D5, 0x05D9, 0x05D9, 0x05D0,
1098 0x05D9, 0x05D9, 0x05DF};
1099 intptr_t one_two_one_len = sizeof(one_two_one) / sizeof(one_two_one[0]);
1100 EXPECT_EQ(one_two_one_len, str5.Length());
1101 EXPECT(str5.Equals(one_two_one, one_two_one_len));
1102
1103 const Array& array4 = Array::Handle(Array::New(3));
1104 EXPECT_EQ(3, array4.Length());
1105 array4.SetAt(0, str2);
1106 array4.SetAt(1, str1);
1107 array4.SetAt(2, str2);
1108 const String& str6 = String::Handle(String::ConcatAll(array4));
1109 EXPECT(str6.IsTwoByteString());
1110 const uint16_t two_one_two[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9,
1111 0x05D0, 0x05D9, 0x05D9, 0x05DF, 0x05E6,
1112 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1113 intptr_t two_one_two_len = sizeof(two_one_two) / sizeof(two_one_two[0]);
1114 EXPECT_EQ(two_one_two_len, str6.Length());
1115 EXPECT(str6.Equals(two_one_two, two_one_two_len));
1116 }
1117
1118 // Concatenated empty and non-empty strings built from 4-byte elements.
1119 {
1120 const String& str1 = String::Handle(String::New(""));
1121 EXPECT(str1.IsOneByteString());
1122 EXPECT_EQ(0, str1.Length());
1123
1124 int32_t four[] = {0x1D4D5, 0x1D4DE, 0x1D4E4, 0x1D4E1};
1125 intptr_t four_len = sizeof(four) / sizeof(four[0]);
1126 intptr_t expected_len = (four_len * 2);
1127 const String& str2 = String::Handle(String::FromUTF32(four, four_len));
1128 EXPECT(str2.IsTwoByteString());
1129 EXPECT_EQ(expected_len, str2.Length());
1130
1131 // Concat
1132
1133 const String& str3 = String::Handle(String::Concat(str1, str2));
1134 EXPECT_EQ(expected_len, str3.Length());
1135 EXPECT(str3.Equals(str2));
1136
1137 const String& str4 = String::Handle(String::Concat(str2, str1));
1138 EXPECT(str4.IsTwoByteString());
1139 EXPECT_EQ(expected_len, str4.Length());
1140 EXPECT(str4.Equals(str2));
1141
1142 // ConcatAll
1143
1144 const Array& array1 = Array::Handle(Array::New(2));
1145 EXPECT_EQ(2, array1.Length());
1146 array1.SetAt(0, str1);
1147 array1.SetAt(1, str2);
1148 const String& str5 = String::Handle(String::ConcatAll(array1));
1149 EXPECT(str5.IsTwoByteString());
1150 EXPECT_EQ(expected_len, str5.Length());
1151 EXPECT(str5.Equals(str2));
1152
1153 const Array& array2 = Array::Handle(Array::New(2));
1154 EXPECT_EQ(2, array2.Length());
1155 array2.SetAt(0, str1);
1156 array2.SetAt(1, str2);
1157 const String& str6 = String::Handle(String::ConcatAll(array2));
1158 EXPECT(str6.IsTwoByteString());
1159 EXPECT_EQ(expected_len, str6.Length());
1160 EXPECT(str6.Equals(str2));
1161
1162 const Array& array3 = Array::Handle(Array::New(3));
1163 EXPECT_EQ(3, array3.Length());
1164 array3.SetAt(0, str2);
1165 array3.SetAt(1, str1);
1166 array3.SetAt(2, str2);
1167 const String& str7 = String::Handle(String::ConcatAll(array3));
1168 EXPECT(str7.IsTwoByteString());
1169 int32_t fourfour[] = {0x1D4D5, 0x1D4DE, 0x1D4E4, 0x1D4E1,
1170 0x1D4D5, 0x1D4DE, 0x1D4E4, 0x1D4E1};
1171 intptr_t fourfour_len = sizeof(fourfour) / sizeof(fourfour[0]);
1172 EXPECT_EQ((fourfour_len * 2), str7.Length());
1173 const String& fourfour_str =
1174 String::Handle(String::FromUTF32(fourfour, fourfour_len));
1175 EXPECT(str7.Equals(fourfour_str));
1176 }
1177
1178 // Concatenate non-empty strings built from 4-byte elements.
1179 {
1180 const int32_t one[] = {0x105D0, 0x105D9, 0x105D9, 0x105DF};
1181 intptr_t one_len = sizeof(one) / sizeof(one[0]);
1182 const String& onestr = String::Handle(String::FromUTF32(one, one_len));
1183 EXPECT(onestr.IsTwoByteString());
1184 EXPECT_EQ((one_len * 2), onestr.Length());
1185
1186 const int32_t two[] = {0x105E6, 0x105D5, 0x105D5, 0x105D9, 0x105D9};
1187 intptr_t two_len = sizeof(two) / sizeof(two[0]);
1188 const String& twostr = String::Handle(String::FromUTF32(two, two_len));
1189 EXPECT(twostr.IsTwoByteString());
1190 EXPECT_EQ((two_len * 2), twostr.Length());
1191
1192 // Concat
1193
1194 const String& str1 = String::Handle(String::Concat(onestr, twostr));
1195 EXPECT(str1.IsTwoByteString());
1196 const int32_t one_two[] = {0x105D0, 0x105D9, 0x105D9, 0x105DF, 0x105E6,
1197 0x105D5, 0x105D5, 0x105D9, 0x105D9};
1198 intptr_t one_two_len = sizeof(one_two) / sizeof(one_two[0]);
1199 EXPECT_EQ((one_two_len * 2), str1.Length());
1200 const String& one_two_str =
1201 String::Handle(String::FromUTF32(one_two, one_two_len));
1202 EXPECT(str1.Equals(one_two_str));
1203
1204 const String& str2 = String::Handle(String::Concat(twostr, onestr));
1205 EXPECT(str2.IsTwoByteString());
1206 const int32_t two_one[] = {0x105E6, 0x105D5, 0x105D5, 0x105D9, 0x105D9,
1207 0x105D0, 0x105D9, 0x105D9, 0x105DF};
1208 intptr_t two_one_len = sizeof(two_one) / sizeof(two_one[0]);
1209 EXPECT_EQ((two_one_len * 2), str2.Length());
1210 const String& two_one_str =
1211 String::Handle(String::FromUTF32(two_one, two_one_len));
1212 EXPECT(str2.Equals(two_one_str));
1213
1214 // ConcatAll
1215
1216 const Array& array1 = Array::Handle(Array::New(2));
1217 EXPECT_EQ(2, array1.Length());
1218 array1.SetAt(0, onestr);
1219 array1.SetAt(1, twostr);
1220 const String& str3 = String::Handle(String::ConcatAll(array1));
1221 EXPECT(str3.IsTwoByteString());
1222 EXPECT_EQ((one_two_len * 2), str3.Length());
1223 EXPECT(str3.Equals(one_two_str));
1224
1225 const Array& array2 = Array::Handle(Array::New(2));
1226 EXPECT_EQ(2, array2.Length());
1227 array2.SetAt(0, twostr);
1228 array2.SetAt(1, onestr);
1229 const String& str4 = String::Handle(String::ConcatAll(array2));
1230 EXPECT(str4.IsTwoByteString());
1231 EXPECT_EQ((two_one_len * 2), str4.Length());
1232 EXPECT(str4.Equals(two_one_str));
1233
1234 const Array& array3 = Array::Handle(Array::New(3));
1235 EXPECT_EQ(3, array3.Length());
1236 array3.SetAt(0, onestr);
1237 array3.SetAt(1, twostr);
1238 array3.SetAt(2, onestr);
1239 const String& str5 = String::Handle(String::ConcatAll(array3));
1240 EXPECT(str5.IsTwoByteString());
1241 const int32_t one_two_one[] = {0x105D0, 0x105D9, 0x105D9, 0x105DF, 0x105E6,
1242 0x105D5, 0x105D5, 0x105D9, 0x105D9, 0x105D0,
1243 0x105D9, 0x105D9, 0x105DF};
1244 intptr_t one_two_one_len = sizeof(one_two_one) / sizeof(one_two_one[0]);
1245 EXPECT_EQ((one_two_one_len * 2), str5.Length());
1246 const String& one_two_one_str =
1247 String::Handle(String::FromUTF32(one_two_one, one_two_one_len));
1248 EXPECT(str5.Equals(one_two_one_str));
1249
1250 const Array& array4 = Array::Handle(Array::New(3));
1251 EXPECT_EQ(3, array4.Length());
1252 array4.SetAt(0, twostr);
1253 array4.SetAt(1, onestr);
1254 array4.SetAt(2, twostr);
1255 const String& str6 = String::Handle(String::ConcatAll(array4));
1256 EXPECT(str6.IsTwoByteString());
1257 const int32_t two_one_two[] = {0x105E6, 0x105D5, 0x105D5, 0x105D9, 0x105D9,
1258 0x105D0, 0x105D9, 0x105D9, 0x105DF, 0x105E6,
1259 0x105D5, 0x105D5, 0x105D9, 0x105D9};
1260 intptr_t two_one_two_len = sizeof(two_one_two) / sizeof(two_one_two[0]);
1261 EXPECT_EQ((two_one_two_len * 2), str6.Length());
1262 const String& two_one_two_str =
1263 String::Handle(String::FromUTF32(two_one_two, two_one_two_len));
1264 EXPECT(str6.Equals(two_one_two_str));
1265 }
1266
1267 // Concatenate 1-byte strings and 2-byte strings.
1268 {
1269 const uint8_t one[] = {'o', 'n', 'e', ' ', 'b', 'y', 't', 'e'};
1270 intptr_t one_len = sizeof(one) / sizeof(one[0]);
1271 const String& onestr = String::Handle(String::FromLatin1(one, one_len));
1272 EXPECT(onestr.IsOneByteString());
1273 EXPECT_EQ(one_len, onestr.Length());
1274 EXPECT(onestr.EqualsLatin1(one, one_len));
1275
1276 uint16_t two[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1277 intptr_t two_len = sizeof(two) / sizeof(two[0]);
1278 const String& twostr = String::Handle(String::FromUTF16(two, two_len));
1279 EXPECT(twostr.IsTwoByteString());
1280 EXPECT_EQ(two_len, twostr.Length());
1281 EXPECT(twostr.Equals(two, two_len));
1282
1283 // Concat
1284
1285 const String& one_two_str = String::Handle(String::Concat(onestr, twostr));
1286 EXPECT(one_two_str.IsTwoByteString());
1287 uint16_t one_two[] = {'o', 'n', 'e', ' ', 'b', 'y', 't',
1288 'e', 0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1289 intptr_t one_two_len = sizeof(one_two) / sizeof(one_two[0]);
1290 EXPECT_EQ(one_two_len, one_two_str.Length());
1291 EXPECT(one_two_str.Equals(one_two, one_two_len));
1292
1293 const String& two_one_str = String::Handle(String::Concat(twostr, onestr));
1294 EXPECT(two_one_str.IsTwoByteString());
1295 uint16_t two_one[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9, 'o', 'n',
1296 'e', ' ', 'b', 'y', 't', 'e'};
1297 intptr_t two_one_len = sizeof(two_one) / sizeof(two_one[0]);
1298 EXPECT_EQ(two_one_len, two_one_str.Length());
1299 EXPECT(two_one_str.Equals(two_one, two_one_len));
1300
1301 // ConcatAll
1302
1303 const Array& array1 = Array::Handle(Array::New(3));
1304 EXPECT_EQ(3, array1.Length());
1305 array1.SetAt(0, onestr);
1306 array1.SetAt(1, twostr);
1307 array1.SetAt(2, onestr);
1308 const String& one_two_one_str = String::Handle(String::ConcatAll(array1));
1309 EXPECT(one_two_one_str.IsTwoByteString());
1310 EXPECT_EQ(onestr.Length() * 2 + twostr.Length(), one_two_one_str.Length());
1311 uint16_t one_two_one[] = {'o', 'n', 'e', ' ', 'b', 'y', 't',
1312 'e', 0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9, 'o',
1313 'n', 'e', ' ', 'b', 'y', 't', 'e'};
1314 intptr_t one_two_one_len = sizeof(one_two_one) / sizeof(one_two_one[0]);
1315 EXPECT(one_two_one_str.Equals(one_two_one, one_two_one_len));
1316
1317 const Array& array2 = Array::Handle(Array::New(3));
1318 EXPECT_EQ(3, array2.Length());
1319 array2.SetAt(0, twostr);
1320 array2.SetAt(1, onestr);
1321 array2.SetAt(2, twostr);
1322 const String& two_one_two_str = String::Handle(String::ConcatAll(array2));
1323 EXPECT(two_one_two_str.IsTwoByteString());
1324 EXPECT_EQ(twostr.Length() * 2 + onestr.Length(), two_one_two_str.Length());
1325 uint16_t two_one_two[] = {0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9, 'o',
1326 'n', 'e', ' ', 'b', 'y', 't',
1327 'e', 0x05E6, 0x05D5, 0x05D5, 0x05D9, 0x05D9};
1328 intptr_t two_one_two_len = sizeof(two_one_two) / sizeof(two_one_two[0]);
1329 EXPECT(two_one_two_str.Equals(two_one_two, two_one_two_len));
1330 }
1331}
1332
1333ISOLATE_UNIT_TEST_CASE(StringHashConcat) {
1334 EXPECT_EQ(String::Handle(String::New("onebyte")).Hash(),
1335 String::HashConcat(String::Handle(String::New("one")),
1336 String::Handle(String::New("byte"))));
1337 uint16_t clef_utf16[] = {0xD834, 0xDD1E};
1338 const String& clef = String::Handle(String::FromUTF16(clef_utf16, 2));
1339 int32_t clef_utf32[] = {0x1D11E};
1340 EXPECT(clef.Equals(clef_utf32, 1));
1341 intptr_t hash32 = String::Hash(clef_utf32, 1);
1342 EXPECT_EQ(hash32, clef.Hash());
1343 EXPECT_EQ(hash32, String::HashConcat(
1344 String::Handle(String::FromUTF16(clef_utf16, 1)),
1345 String::Handle(String::FromUTF16(clef_utf16 + 1, 1))));
1346}
1347
1348ISOLATE_UNIT_TEST_CASE(StringSubStringDifferentWidth) {
1349 // Create 1-byte substring from a 1-byte source string.
1350 const char* onechars = "\xC3\xB6\xC3\xB1\xC3\xA9";
1351
1352 const String& onestr = String::Handle(String::New(onechars));
1353 EXPECT(!onestr.IsNull());
1354 EXPECT(onestr.IsOneByteString());
1355 EXPECT(!onestr.IsTwoByteString());
1356
1357 const String& onesub = String::Handle(String::SubString(onestr, 0));
1358 EXPECT(!onesub.IsNull());
1359 EXPECT(onestr.IsOneByteString());
1360 EXPECT(!onestr.IsTwoByteString());
1361 EXPECT_EQ(onesub.Length(), 3);
1362
1363 // Create 1- and 2-byte substrings from a 2-byte source string.
1364 const char* twochars =
1365 "\x1f\x2f\x3f"
1366 "\xE1\xB9\xAB\xE1\xBA\x85\xE1\xB9\x93";
1367
1368 const String& twostr = String::Handle(String::New(twochars));
1369 EXPECT(!twostr.IsNull());
1370 EXPECT(twostr.IsTwoByteString());
1371
1372 const String& twosub1 = String::Handle(String::SubString(twostr, 0, 3));
1373 EXPECT(!twosub1.IsNull());
1374 EXPECT(twosub1.IsOneByteString());
1375 EXPECT_EQ(twosub1.Length(), 3);
1376
1377 const String& twosub2 = String::Handle(String::SubString(twostr, 3));
1378 EXPECT(!twosub2.IsNull());
1379 EXPECT(twosub2.IsTwoByteString());
1380 EXPECT_EQ(twosub2.Length(), 3);
1381
1382 // Create substrings from a string built using 1-, 2- and 4-byte elements.
1383 const char* fourchars =
1384 "\x1f\x2f\x3f"
1385 "\xE1\xB9\xAB\xE1\xBA\x85\xE1\xB9\x93"
1386 "\xF0\x9D\x96\xBF\xF0\x9D\x97\x88\xF0\x9D\x97\x8E\xF0\x9D\x97\x8B";
1387
1388 const String& fourstr = String::Handle(String::New(fourchars));
1389 EXPECT(!fourstr.IsNull());
1390 EXPECT(fourstr.IsTwoByteString());
1391
1392 const String& foursub1 = String::Handle(String::SubString(fourstr, 0, 3));
1393 EXPECT(!foursub1.IsNull());
1394 EXPECT(foursub1.IsOneByteString());
1395 EXPECT_EQ(foursub1.Length(), 3);
1396
1397 const String& foursub2 = String::Handle(String::SubString(fourstr, 3, 3));
1398 EXPECT(!foursub2.IsNull());
1399 EXPECT(foursub2.IsTwoByteString());
1400 EXPECT_EQ(foursub2.Length(), 3);
1401
1402 const String& foursub4 = String::Handle(String::SubString(fourstr, 6));
1403 EXPECT_EQ(foursub4.Length(), 8);
1404 EXPECT(!foursub4.IsNull());
1405 EXPECT(foursub4.IsTwoByteString());
1406}
1407
1408ISOLATE_UNIT_TEST_CASE(StringFromUtf8Literal) {
1409 // Create a 1-byte string from a UTF-8 encoded string literal.
1410 {
1411 const char* src =
1412 "\xC2\xA0\xC2\xA1\xC2\xA2\xC2\xA3"
1413 "\xC2\xA4\xC2\xA5\xC2\xA6\xC2\xA7"
1414 "\xC2\xA8\xC2\xA9\xC2\xAA\xC2\xAB"
1415 "\xC2\xAC\xC2\xAD\xC2\xAE\xC2\xAF"
1416 "\xC2\xB0\xC2\xB1\xC2\xB2\xC2\xB3"
1417 "\xC2\xB4\xC2\xB5\xC2\xB6\xC2\xB7"
1418 "\xC2\xB8\xC2\xB9\xC2\xBA\xC2\xBB"
1419 "\xC2\xBC\xC2\xBD\xC2\xBE\xC2\xBF"
1420 "\xC3\x80\xC3\x81\xC3\x82\xC3\x83"
1421 "\xC3\x84\xC3\x85\xC3\x86\xC3\x87"
1422 "\xC3\x88\xC3\x89\xC3\x8A\xC3\x8B"
1423 "\xC3\x8C\xC3\x8D\xC3\x8E\xC3\x8F"
1424 "\xC3\x90\xC3\x91\xC3\x92\xC3\x93"
1425 "\xC3\x94\xC3\x95\xC3\x96\xC3\x97"
1426 "\xC3\x98\xC3\x99\xC3\x9A\xC3\x9B"
1427 "\xC3\x9C\xC3\x9D\xC3\x9E\xC3\x9F"
1428 "\xC3\xA0\xC3\xA1\xC3\xA2\xC3\xA3"
1429 "\xC3\xA4\xC3\xA5\xC3\xA6\xC3\xA7"
1430 "\xC3\xA8\xC3\xA9\xC3\xAA\xC3\xAB"
1431 "\xC3\xAC\xC3\xAD\xC3\xAE\xC3\xAF"
1432 "\xC3\xB0\xC3\xB1\xC3\xB2\xC3\xB3"
1433 "\xC3\xB4\xC3\xB5\xC3\xB6\xC3\xB7"
1434 "\xC3\xB8\xC3\xB9\xC3\xBA\xC3\xBB"
1435 "\xC3\xBC\xC3\xBD\xC3\xBE\xC3\xBF";
1436 const uint8_t expected[] = {
1437 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB,
1438 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7,
1439 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3,
1440 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF,
1441 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB,
1442 0xDC, 0xDD, 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7,
1443 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3,
1444 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF,
1445 };
1446 const String& str = String::Handle(String::New(src));
1447 EXPECT(str.IsOneByteString());
1448 intptr_t expected_length = sizeof(expected);
1449 EXPECT_EQ(expected_length, str.Length());
1450 for (int i = 0; i < str.Length(); ++i) {
1451 EXPECT_EQ(expected[i], str.CharAt(i));
1452 }
1453 }
1454
1455 // Create a 2-byte string from a UTF-8 encoded string literal.
1456 {
1457 const char* src =
1458 "\xD7\x92\xD7\x9C\xD7\xA2\xD7\x93"
1459 "\xD7\x91\xD7\xA8\xD7\x9B\xD7\x94";
1460 const uint16_t expected[] = {0x5D2, 0x5DC, 0x5E2, 0x5D3,
1461 0x5D1, 0x5E8, 0x5DB, 0x5D4};
1462 const String& str = String::Handle(String::New(src));
1463 EXPECT(str.IsTwoByteString());
1464 intptr_t expected_size = sizeof(expected) / sizeof(expected[0]);
1465 EXPECT_EQ(expected_size, str.Length());
1466 for (int i = 0; i < str.Length(); ++i) {
1467 EXPECT_EQ(expected[i], str.CharAt(i));
1468 }
1469 }
1470
1471 // Create a BMP 2-byte string from UTF-8 encoded 1- and 2-byte
1472 // characters.
1473 {
1474 const char* src =
1475 "\x0A\x0B\x0D\x0C\x0E\x0F\xC2\xA0"
1476 "\xC2\xB0\xC3\x80\xC3\x90\xC3\xA0"
1477 "\xC3\xB0\xE0\xA8\x80\xE0\xAC\x80"
1478 "\xE0\xB0\x80\xE0\xB4\x80\xE0\xB8"
1479 "\x80\xE0\xBC\x80\xEA\x80\x80\xEB"
1480 "\x80\x80\xEC\x80\x80\xED\x80\x80"
1481 "\xEE\x80\x80\xEF\x80\x80";
1482 const intptr_t expected[] = {
1483 0x000A, 0x000B, 0x000D, 0x000C, 0x000E, 0x000F, 0x00A0, 0x00B0,
1484 0x00C0, 0x00D0, 0x00E0, 0x00F0, 0x0A00, 0x0B00, 0x0C00, 0x0D00,
1485 0x0E00, 0x0F00, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000};
1486 const String& str = String::Handle(String::New(src));
1487 EXPECT(str.IsTwoByteString());
1488 intptr_t expected_size = sizeof(expected) / sizeof(expected[0]);
1489 EXPECT_EQ(expected_size, str.Length());
1490 for (int i = 0; i < str.Length(); ++i) {
1491 EXPECT_EQ(expected[i], str.CharAt(i));
1492 }
1493 }
1494
1495 // Create a 2-byte string with supplementary characters from a UTF-8
1496 // string literal.
1497 {
1498 const char* src =
1499 "\xF0\x9D\x91\xA0\xF0\x9D\x91\xA1"
1500 "\xF0\x9D\x91\xA2\xF0\x9D\x91\xA3";
1501 const intptr_t expected[] = {0xd835, 0xdc60, 0xd835, 0xdc61,
1502 0xd835, 0xdc62, 0xd835, 0xdc63};
1503 const String& str = String::Handle(String::New(src));
1504 EXPECT(str.IsTwoByteString());
1505 intptr_t expected_size = (sizeof(expected) / sizeof(expected[0]));
1506 EXPECT_EQ(expected_size, str.Length());
1507 for (int i = 0; i < str.Length(); ++i) {
1508 EXPECT_EQ(expected[i], str.CharAt(i));
1509 }
1510 }
1511
1512 // Create a 2-byte string from UTF-8 encoded 2- and 4-byte
1513 // characters.
1514 {
1515 const char* src =
1516 "\xE0\xA8\x80\xE0\xAC\x80\xE0\xB0"
1517 "\x80\xE0\xB4\x80\xE0\xB8\x80\xE0"
1518 "\xBC\x80\xEA\x80\x80\xEB\x80\x80"
1519 "\xEC\x80\x80\xED\x80\x80\xEE\x80"
1520 "\x80\xEF\x80\x80\xF0\x9A\x80\x80"
1521 "\xF0\x9B\x80\x80\xF0\x9D\x80\x80"
1522 "\xF0\x9E\x80\x80\xF0\x9F\x80\x80";
1523 const intptr_t expected[] = {
1524 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, 0x0F00, 0xA000, 0xB000,
1525 0xC000, 0xD000, 0xE000, 0xF000, 0xD828, 0xDC00, 0xD82c, 0xDC00,
1526 0xD834, 0xDC00, 0xD838, 0xDC00, 0xD83c, 0xDC00,
1527 };
1528 const String& str = String::Handle(String::New(src));
1529 EXPECT(str.IsTwoByteString());
1530 intptr_t expected_size = sizeof(expected) / sizeof(expected[0]);
1531 EXPECT_EQ(expected_size, str.Length());
1532 for (int i = 0; i < str.Length(); ++i) {
1533 EXPECT_EQ(expected[i], str.CharAt(i));
1534 }
1535 }
1536
1537 // Create a 2-byte string from UTF-8 encoded 1-, 2- and 4-byte
1538 // characters.
1539 {
1540 const char* src =
1541 "\x0A\x0B\x0D\x0C\x0E\x0F\xC2\xA0"
1542 "\xC2\xB0\xC3\x80\xC3\x90\xC3\xA0"
1543 "\xC3\xB0\xE0\xA8\x80\xE0\xAC\x80"
1544 "\xE0\xB0\x80\xE0\xB4\x80\xE0\xB8"
1545 "\x80\xE0\xBC\x80\xEA\x80\x80\xEB"
1546 "\x80\x80\xEC\x80\x80\xED\x80\x80"
1547 "\xEE\x80\x80\xEF\x80\x80\xF0\x9A"
1548 "\x80\x80\xF0\x9B\x80\x80\xF0\x9D"
1549 "\x80\x80\xF0\x9E\x80\x80\xF0\x9F"
1550 "\x80\x80";
1551 const intptr_t expected[] = {
1552 0x000A, 0x000B, 0x000D, 0x000C, 0x000E, 0x000F, 0x00A0, 0x00B0, 0x00C0,
1553 0x00D0, 0x00E0, 0x00F0, 0x0A00, 0x0B00, 0x0C00, 0x0D00, 0x0E00, 0x0F00,
1554 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0xD828, 0xDC00, 0xD82c,
1555 0xDC00, 0xD834, 0xDC00, 0xD838, 0xDC00, 0xD83c, 0xDC00,
1556 };
1557 const String& str = String::Handle(String::New(src));
1558 EXPECT(str.IsTwoByteString());
1559 intptr_t expected_size = sizeof(expected) / sizeof(expected[0]);
1560 EXPECT_EQ(expected_size, str.Length());
1561 for (int i = 0; i < str.Length(); ++i) {
1562 EXPECT_EQ(expected[i], str.CharAt(i));
1563 }
1564 }
1565}
1566
1567ISOLATE_UNIT_TEST_CASE(StringEqualsUtf8) {
1568 const char* onesrc = "abc";
1569 const String& onestr = String::Handle(String::New(onesrc));
1570 EXPECT(onestr.IsOneByteString());
1571 EXPECT(!onestr.Equals(""));
1572 EXPECT(!onestr.Equals("a"));
1573 EXPECT(!onestr.Equals("ab"));
1574 EXPECT(onestr.Equals("abc"));
1575 EXPECT(!onestr.Equals("abcd"));
1576
1577 const char* twosrc = "\xD7\x90\xD7\x91\xD7\x92";
1578 const String& twostr = String::Handle(String::New(twosrc));
1579 EXPECT(twostr.IsTwoByteString());
1580 EXPECT(!twostr.Equals(""));
1581 EXPECT(!twostr.Equals("\xD7\x90"));
1582 EXPECT(!twostr.Equals("\xD7\x90\xD7\x91"));
1583 EXPECT(twostr.Equals("\xD7\x90\xD7\x91\xD7\x92"));
1584 EXPECT(!twostr.Equals("\xD7\x90\xD7\x91\xD7\x92\xD7\x93"));
1585
1586 const char* foursrc = "\xF0\x90\x8E\xA0\xF0\x90\x8E\xA1\xF0\x90\x8E\xA2";
1587 const String& fourstr = String::Handle(String::New(foursrc));
1588 EXPECT(fourstr.IsTwoByteString());
1589 EXPECT(!fourstr.Equals(""));
1590 EXPECT(!fourstr.Equals("\xF0\x90\x8E\xA0"));
1591 EXPECT(!fourstr.Equals("\xF0\x90\x8E\xA0\xF0\x90\x8E\xA1"));
1592 EXPECT(fourstr.Equals("\xF0\x90\x8E\xA0\xF0\x90\x8E\xA1\xF0\x90\x8E\xA2"));
1593 EXPECT(
1594 !fourstr.Equals("\xF0\x90\x8E\xA0\xF0\x90\x8E\xA1"
1595 "\xF0\x90\x8E\xA2\xF0\x90\x8E\xA3"));
1596}
1597
1598ISOLATE_UNIT_TEST_CASE(StringEqualsUTF32) {
1599 const String& empty = String::Handle(String::New(""));
1600 const String& t_str = String::Handle(String::New("t"));
1601 const String& th_str = String::Handle(String::New("th"));
1602 const int32_t chars[] = {'t', 'h', 'i', 's'};
1603 EXPECT(!empty.Equals(chars, -1));
1604 EXPECT(empty.Equals(chars, 0));
1605 EXPECT(!empty.Equals(chars, 1));
1606 EXPECT(!t_str.Equals(chars, 0));
1607 EXPECT(t_str.Equals(chars, 1));
1608 EXPECT(!t_str.Equals(chars, 2));
1609 EXPECT(!th_str.Equals(chars, 1));
1610 EXPECT(th_str.Equals(chars, 2));
1611 EXPECT(!th_str.Equals(chars, 3));
1612}
1613
1614static void NoopFinalizer(void* isolate_callback_data,
1615 Dart_WeakPersistentHandle handle,
1616 void* peer) {}
1617
1618ISOLATE_UNIT_TEST_CASE(ExternalOneByteString) {
1619 uint8_t characters[] = {0xF6, 0xF1, 0xE9};
1620 intptr_t len = ARRAY_SIZE(characters);
1621
1622 const String& str = String::Handle(ExternalOneByteString::New(
1623 characters, len, NULL, 0, NoopFinalizer, Heap::kNew));
1624 EXPECT(!str.IsOneByteString());
1625 EXPECT(str.IsExternalOneByteString());
1626 EXPECT_EQ(str.Length(), len);
1627 EXPECT(str.Equals("\xC3\xB6\xC3\xB1\xC3\xA9"));
1628
1629 const String& copy = String::Handle(String::SubString(str, 0, len));
1630 EXPECT(!copy.IsExternalOneByteString());
1631 EXPECT(copy.IsOneByteString());
1632 EXPECT_EQ(len, copy.Length());
1633 EXPECT(copy.Equals(str));
1634
1635 const String& concat = String::Handle(String::Concat(str, str));
1636 EXPECT(!concat.IsExternalOneByteString());
1637 EXPECT(concat.IsOneByteString());
1638 EXPECT_EQ(len * 2, concat.Length());
1639 EXPECT(concat.Equals("\xC3\xB6\xC3\xB1\xC3\xA9\xC3\xB6\xC3\xB1\xC3\xA9"));
1640
1641 const String& substr = String::Handle(String::SubString(str, 1, 1));
1642 EXPECT(!substr.IsExternalOneByteString());
1643 EXPECT(substr.IsOneByteString());
1644 EXPECT_EQ(1, substr.Length());
1645 EXPECT(substr.Equals("\xC3\xB1"));
1646}
1647
1648ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersOneByteString) {
1649 uint8_t characters[] = {'a', '\n', '\f', '\b', '\t',
1650 '\v', '\r', '\\', '$', 'z'};
1651 intptr_t len = ARRAY_SIZE(characters);
1652
1653 const String& str =
1654 String::Handle(OneByteString::New(characters, len, Heap::kNew));
1655 EXPECT(str.IsOneByteString());
1656 EXPECT_EQ(str.Length(), len);
1657 EXPECT(str.Equals("a\n\f\b\t\v\r\\$z"));
1658 const String& escaped_str =
1659 String::Handle(String::EscapeSpecialCharacters(str));
1660 EXPECT(escaped_str.Equals("a\\n\\f\\b\\t\\v\\r\\\\\\$z"));
1661
1662 const String& escaped_empty_str =
1663 String::Handle(String::EscapeSpecialCharacters(Symbols::Empty()));
1664 EXPECT_EQ(escaped_empty_str.Length(), 0);
1665}
1666
1667ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersExternalOneByteString) {
1668 uint8_t characters[] = {'a', '\n', '\f', '\b', '\t',
1669 '\v', '\r', '\\', '$', 'z'};
1670 intptr_t len = ARRAY_SIZE(characters);
1671
1672 const String& str = String::Handle(ExternalOneByteString::New(
1673 characters, len, NULL, 0, NoopFinalizer, Heap::kNew));
1674 EXPECT(!str.IsOneByteString());
1675 EXPECT(str.IsExternalOneByteString());
1676 EXPECT_EQ(str.Length(), len);
1677 EXPECT(str.Equals("a\n\f\b\t\v\r\\$z"));
1678 const String& escaped_str =
1679 String::Handle(String::EscapeSpecialCharacters(str));
1680 EXPECT(escaped_str.Equals("a\\n\\f\\b\\t\\v\\r\\\\\\$z"));
1681
1682 const String& empty_str = String::Handle(ExternalOneByteString::New(
1683 characters, 0, NULL, 0, NoopFinalizer, Heap::kNew));
1684 const String& escaped_empty_str =
1685 String::Handle(String::EscapeSpecialCharacters(empty_str));
1686 EXPECT_EQ(empty_str.Length(), 0);
1687 EXPECT_EQ(escaped_empty_str.Length(), 0);
1688}
1689
1690ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersTwoByteString) {
1691 uint16_t characters[] = {'a', '\n', '\f', '\b', '\t',
1692 '\v', '\r', '\\', '$', 'z'};
1693 intptr_t len = ARRAY_SIZE(characters);
1694
1695 const String& str =
1696 String::Handle(TwoByteString::New(characters, len, Heap::kNew));
1697 EXPECT(str.IsTwoByteString());
1698 EXPECT_EQ(str.Length(), len);
1699 EXPECT(str.Equals("a\n\f\b\t\v\r\\$z"));
1700 const String& escaped_str =
1701 String::Handle(String::EscapeSpecialCharacters(str));
1702 EXPECT(escaped_str.Equals("a\\n\\f\\b\\t\\v\\r\\\\\\$z"));
1703
1704 const String& empty_str =
1705 String::Handle(TwoByteString::New(static_cast<intptr_t>(0), Heap::kNew));
1706 const String& escaped_empty_str =
1707 String::Handle(String::EscapeSpecialCharacters(empty_str));
1708 EXPECT_EQ(empty_str.Length(), 0);
1709 EXPECT_EQ(escaped_empty_str.Length(), 0);
1710}
1711
1712ISOLATE_UNIT_TEST_CASE(EscapeSpecialCharactersExternalTwoByteString) {
1713 uint16_t characters[] = {'a', '\n', '\f', '\b', '\t',
1714 '\v', '\r', '\\', '$', 'z'};
1715 intptr_t len = ARRAY_SIZE(characters);
1716
1717 const String& str = String::Handle(ExternalTwoByteString::New(
1718 characters, len, NULL, 0, NoopFinalizer, Heap::kNew));
1719 EXPECT(str.IsExternalTwoByteString());
1720 EXPECT_EQ(str.Length(), len);
1721 EXPECT(str.Equals("a\n\f\b\t\v\r\\$z"));
1722 const String& escaped_str =
1723 String::Handle(String::EscapeSpecialCharacters(str));
1724 EXPECT(escaped_str.Equals("a\\n\\f\\b\\t\\v\\r\\\\\\$z"));
1725
1726 const String& empty_str = String::Handle(ExternalTwoByteString::New(
1727 characters, 0, NULL, 0, NoopFinalizer, Heap::kNew));
1728 const String& escaped_empty_str =
1729 String::Handle(String::EscapeSpecialCharacters(empty_str));
1730 EXPECT_EQ(empty_str.Length(), 0);
1731 EXPECT_EQ(escaped_empty_str.Length(), 0);
1732}
1733
1734ISOLATE_UNIT_TEST_CASE(ExternalTwoByteString) {
1735 uint16_t characters[] = {0x1E6B, 0x1E85, 0x1E53};
1736 intptr_t len = ARRAY_SIZE(characters);
1737
1738 const String& str = String::Handle(ExternalTwoByteString::New(
1739 characters, len, NULL, 0, NoopFinalizer, Heap::kNew));
1740 EXPECT(!str.IsTwoByteString());
1741 EXPECT(str.IsExternalTwoByteString());
1742 EXPECT_EQ(str.Length(), len);
1743 EXPECT(str.Equals("\xE1\xB9\xAB\xE1\xBA\x85\xE1\xB9\x93"));
1744
1745 const String& copy = String::Handle(String::SubString(str, 0, len));
1746 EXPECT(!copy.IsExternalTwoByteString());
1747 EXPECT(copy.IsTwoByteString());
1748 EXPECT_EQ(len, copy.Length());
1749 EXPECT(copy.Equals(str));
1750
1751 const String& concat = String::Handle(String::Concat(str, str));
1752 EXPECT(!concat.IsExternalTwoByteString());
1753 EXPECT(concat.IsTwoByteString());
1754 EXPECT_EQ(len * 2, concat.Length());
1755 EXPECT(
1756 concat.Equals("\xE1\xB9\xAB\xE1\xBA\x85\xE1\xB9\x93"
1757 "\xE1\xB9\xAB\xE1\xBA\x85\xE1\xB9\x93"));
1758
1759 const String& substr = String::Handle(String::SubString(str, 1, 1));
1760 EXPECT(!substr.IsExternalTwoByteString());
1761 EXPECT(substr.IsTwoByteString());
1762 EXPECT_EQ(1, substr.Length());
1763 EXPECT(substr.Equals("\xE1\xBA\x85"));
1764}
1765
1766ISOLATE_UNIT_TEST_CASE(Symbol) {
1767 const String& one = String::Handle(Symbols::New(thread, "Eins"));
1768 EXPECT(one.IsSymbol());
1769 const String& two = String::Handle(Symbols::New(thread, "Zwei"));
1770 const String& three = String::Handle(Symbols::New(thread, "Drei"));
1771 const String& four = String::Handle(Symbols::New(thread, "Vier"));
1772 const String& five = String::Handle(Symbols::New(thread, "Fuenf"));
1773 const String& six = String::Handle(Symbols::New(thread, "Sechs"));
1774 const String& seven = String::Handle(Symbols::New(thread, "Sieben"));
1775 const String& eight = String::Handle(Symbols::New(thread, "Acht"));
1776 const String& nine = String::Handle(Symbols::New(thread, "Neun"));
1777 const String& ten = String::Handle(Symbols::New(thread, "Zehn"));
1778 String& eins = String::Handle(Symbols::New(thread, "Eins"));
1779 EXPECT_EQ(one.raw(), eins.raw());
1780 EXPECT(one.raw() != two.raw());
1781 EXPECT(two.Equals(String::Handle(String::New("Zwei"))));
1782 EXPECT_EQ(two.raw(), Symbols::New(thread, "Zwei"));
1783 EXPECT_EQ(three.raw(), Symbols::New(thread, "Drei"));
1784 EXPECT_EQ(four.raw(), Symbols::New(thread, "Vier"));
1785 EXPECT_EQ(five.raw(), Symbols::New(thread, "Fuenf"));
1786 EXPECT_EQ(six.raw(), Symbols::New(thread, "Sechs"));
1787 EXPECT_EQ(seven.raw(), Symbols::New(thread, "Sieben"));
1788 EXPECT_EQ(eight.raw(), Symbols::New(thread, "Acht"));
1789 EXPECT_EQ(nine.raw(), Symbols::New(thread, "Neun"));
1790 EXPECT_EQ(ten.raw(), Symbols::New(thread, "Zehn"));
1791
1792 // Make sure to cause symbol table overflow.
1793 for (int i = 0; i < 1024; i++) {
1794 char buf[256];
1795 Utils::SNPrint(buf, sizeof(buf), "%d", i);
1796 Symbols::New(thread, buf);
1797 }
1798 eins = Symbols::New(thread, "Eins");
1799 EXPECT_EQ(one.raw(), eins.raw());
1800 EXPECT_EQ(two.raw(), Symbols::New(thread, "Zwei"));
1801 EXPECT_EQ(three.raw(), Symbols::New(thread, "Drei"));
1802 EXPECT_EQ(four.raw(), Symbols::New(thread, "Vier"));
1803 EXPECT_EQ(five.raw(), Symbols::New(thread, "Fuenf"));
1804 EXPECT_EQ(six.raw(), Symbols::New(thread, "Sechs"));
1805 EXPECT_EQ(seven.raw(), Symbols::New(thread, "Sieben"));
1806 EXPECT_EQ(eight.raw(), Symbols::New(thread, "Acht"));
1807 EXPECT_EQ(nine.raw(), Symbols::New(thread, "Neun"));
1808 EXPECT_EQ(ten.raw(), Symbols::New(thread, "Zehn"));
1809
1810 // Symbols from Strings.
1811 eins = String::New("Eins");
1812 EXPECT(!eins.IsSymbol());
1813 String& ein_symbol = String::Handle(Symbols::New(thread, eins));
1814 EXPECT_EQ(one.raw(), ein_symbol.raw());
1815 EXPECT(one.raw() != eins.raw());
1816
1817 uint16_t char16[] = {'E', 'l', 'f'};
1818 String& elf1 = String::Handle(Symbols::FromUTF16(thread, char16, 3));
1819 int32_t char32[] = {'E', 'l', 'f'};
1820 String& elf2 = String::Handle(Symbols::FromUTF32(thread, char32, 3));
1821 EXPECT(elf1.IsSymbol());
1822 EXPECT(elf2.IsSymbol());
1823 EXPECT_EQ(elf1.raw(), Symbols::New(thread, "Elf"));
1824 EXPECT_EQ(elf2.raw(), Symbols::New(thread, "Elf"));
1825}
1826
1827ISOLATE_UNIT_TEST_CASE(SymbolUnicode) {
1828 uint16_t monkey_utf16[] = {0xd83d, 0xdc35}; // Unicode Monkey Face.
1829 String& monkey = String::Handle(Symbols::FromUTF16(thread, monkey_utf16, 2));
1830 EXPECT(monkey.IsSymbol());
1831 const char monkey_utf8[] = {'\xf0', '\x9f', '\x90', '\xb5', 0};
1832 EXPECT_EQ(monkey.raw(), Symbols::New(thread, monkey_utf8));
1833
1834 int32_t kMonkeyFace = 0x1f435;
1835 String& monkey2 = String::Handle(Symbols::FromCharCode(thread, kMonkeyFace));
1836 EXPECT_EQ(monkey.raw(), monkey2.raw());
1837
1838 // Unicode cat face with tears of joy.
1839 int32_t kCatFaceWithTearsOfJoy = 0x1f639;
1840 String& cat =
1841 String::Handle(Symbols::FromCharCode(thread, kCatFaceWithTearsOfJoy));
1842
1843 uint16_t cat_utf16[] = {0xd83d, 0xde39};
1844 String& cat2 = String::Handle(Symbols::FromUTF16(thread, cat_utf16, 2));
1845 EXPECT(cat2.IsSymbol());
1846 EXPECT_EQ(cat2.raw(), cat.raw());
1847}
1848
1849ISOLATE_UNIT_TEST_CASE(Bool) {
1850 EXPECT(Bool::True().value());
1851 EXPECT(!Bool::False().value());
1852}
1853
1854ISOLATE_UNIT_TEST_CASE(Array) {
1855 const int kArrayLen = 5;
1856 const Array& array = Array::Handle(Array::New(kArrayLen));
1857 EXPECT_EQ(kArrayLen, array.Length());
1858 Object& element = Object::Handle(array.At(0));
1859 EXPECT(element.IsNull());
1860 element = array.At(kArrayLen - 1);
1861 EXPECT(element.IsNull());
1862 array.SetAt(0, array);
1863 array.SetAt(2, array);
1864 element = array.At(0);
1865 EXPECT_EQ(array.raw(), element.raw());
1866 element = array.At(1);
1867 EXPECT(element.IsNull());
1868 element = array.At(2);
1869 EXPECT_EQ(array.raw(), element.raw());
1870
1871 Array& other_array = Array::Handle(Array::New(kArrayLen));
1872 other_array.SetAt(0, array);
1873 other_array.SetAt(2, array);
1874
1875 EXPECT(array.CanonicalizeEquals(array));
1876 EXPECT(array.CanonicalizeEquals(other_array));
1877
1878 other_array.SetAt(1, other_array);
1879 EXPECT(!array.CanonicalizeEquals(other_array));
1880
1881 other_array = Array::New(kArrayLen - 1);
1882 other_array.SetAt(0, array);
1883 other_array.SetAt(2, array);
1884 EXPECT(!array.CanonicalizeEquals(other_array));
1885
1886 EXPECT_EQ(0, Object::empty_array().Length());
1887
1888 EXPECT_EQ(1, Object::zero_array().Length());
1889 element = Object::zero_array().At(0);
1890 EXPECT(Smi::Cast(element).IsZero());
1891
1892 array.MakeImmutable();
1893 Object& obj = Object::Handle(array.raw());
1894 EXPECT(obj.IsArray());
1895}
1896
1897static void TestIllegalArrayLength(intptr_t length) {
1898 char buffer[1024];
1899 Utils::SNPrint(buffer, sizeof(buffer),
1900 "main() {\n"
1901 " List.filled(%" Pd
1902 ", null);\n"
1903 "}\n",
1904 length);
1905 Dart_Handle lib = TestCase::LoadTestScript(buffer, NULL);
1906 EXPECT_VALID(lib);
1907 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
1908 Utils::SNPrint(buffer, sizeof(buffer),
1909 "Unhandled exception:\n"
1910 "RangeError (length): Invalid value: "
1911 "Not in inclusive range 0..%" Pd ": %" Pd,
1912 Array::kMaxElements, length);
1913 EXPECT_ERROR(result, buffer);
1914}
1915
1916TEST_CASE(ArrayLengthNegativeOne) {
1917 TestIllegalArrayLength(-1);
1918}
1919TEST_CASE(ArrayLengthSmiMin) {
1920 TestIllegalArrayLength(kSmiMin);
1921}
1922
1923TEST_CASE(ArrayLengthOneTooMany) {
1924 const intptr_t kOneTooMany = Array::kMaxElements + 1;
1925 ASSERT(kOneTooMany >= 0);
1926
1927 char buffer[1024];
1928 Utils::SNPrint(buffer, sizeof(buffer),
1929 "main() {\n"
1930 " return List.filled(%" Pd
1931 ", null);\n"
1932 "}\n",
1933 kOneTooMany);
1934 Dart_Handle lib = TestCase::LoadTestScript(buffer, NULL);
1935 EXPECT_VALID(lib);
1936 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
1937 EXPECT_ERROR(result, "Out of Memory");
1938}
1939
1940TEST_CASE(ArrayLengthMaxElements) {
1941 char buffer[1024];
1942 Utils::SNPrint(buffer, sizeof(buffer),
1943 "main() {\n"
1944 " return List.filled(%" Pd
1945 ", null);\n"
1946 "}\n",
1947 Array::kMaxElements);
1948 Dart_Handle lib = TestCase::LoadTestScript(buffer, NULL);
1949 EXPECT_VALID(lib);
1950 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
1951 if (Dart_IsError(result)) {
1952 EXPECT_ERROR(result, "Out of Memory");
1953 } else {
1954 const intptr_t kExpected = Array::kMaxElements;
1955 intptr_t actual = 0;
1956 EXPECT_VALID(Dart_ListLength(result, &actual));
1957 EXPECT_EQ(kExpected, actual);
1958 }
1959}
1960
1961static void TestIllegalTypedDataLength(const char* class_name,
1962 intptr_t length) {
1963 char buffer[1024];
1964 Utils::SNPrint(buffer, sizeof(buffer),
1965 "import 'dart:typed_data';\n"
1966 "main() {\n"
1967 " new %s(%" Pd
1968 ");\n"
1969 "}\n",
1970 class_name, length);
1971 Dart_Handle lib = TestCase::LoadTestScript(buffer, NULL);
1972 EXPECT_VALID(lib);
1973 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
1974 Utils::SNPrint(buffer, sizeof(buffer), "%" Pd, length);
1975 EXPECT_ERROR(result, "RangeError (length): Invalid value");
1976 EXPECT_ERROR(result, buffer);
1977}
1978
1979TEST_CASE(Int8ListLengthNegativeOne) {
1980 TestIllegalTypedDataLength("Int8List", -1);
1981}
1982TEST_CASE(Int8ListLengthSmiMin) {
1983 TestIllegalTypedDataLength("Int8List", kSmiMin);
1984}
1985TEST_CASE(Int8ListLengthOneTooMany) {
1986 const intptr_t kOneTooMany =
1987 TypedData::MaxElements(kTypedDataInt8ArrayCid) + 1;
1988 ASSERT(kOneTooMany >= 0);
1989
1990 char buffer[1024];
1991 Utils::SNPrint(buffer, sizeof(buffer),
1992 "import 'dart:typed_data';\n"
1993 "main() {\n"
1994 " return new Int8List(%" Pd
1995 ");\n"
1996 "}\n",
1997 kOneTooMany);
1998 Dart_Handle lib = TestCase::LoadTestScript(buffer, NULL);
1999 EXPECT_VALID(lib);
2000 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
2001 EXPECT_ERROR(result, "Out of Memory");
2002}
2003
2004TEST_CASE(Int8ListLengthMaxElements) {
2005 const intptr_t max_elements = TypedData::MaxElements(kTypedDataInt8ArrayCid);
2006 char buffer[1024];
2007 Utils::SNPrint(buffer, sizeof(buffer),
2008 "import 'dart:typed_data';\n"
2009 "main() {\n"
2010 " return new Int8List(%" Pd
2011 ");\n"
2012 "}\n",
2013 max_elements);
2014 Dart_Handle lib = TestCase::LoadTestScript(buffer, NULL);
2015 EXPECT_VALID(lib);
2016 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
2017 if (Dart_IsError(result)) {
2018 EXPECT_ERROR(result, "Out of Memory");
2019 } else {
2020 intptr_t actual = 0;
2021 EXPECT_VALID(Dart_ListLength(result, &actual));
2022 EXPECT_EQ(max_elements, actual);
2023 }
2024}
2025
2026ISOLATE_UNIT_TEST_CASE(StringCodePointIterator) {
2027 const String& str0 = String::Handle(String::New(""));
2028 String::CodePointIterator it0(str0);
2029 EXPECT(!it0.Next());
2030
2031 const String& str1 = String::Handle(String::New(" \xc3\xa7 "));
2032 String::CodePointIterator it1(str1);
2033 EXPECT(it1.Next());
2034 EXPECT_EQ(' ', it1.Current());
2035 EXPECT(it1.Next());
2036 EXPECT_EQ(0xE7, it1.Current());
2037 EXPECT(it1.Next());
2038 EXPECT_EQ(' ', it1.Current());
2039 EXPECT(!it1.Next());
2040
2041 const String& str2 =
2042 String::Handle(String::New("\xD7\x92\xD7\x9C"
2043 "\xD7\xA2\xD7\x93"
2044 "\xD7\x91\xD7\xA8"
2045 "\xD7\x9B\xD7\x94"));
2046 String::CodePointIterator it2(str2);
2047 EXPECT(it2.Next());
2048 EXPECT_EQ(0x5D2, it2.Current());
2049 EXPECT(it2.Next());
2050 EXPECT_EQ(0x5DC, it2.Current());
2051 EXPECT(it2.Next());
2052 EXPECT_EQ(0x5E2, it2.Current());
2053 EXPECT(it2.Next());
2054 EXPECT_EQ(0x5D3, it2.Current());
2055 EXPECT(it2.Next());
2056 EXPECT_EQ(0x5D1, it2.Current());
2057 EXPECT(it2.Next());
2058 EXPECT_EQ(0x5E8, it2.Current());
2059 EXPECT(it2.Next());
2060 EXPECT_EQ(0x5DB, it2.Current());
2061 EXPECT(it2.Next());
2062 EXPECT_EQ(0x5D4, it2.Current());
2063 EXPECT(!it2.Next());
2064
2065 const String& str3 =
2066 String::Handle(String::New("\xF0\x9D\x91\xA0"
2067 "\xF0\x9D\x91\xA1"
2068 "\xF0\x9D\x91\xA2"
2069 "\xF0\x9D\x91\xA3"));
2070 String::CodePointIterator it3(str3);
2071 EXPECT(it3.Next());
2072 EXPECT_EQ(0x1D460, it3.Current());
2073 EXPECT(it3.Next());
2074 EXPECT_EQ(0x1D461, it3.Current());
2075 EXPECT(it3.Next());
2076 EXPECT_EQ(0x1D462, it3.Current());
2077 EXPECT(it3.Next());
2078 EXPECT_EQ(0x1D463, it3.Current());
2079 EXPECT(!it3.Next());
2080}
2081
2082ISOLATE_UNIT_TEST_CASE(StringCodePointIteratorRange) {
2083 const String& str = String::Handle(String::New("foo bar baz"));
2084
2085 String::CodePointIterator it0(str, 3, 0);
2086 EXPECT(!it0.Next());
2087
2088 String::CodePointIterator it1(str, 4, 3);
2089 EXPECT(it1.Next());
2090 EXPECT_EQ('b', it1.Current());
2091 EXPECT(it1.Next());
2092 EXPECT_EQ('a', it1.Current());
2093 EXPECT(it1.Next());
2094 EXPECT_EQ('r', it1.Current());
2095 EXPECT(!it1.Next());
2096}
2097
2098ISOLATE_UNIT_TEST_CASE(GrowableObjectArray) {
2099 const int kArrayLen = 5;
2100 Smi& value = Smi::Handle();
2101 Smi& expected_value = Smi::Handle();
2102 GrowableObjectArray& array = GrowableObjectArray::Handle();
2103
2104 // Test basic growing functionality.
2105 array = GrowableObjectArray::New(kArrayLen);
2106 EXPECT_EQ(kArrayLen, array.Capacity());
2107 EXPECT_EQ(0, array.Length());
2108 for (intptr_t i = 0; i < 10; i++) {
2109 value = Smi::New(i);
2110 array.Add(value);
2111 }
2112 EXPECT_EQ(10, array.Length());
2113 for (intptr_t i = 0; i < 10; i++) {
2114 expected_value = Smi::New(i);
2115 value ^= array.At(i);
2116 EXPECT(value.Equals(expected_value));
2117 }
2118 for (intptr_t i = 0; i < 10; i++) {
2119 value = Smi::New(i * 10);
2120 array.SetAt(i, value);
2121 }
2122 EXPECT_EQ(10, array.Length());
2123 for (intptr_t i = 0; i < 10; i++) {
2124 expected_value = Smi::New(i * 10);
2125 value ^= array.At(i);
2126 EXPECT(value.Equals(expected_value));
2127 }
2128
2129 // Test the MakeFixedLength functionality to make sure the resulting array
2130 // object is properly setup.
2131 // 1. Should produce an array of length 2 and a left over int8 array.
2132 Array& new_array = Array::Handle();
2133 TypedData& left_over_array = TypedData::Handle();
2134 Object& obj = Object::Handle();
2135 uword addr = 0;
2136 intptr_t used_size = 0;
2137
2138 array = GrowableObjectArray::New(kArrayLen + 1);
2139 EXPECT_EQ(kArrayLen + 1, array.Capacity());
2140 EXPECT_EQ(0, array.Length());
2141 for (intptr_t i = 0; i < 2; i++) {
2142 value = Smi::New(i);
2143 array.Add(value);
2144 }
2145 used_size = Array::InstanceSize(array.Length());
2146 new_array = Array::MakeFixedLength(array);
2147 addr = ObjectLayout::ToAddr(new_array.raw());
2148 obj = ObjectLayout::FromAddr(addr);
2149 EXPECT(obj.IsArray());
2150 new_array ^= obj.raw();
2151 EXPECT_EQ(2, new_array.Length());
2152 addr += used_size;
2153 obj = ObjectLayout::FromAddr(addr);
2154 EXPECT(obj.IsTypedData());
2155 left_over_array ^= obj.raw();
2156 EXPECT_EQ(4 * kWordSize - TypedData::InstanceSize(0),
2157 left_over_array.Length());
2158
2159 // 2. Should produce an array of length 3 and a left over int8 array or
2160 // instance.
2161 array = GrowableObjectArray::New(kArrayLen);
2162 EXPECT_EQ(kArrayLen, array.Capacity());
2163 EXPECT_EQ(0, array.Length());
2164 for (intptr_t i = 0; i < 3; i++) {
2165 value = Smi::New(i);
2166 array.Add(value);
2167 }
2168 used_size = Array::InstanceSize(array.Length());
2169 new_array = Array::MakeFixedLength(array);
2170 addr = ObjectLayout::ToAddr(new_array.raw());
2171 obj = ObjectLayout::FromAddr(addr);
2172 EXPECT(obj.IsArray());
2173 new_array ^= obj.raw();
2174 EXPECT_EQ(3, new_array.Length());
2175 addr += used_size;
2176 obj = ObjectLayout::FromAddr(addr);
2177 if (TypedData::InstanceSize(0) <= 2 * kWordSize) {
2178 EXPECT(obj.IsTypedData());
2179 left_over_array ^= obj.raw();
2180 EXPECT_EQ(2 * kWordSize - TypedData::InstanceSize(0),
2181 left_over_array.Length());
2182 } else {
2183 EXPECT(obj.IsInstance());
2184 }
2185
2186 // 3. Should produce an array of length 1 and a left over int8 array.
2187 array = GrowableObjectArray::New(kArrayLen + 3);
2188 EXPECT_EQ((kArrayLen + 3), array.Capacity());
2189 EXPECT_EQ(0, array.Length());
2190 for (intptr_t i = 0; i < 1; i++) {
2191 value = Smi::New(i);
2192 array.Add(value);
2193 }
2194 used_size = Array::InstanceSize(array.Length());
2195 new_array = Array::MakeFixedLength(array);
2196 addr = ObjectLayout::ToAddr(new_array.raw());
2197 obj = ObjectLayout::FromAddr(addr);
2198 EXPECT(obj.IsArray());
2199 new_array ^= obj.raw();
2200 EXPECT_EQ(1, new_array.Length());
2201 addr += used_size;
2202 obj = ObjectLayout::FromAddr(addr);
2203 EXPECT(obj.IsTypedData());
2204 left_over_array ^= obj.raw();
2205 EXPECT_EQ(8 * kWordSize - TypedData::InstanceSize(0),
2206 left_over_array.Length());
2207
2208 // 4. Verify that GC can handle the filler object for a large array.
2209 array = GrowableObjectArray::New((1 * MB) >> kWordSizeLog2);
2210 EXPECT_EQ(0, array.Length());
2211 for (intptr_t i = 0; i < 1; i++) {
2212 value = Smi::New(i);
2213 array.Add(value);
2214 }
2215 Heap* heap = Isolate::Current()->heap();
2216 GCTestHelper::CollectAllGarbage();
2217 intptr_t capacity_before = heap->CapacityInWords(Heap::kOld);
2218 new_array = Array::MakeFixedLength(array);
2219 EXPECT_EQ(1, new_array.Length());
2220 GCTestHelper::CollectAllGarbage();
2221 intptr_t capacity_after = heap->CapacityInWords(Heap::kOld);
2222 // Page should shrink.
2223 EXPECT_LT(capacity_after, capacity_before);
2224 EXPECT_EQ(1, new_array.Length());
2225}
2226
2227ISOLATE_UNIT_TEST_CASE(InternalTypedData) {
2228 uint8_t data[] = {253, 254, 255, 0, 1, 2, 3, 4};
2229 intptr_t data_length = ARRAY_SIZE(data);
2230
2231 const TypedData& int8_array =
2232 TypedData::Handle(TypedData::New(kTypedDataInt8ArrayCid, data_length));
2233 EXPECT(!int8_array.IsNull());
2234 EXPECT_EQ(data_length, int8_array.Length());
2235 for (intptr_t i = 0; i < data_length; ++i) {
2236 int8_array.SetInt8(i, data[i]);
2237 }
2238
2239 EXPECT_EQ(-3, int8_array.GetInt8(0));
2240 EXPECT_EQ(253, int8_array.GetUint8(0));
2241
2242 EXPECT_EQ(-2, int8_array.GetInt8(1));
2243 EXPECT_EQ(254, int8_array.GetUint8(1));
2244
2245 EXPECT_EQ(-1, int8_array.GetInt8(2));
2246 EXPECT_EQ(255, int8_array.GetUint8(2));
2247
2248 EXPECT_EQ(0, int8_array.GetInt8(3));
2249 EXPECT_EQ(0, int8_array.GetUint8(3));
2250
2251 EXPECT_EQ(1, int8_array.GetInt8(4));
2252 EXPECT_EQ(1, int8_array.GetUint8(4));
2253
2254 EXPECT_EQ(2, int8_array.GetInt8(5));
2255 EXPECT_EQ(2, int8_array.GetUint8(5));
2256
2257 EXPECT_EQ(3, int8_array.GetInt8(6));
2258 EXPECT_EQ(3, int8_array.GetUint8(6));
2259
2260 EXPECT_EQ(4, int8_array.GetInt8(7));
2261 EXPECT_EQ(4, int8_array.GetUint8(7));
2262
2263 const TypedData& int8_array2 =
2264 TypedData::Handle(TypedData::New(kTypedDataInt8ArrayCid, data_length));
2265 EXPECT(!int8_array.IsNull());
2266 EXPECT_EQ(data_length, int8_array.Length());
2267 for (intptr_t i = 0; i < data_length; ++i) {
2268 int8_array2.SetInt8(i, data[i]);
2269 }
2270
2271 for (intptr_t i = 0; i < data_length; ++i) {
2272 EXPECT_EQ(int8_array.GetInt8(i), int8_array2.GetInt8(i));
2273 }
2274 for (intptr_t i = 0; i < data_length; ++i) {
2275 int8_array.SetInt8(i, 123 + i);
2276 }
2277 for (intptr_t i = 0; i < data_length; ++i) {
2278 EXPECT(int8_array.GetInt8(i) != int8_array2.GetInt8(i));
2279 }
2280}
2281
2282ISOLATE_UNIT_TEST_CASE(ExternalTypedData) {
2283 uint8_t data[] = {253, 254, 255, 0, 1, 2, 3, 4};
2284 intptr_t data_length = ARRAY_SIZE(data);
2285
2286 const ExternalTypedData& int8_array =
2287 ExternalTypedData::Handle(ExternalTypedData::New(
2288 kExternalTypedDataInt8ArrayCid, data, data_length));
2289 EXPECT(!int8_array.IsNull());
2290 EXPECT_EQ(data_length, int8_array.Length());
2291
2292 const ExternalTypedData& uint8_array =
2293 ExternalTypedData::Handle(ExternalTypedData::New(
2294 kExternalTypedDataUint8ArrayCid, data, data_length));
2295 EXPECT(!uint8_array.IsNull());
2296 EXPECT_EQ(data_length, uint8_array.Length());
2297
2298 const ExternalTypedData& uint8_clamped_array =
2299 ExternalTypedData::Handle(ExternalTypedData::New(
2300 kExternalTypedDataUint8ClampedArrayCid, data, data_length));
2301 EXPECT(!uint8_clamped_array.IsNull());
2302 EXPECT_EQ(data_length, uint8_clamped_array.Length());
2303
2304 EXPECT_EQ(-3, int8_array.GetInt8(0));
2305 EXPECT_EQ(253, uint8_array.GetUint8(0));
2306 EXPECT_EQ(253, uint8_clamped_array.GetUint8(0));
2307
2308 EXPECT_EQ(-2, int8_array.GetInt8(1));
2309 EXPECT_EQ(254, uint8_array.GetUint8(1));
2310 EXPECT_EQ(254, uint8_clamped_array.GetUint8(1));
2311
2312 EXPECT_EQ(-1, int8_array.GetInt8(2));
2313 EXPECT_EQ(255, uint8_array.GetUint8(2));
2314 EXPECT_EQ(255, uint8_clamped_array.GetUint8(2));
2315
2316 EXPECT_EQ(0, int8_array.GetInt8(3));
2317 EXPECT_EQ(0, uint8_array.GetUint8(3));
2318 EXPECT_EQ(0, uint8_clamped_array.GetUint8(3));
2319
2320 EXPECT_EQ(1, int8_array.GetInt8(4));
2321 EXPECT_EQ(1, uint8_array.GetUint8(4));
2322 EXPECT_EQ(1, uint8_clamped_array.GetUint8(4));
2323
2324 EXPECT_EQ(2, int8_array.GetInt8(5));
2325 EXPECT_EQ(2, uint8_array.GetUint8(5));
2326 EXPECT_EQ(2, uint8_clamped_array.GetUint8(5));
2327
2328 for (intptr_t i = 0; i < int8_array.Length(); ++i) {
2329 EXPECT_EQ(int8_array.GetUint8(i), uint8_array.GetUint8(i));
2330 }
2331
2332 int8_array.SetInt8(2, -123);
2333 uint8_array.SetUint8(0, 123);
2334 for (intptr_t i = 0; i < int8_array.Length(); ++i) {
2335 EXPECT_EQ(int8_array.GetInt8(i), uint8_array.GetInt8(i));
2336 }
2337
2338 uint8_clamped_array.SetUint8(0, 123);
2339 for (intptr_t i = 0; i < int8_array.Length(); ++i) {
2340 EXPECT_EQ(int8_array.GetUint8(i), uint8_clamped_array.GetUint8(i));
2341 }
2342}
2343
2344ISOLATE_UNIT_TEST_CASE(Script) {
2345 const char* url_chars = "builtin:test-case";
2346 const char* source_chars = "This will not compile.";
2347 const String& url = String::Handle(String::New(url_chars));
2348 const String& source = String::Handle(String::New(source_chars));
2349 const Script& script = Script::Handle(Script::New(url, source));
2350 EXPECT(!script.IsNull());
2351 EXPECT(script.IsScript());
2352 String& str = String::Handle(script.url());
2353 EXPECT_EQ(17, str.Length());
2354 EXPECT_EQ('b', str.CharAt(0));
2355 EXPECT_EQ(':', str.CharAt(7));
2356 EXPECT_EQ('e', str.CharAt(16));
2357 str = script.Source();
2358 EXPECT_EQ(22, str.Length());
2359 EXPECT_EQ('T', str.CharAt(0));
2360 EXPECT_EQ('n', str.CharAt(10));
2361 EXPECT_EQ('.', str.CharAt(21));
2362
2363 TransitionVMToNative transition(thread);
2364 const char* kScript = "main() {}";
2365 Dart_Handle h_lib = TestCase::LoadTestScript(kScript, NULL);
2366 EXPECT_VALID(h_lib);
2367 Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, NULL);
2368 EXPECT_VALID(result);
2369}
2370
2371ISOLATE_UNIT_TEST_CASE(Context) {
2372 const int kNumVariables = 5;
2373 const Context& parent_context = Context::Handle(Context::New(0));
2374 const Context& context = Context::Handle(Context::New(kNumVariables));
2375 context.set_parent(parent_context);
2376 EXPECT_EQ(kNumVariables, context.num_variables());
2377 EXPECT(Context::Handle(context.parent()).raw() == parent_context.raw());
2378 EXPECT_EQ(0, Context::Handle(context.parent()).num_variables());
2379 EXPECT(Context::Handle(Context::Handle(context.parent()).parent()).IsNull());
2380 Object& variable = Object::Handle(context.At(0));
2381 EXPECT(variable.IsNull());
2382 variable = context.At(kNumVariables - 1);
2383 EXPECT(variable.IsNull());
2384 context.SetAt(0, Smi::Handle(Smi::New(2)));
2385 context.SetAt(2, Smi::Handle(Smi::New(3)));
2386 Smi& smi = Smi::Handle();
2387 smi ^= context.At(0);
2388 EXPECT_EQ(2, smi.Value());
2389 smi ^= context.At(2);
2390 EXPECT_EQ(3, smi.Value());
2391}
2392
2393ISOLATE_UNIT_TEST_CASE(ContextScope) {
2394 // We need an active compiler context to manipulate scopes, since local
2395 // variables and slots can be canonicalized in the compiler state.
2396 CompilerState compiler_state(Thread::Current(), /*is_aot=*/false);
2397
2398 const intptr_t parent_scope_function_level = 0;
2399 LocalScope* parent_scope =
2400 new LocalScope(NULL, parent_scope_function_level, 0);
2401
2402 const intptr_t local_scope_function_level = 1;
2403 LocalScope* local_scope =
2404 new LocalScope(parent_scope, local_scope_function_level, 0);
2405
2406 const Type& dynamic_type = Type::ZoneHandle(Type::DynamicType());
2407 const String& ta = Symbols::FunctionTypeArgumentsVar();
2408 LocalVariable* var_ta = new LocalVariable(
2409 TokenPosition::kNoSource, TokenPosition::kNoSource, ta, dynamic_type);
2410 parent_scope->AddVariable(var_ta);
2411
2412 const String& a = String::ZoneHandle(Symbols::New(thread, "a"));
2413 LocalVariable* var_a = new LocalVariable(
2414 TokenPosition::kNoSource, TokenPosition::kNoSource, a, dynamic_type);
2415 parent_scope->AddVariable(var_a);
2416
2417 const String& b = String::ZoneHandle(Symbols::New(thread, "b"));
2418 LocalVariable* var_b = new LocalVariable(
2419 TokenPosition::kNoSource, TokenPosition::kNoSource, b, dynamic_type);
2420 local_scope->AddVariable(var_b);
2421
2422 const String& c = String::ZoneHandle(Symbols::New(thread, "c"));
2423 LocalVariable* var_c = new LocalVariable(
2424 TokenPosition::kNoSource, TokenPosition::kNoSource, c, dynamic_type);
2425 parent_scope->AddVariable(var_c);
2426
2427 bool test_only = false; // Please, insert alias.
2428 var_ta = local_scope->LookupVariable(ta, test_only);
2429 EXPECT(var_ta->is_captured());
2430 EXPECT_EQ(parent_scope_function_level, var_ta->owner()->function_level());
2431 EXPECT(local_scope->LocalLookupVariable(ta) == var_ta); // Alias.
2432
2433 var_a = local_scope->LookupVariable(a, test_only);
2434 EXPECT(var_a->is_captured());
2435 EXPECT_EQ(parent_scope_function_level, var_a->owner()->function_level());
2436 EXPECT(local_scope->LocalLookupVariable(a) == var_a); // Alias.
2437
2438 var_b = local_scope->LookupVariable(b, test_only);
2439 EXPECT(!var_b->is_captured());
2440 EXPECT_EQ(local_scope_function_level, var_b->owner()->function_level());
2441 EXPECT(local_scope->LocalLookupVariable(b) == var_b);
2442
2443 test_only = true; // Please, do not insert alias.
2444 var_c = local_scope->LookupVariable(c, test_only);
2445 EXPECT(!var_c->is_captured());
2446 EXPECT_EQ(parent_scope_function_level, var_c->owner()->function_level());
2447 // c is not in local_scope.
2448 EXPECT(local_scope->LocalLookupVariable(c) == NULL);
2449
2450 test_only = false; // Please, insert alias.
2451 var_c = local_scope->LookupVariable(c, test_only);
2452 EXPECT(var_c->is_captured());
2453
2454 EXPECT_EQ(4, local_scope->num_variables()); // ta, a, b, c.
2455 EXPECT_EQ(3, local_scope->NumCapturedVariables()); // ta, a, c.
2456
2457 const VariableIndex first_parameter_index(0);
2458 const int num_parameters = 0;
2459 const VariableIndex first_local_index(-1);
2460 bool found_captured_vars = false;
2461 VariableIndex next_index = parent_scope->AllocateVariables(
2462 first_parameter_index, num_parameters, first_local_index, NULL,
2463 &found_captured_vars);
2464 // Variables a, c and var_ta are captured, therefore are not allocated in
2465 // frame.
2466 EXPECT_EQ(0, next_index.value() -
2467 first_local_index.value()); // Indices in frame < 0.
2468 const intptr_t parent_scope_context_level = 1;
2469 EXPECT_EQ(parent_scope_context_level, parent_scope->context_level());
2470 EXPECT(found_captured_vars);
2471
2472 const intptr_t local_scope_context_level = 5;
2473 const ContextScope& context_scope = ContextScope::Handle(
2474 local_scope->PreserveOuterScope(local_scope_context_level));
2475 LocalScope* outer_scope = LocalScope::RestoreOuterScope(context_scope);
2476 EXPECT_EQ(3, outer_scope->num_variables());
2477
2478 var_ta = outer_scope->LocalLookupVariable(ta);
2479 EXPECT(var_ta->is_captured());
2480 EXPECT_EQ(0, var_ta->index().value()); // First index.
2481 EXPECT_EQ(parent_scope_context_level - local_scope_context_level,
2482 var_ta->owner()->context_level()); // Adjusted context level.
2483
2484 var_a = outer_scope->LocalLookupVariable(a);
2485 EXPECT(var_a->is_captured());
2486 EXPECT_EQ(1, var_a->index().value()); // First index.
2487 EXPECT_EQ(parent_scope_context_level - local_scope_context_level,
2488 var_a->owner()->context_level()); // Adjusted context level.
2489
2490 // var b was not captured.
2491 EXPECT(outer_scope->LocalLookupVariable(b) == NULL);
2492
2493 var_c = outer_scope->LocalLookupVariable(c);
2494 EXPECT(var_c->is_captured());
2495 EXPECT_EQ(2, var_c->index().value());
2496 EXPECT_EQ(parent_scope_context_level - local_scope_context_level,
2497 var_c->owner()->context_level()); // Adjusted context level.
2498}
2499
2500ISOLATE_UNIT_TEST_CASE(Closure) {
2501 // Allocate the class first.
2502 const String& class_name = String::Handle(Symbols::New(thread, "MyClass"));
2503 const Script& script = Script::Handle();
2504 const Class& cls = Class::Handle(CreateDummyClass(class_name, script));
2505 const Array& functions = Array::Handle(Array::New(1));
2506
2507 const Context& context = Context::Handle(Context::New(0));
2508 Function& parent = Function::Handle();
2509 const String& parent_name = String::Handle(Symbols::New(thread, "foo_papa"));
2510 parent =
2511 Function::New(parent_name, FunctionLayout::kRegularFunction, false, false,
2512 false, false, false, cls, TokenPosition::kMinSource);
2513 functions.SetAt(0, parent);
2514 cls.SetFunctions(functions);
2515
2516 Function& function = Function::Handle();
2517 const String& function_name = String::Handle(Symbols::New(thread, "foo"));
2518 function = Function::NewClosureFunction(function_name, parent,
2519 TokenPosition::kMinSource);
2520 const Closure& closure = Closure::Handle(
2521 Closure::New(Object::null_type_arguments(), Object::null_type_arguments(),
2522 function, context));
2523 const Class& closure_class = Class::Handle(closure.clazz());
2524 EXPECT_EQ(closure_class.id(), kClosureCid);
2525 const Function& closure_function = Function::Handle(closure.function());
2526 EXPECT_EQ(closure_function.raw(), function.raw());
2527 const Context& closure_context = Context::Handle(closure.context());
2528 EXPECT_EQ(closure_context.raw(), context.raw());
2529}
2530
2531ISOLATE_UNIT_TEST_CASE(ObjectPrinting) {
2532 // Simple Smis.
2533 EXPECT_STREQ("2", Smi::Handle(Smi::New(2)).ToCString());
2534 EXPECT_STREQ("-15", Smi::Handle(Smi::New(-15)).ToCString());
2535
2536 // bool class and true/false values.
2537 ObjectStore* object_store = Isolate::Current()->object_store();
2538 const Class& bool_class = Class::Handle(object_store->bool_class());
2539 EXPECT_STREQ("Library:'dart:core' Class: bool", bool_class.ToCString());
2540 EXPECT_STREQ("true", Bool::True().ToCString());
2541 EXPECT_STREQ("false", Bool::False().ToCString());
2542
2543 // Strings.
2544 EXPECT_STREQ("Sugarbowl",
2545 String::Handle(String::New("Sugarbowl")).ToCString());
2546}
2547
2548ISOLATE_UNIT_TEST_CASE(CheckedHandle) {
2549 // Ensure that null handles have the correct C++ vtable setup.
2550 Zone* zone = Thread::Current()->zone();
2551 const String& str1 = String::Handle(zone);
2552 EXPECT(str1.IsString());
2553 EXPECT(str1.IsNull());
2554 const String& str2 = String::CheckedHandle(zone, Object::null());
2555 EXPECT(str2.IsString());
2556 EXPECT(str2.IsNull());
2557 String& str3 = String::Handle(zone);
2558 str3 ^= Object::null();
2559 EXPECT(str3.IsString());
2560 EXPECT(str3.IsNull());
2561 EXPECT(!str3.IsOneByteString());
2562 str3 = String::New("Steep and Deep!");
2563 EXPECT(str3.IsString());
2564 EXPECT(str3.IsOneByteString());
2565 str3 = OneByteString::null();
2566 EXPECT(str3.IsString());
2567 EXPECT(!str3.IsOneByteString());
2568}
2569
2570static LibraryPtr CreateDummyLibrary(const String& library_name) {
2571 return Library::New(library_name);
2572}
2573
2574static FunctionPtr CreateFunction(const char* name) {
2575 Thread* thread = Thread::Current();
2576 const String& class_name = String::Handle(Symbols::New(thread, "ownerClass"));
2577 const String& lib_name = String::Handle(Symbols::New(thread, "ownerLibrary"));
2578 const Script& script = Script::Handle();
2579 const Class& owner_class =
2580 Class::Handle(CreateDummyClass(class_name, script));
2581 const Library& owner_library = Library::Handle(CreateDummyLibrary(lib_name));
2582 owner_class.set_library(owner_library);
2583 const String& function_name = String::ZoneHandle(Symbols::New(thread, name));
2584 return Function::New(function_name, FunctionLayout::kRegularFunction, true,
2585 false, false, false, false, owner_class,
2586 TokenPosition::kMinSource);
2587}
2588
2589// Test for Code and Instruction object creation.
2590ISOLATE_UNIT_TEST_CASE(Code) {
2591 extern void GenerateIncrement(compiler::Assembler * assembler);
2592 compiler::ObjectPoolBuilder object_pool_builder;
2593 compiler::Assembler _assembler_(&object_pool_builder);
2594 GenerateIncrement(&_assembler_);
2595 const Function& function = Function::Handle(CreateFunction("Test_Code"));
2596 Code& code = Code::Handle(Code::FinalizeCodeAndNotify(
2597 function, nullptr, &_assembler_, Code::PoolAttachment::kAttachPool));
2598 function.AttachCode(code);
2599 const Instructions& instructions = Instructions::Handle(code.instructions());
2600 uword payload_start = instructions.PayloadStart();
2601 EXPECT_EQ(instructions.raw(), Instructions::FromPayloadStart(payload_start));
2602 const Object& result =
2603 Object::Handle(DartEntry::InvokeFunction(function, Array::empty_array()));
2604 EXPECT_EQ(1, Smi::Cast(result).Value());
2605}
2606
2607// Test for immutability of generated instructions. The test crashes with a
2608// segmentation fault when writing into it.
2609ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION(CodeImmutability, "Crash") {
2610 bool stack_trace_collection_enabled =
2611 MallocHooks::stack_trace_collection_enabled();
2612 MallocHooks::set_stack_trace_collection_enabled(false);
2613 extern void GenerateIncrement(compiler::Assembler * assembler);
2614 compiler::ObjectPoolBuilder object_pool_builder;
2615 compiler::Assembler _assembler_(&object_pool_builder);
2616 GenerateIncrement(&_assembler_);
2617 const Function& function = Function::Handle(CreateFunction("Test_Code"));
2618 Code& code = Code::Handle(Code::FinalizeCodeAndNotify(
2619 function, nullptr, &_assembler_, Code::PoolAttachment::kAttachPool));
2620 function.AttachCode(code);
2621 Instructions& instructions = Instructions::Handle(code.instructions());
2622 uword payload_start = instructions.PayloadStart();
2623 EXPECT_EQ(instructions.raw(), Instructions::FromPayloadStart(payload_start));
2624 // Try writing into the generated code, expected to crash.
2625 *(reinterpret_cast<char*>(payload_start) + 1) = 1;
2626 if (!FLAG_write_protect_code) {
2627 // Since this test is expected to crash, crash if write protection of code
2628 // is switched off.
2629 FATAL("Test requires --write-protect-code; skip by forcing expected crash");
2630 }
2631 MallocHooks::set_stack_trace_collection_enabled(
2632 stack_trace_collection_enabled);
2633}
2634
2635class CodeTestHelper {
2636 public:
2637 static void SetInstructions(const Code& code,
2638 const Instructions& instructions,
2639 uword unchecked_offset) {
2640 code.SetActiveInstructions(instructions, unchecked_offset);
2641 code.set_instructions(instructions);
2642 }
2643};
2644
2645// Test for executability of generated instructions. The test crashes with a
2646// segmentation fault when executing the writeable view.
2647ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION(CodeExecutability, "Crash") {
2648 bool stack_trace_collection_enabled =
2649 MallocHooks::stack_trace_collection_enabled();
2650 MallocHooks::set_stack_trace_collection_enabled(false);
2651 extern void GenerateIncrement(compiler::Assembler * assembler);
2652 compiler::ObjectPoolBuilder object_pool_builder;
2653 compiler::Assembler _assembler_(&object_pool_builder);
2654 GenerateIncrement(&_assembler_);
2655 const Function& function = Function::Handle(CreateFunction("Test_Code"));
2656 Code& code = Code::Handle(Code::FinalizeCodeAndNotify(
2657 function, nullptr, &_assembler_, Code::PoolAttachment::kAttachPool));
2658 function.AttachCode(code);
2659 Instructions& instructions = Instructions::Handle(code.instructions());
2660 uword payload_start = code.PayloadStart();
2661 const uword unchecked_offset = code.UncheckedEntryPoint() - code.EntryPoint();
2662 EXPECT_EQ(instructions.raw(), Instructions::FromPayloadStart(payload_start));
2663 // Execute the executable view of the instructions (default).
2664 Object& result =
2665 Object::Handle(DartEntry::InvokeFunction(function, Array::empty_array()));
2666 EXPECT_EQ(1, Smi::Cast(result).Value());
2667 // Switch to the writeable but non-executable view of the instructions.
2668 instructions ^= OldPage::ToWritable(instructions.raw());
2669 payload_start = instructions.PayloadStart();
2670 EXPECT_EQ(instructions.raw(), Instructions::FromPayloadStart(payload_start));
2671 // Hook up Code and Instructions objects.
2672 CodeTestHelper::SetInstructions(code, instructions, unchecked_offset);
2673 function.AttachCode(code);
2674 // Try executing the generated code, expected to crash.
2675 result = DartEntry::InvokeFunction(function, Array::empty_array());
2676 EXPECT_EQ(1, Smi::Cast(result).Value());
2677 if (!FLAG_dual_map_code) {
2678 // Since this test is expected to crash, crash if dual mapping of code
2679 // is switched off.
2680 FATAL("Test requires --dual-map-code; skip by forcing expected crash");
2681 }
2682 MallocHooks::set_stack_trace_collection_enabled(
2683 stack_trace_collection_enabled);
2684}
2685
2686// Test for Embedded String object in the instructions.
2687ISOLATE_UNIT_TEST_CASE(EmbedStringInCode) {
2688 extern void GenerateEmbedStringInCode(compiler::Assembler * assembler,
2689 const char* str);
2690 const char* kHello = "Hello World!";
2691 word expected_length = static_cast<word>(strlen(kHello));
2692 compiler::ObjectPoolBuilder object_pool_builder;
2693 compiler::Assembler _assembler_(&object_pool_builder);
2694 GenerateEmbedStringInCode(&_assembler_, kHello);
2695 const Function& function =
2696 Function::Handle(CreateFunction("Test_EmbedStringInCode"));
2697 const Code& code = Code::Handle(Code::FinalizeCodeAndNotify(
2698 function, nullptr, &_assembler_, Code::PoolAttachment::kAttachPool));
2699 function.AttachCode(code);
2700 const Object& result =
2701 Object::Handle(DartEntry::InvokeFunction(function, Array::empty_array()));
2702 EXPECT(result.raw()->IsHeapObject());
2703 String& string_object = String::Handle();
2704 string_object ^= result.raw();
2705 EXPECT(string_object.Length() == expected_length);
2706 for (int i = 0; i < expected_length; i++) {
2707 EXPECT(string_object.CharAt(i) == kHello[i]);
2708 }
2709}
2710
2711// Test for Embedded Smi object in the instructions.
2712ISOLATE_UNIT_TEST_CASE(EmbedSmiInCode) {
2713 extern void GenerateEmbedSmiInCode(compiler::Assembler * assembler,
2714 intptr_t value);
2715 const intptr_t kSmiTestValue = 5;
2716 compiler::ObjectPoolBuilder object_pool_builder;
2717 compiler::Assembler _assembler_(&object_pool_builder);
2718 GenerateEmbedSmiInCode(&_assembler_, kSmiTestValue);
2719 const Function& function =
2720 Function::Handle(CreateFunction("Test_EmbedSmiInCode"));
2721 const Code& code = Code::Handle(Code::FinalizeCodeAndNotify(
2722 function, nullptr, &_assembler_, Code::PoolAttachment::kAttachPool));
2723 function.AttachCode(code);
2724 const Object& result =
2725 Object::Handle(DartEntry::InvokeFunction(function, Array::empty_array()));
2726 EXPECT(Smi::Cast(result).Value() == kSmiTestValue);
2727}
2728
2729#if defined(ARCH_IS_64_BIT)
2730// Test for Embedded Smi object in the instructions.
2731ISOLATE_UNIT_TEST_CASE(EmbedSmiIn64BitCode) {
2732 extern void GenerateEmbedSmiInCode(compiler::Assembler * assembler,
2733 intptr_t value);
2734 const intptr_t kSmiTestValue = DART_INT64_C(5) << 32;
2735 compiler::ObjectPoolBuilder object_pool_builder;
2736 compiler::Assembler _assembler_(&object_pool_builder);
2737 GenerateEmbedSmiInCode(&_assembler_, kSmiTestValue);
2738 const Function& function =
2739 Function::Handle(CreateFunction("Test_EmbedSmiIn64BitCode"));
2740 const Code& code = Code::Handle(Code::FinalizeCodeAndNotify(
2741 function, nullptr, &_assembler_, Code::PoolAttachment::kAttachPool));
2742 function.AttachCode(code);
2743 const Object& result =
2744 Object::Handle(DartEntry::InvokeFunction(function, Array::empty_array()));
2745 EXPECT(Smi::Cast(result).Value() == kSmiTestValue);
2746}
2747#endif // ARCH_IS_64_BIT
2748
2749ISOLATE_UNIT_TEST_CASE(ExceptionHandlers) {
2750 const int kNumEntries = 4;
2751 // Add an exception handler table to the code.
2752 ExceptionHandlers& exception_handlers = ExceptionHandlers::Handle();
2753 exception_handlers ^= ExceptionHandlers::New(kNumEntries);
2754 const bool kNeedsStackTrace = true;
2755 const bool kNoStackTrace = false;
2756 exception_handlers.SetHandlerInfo(0, -1, 20u, kNeedsStackTrace, false, true);
2757 exception_handlers.SetHandlerInfo(1, 0, 30u, kNeedsStackTrace, false, true);
2758 exception_handlers.SetHandlerInfo(2, -1, 40u, kNoStackTrace, true, true);
2759 exception_handlers.SetHandlerInfo(3, 1, 150u, kNoStackTrace, true, true);
2760
2761 extern void GenerateIncrement(compiler::Assembler * assembler);
2762 compiler::ObjectPoolBuilder object_pool_builder;
2763 compiler::Assembler _assembler_(&object_pool_builder);
2764 GenerateIncrement(&_assembler_);
2765 Code& code = Code::Handle(Code::FinalizeCodeAndNotify(
2766 Function::Handle(CreateFunction("Test_Code")), nullptr, &_assembler_,
2767 Code::PoolAttachment::kAttachPool));
2768 code.set_exception_handlers(exception_handlers);
2769
2770 // Verify the exception handler table entries by accessing them.
2771 const ExceptionHandlers& handlers =
2772 ExceptionHandlers::Handle(code.exception_handlers());
2773 EXPECT_EQ(kNumEntries, handlers.num_entries());
2774 ExceptionHandlerInfo info;
2775 handlers.GetHandlerInfo(0, &info);
2776 EXPECT_EQ(-1, handlers.OuterTryIndex(0));
2777 EXPECT_EQ(-1, info.outer_try_index);
2778 EXPECT_EQ(20u, handlers.HandlerPCOffset(0));
2779 EXPECT(handlers.NeedsStackTrace(0));
2780 EXPECT(!handlers.HasCatchAll(0));
2781 EXPECT_EQ(20u, info.handler_pc_offset);
2782 EXPECT_EQ(1, handlers.OuterTryIndex(3));
2783 EXPECT_EQ(150u, handlers.HandlerPCOffset(3));
2784 EXPECT(!handlers.NeedsStackTrace(3));
2785 EXPECT(handlers.HasCatchAll(3));
2786}
2787
2788ISOLATE_UNIT_TEST_CASE(PcDescriptors) {
2789 DescriptorList* builder = new DescriptorList(0);
2790
2791 // kind, pc_offset, deopt_id, token_pos, try_index, yield_index
2792 builder->AddDescriptor(PcDescriptorsLayout::kOther, 10, 1, TokenPosition(20),
2793 1, 1);
2794 builder->AddDescriptor(PcDescriptorsLayout::kDeopt, 20, 2, TokenPosition(30),
2795 0, -1);
2796 builder->AddDescriptor(PcDescriptorsLayout::kOther, 30, 3, TokenPosition(40),
2797 1, 10);
2798 builder->AddDescriptor(PcDescriptorsLayout::kOther, 10, 4, TokenPosition(40),
2799 2, 20);
2800 builder->AddDescriptor(PcDescriptorsLayout::kOther, 10, 5, TokenPosition(80),
2801 3, 30);
2802 builder->AddDescriptor(PcDescriptorsLayout::kOther, 80, 6, TokenPosition(150),
2803 3, 30);
2804
2805 PcDescriptors& descriptors = PcDescriptors::Handle();
2806 descriptors ^= builder->FinalizePcDescriptors(0);
2807
2808 extern void GenerateIncrement(compiler::Assembler * assembler);
2809 compiler::ObjectPoolBuilder object_pool_builder;
2810 compiler::Assembler _assembler_(&object_pool_builder);
2811 GenerateIncrement(&_assembler_);
2812 Code& code = Code::Handle(Code::FinalizeCodeAndNotify(
2813 Function::Handle(CreateFunction("Test_Code")), nullptr, &_assembler_,
2814 Code::PoolAttachment::kAttachPool));
2815 code.set_pc_descriptors(descriptors);
2816
2817 // Verify the PcDescriptor entries by accessing them.
2818 const PcDescriptors& pc_descs = PcDescriptors::Handle(code.pc_descriptors());
2819 PcDescriptors::Iterator iter(pc_descs, PcDescriptorsLayout::kAnyKind);
2820
2821 EXPECT_EQ(true, iter.MoveNext());
2822 EXPECT_EQ(1, iter.YieldIndex());
2823 EXPECT_EQ(20, iter.TokenPos().value());
2824 EXPECT_EQ(1, iter.TryIndex());
2825 EXPECT_EQ(static_cast<uword>(10), iter.PcOffset());
2826 EXPECT_EQ(1, iter.DeoptId());
2827 EXPECT_EQ(PcDescriptorsLayout::kOther, iter.Kind());
2828
2829 EXPECT_EQ(true, iter.MoveNext());
2830 EXPECT_EQ(-1, iter.YieldIndex());
2831 EXPECT_EQ(30, iter.TokenPos().value());
2832 EXPECT_EQ(PcDescriptorsLayout::kDeopt, iter.Kind());
2833
2834 EXPECT_EQ(true, iter.MoveNext());
2835 EXPECT_EQ(10, iter.YieldIndex());
2836 EXPECT_EQ(40, iter.TokenPos().value());
2837
2838 EXPECT_EQ(true, iter.MoveNext());
2839 EXPECT_EQ(20, iter.YieldIndex());
2840 EXPECT_EQ(40, iter.TokenPos().value());
2841
2842 EXPECT_EQ(true, iter.MoveNext());
2843 EXPECT_EQ(30, iter.YieldIndex());
2844 EXPECT_EQ(80, iter.TokenPos().value());
2845
2846 EXPECT_EQ(true, iter.MoveNext());
2847 EXPECT_EQ(30, iter.YieldIndex());
2848 EXPECT_EQ(150, iter.TokenPos().value());
2849
2850 EXPECT_EQ(3, iter.TryIndex());
2851 EXPECT_EQ(static_cast<uword>(80), iter.PcOffset());
2852 EXPECT_EQ(150, iter.TokenPos().value());
2853 EXPECT_EQ(PcDescriptorsLayout::kOther, iter.Kind());
2854
2855 EXPECT_EQ(false, iter.MoveNext());
2856}
2857
2858ISOLATE_UNIT_TEST_CASE(PcDescriptorsLargeDeltas) {
2859 DescriptorList* builder = new DescriptorList(0);
2860
2861 // kind, pc_offset, deopt_id, token_pos, try_index
2862 builder->AddDescriptor(PcDescriptorsLayout::kOther, 100, 1,
2863 TokenPosition(200), 1, 10);
2864 builder->AddDescriptor(PcDescriptorsLayout::kDeopt, 200, 2,
2865 TokenPosition(300), 0, -1);
2866 builder->AddDescriptor(PcDescriptorsLayout::kOther, 300, 3,
2867 TokenPosition(400), 1, 10);
2868 builder->AddDescriptor(PcDescriptorsLayout::kOther, 100, 4, TokenPosition(0),
2869 2, 20);
2870 builder->AddDescriptor(PcDescriptorsLayout::kOther, 100, 5,
2871 TokenPosition(800), 3, 30);
2872 builder->AddDescriptor(PcDescriptorsLayout::kOther, 800, 6,
2873 TokenPosition(150), 3, 30);
2874
2875 PcDescriptors& descriptors = PcDescriptors::Handle();
2876 descriptors ^= builder->FinalizePcDescriptors(0);
2877
2878 extern void GenerateIncrement(compiler::Assembler * assembler);
2879 compiler::ObjectPoolBuilder object_pool_builder;
2880 compiler::Assembler _assembler_(&object_pool_builder);
2881 GenerateIncrement(&_assembler_);
2882 Code& code = Code::Handle(Code::FinalizeCodeAndNotify(
2883 Function::Handle(CreateFunction("Test_Code")), nullptr, &_assembler_,
2884 Code::PoolAttachment::kAttachPool));
2885 code.set_pc_descriptors(descriptors);
2886
2887 // Verify the PcDescriptor entries by accessing them.
2888 const PcDescriptors& pc_descs = PcDescriptors::Handle(code.pc_descriptors());
2889 PcDescriptors::Iterator iter(pc_descs, PcDescriptorsLayout::kAnyKind);
2890
2891 EXPECT_EQ(true, iter.MoveNext());
2892 EXPECT_EQ(10, iter.YieldIndex());
2893 EXPECT_EQ(200, iter.TokenPos().value());
2894 EXPECT_EQ(1, iter.TryIndex());
2895 EXPECT_EQ(static_cast<uword>(100), iter.PcOffset());
2896 EXPECT_EQ(1, iter.DeoptId());
2897 EXPECT_EQ(PcDescriptorsLayout::kOther, iter.Kind());
2898
2899 EXPECT_EQ(true, iter.MoveNext());
2900 EXPECT_EQ(-1, iter.YieldIndex());
2901 EXPECT_EQ(300, iter.TokenPos().value());
2902 EXPECT_EQ(PcDescriptorsLayout::kDeopt, iter.Kind());
2903
2904 EXPECT_EQ(true, iter.MoveNext());
2905 EXPECT_EQ(10, iter.YieldIndex());
2906 EXPECT_EQ(400, iter.TokenPos().value());
2907
2908 EXPECT_EQ(true, iter.MoveNext());
2909 EXPECT_EQ(20, iter.YieldIndex());
2910 EXPECT_EQ(0, iter.TokenPos().value());
2911
2912 EXPECT_EQ(true, iter.MoveNext());
2913 EXPECT_EQ(30, iter.YieldIndex());
2914 EXPECT_EQ(800, iter.TokenPos().value());
2915
2916 EXPECT_EQ(true, iter.MoveNext());
2917 EXPECT_EQ(30, iter.YieldIndex());
2918 EXPECT_EQ(150, iter.TokenPos().value());
2919
2920 EXPECT_EQ(3, iter.TryIndex());
2921 EXPECT_EQ(static_cast<uword>(800), iter.PcOffset());
2922 EXPECT_EQ(150, iter.TokenPos().value());
2923 EXPECT_EQ(PcDescriptorsLayout::kOther, iter.Kind());
2924
2925 EXPECT_EQ(false, iter.MoveNext());
2926}
2927
2928static ClassPtr CreateTestClass(const char* name) {
2929 const String& class_name =
2930 String::Handle(Symbols::New(Thread::Current(), name));
2931 const Class& cls =
2932 Class::Handle(CreateDummyClass(class_name, Script::Handle()));
2933 return cls.raw();
2934}
2935
2936static FieldPtr CreateTestField(const char* name) {
2937 const Class& cls = Class::Handle(CreateTestClass("global:"));
2938 const String& field_name =
2939 String::Handle(Symbols::New(Thread::Current(), name));
2940 const Field& field = Field::Handle(Field::New(
2941 field_name, true, false, false, true, false, cls, Object::dynamic_type(),
2942 TokenPosition::kMinSource, TokenPosition::kMinSource));
2943 return field.raw();
2944}
2945
2946ISOLATE_UNIT_TEST_CASE(ClassDictionaryIterator) {
2947 Class& ae66 = Class::ZoneHandle(CreateTestClass("Ae6/6"));
2948 Class& re44 = Class::ZoneHandle(CreateTestClass("Re4/4"));
2949 Field& ce68 = Field::ZoneHandle(CreateTestField("Ce6/8"));
2950 Field& tee = Field::ZoneHandle(CreateTestField("TEE"));
2951 String& url = String::ZoneHandle(String::New("SBB"));
2952 Library& lib = Library::Handle(Library::New(url));
2953 lib.AddClass(ae66);
2954 lib.AddObject(ce68, String::ZoneHandle(ce68.name()));
2955 lib.AddClass(re44);
2956 lib.AddObject(tee, String::ZoneHandle(tee.name()));
2957 ClassDictionaryIterator iterator(lib);
2958 int count = 0;
2959 Class& cls = Class::Handle();
2960 while (iterator.HasNext()) {
2961 cls = iterator.GetNextClass();
2962 EXPECT((cls.raw() == ae66.raw()) || (cls.raw() == re44.raw()));
2963 count++;
2964 }
2965 EXPECT(count == 2);
2966}
2967
2968static FunctionPtr GetDummyTarget(const char* name) {
2969 const String& function_name =
2970 String::Handle(Symbols::New(Thread::Current(), name));
2971 const Class& cls =
2972 Class::Handle(CreateDummyClass(function_name, Script::Handle()));
2973 const bool is_static = false;
2974 const bool is_const = false;
2975 const bool is_abstract = false;
2976 const bool is_external = false;
2977 const bool is_native = false;
2978 return Function::New(function_name, FunctionLayout::kRegularFunction,
2979 is_static, is_const, is_abstract, is_external, is_native,
2980 cls, TokenPosition::kMinSource);
2981}
2982
2983ISOLATE_UNIT_TEST_CASE(ICData) {
2984 Function& function = Function::Handle(GetDummyTarget("Bern"));
2985 const intptr_t id = 12;
2986 const intptr_t num_args_tested = 1;
2987 const String& target_name = String::Handle(Symbols::New(thread, "Thun"));
2988 const intptr_t kTypeArgsLen = 0;
2989 const intptr_t kNumArgs = 1;
2990 const Array& args_descriptor = Array::Handle(ArgumentsDescriptor::NewBoxed(
2991 kTypeArgsLen, kNumArgs, Object::null_array()));
2992 ICData& o1 = ICData::Handle();
2993 o1 = ICData::New(function, target_name, args_descriptor, id, num_args_tested,
2994 ICData::kInstance);
2995 EXPECT_EQ(1, o1.NumArgsTested());
2996 EXPECT_EQ(id, o1.deopt_id());
2997 EXPECT_EQ(function.raw(), o1.Owner());
2998 EXPECT_EQ(0, o1.NumberOfChecks());
2999 EXPECT_EQ(target_name.raw(), o1.target_name());
3000 EXPECT_EQ(args_descriptor.raw(), o1.arguments_descriptor());
3001
3002 const Function& target1 = Function::Handle(GetDummyTarget("Thun"));
3003 o1.AddReceiverCheck(kSmiCid, target1);
3004 EXPECT_EQ(1, o1.NumberOfChecks());
3005 EXPECT_EQ(1, o1.NumberOfUsedChecks());
3006 intptr_t test_class_id = -1;
3007 Function& test_target = Function::Handle();
3008 o1.GetOneClassCheckAt(0, &test_class_id, &test_target);
3009 EXPECT_EQ(kSmiCid, test_class_id);
3010 EXPECT_EQ(target1.raw(), test_target.raw());
3011 EXPECT_EQ(kSmiCid, o1.GetCidAt(0));
3012 GrowableArray<intptr_t> test_class_ids;
3013 o1.GetCheckAt(0, &test_class_ids, &test_target);
3014 EXPECT_EQ(1, test_class_ids.length());
3015 EXPECT_EQ(kSmiCid, test_class_ids[0]);
3016 EXPECT_EQ(target1.raw(), test_target.raw());
3017
3018 const Function& target2 = Function::Handle(GetDummyTarget("Thun"));
3019 o1.AddReceiverCheck(kDoubleCid, target2);
3020 EXPECT_EQ(2, o1.NumberOfChecks());
3021 EXPECT_EQ(2, o1.NumberOfUsedChecks());
3022 o1.GetOneClassCheckAt(1, &test_class_id, &test_target);
3023 EXPECT_EQ(kDoubleCid, test_class_id);
3024 EXPECT_EQ(target2.raw(), test_target.raw());
3025 EXPECT_EQ(kDoubleCid, o1.GetCidAt(1));
3026
3027 o1.AddReceiverCheck(kMintCid, target2);
3028 EXPECT_EQ(3, o1.NumberOfUsedChecks());
3029 o1.SetCountAt(o1.NumberOfChecks() - 1, 0);
3030 EXPECT_EQ(2, o1.NumberOfUsedChecks());
3031
3032 ICData& o2 = ICData::Handle();
3033 o2 = ICData::New(function, target_name, args_descriptor, 57, 2,
3034 ICData::kInstance);
3035 EXPECT_EQ(2, o2.NumArgsTested());
3036 EXPECT_EQ(57, o2.deopt_id());
3037 EXPECT_EQ(function.raw(), o2.Owner());
3038 EXPECT_EQ(0, o2.NumberOfChecks());
3039 GrowableArray<intptr_t> classes;
3040 classes.Add(kSmiCid);
3041 classes.Add(kSmiCid);
3042 o2.AddCheck(classes, target1);
3043 EXPECT_EQ(1, o2.NumberOfChecks());
3044 o2.GetCheckAt(0, &test_class_ids, &test_target);
3045 EXPECT_EQ(2, test_class_ids.length());
3046 EXPECT_EQ(kSmiCid, test_class_ids[0]);
3047 EXPECT_EQ(kSmiCid, test_class_ids[1]);
3048 EXPECT_EQ(target1.raw(), test_target.raw());
3049
3050 // Check ICData for unoptimized static calls.
3051 const intptr_t kNumArgsChecked = 0;
3052 const ICData& scall_icdata =
3053 ICData::Handle(ICData::New(function, target_name, args_descriptor, 57,
3054 kNumArgsChecked, ICData::kInstance));
3055 scall_icdata.AddTarget(target1);
3056 EXPECT_EQ(target1.raw(), scall_icdata.GetTargetAt(0));
3057}
3058
3059ISOLATE_UNIT_TEST_CASE(SubtypeTestCache) {
3060 SafepointMutexLocker ml(thread->isolate_group()->subtype_test_cache_mutex());
3061
3062 String& class_name = String::Handle(Symbols::New(thread, "EmptyClass"));
3063 Script& script = Script::Handle();
3064 const Class& empty_class =
3065 Class::Handle(CreateDummyClass(class_name, script));
3066 SubtypeTestCache& cache = SubtypeTestCache::Handle(SubtypeTestCache::New());
3067 EXPECT(!cache.IsNull());
3068 EXPECT_EQ(0, cache.NumberOfChecks());
3069 const Object& class_id_or_fun = Object::Handle(Smi::New(empty_class.id()));
3070 const TypeArguments& targ_0 = TypeArguments::Handle(TypeArguments::New(2));
3071 const TypeArguments& targ_1 = TypeArguments::Handle(TypeArguments::New(3));
3072 const TypeArguments& targ_2 = TypeArguments::Handle(TypeArguments::New(4));
3073 const TypeArguments& targ_3 = TypeArguments::Handle(TypeArguments::New(5));
3074 const TypeArguments& targ_4 = TypeArguments::Handle(TypeArguments::New(6));
3075 cache.AddCheck(class_id_or_fun, targ_0, targ_1, targ_2, targ_3, targ_4,
3076 Bool::True());
3077 EXPECT_EQ(1, cache.NumberOfChecks());
3078 Object& test_class_id_or_fun = Object::Handle();
3079 TypeArguments& test_targ_0 = TypeArguments::Handle();
3080 TypeArguments& test_targ_1 = TypeArguments::Handle();
3081 TypeArguments& test_targ_2 = TypeArguments::Handle();
3082 TypeArguments& test_targ_3 = TypeArguments::Handle();
3083 TypeArguments& test_targ_4 = TypeArguments::Handle();
3084 Bool& test_result = Bool::Handle();
3085 cache.GetCheck(0, &test_class_id_or_fun, &test_targ_0, &test_targ_1,
3086 &test_targ_2, &test_targ_3, &test_targ_4, &test_result);
3087 EXPECT_EQ(class_id_or_fun.raw(), test_class_id_or_fun.raw());
3088 EXPECT_EQ(targ_0.raw(), test_targ_0.raw());
3089 EXPECT_EQ(targ_1.raw(), test_targ_1.raw());
3090 EXPECT_EQ(targ_2.raw(), test_targ_2.raw());
3091 EXPECT_EQ(Bool::True().raw(), test_result.raw());
3092}
3093
3094ISOLATE_UNIT_TEST_CASE(FieldTests) {
3095 const String& f = String::Handle(String::New("oneField"));
3096 const String& getter_f = String::Handle(Field::GetterName(f));
3097 const String& setter_f = String::Handle(Field::SetterName(f));
3098 EXPECT(!Field::IsGetterName(f));
3099 EXPECT(!Field::IsSetterName(f));
3100 EXPECT(Field::IsGetterName(getter_f));
3101 EXPECT(!Field::IsSetterName(getter_f));
3102 EXPECT(!Field::IsGetterName(setter_f));
3103 EXPECT(Field::IsSetterName(setter_f));
3104 EXPECT_STREQ(f.ToCString(),
3105 String::Handle(Field::NameFromGetter(getter_f)).ToCString());
3106 EXPECT_STREQ(f.ToCString(),
3107 String::Handle(Field::NameFromSetter(setter_f)).ToCString());
3108}
3109
3110// Expose helper function from object.cc for testing.
3111bool EqualsIgnoringPrivate(const String& name, const String& private_name);
3112
3113ISOLATE_UNIT_TEST_CASE(EqualsIgnoringPrivate) {
3114 String& mangled_name = String::Handle();
3115 String& bare_name = String::Handle();
3116
3117 // Simple matches.
3118 mangled_name = OneByteString::New("foo");
3119 bare_name = OneByteString::New("foo");
3120 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3121
3122 mangled_name = OneByteString::New("foo.");
3123 bare_name = OneByteString::New("foo.");
3124 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3125
3126 mangled_name = OneByteString::New("foo.named");
3127 bare_name = OneByteString::New("foo.named");
3128 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3129
3130 // Simple mismatches.
3131 mangled_name = OneByteString::New("bar");
3132 bare_name = OneByteString::New("foo");
3133 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3134
3135 mangled_name = OneByteString::New("foo.");
3136 bare_name = OneByteString::New("foo");
3137 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3138
3139 mangled_name = OneByteString::New("foo");
3140 bare_name = OneByteString::New("foo.");
3141 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3142
3143 mangled_name = OneByteString::New("foo.name");
3144 bare_name = OneByteString::New("foo.named");
3145 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3146
3147 mangled_name = OneByteString::New("foo.named");
3148 bare_name = OneByteString::New("foo.name");
3149 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3150
3151 // Private match.
3152 mangled_name = OneByteString::New("foo@12345");
3153 bare_name = OneByteString::New("foo");
3154 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3155
3156 // Private mismatch.
3157 mangled_name = OneByteString::New("food@12345");
3158 bare_name = OneByteString::New("foo");
3159 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3160
3161 // Private mismatch 2.
3162 mangled_name = OneByteString::New("foo@12345");
3163 bare_name = OneByteString::New("food");
3164 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3165
3166 // Private mixin application match.
3167 mangled_name = OneByteString::New("_M1@12345&_M2@12345&_M3@12345");
3168 bare_name = OneByteString::New("_M1&_M2&_M3");
3169 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3170
3171 // Private mixin application mismatch.
3172 mangled_name = OneByteString::New("_M1@12345&_M2@12345&_M3@12345");
3173 bare_name = OneByteString::New("_M1&_M2&_M4");
3174 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3175
3176 // Private constructor match.
3177 mangled_name = OneByteString::New("foo@12345.");
3178 bare_name = OneByteString::New("foo.");
3179 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3180
3181 // Private constructor mismatch.
3182 mangled_name = OneByteString::New("foo@12345.");
3183 bare_name = OneByteString::New("foo");
3184 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3185
3186 // Private constructor mismatch 2.
3187 mangled_name = OneByteString::New("foo@12345");
3188 bare_name = OneByteString::New("foo.");
3189 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3190
3191 // Named private constructor match.
3192 mangled_name = OneByteString::New("foo@12345.named");
3193 bare_name = OneByteString::New("foo.named");
3194 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3195
3196 // Named private constructor mismatch.
3197 mangled_name = OneByteString::New("foo@12345.name");
3198 bare_name = OneByteString::New("foo.named");
3199 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3200
3201 // Named private constructor mismatch 2.
3202 mangled_name = OneByteString::New("foo@12345.named");
3203 bare_name = OneByteString::New("foo.name");
3204 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3205
3206 // Named double-private constructor match. Yes, this happens.
3207 mangled_name = OneByteString::New("foo@12345.named@12345");
3208 bare_name = OneByteString::New("foo.named");
3209 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3210
3211 // Named double-private constructor mismatch.
3212 mangled_name = OneByteString::New("foo@12345.name@12345");
3213 bare_name = OneByteString::New("foo.named");
3214 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3215
3216 // Named double-private constructor mismatch.
3217 mangled_name = OneByteString::New("foo@12345.named@12345");
3218 bare_name = OneByteString::New("foo.name");
3219 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, bare_name));
3220
3221 const char* ext_mangled_str = "foo@12345.name@12345";
3222 const char* ext_bare_str = "foo.name";
3223 const char* ext_bad_bare_str = "foo.named";
3224 String& ext_mangled_name = String::Handle();
3225 String& ext_bare_name = String::Handle();
3226 String& ext_bad_bare_name = String::Handle();
3227
3228 mangled_name = OneByteString::New("foo@12345.name@12345");
3229 ext_mangled_name = ExternalOneByteString::New(
3230 reinterpret_cast<const uint8_t*>(ext_mangled_str),
3231 strlen(ext_mangled_str), NULL, 0, NoopFinalizer, Heap::kNew);
3232 EXPECT(ext_mangled_name.IsExternalOneByteString());
3233 ext_bare_name = ExternalOneByteString::New(
3234 reinterpret_cast<const uint8_t*>(ext_bare_str), strlen(ext_bare_str),
3235 NULL, 0, NoopFinalizer, Heap::kNew);
3236 EXPECT(ext_bare_name.IsExternalOneByteString());
3237 ext_bad_bare_name = ExternalOneByteString::New(
3238 reinterpret_cast<const uint8_t*>(ext_bad_bare_str),
3239 strlen(ext_bad_bare_str), NULL, 0, NoopFinalizer, Heap::kNew);
3240 EXPECT(ext_bad_bare_name.IsExternalOneByteString());
3241
3242 // str1 - OneByteString, str2 - ExternalOneByteString.
3243 EXPECT(String::EqualsIgnoringPrivateKey(mangled_name, ext_bare_name));
3244 EXPECT(!String::EqualsIgnoringPrivateKey(mangled_name, ext_bad_bare_name));
3245
3246 // str1 - ExternalOneByteString, str2 - OneByteString.
3247 EXPECT(String::EqualsIgnoringPrivateKey(ext_mangled_name, bare_name));
3248
3249 // str1 - ExternalOneByteString, str2 - ExternalOneByteString.
3250 EXPECT(String::EqualsIgnoringPrivateKey(ext_mangled_name, ext_bare_name));
3251 EXPECT(
3252 !String::EqualsIgnoringPrivateKey(ext_mangled_name, ext_bad_bare_name));
3253}
3254
3255ISOLATE_UNIT_TEST_CASE_WITH_EXPECTATION(ArrayNew_Overflow_Crash, "Crash") {
3256 Array::Handle(Array::New(Array::kMaxElements + 1));
3257}
3258
3259TEST_CASE(StackTraceFormat) {
3260 const char* kScriptChars =
3261 "void baz() {\n"
3262 " throw 'MyException';\n"
3263 "}\n"
3264 "\n"
3265 "class _OtherClass {\n"
3266 " _OtherClass._named() {\n"
3267 " baz();\n"
3268 " }\n"
3269 "}\n"
3270 "\n"
3271 "set globalVar(var value) {\n"
3272 " new _OtherClass._named();\n"
3273 "}\n"
3274 "\n"
3275 "void _bar() {\n"
3276 " globalVar = null;\n"
3277 "}\n"
3278 "\n"
3279 "class MyClass {\n"
3280 " MyClass() {\n"
3281 " (() => foo())();\n"
3282 " }\n"
3283 "\n"
3284 " static get field {\n"
3285 " _bar();\n"
3286 " }\n"
3287 "\n"
3288 " static foo() {\n"
3289 " fooHelper() {\n"
3290 " field;\n"
3291 " }\n"
3292 " fooHelper();\n"
3293 " }\n"
3294 "}\n"
3295 "\n"
3296 "main() {\n"
3297 " (() => new MyClass())();\n"
3298 "}\n";
3299 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
3300 EXPECT_VALID(lib);
3301 Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
3302
3303 const char* lib_url = "file:///test-lib";
3304 const size_t kBufferSize = 1024;
3305 char expected[kBufferSize];
3306 snprintf(expected, kBufferSize,
3307 "Unhandled exception:\n"
3308 "MyException\n"
3309 "#0 baz (%1$s:2:3)\n"
3310 "#1 new _OtherClass._named (%1$s:7:5)\n"
3311 "#2 globalVar= (%1$s:12:7)\n"
3312 "#3 _bar (%1$s:16:3)\n"
3313 "#4 MyClass.field (%1$s:25:5)\n"
3314 "#5 MyClass.foo.fooHelper (%1$s:30:7)\n"
3315 "#6 MyClass.foo (%1$s:32:14)\n"
3316 "#7 new MyClass.<anonymous closure> (%1$s:21:12)\n"
3317 "#8 new MyClass (%1$s:21:18)\n"
3318 "#9 main.<anonymous closure> (%1$s:37:14)\n"
3319 "#10 main (%1$s:37:24)",
3320 lib_url);
3321
3322 EXPECT_ERROR(result, expected);
3323}
3324
3325ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveCrossGen) {
3326 WeakProperty& weak = WeakProperty::Handle();
3327 {
3328 // Weak property and value in new. Key in old.
3329 HANDLESCOPE(thread);
3330 String& key = String::Handle();
3331 key ^= OneByteString::New("key", Heap::kOld);
3332 String& value = String::Handle();
3333 value ^= OneByteString::New("value", Heap::kNew);
3334 weak ^= WeakProperty::New(Heap::kNew);
3335 weak.set_key(key);
3336 weak.set_value(value);
3337 key ^= OneByteString::null();
3338 value ^= OneByteString::null();
3339 }
3340 GCTestHelper::CollectNewSpace();
3341 GCTestHelper::CollectOldSpace();
3342 // Weak property key and value should survive due to cross-generation
3343 // pointers.
3344 EXPECT(weak.key() != Object::null());
3345 EXPECT(weak.value() != Object::null());
3346 {
3347 // Weak property and value in old. Key in new.
3348 HANDLESCOPE(thread);
3349 String& key = String::Handle();
3350 key ^= OneByteString::New("key", Heap::kNew);
3351 String& value = String::Handle();
3352 value ^= OneByteString::New("value", Heap::kOld);
3353 weak ^= WeakProperty::New(Heap::kOld);
3354 weak.set_key(key);
3355 weak.set_value(value);
3356 key ^= OneByteString::null();
3357 value ^= OneByteString::null();
3358 }
3359 GCTestHelper::CollectNewSpace();
3360 GCTestHelper::CollectOldSpace();
3361 // Weak property key and value should survive due to cross-generation
3362 // pointers.
3363 EXPECT(weak.key() != Object::null());
3364 EXPECT(weak.value() != Object::null());
3365 {
3366 // Weak property and value in new. Key is a Smi.
3367 HANDLESCOPE(thread);
3368 Integer& key = Integer::Handle();
3369 key ^= Integer::New(31);
3370 String& value = String::Handle();
3371 value ^= OneByteString::New("value", Heap::kNew);
3372 weak ^= WeakProperty::New(Heap::kNew);
3373 weak.set_key(key);
3374 weak.set_value(value);
3375 key ^= Integer::null();
3376 value ^= OneByteString::null();
3377 }
3378 GCTestHelper::CollectAllGarbage();
3379 // Weak property key and value should survive due implicit liveness of
3380 // non-heap objects.
3381 EXPECT(weak.key() != Object::null());
3382 EXPECT(weak.value() != Object::null());
3383 {
3384 // Weak property and value in old. Key is a Smi.
3385 HANDLESCOPE(thread);
3386 Integer& key = Integer::Handle();
3387 key ^= Integer::New(32);
3388 String& value = String::Handle();
3389 value ^= OneByteString::New("value", Heap::kOld);
3390 weak ^= WeakProperty::New(Heap::kOld);
3391 weak.set_key(key);
3392 weak.set_value(value);
3393 key ^= OneByteString::null();
3394 value ^= OneByteString::null();
3395 }
3396 GCTestHelper::CollectAllGarbage();
3397 // Weak property key and value should survive due implicit liveness of
3398 // non-heap objects.
3399 EXPECT(weak.key() != Object::null());
3400 EXPECT(weak.value() != Object::null());
3401 {
3402 // Weak property and value in new. Key in VM isolate.
3403 HANDLESCOPE(thread);
3404 String& value = String::Handle();
3405 value ^= OneByteString::New("value", Heap::kNew);
3406 weak ^= WeakProperty::New(Heap::kNew);
3407 weak.set_key(Symbols::Dot());
3408 weak.set_value(value);
3409 String& key = String::Handle();
3410 key ^= OneByteString::null();
3411 value ^= OneByteString::null();
3412 }
3413 GCTestHelper::CollectNewSpace();
3414 GCTestHelper::CollectOldSpace();
3415 // Weak property key and value should survive due to cross-generation
3416 // pointers.
3417 EXPECT(weak.key() != Object::null());
3418 EXPECT(weak.value() != Object::null());
3419 {
3420 // Weak property and value in old. Key in VM isolate.
3421 HANDLESCOPE(thread);
3422 String& value = String::Handle();
3423 value ^= OneByteString::New("value", Heap::kOld);
3424 weak ^= WeakProperty::New(Heap::kOld);
3425 weak.set_key(Symbols::Dot());
3426 weak.set_value(value);
3427 String& key = String::Handle();
3428 key ^= OneByteString::null();
3429 value ^= OneByteString::null();
3430 }
3431 GCTestHelper::CollectNewSpace();
3432 GCTestHelper::CollectOldSpace();
3433 // Weak property key and value should survive due to cross-generation
3434 // pointers.
3435 EXPECT(weak.key() != Object::null());
3436 EXPECT(weak.value() != Object::null());
3437}
3438
3439ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveRecurse) {
3440 // This used to end in an infinite recursion. Caused by scavenging the weak
3441 // property before scavenging the key.
3442 WeakProperty& weak = WeakProperty::Handle();
3443 Array& arr = Array::Handle(Array::New(1));
3444 {
3445 HANDLESCOPE(thread);
3446 String& key = String::Handle();
3447 key ^= OneByteString::New("key");
3448 arr.SetAt(0, key);
3449 String& value = String::Handle();
3450 value ^= OneByteString::New("value");
3451 weak ^= WeakProperty::New();
3452 weak.set_key(key);
3453 weak.set_value(value);
3454 }
3455 GCTestHelper::CollectAllGarbage();
3456 EXPECT(weak.key() != Object::null());
3457 EXPECT(weak.value() != Object::null());
3458}
3459
3460ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveOne_NewSpace) {
3461 WeakProperty& weak = WeakProperty::Handle();
3462 String& key = String::Handle();
3463 key ^= OneByteString::New("key");
3464 {
3465 HANDLESCOPE(thread);
3466 String& value = String::Handle();
3467 value ^= OneByteString::New("value");
3468 weak ^= WeakProperty::New();
3469 weak.set_key(key);
3470 weak.set_value(value);
3471 }
3472 GCTestHelper::CollectAllGarbage();
3473 EXPECT(weak.key() != Object::null());
3474 EXPECT(weak.value() != Object::null());
3475}
3476
3477ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwo_NewSpace) {
3478 WeakProperty& weak1 = WeakProperty::Handle();
3479 String& key1 = String::Handle();
3480 key1 ^= OneByteString::New("key1");
3481 WeakProperty& weak2 = WeakProperty::Handle();
3482 String& key2 = String::Handle();
3483 key2 ^= OneByteString::New("key2");
3484 {
3485 HANDLESCOPE(thread);
3486 String& value1 = String::Handle();
3487 value1 ^= OneByteString::New("value1");
3488 weak1 ^= WeakProperty::New();
3489 weak1.set_key(key1);
3490 weak1.set_value(value1);
3491 String& value2 = String::Handle();
3492 value2 ^= OneByteString::New("value2");
3493 weak2 ^= WeakProperty::New();
3494 weak2.set_key(key2);
3495 weak2.set_value(value2);
3496 }
3497 GCTestHelper::CollectAllGarbage();
3498 EXPECT(weak1.key() != Object::null());
3499 EXPECT(weak1.value() != Object::null());
3500 EXPECT(weak2.key() != Object::null());
3501 EXPECT(weak2.value() != Object::null());
3502}
3503
3504ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwoShared_NewSpace) {
3505 WeakProperty& weak1 = WeakProperty::Handle();
3506 WeakProperty& weak2 = WeakProperty::Handle();
3507 String& key = String::Handle();
3508 key ^= OneByteString::New("key");
3509 {
3510 HANDLESCOPE(thread);
3511 String& value1 = String::Handle();
3512 value1 ^= OneByteString::New("value1");
3513 weak1 ^= WeakProperty::New();
3514 weak1.set_key(key);
3515 weak1.set_value(value1);
3516 String& value2 = String::Handle();
3517 value2 ^= OneByteString::New("value2");
3518 weak2 ^= WeakProperty::New();
3519 weak2.set_key(key);
3520 weak2.set_value(value2);
3521 }
3522 GCTestHelper::CollectAllGarbage();
3523 EXPECT(weak1.key() != Object::null());
3524 EXPECT(weak1.value() != Object::null());
3525 EXPECT(weak2.key() != Object::null());
3526 EXPECT(weak2.value() != Object::null());
3527}
3528
3529ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveOne_OldSpace) {
3530 WeakProperty& weak = WeakProperty::Handle();
3531 String& key = String::Handle();
3532 key ^= OneByteString::New("key", Heap::kOld);
3533 {
3534 HANDLESCOPE(thread);
3535 String& value = String::Handle();
3536 value ^= OneByteString::New("value", Heap::kOld);
3537 weak ^= WeakProperty::New(Heap::kOld);
3538 weak.set_key(key);
3539 weak.set_value(value);
3540 }
3541 GCTestHelper::CollectAllGarbage();
3542 EXPECT(weak.key() != Object::null());
3543 EXPECT(weak.value() != Object::null());
3544}
3545
3546ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwo_OldSpace) {
3547 WeakProperty& weak1 = WeakProperty::Handle();
3548 String& key1 = String::Handle();
3549 key1 ^= OneByteString::New("key1", Heap::kOld);
3550 WeakProperty& weak2 = WeakProperty::Handle();
3551 String& key2 = String::Handle();
3552 key2 ^= OneByteString::New("key2", Heap::kOld);
3553 {
3554 HANDLESCOPE(thread);
3555 String& value1 = String::Handle();
3556 value1 ^= OneByteString::New("value1", Heap::kOld);
3557 weak1 ^= WeakProperty::New(Heap::kOld);
3558 weak1.set_key(key1);
3559 weak1.set_value(value1);
3560 String& value2 = String::Handle();
3561 value2 ^= OneByteString::New("value2", Heap::kOld);
3562 weak2 ^= WeakProperty::New(Heap::kOld);
3563 weak2.set_key(key2);
3564 weak2.set_value(value2);
3565 }
3566 GCTestHelper::CollectAllGarbage();
3567 EXPECT(weak1.key() != Object::null());
3568 EXPECT(weak1.value() != Object::null());
3569 EXPECT(weak2.key() != Object::null());
3570 EXPECT(weak2.value() != Object::null());
3571}
3572
3573ISOLATE_UNIT_TEST_CASE(WeakProperty_PreserveTwoShared_OldSpace) {
3574 WeakProperty& weak1 = WeakProperty::Handle();
3575 WeakProperty& weak2 = WeakProperty::Handle();
3576 String& key = String::Handle();
3577 key ^= OneByteString::New("key", Heap::kOld);
3578 {
3579 HANDLESCOPE(thread);
3580 String& value1 = String::Handle();
3581 value1 ^= OneByteString::New("value1", Heap::kOld);
3582 weak1 ^= WeakProperty::New(Heap::kOld);
3583 weak1.set_key(key);
3584 weak1.set_value(value1);
3585 String& value2 = String::Handle();
3586 value2 ^= OneByteString::New("value2", Heap::kOld);
3587 weak2 ^= WeakProperty::New(Heap::kOld);
3588 weak2.set_key(key);
3589 weak2.set_value(value2);
3590 }
3591 GCTestHelper::CollectAllGarbage();
3592 EXPECT(weak1.key() != Object::null());
3593 EXPECT(weak1.value() != Object::null());
3594 EXPECT(weak2.key() != Object::null());
3595 EXPECT(weak2.value() != Object::null());
3596}
3597
3598ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearOne_NewSpace) {
3599 WeakProperty& weak = WeakProperty::Handle();
3600 {
3601 HANDLESCOPE(thread);
3602 String& key = String::Handle();
3603 key ^= OneByteString::New("key");
3604 String& value = String::Handle();
3605 value ^= OneByteString::New("value");
3606 weak ^= WeakProperty::New();
3607 weak.set_key(key);
3608 weak.set_value(value);
3609 key ^= OneByteString::null();
3610 value ^= OneByteString::null();
3611 }
3612 GCTestHelper::CollectAllGarbage();
3613 EXPECT(weak.key() == Object::null());
3614 EXPECT(weak.value() == Object::null());
3615}
3616
3617ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearTwoShared_NewSpace) {
3618 WeakProperty& weak1 = WeakProperty::Handle();
3619 WeakProperty& weak2 = WeakProperty::Handle();
3620 {
3621 HANDLESCOPE(thread);
3622 String& key = String::Handle();
3623 key ^= OneByteString::New("key");
3624 String& value1 = String::Handle();
3625 value1 ^= OneByteString::New("value1");
3626 weak1 ^= WeakProperty::New();
3627 weak1.set_key(key);
3628 weak1.set_value(value1);
3629 String& value2 = String::Handle();
3630 value2 ^= OneByteString::New("value2");
3631 weak2 ^= WeakProperty::New();
3632 weak2.set_key(key);
3633 weak2.set_value(value2);
3634 }
3635 GCTestHelper::CollectAllGarbage();
3636 EXPECT(weak1.key() == Object::null());
3637 EXPECT(weak1.value() == Object::null());
3638 EXPECT(weak2.key() == Object::null());
3639 EXPECT(weak2.value() == Object::null());
3640}
3641
3642ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearOne_OldSpace) {
3643 WeakProperty& weak = WeakProperty::Handle();
3644 {
3645 HANDLESCOPE(thread);
3646 String& key = String::Handle();
3647 key ^= OneByteString::New("key", Heap::kOld);
3648 String& value = String::Handle();
3649 value ^= OneByteString::New("value", Heap::kOld);
3650 weak ^= WeakProperty::New(Heap::kOld);
3651 weak.set_key(key);
3652 weak.set_value(value);
3653 key ^= OneByteString::null();
3654 value ^= OneByteString::null();
3655 }
3656 GCTestHelper::CollectAllGarbage();
3657 EXPECT(weak.key() == Object::null());
3658 EXPECT(weak.value() == Object::null());
3659}
3660
3661ISOLATE_UNIT_TEST_CASE(WeakProperty_ClearTwoShared_OldSpace) {
3662 WeakProperty& weak1 = WeakProperty::Handle();
3663 WeakProperty& weak2 = WeakProperty::Handle();
3664 {
3665 HANDLESCOPE(thread);
3666 String& key = String::Handle();
3667 key ^= OneByteString::New("key", Heap::kOld);
3668 String& value1 = String::Handle();
3669 value1 ^= OneByteString::New("value1");
3670 weak1 ^= WeakProperty::New(Heap::kOld);
3671 weak1.set_key(key);
3672 weak1.set_value(value1);
3673 String& value2 = String::Handle();
3674 value2 ^= OneByteString::New("value2", Heap::kOld);
3675 weak2 ^= WeakProperty::New(Heap::kOld);
3676 weak2.set_key(key);
3677 weak2.set_value(value2);
3678 }
3679 GCTestHelper::CollectAllGarbage();
3680 EXPECT(weak1.key() == Object::null());
3681 EXPECT(weak1.value() == Object::null());
3682 EXPECT(weak2.key() == Object::null());
3683 EXPECT(weak2.value() == Object::null());
3684}
3685
3686ISOLATE_UNIT_TEST_CASE(MirrorReference) {
3687 const MirrorReference& reference =
3688 MirrorReference::Handle(MirrorReference::New(Object::Handle()));
3689 Object& initial_referent = Object::Handle(reference.referent());
3690 EXPECT(initial_referent.IsNull());
3691
3692 Library& library = Library::Handle(Library::CoreLibrary());
3693 EXPECT(!library.IsNull());
3694 EXPECT(library.IsLibrary());
3695 reference.set_referent(library);
3696 const Object& returned_referent = Object::Handle(reference.referent());
3697 EXPECT(returned_referent.IsLibrary());
3698 EXPECT_EQ(returned_referent.raw(), library.raw());
3699
3700 const MirrorReference& other_reference =
3701 MirrorReference::Handle(MirrorReference::New(Object::Handle()));
3702 EXPECT_NE(reference.raw(), other_reference.raw());
3703 other_reference.set_referent(library);
3704 EXPECT_NE(reference.raw(), other_reference.raw());
3705 EXPECT_EQ(reference.referent(), other_reference.referent());
3706
3707 Object& obj = Object::Handle(reference.raw());
3708 EXPECT(obj.IsMirrorReference());
3709}
3710
3711static FunctionPtr GetFunction(const Class& cls, const char* name) {
3712 const Function& result = Function::Handle(
3713 cls.LookupDynamicFunction(String::Handle(String::New(name))));
3714 EXPECT(!result.IsNull());
3715 return result.raw();
3716}
3717
3718static FunctionPtr GetStaticFunction(const Class& cls, const char* name) {
3719 const Function& result = Function::Handle(
3720 cls.LookupStaticFunction(String::Handle(String::New(name))));
3721 EXPECT(!result.IsNull());
3722 return result.raw();
3723}
3724
3725static FieldPtr GetField(const Class& cls, const char* name) {
3726 const Field& field =
3727 Field::Handle(cls.LookupField(String::Handle(String::New(name))));
3728 EXPECT(!field.IsNull());
3729 return field.raw();
3730}
3731
3732static ClassPtr GetClass(const Library& lib, const char* name) {
3733 const Class& cls = Class::Handle(
3734 lib.LookupClass(String::Handle(Symbols::New(Thread::Current(), name))));
3735 EXPECT(!cls.IsNull()); // No ambiguity error expected.
3736 return cls.raw();
3737}
3738
3739ISOLATE_UNIT_TEST_CASE(FindClosureIndex) {
3740 // Allocate the class first.
3741 const String& class_name = String::Handle(Symbols::New(thread, "MyClass"));
3742 const Script& script = Script::Handle();
3743 const Class& cls = Class::Handle(CreateDummyClass(class_name, script));
3744 const Array& functions = Array::Handle(Array::New(1));
3745 const Isolate* iso = Isolate::Current();
3746
3747 Function& parent = Function::Handle();
3748 const String& parent_name = String::Handle(Symbols::New(thread, "foo_papa"));
3749 parent =
3750 Function::New(parent_name, FunctionLayout::kRegularFunction, false, false,
3751 false, false, false, cls, TokenPosition::kMinSource);
3752 functions.SetAt(0, parent);
3753 cls.SetFunctions(functions);
3754
3755 Function& function = Function::Handle();
3756 const String& function_name = String::Handle(Symbols::New(thread, "foo"));
3757 function = Function::NewClosureFunction(function_name, parent,
3758 TokenPosition::kMinSource);
3759 // Add closure function to class.
3760 iso->AddClosureFunction(function);
3761
3762 // The closure should return a valid index.
3763 intptr_t good_closure_index = iso->FindClosureIndex(function);
3764 EXPECT_GE(good_closure_index, 0);
3765 // The parent function should return an invalid index.
3766 intptr_t bad_closure_index = iso->FindClosureIndex(parent);
3767 EXPECT_EQ(bad_closure_index, -1);
3768
3769 // Retrieve closure function via index.
3770 Function& func_from_index = Function::Handle();
3771 func_from_index ^= iso->ClosureFunctionFromIndex(good_closure_index);
3772 // Same closure function.
3773 EXPECT_EQ(func_from_index.raw(), function.raw());
3774}
3775
3776ISOLATE_UNIT_TEST_CASE(FindInvocationDispatcherFunctionIndex) {
3777 const String& class_name = String::Handle(Symbols::New(thread, "MyClass"));
3778 const Script& script = Script::Handle();
3779 const Class& cls = Class::Handle(CreateDummyClass(class_name, script));
3780 ClassFinalizer::FinalizeTypesInClass(cls);
3781
3782 const Array& functions = Array::Handle(Array::New(1));
3783 Function& parent = Function::Handle();
3784 const String& parent_name = String::Handle(Symbols::New(thread, "foo_papa"));
3785 parent =
3786 Function::New(parent_name, FunctionLayout::kRegularFunction, false, false,
3787 false, false, false, cls, TokenPosition::kMinSource);
3788 functions.SetAt(0, parent);
3789 cls.SetFunctions(functions);
3790 cls.Finalize();
3791
3792 // Add invocation dispatcher.
3793 const String& invocation_dispatcher_name =
3794 String::Handle(Symbols::New(thread, "myMethod"));
3795 const Array& args_desc = Array::Handle(ArgumentsDescriptor::NewBoxed(0, 1));
3796 Function& invocation_dispatcher = Function::Handle();
3797 invocation_dispatcher ^= cls.GetInvocationDispatcher(
3798 invocation_dispatcher_name, args_desc,
3799 FunctionLayout::kNoSuchMethodDispatcher, true /* create_if_absent */);
3800 EXPECT(!invocation_dispatcher.IsNull());
3801 // Get index to function.
3802 intptr_t invocation_dispatcher_index =
3803 cls.FindInvocationDispatcherFunctionIndex(invocation_dispatcher);
3804 // Expect a valid index.
3805 EXPECT_GE(invocation_dispatcher_index, 0);
3806 // Retrieve function through index.
3807 Function& invocation_dispatcher_from_index = Function::Handle();
3808 invocation_dispatcher_from_index ^=
3809 cls.InvocationDispatcherFunctionFromIndex(invocation_dispatcher_index);
3810 // Same function.
3811 EXPECT_EQ(invocation_dispatcher.raw(),
3812 invocation_dispatcher_from_index.raw());
3813 // Test function not found case.
3814 const Function& bad_function = Function::Handle(Function::null());
3815 intptr_t bad_invocation_dispatcher_index =
3816 cls.FindInvocationDispatcherFunctionIndex(bad_function);
3817 EXPECT_EQ(bad_invocation_dispatcher_index, -1);
3818}
3819
3820static void PrintMetadata(const char* name, const Object& data) {
3821 if (data.IsError()) {
3822 OS::PrintErr("Error in metadata evaluation for %s: '%s'\n", name,
3823 Error::Cast(data).ToErrorCString());
3824 }
3825 EXPECT(data.IsArray());
3826 const Array& metadata = Array::Cast(data);
3827 OS::PrintErr("Metadata for %s has %" Pd " values:\n", name,
3828 metadata.Length());
3829 Object& elem = Object::Handle();
3830 for (int i = 0; i < metadata.Length(); i++) {
3831 elem = metadata.At(i);
3832 OS::PrintErr(" %d: %s\n", i, elem.ToCString());
3833 }
3834}
3835
3836TEST_CASE(Metadata) {
3837 // clang-format off
3838 auto kScriptChars =
3839 Utils::CStringUniquePtr(OS::SCreate(nullptr,
3840 "@metafoo \n"
3841 "class Meta { \n"
3842 " final m; \n"
3843 " const Meta(this.m); \n"
3844 "} \n"
3845 " \n"
3846 "const metafoo = 'metafoo'; \n"
3847 "const metabar = 'meta' 'bar'; \n"
3848 " \n"
3849 "@metafoo \n"
3850 "@Meta(0) String%s gVar; \n"
3851 " \n"
3852 "@metafoo \n"
3853 "get tlGetter => gVar; \n"
3854 " \n"
3855 "@metabar \n"
3856 "class A { \n"
3857 " @metafoo \n"
3858 " @metabar \n"
3859 " @Meta('baz') \n"
3860 " var aField; \n"
3861 " \n"
3862 " @metabar @Meta('baa') \n"
3863 " int aFunc(a,b) => a + b; \n"
3864 "} \n"
3865 " \n"
3866 "@Meta('main') \n"
3867 "A main() { \n"
3868 " return A(); \n"
3869 "} \n",
3870 TestCase::NullableTag()), std::free);
3871 // clang-format on
3872
3873 Dart_Handle h_lib = TestCase::LoadTestScript(kScriptChars.get(), NULL);
3874 EXPECT_VALID(h_lib);
3875 Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, NULL);
3876 EXPECT_VALID(result);
3877 TransitionNativeToVM transition(thread);
3878 Library& lib = Library::Handle();
3879 lib ^= Api::UnwrapHandle(h_lib);
3880 EXPECT(!lib.IsNull());
3881 const Class& class_a = Class::Handle(GetClass(lib, "A"));
3882 Object& res = Object::Handle(lib.GetMetadata(class_a));
3883 PrintMetadata("A", res);
3884
3885 const Class& class_meta = Class::Handle(GetClass(lib, "Meta"));
3886 res = lib.GetMetadata(class_meta);
3887 PrintMetadata("Meta", res);
3888
3889 Field& field = Field::Handle(GetField(class_a, "aField"));
3890 res = lib.GetMetadata(field);
3891 PrintMetadata("A.aField", res);
3892
3893 Function& func = Function::Handle(GetFunction(class_a, "aFunc"));
3894 res = lib.GetMetadata(func);
3895 PrintMetadata("A.aFunc", res);
3896
3897 func = lib.LookupLocalFunction(String::Handle(Symbols::New(thread, "main")));
3898 EXPECT(!func.IsNull());
3899 res = lib.GetMetadata(func);
3900 PrintMetadata("main", res);
3901
3902 func = lib.LookupLocalFunction(
3903 String::Handle(Symbols::New(thread, "get:tlGetter")));
3904 EXPECT(!func.IsNull());
3905 res = lib.GetMetadata(func);
3906 PrintMetadata("tlGetter", res);
3907
3908 field = lib.LookupLocalField(String::Handle(Symbols::New(thread, "gVar")));
3909 EXPECT(!field.IsNull());
3910 res = lib.GetMetadata(field);
3911 PrintMetadata("gVar", res);
3912}
3913
3914TEST_CASE(FunctionSourceFingerprint) {
3915 const char* kScriptChars =
3916 "class A {\n"
3917 " static test1(int a) {\n"
3918 " return a > 1 ? a + 1 : a;\n"
3919 " }\n"
3920 " static test2(a) {\n"
3921 " return a > 1 ? a + 1 : a;\n"
3922 " }\n"
3923 " static test3(b) {\n"
3924 " return b > 1 ? b + 1 : b;\n"
3925 " }\n"
3926 " static test4(b) {\n"
3927 " return b > 1 ? b - 1 : b;\n"
3928 " }\n"
3929 " static test5(b) {\n"
3930 " return b > 1 ? b - 2 : b;\n"
3931 " }\n"
3932 " test6(int a) {\n"
3933 " return a > 1 ? a + 1 : a;\n"
3934 " }\n"
3935 "}\n"
3936 "class B {\n"
3937 " static /* Different declaration style. */\n"
3938 " test1(int a) {\n"
3939 " /* Returns a + 1 for a > 1, a otherwise. */\n"
3940 " return a > 1 ?\n"
3941 " a + 1 :\n"
3942 " a;\n"
3943 " }\n"
3944 " static test5(b) {\n"
3945 " return b > 1 ?\n"
3946 " b - 2 : b;\n"
3947 " }\n"
3948 " test6(int a) {\n"
3949 " return a > 1 ? a + 1 : a;\n"
3950 " }\n"
3951 "}";
3952 TestCase::LoadTestScript(kScriptChars, NULL);
3953 TransitionNativeToVM transition(thread);
3954 EXPECT(ClassFinalizer::ProcessPendingClasses());
3955 const String& name = String::Handle(String::New(TestCase::url()));
3956 const Library& lib = Library::Handle(Library::LookupLibrary(thread, name));
3957 EXPECT(!lib.IsNull());
3958
3959 const Class& class_a =
3960 Class::Handle(lib.LookupClass(String::Handle(Symbols::New(thread, "A"))));
3961 const Class& class_b =
3962 Class::Handle(lib.LookupClass(String::Handle(Symbols::New(thread, "B"))));
3963 const Function& a_test1 =
3964 Function::Handle(GetStaticFunction(class_a, "test1"));
3965 const Function& b_test1 =
3966 Function::Handle(GetStaticFunction(class_b, "test1"));
3967 const Function& a_test2 =
3968 Function::Handle(GetStaticFunction(class_a, "test2"));
3969 const Function& a_test3 =
3970 Function::Handle(GetStaticFunction(class_a, "test3"));
3971 const Function& a_test4 =
3972 Function::Handle(GetStaticFunction(class_a, "test4"));
3973 const Function& a_test5 =
3974 Function::Handle(GetStaticFunction(class_a, "test5"));
3975 const Function& b_test5 =
3976 Function::Handle(GetStaticFunction(class_b, "test5"));
3977 const Function& a_test6 = Function::Handle(GetFunction(class_a, "test6"));
3978 const Function& b_test6 = Function::Handle(GetFunction(class_b, "test6"));
3979
3980 EXPECT_EQ(a_test1.SourceFingerprint(), b_test1.SourceFingerprint());
3981 EXPECT_NE(a_test1.SourceFingerprint(), a_test2.SourceFingerprint());
3982 EXPECT_NE(a_test2.SourceFingerprint(), a_test3.SourceFingerprint());
3983 EXPECT_NE(a_test3.SourceFingerprint(), a_test4.SourceFingerprint());
3984 EXPECT_NE(a_test4.SourceFingerprint(), a_test5.SourceFingerprint());
3985 EXPECT_EQ(a_test5.SourceFingerprint(), b_test5.SourceFingerprint());
3986 // Although a_test6's receiver type is different than b_test6's receiver type,
3987 // the fingerprints are identical. The token stream does not reflect the
3988 // receiver's type. This is not a problem, since we recognize functions
3989 // of a given class and of a given name.
3990 EXPECT_EQ(a_test6.SourceFingerprint(), b_test6.SourceFingerprint());
3991}
3992
3993#ifndef PRODUCT
3994
3995TEST_CASE(FunctionWithBreakpointNotInlined) {
3996 const char* kScriptChars =
3997 "class A {\n"
3998 " a() {\n"
3999 " }\n"
4000 " b() {\n"
4001 " a();\n" // This is line 5.
4002 " }\n"
4003 "}\n"
4004 "test() {\n"
4005 " new A().b();\n"
4006 "}";
4007 const int kBreakpointLine = 5;
4008 Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
4009 EXPECT_VALID(lib);
4010
4011 // Run function A.b one time.
4012 Dart_Handle result = Dart_Invoke(lib, NewString("test"), 0, NULL);
4013 EXPECT_VALID(result);
4014
4015 // With no breakpoint, function A.b is inlineable.
4016 {
4017 TransitionNativeToVM transition(thread);
4018 const String& name = String::Handle(String::New(TestCase::url()));
4019 const Library& vmlib =
4020 Library::Handle(Library::LookupLibrary(thread, name));
4021 EXPECT(!vmlib.IsNull());
4022 const Class& class_a = Class::Handle(
4023 vmlib.LookupClass(String::Handle(Symbols::New(thread, "A"))));
4024 Function& func_b = Function::Handle(GetFunction(class_a, "b"));
4025 EXPECT(func_b.CanBeInlined());
4026 }
4027
4028 result = Dart_SetBreakpoint(NewString(TestCase::url()), kBreakpointLine);
4029 EXPECT_VALID(result);
4030
4031 // After setting a breakpoint in a function A.b, it is no longer inlineable.
4032 {
4033 TransitionNativeToVM transition(thread);
4034 const String& name = String::Handle(String::New(TestCase::url()));
4035 const Library& vmlib =
4036 Library::Handle(Library::LookupLibrary(thread, name));
4037 EXPECT(!vmlib.IsNull());
4038 const Class& class_a = Class::Handle(
4039 vmlib.LookupClass(String::Handle(Symbols::New(thread, "A"))));
4040 Function& func_b = Function::Handle(GetFunction(class_a, "b"));
4041 EXPECT(!func_b.CanBeInlined());
4042 }
4043}
4044
4045ISOLATE_UNIT_TEST_CASE(SpecialClassesHaveEmptyArrays) {
4046 ObjectStore* object_store = Isolate::Current()->object_store();
4047 Class& cls = Class::Handle();
4048 Object& array = Object::Handle();
4049
4050 cls = object_store->null_class();
4051 array = cls.fields();
4052 EXPECT(!array.IsNull());
4053 EXPECT(array.IsArray());
4054 array = cls.functions();
4055 EXPECT(!array.IsNull());
4056 EXPECT(array.IsArray());
4057
4058 cls = Object::void_class();
4059 array = cls.fields();
4060 EXPECT(!array.IsNull());
4061 EXPECT(array.IsArray());
4062 array = cls.functions();
4063 EXPECT(!array.IsNull());
4064 EXPECT(array.IsArray());
4065
4066 cls = Object::dynamic_class();
4067 array = cls.fields();
4068 EXPECT(!array.IsNull());
4069 EXPECT(array.IsArray());
4070 array = cls.functions();
4071 EXPECT(!array.IsNull());
4072 EXPECT(array.IsArray());
4073}
4074
4075class ObjectAccumulator : public ObjectVisitor {
4076 public:
4077 explicit ObjectAccumulator(GrowableArray<Object*>* objects)
4078 : objects_(objects) {}
4079 virtual ~ObjectAccumulator() {}
4080 virtual void VisitObject(ObjectPtr obj) {
4081 if (obj->IsPseudoObject()) {
4082 return; // Cannot be wrapped in handles.
4083 }
4084 Object& handle = Object::Handle(obj);
4085 // Skip some common simple objects to run in reasonable time.
4086 if (handle.IsString() || handle.IsArray()) {
4087 return;
4088 }
4089 objects_->Add(&handle);
4090 }
4091
4092 private:
4093 GrowableArray<Object*>* objects_;
4094};
4095
4096ISOLATE_UNIT_TEST_CASE(ToCString) {
4097 // Set native resolvers in case we need to read native methods.
4098 {
4099 TransitionVMToNative transition(thread);
4100 bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
4101 bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
4102 bin::Builtin::SetNativeResolver(bin::Builtin::kCLILibrary);
4103 bin::VmService::SetNativeResolver();
4104 }
4105
4106 GCTestHelper::CollectAllGarbage();
4107 GrowableArray<Object*> objects;
4108 {
4109 HeapIterationScope iteration(Thread::Current());
4110 ObjectAccumulator acc(&objects);
4111 iteration.IterateObjects(&acc);
4112 }
4113 for (intptr_t i = 0; i < objects.length(); ++i) {
4114 StackZone zone(thread);
4115 HANDLESCOPE(thread);
4116
4117 // All ToCString implementations should not allocate on the Dart heap so
4118 // they remain useful in all parts of the VM.
4119 NoSafepointScope no_safepoint;
4120 objects[i]->ToCString();
4121 }
4122}
4123
4124ISOLATE_UNIT_TEST_CASE(PrintJSON) {
4125 // Set native resolvers in case we need to read native methods.
4126 {
4127 TransitionVMToNative transition(thread);
4128 bin::Builtin::SetNativeResolver(bin::Builtin::kBuiltinLibrary);
4129 bin::Builtin::SetNativeResolver(bin::Builtin::kIOLibrary);
4130 bin::Builtin::SetNativeResolver(bin::Builtin::kCLILibrary);
4131 bin::VmService::SetNativeResolver();
4132 }
4133
4134 GCTestHelper::CollectAllGarbage();
4135 GrowableArray<Object*> objects;
4136 {
4137 HeapIterationScope iteration(Thread::Current());
4138 ObjectAccumulator acc(&objects);
4139 iteration.IterateObjects(&acc);
4140 }
4141 for (intptr_t i = 0; i < objects.length(); ++i) {
4142 JSONStream js;
4143 objects[i]->PrintJSON(&js, false);
4144 EXPECT_SUBSTRING("\"type\":", js.ToCString());
4145 }
4146}
4147
4148ISOLATE_UNIT_TEST_CASE(PrintJSONPrimitives) {
4149 char buffer[1024];
4150 Isolate* isolate = Isolate::Current();
4151
4152 // Class reference
4153 {
4154 JSONStream js;
4155 Class& cls = Class::Handle(isolate->object_store()->bool_class());
4156 cls.PrintJSON(&js, true);
4157 ElideJSONSubstring("classes", js.ToCString(), buffer);
4158 EXPECT_STREQ(
4159 "{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\",\"name\":\"bool\"}",
4160 buffer);
4161 }
4162 // Function reference
4163 {
4164 JSONStream js;
4165 Class& cls = Class::Handle(isolate->object_store()->bool_class());
4166 const String& func_name = String::Handle(String::New("toString"));
4167 Function& func = Function::Handle(cls.LookupFunction(func_name));
4168 ASSERT(!func.IsNull());
4169 func.PrintJSON(&js, true);
4170 ElideJSONSubstring("classes", js.ToCString(), buffer);
4171 EXPECT_STREQ(
4172 "{\"type\":\"@Function\",\"fixedId\":true,"
4173 "\"id\":\"\",\"name\":\"toString\","
4174 "\"owner\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
4175 "\"name\":\"bool\"},"
4176 "\"_kind\":\"RegularFunction\","
4177 "\"static\":false,\"const\":false,"
4178 "\"_intrinsic\":false,\"_native\":false}",
4179 buffer);
4180 }
4181 // Library reference
4182 {
4183 JSONStream js;
4184 Library& lib = Library::Handle(isolate->object_store()->core_library());
4185 lib.PrintJSON(&js, true);
4186 ElideJSONSubstring("libraries", js.ToCString(), buffer);
4187 EXPECT_STREQ(
4188 "{\"type\":\"@Library\",\"fixedId\":true,\"id\":\"\","
4189 "\"name\":\"dart.core\",\"uri\":\"dart:core\"}",
4190 buffer);
4191 }
4192 // Bool reference
4193 {
4194 JSONStream js;
4195 Bool::True().PrintJSON(&js, true);
4196 ElideJSONSubstring("classes", js.ToCString(), buffer);
4197 EXPECT_STREQ(
4198 "{\"type\":\"@Instance\","
4199 "\"_vmType\":\"Bool\","
4200 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
4201 "\"name\":\"bool\"},"
4202 "\"kind\":\"Bool\","
4203 "\"fixedId\":true,"
4204 "\"id\":\"objects\\/bool-true\",\"valueAsString\":\"true\"}",
4205 buffer);
4206 }
4207 // Smi reference
4208 {
4209 JSONStream js;
4210 const Integer& smi = Integer::Handle(Integer::New(7));
4211 smi.PrintJSON(&js, true);
4212 ElideJSONSubstring("classes", js.ToCString(), buffer);
4213 ElideJSONSubstring("_Smi@", buffer, buffer);
4214 EXPECT_STREQ(
4215 "{\"type\":\"@Instance\","
4216 "\"_vmType\":\"Smi\","
4217 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
4218 "\"name\":\"_Smi\","
4219 "\"_vmName\":\"\"},"
4220 "\"kind\":\"Int\","
4221 "\"fixedId\":true,"
4222 "\"id\":\"objects\\/int-7\",\"valueAsString\":\"7\"}",
4223 buffer);
4224 }
4225 // Mint reference
4226 {
4227 JSONStream js;
4228 const Integer& smi = Integer::Handle(Integer::New(Mint::kMinValue));
4229 smi.PrintJSON(&js, true);
4230 ElideJSONSubstring("classes", js.ToCString(), buffer);
4231 ElideJSONSubstring("objects", buffer, buffer);
4232 ElideJSONSubstring("_Mint@", buffer, buffer);
4233 EXPECT_STREQ(
4234 "{\"type\":\"@Instance\","
4235 "\"_vmType\":\"Mint\","
4236 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
4237 "\"name\":\"_Mint\",\"_vmName\":\"\"},"
4238 "\"kind\":\"Int\","
4239 "\"id\":\"\",\"valueAsString\":\"-9223372036854775808\"}",
4240 buffer);
4241 }
4242 // Double reference
4243 {
4244 JSONStream js;
4245 const Double& dub = Double::Handle(Double::New(0.1234));
4246 dub.PrintJSON(&js, true);
4247 ElideJSONSubstring("classes", js.ToCString(), buffer);
4248 ElideJSONSubstring("objects", buffer, buffer);
4249 ElideJSONSubstring("_Double@", buffer, buffer);
4250 EXPECT_STREQ(
4251 "{\"type\":\"@Instance\","
4252 "\"_vmType\":\"Double\","
4253 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
4254 "\"name\":\"_Double\",\"_vmName\":\"\"},"
4255 "\"kind\":\"Double\","
4256 "\"id\":\"\",\"valueAsString\":\"0.1234\"}",
4257 buffer);
4258 }
4259 // String reference
4260 {
4261 JSONStream js;
4262 const String& str = String::Handle(String::New("dw"));
4263 str.PrintJSON(&js, true);
4264 ElideJSONSubstring("classes", js.ToCString(), buffer);
4265 ElideJSONSubstring("objects", buffer, buffer);
4266 ElideJSONSubstring("_OneByteString@", buffer, buffer);
4267 EXPECT_STREQ(
4268 "{\"type\":\"@Instance\","
4269 "\"_vmType\":\"String\","
4270 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
4271 "\"name\":\"_OneByteString\",\"_vmName\":\"\"},"
4272 "\"kind\":\"String\","
4273 "\"id\":\"\",\"length\":2,\"valueAsString\":\"dw\"}",
4274 buffer);
4275 }
4276 // Array reference
4277 {
4278 JSONStream js;
4279 const Array& array = Array::Handle(Array::New(0));
4280 array.PrintJSON(&js, true);
4281 ElideJSONSubstring("classes", js.ToCString(), buffer);
4282 ElideJSONSubstring("objects", buffer, buffer);
4283 ElideJSONSubstring("_List@", buffer, buffer);
4284 EXPECT_STREQ(
4285 "{\"type\":\"@Instance\","
4286 "\"_vmType\":\"Array\","
4287 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
4288 "\"name\":\"_List\",\"_vmName\":\"\"},"
4289 "\"kind\":\"List\","
4290 "\"id\":\"\",\"length\":0}",
4291 buffer);
4292 }
4293 // GrowableObjectArray reference
4294 {
4295 JSONStream js;
4296 const GrowableObjectArray& array =
4297 GrowableObjectArray::Handle(GrowableObjectArray::New());
4298 array.PrintJSON(&js, true);
4299 ElideJSONSubstring("classes", js.ToCString(), buffer);
4300 ElideJSONSubstring("objects", buffer, buffer);
4301 ElideJSONSubstring("_GrowableList@", buffer, buffer);
4302 EXPECT_STREQ(
4303 "{\"type\":\"@Instance\","
4304 "\"_vmType\":\"GrowableObjectArray\","
4305 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
4306 "\"name\":\"_GrowableList\","
4307 "\"_vmName\":\"\"},"
4308 "\"kind\":\"List\","
4309 "\"id\":\"\",\"length\":0}",
4310 buffer);
4311 }
4312 // LinkedHashMap reference
4313 {
4314 JSONStream js;
4315 const LinkedHashMap& array =
4316 LinkedHashMap::Handle(LinkedHashMap::NewDefault());
4317 array.PrintJSON(&js, true);
4318 ElideJSONSubstring("classes", js.ToCString(), buffer);
4319 ElideJSONSubstring("objects", buffer, buffer);
4320 ElideJSONSubstring("_InternalLinkedHashMap@", buffer, buffer);
4321 EXPECT_STREQ(
4322 "{\"type\":\"@Instance\","
4323 "\"_vmType\":\"LinkedHashMap\","
4324 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
4325 "\"name\":\"_InternalLinkedHashMap\",\"_vmName\":\"\"},"
4326 "\"kind\":\"Map\","
4327 "\"id\":\"\","
4328 "\"length\":0}",
4329 buffer);
4330 }
4331 // UserTag reference
4332 {
4333 JSONStream js;
4334 Instance& tag = Instance::Handle(isolate->default_tag());
4335 tag.PrintJSON(&js, true);
4336 ElideJSONSubstring("classes", js.ToCString(), buffer);
4337 ElideJSONSubstring("objects", buffer, buffer);
4338 ElideJSONSubstring("_UserTag@", buffer, buffer);
4339 EXPECT_STREQ(
4340 "{\"type\":\"@Instance\","
4341 "\"_vmType\":\"UserTag\","
4342 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
4343 "\"name\":\"_UserTag\",\"_vmName\":\"\"},"
4344 "\"kind\":\"PlainInstance\","
4345 "\"id\":\"\"}",
4346 buffer);
4347 }
4348 // Type reference
4349 // TODO(turnidge): Add in all of the other Type siblings.
4350 {
4351 JSONStream js;
4352 Instance& type = Instance::Handle(isolate->object_store()->bool_type());
4353 type.PrintJSON(&js, true);
4354 ElideJSONSubstring("classes", js.ToCString(), buffer);
4355 ElideJSONSubstring("objects", buffer, buffer);
4356 ElideJSONSubstring("_Type@", buffer, buffer);
4357 EXPECT_STREQ(
4358 "{\"type\":\"@Instance\","
4359 "\"_vmType\":\"Type\","
4360 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
4361 "\"name\":\"_Type\",\"_vmName\":\"\"},"
4362 "\"kind\":\"Type\","
4363 "\"fixedId\":true,\"id\":\"\","
4364 "\"typeClass\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
4365 "\"name\":\"bool\"},\"name\":\"bool\"}",
4366 buffer);
4367 }
4368 // Null reference
4369 {
4370 JSONStream js;
4371 Object::null_object().PrintJSON(&js, true);
4372 ElideJSONSubstring("classes", js.ToCString(), buffer);
4373 EXPECT_STREQ(
4374 "{\"type\":\"@Instance\","
4375 "\"_vmType\":\"null\","
4376 "\"class\":{\"type\":\"@Class\",\"fixedId\":true,\"id\":\"\","
4377 "\"name\":\"Null\"},"
4378 "\"kind\":\"Null\","
4379 "\"fixedId\":true,"
4380 "\"id\":\"objects\\/null\","
4381 "\"valueAsString\":\"null\"}",
4382 buffer);
4383 }
4384 // Sentinel reference
4385 {
4386 JSONStream js;
4387 Object::sentinel().PrintJSON(&js, true);
4388 EXPECT_STREQ(
4389 "{\"type\":\"Sentinel\","
4390 "\"kind\":\"NotInitialized\","
4391 "\"valueAsString\":\"<not initialized>\"}",
4392 js.ToCString());
4393 }
4394 // Transition sentinel reference
4395 {
4396 JSONStream js;
4397 Object::transition_sentinel().PrintJSON(&js, true);
4398 EXPECT_STREQ(
4399 "{\"type\":\"Sentinel\","
4400 "\"kind\":\"BeingInitialized\","
4401 "\"valueAsString\":\"<being initialized>\"}",
4402 js.ToCString());
4403 }
4404}
4405
4406#endif // !PRODUCT
4407
4408TEST_CASE(InstanceEquality) {
4409 // Test that Instance::OperatorEquals can call a user-defined operator==.
4410 const char* kScript =
4411 "class A {\n"
4412 " bool operator==(covariant A other) { return true; }\n"
4413 "}\n"
4414 "main() {\n"
4415 " A a = new A();\n"
4416 "}";
4417
4418 Dart_Handle h_lib = TestCase::LoadTestScript(kScript, NULL);
4419 EXPECT_VALID(h_lib);
4420 Dart_Handle result = Dart_Invoke(h_lib, NewString("main"), 0, NULL);
4421 EXPECT_VALID(result);
4422
4423 TransitionNativeToVM transition(thread);
4424 Library& lib = Library::Handle();
4425 lib ^= Api::UnwrapHandle(h_lib);
4426 const Class& clazz = Class::Handle(GetClass(lib, "A"));
4427 EXPECT(!clazz.IsNull());
4428 const Instance& a0 = Instance::Handle(Instance::New(clazz));
4429 const Instance& a1 = Instance::Handle(Instance::New(clazz));
4430 EXPECT(a0.raw() != a1.raw());
4431 EXPECT(a0.OperatorEquals(a0));
4432 EXPECT(a0.OperatorEquals(a1));
4433 EXPECT(a0.IsIdenticalTo(a0));
4434 EXPECT(!a0.IsIdenticalTo(a1));
4435}
4436
4437TEST_CASE(HashCode) {
4438 // Ensure C++ overrides of Instance::HashCode match the Dart implementations.
4439 const char* kScript =
4440 "foo() {\n"
4441 " return \"foo\".hashCode;\n"
4442 "}";
4443
4444 Dart_Handle h_lib = TestCase::LoadTestScript(kScript, NULL);
4445 EXPECT_VALID(h_lib);
4446 Dart_Handle h_result = Dart_Invoke(h_lib, NewString("foo"), 0, NULL);
4447 EXPECT_VALID(h_result);
4448
4449 TransitionNativeToVM transition(thread);
4450 Integer& result = Integer::Handle();
4451 result ^= Api::UnwrapHandle(h_result);
4452 String& foo = String::Handle(String::New("foo"));
4453 Integer& expected = Integer::Handle();
4454 expected ^= foo.HashCode();
4455 EXPECT(result.IsIdenticalTo(expected));
4456}
4457
4458static void CheckIdenticalHashStructure(Thread* T,
4459 const Instance& a,
4460 const Instance& b) {
4461 const char* kScript =
4462 "(a, b) {\n"
4463 " if (a._usedData != b._usedData ||\n"
4464 " a._deletedKeys != b._deletedKeys ||\n"
4465 " a._hashMask != b._hashMask ||\n"
4466 " a._index.length != b._index.length ||\n"
4467 " a._data.length != b._data.length) {\n"
4468 " return false;\n"
4469 " }\n"
4470 " for (var i = 0; i < a._index.length; ++i) {\n"
4471 " if (a._index[i] != b._index[i]) {\n"
4472 " return false;\n"
4473 " }\n"
4474 " }\n"
4475 " for (var i = 0; i < a._data.length; ++i) {\n"
4476 " var ad = a._data[i];\n"
4477 " var bd = b._data[i];\n"
4478 " if (!identical(ad, bd) && !(ad == a && bd == b)) {\n"
4479 " return false;\n"
4480 " }\n"
4481 " }\n"
4482 " return true;\n"
4483 "}(a, b)";
4484 String& name = String::Handle();
4485 Array& param_names = Array::Handle(Array::New(2));
4486 name = String::New("a");
4487 param_names.SetAt(0, name);
4488 name = String::New("b");
4489 param_names.SetAt(1, name);
4490 Array& param_values = Array::Handle(Array::New(2));
4491 param_values.SetAt(0, a);
4492 param_values.SetAt(1, b);
4493 name = String::New(kScript);
4494 Library& lib = Library::Handle(Library::CollectionLibrary());
4495 EXPECT(Api::UnwrapHandle(TestCase::EvaluateExpression(
4496 lib, name, param_names, param_values)) == Bool::True().raw());
4497}
4498
4499TEST_CASE(LinkedHashMap) {
4500 // Check that initial index size and hash mask match in Dart vs. C++.
4501 // 1. Create an empty custom linked hash map in Dart.
4502 const char* kScript =
4503 "import 'dart:collection';\n"
4504 "makeMap() {\n"
4505 " bool Function(dynamic, dynamic) eq = (a, b) => true;\n"
4506 " int Function(dynamic) hc = (a) => 42;\n"
4507 " return new LinkedHashMap(equals: eq, hashCode: hc);\n"
4508 "}";
4509 Dart_Handle h_lib = TestCase::LoadTestScript(kScript, NULL);
4510 EXPECT_VALID(h_lib);
4511 Dart_Handle h_result = Dart_Invoke(h_lib, NewString("makeMap"), 0, NULL);
4512 EXPECT_VALID(h_result);
4513
4514 TransitionNativeToVM transition(thread);
4515
4516 // 2. Create an empty internalized LinkedHashMap in C++.
4517 Instance& dart_map = Instance::Handle();
4518 dart_map ^= Api::UnwrapHandle(h_result);
4519 LinkedHashMap& cc_map = LinkedHashMap::Handle(LinkedHashMap::NewDefault());
4520
4521 // 3. Expect them to have identical structure.
4522 CheckIdenticalHashStructure(thread, dart_map, cc_map);
4523}
4524
4525TEST_CASE(LinkedHashMap_iteration) {
4526 const char* kScript =
4527 "makeMap() {\n"
4528 " var map = {'x': 3, 'y': 4, 'z': 5, 'w': 6};\n"
4529 " map.remove('y');\n"
4530 " map.remove('w');\n"
4531 " return map;\n"
4532 "}";
4533 Dart_Handle h_lib = TestCase::LoadTestScript(kScript, NULL);
4534 EXPECT_VALID(h_lib);
4535 Dart_Handle h_result = Dart_Invoke(h_lib, NewString("makeMap"), 0, NULL);
4536 EXPECT_VALID(h_result);
4537
4538 TransitionNativeToVM transition(thread);
4539 Instance& dart_map = Instance::Handle();
4540 dart_map ^= Api::UnwrapHandle(h_result);
4541 ASSERT(dart_map.IsLinkedHashMap());
4542 const LinkedHashMap& cc_map = LinkedHashMap::Cast(dart_map);
4543
4544 EXPECT_EQ(2, cc_map.Length());
4545
4546 LinkedHashMap::Iterator iterator(cc_map);
4547 Object& object = Object::Handle();
4548
4549 EXPECT(iterator.MoveNext());
4550 object = iterator.CurrentKey();
4551 EXPECT_STREQ("x", object.ToCString());
4552 object = iterator.CurrentValue();
4553 EXPECT_STREQ("3", object.ToCString());
4554
4555 EXPECT(iterator.MoveNext());
4556 object = iterator.CurrentKey();
4557 EXPECT_STREQ("z", object.ToCString());
4558 object = iterator.CurrentValue();
4559 EXPECT_STREQ("5", object.ToCString());
4560
4561 EXPECT(!iterator.MoveNext());
4562}
4563
4564static void CheckConcatAll(const String* data[], intptr_t n) {
4565 Thread* thread = Thread::Current();
4566 Zone* zone = thread->zone();
4567 GrowableHandlePtrArray<const String> pieces(zone, n);
4568 const Array& array = Array::Handle(zone, Array::New(n));
4569 for (int i = 0; i < n; i++) {
4570 pieces.Add(*data[i]);
4571 array.SetAt(i, *data[i]);
4572 }
4573 const String& res1 =
4574 String::Handle(zone, Symbols::FromConcatAll(thread, pieces));
4575 const String& res2 = String::Handle(zone, String::ConcatAll(array));
4576 EXPECT(res1.Equals(res2));
4577}
4578
4579ISOLATE_UNIT_TEST_CASE(Symbols_FromConcatAll) {
4580 {
4581 const String* data[3] = {&Symbols::FallThroughError(), &Symbols::Dot(),
4582 &Symbols::isPaused()};
4583 CheckConcatAll(data, 3);
4584 }
4585
4586 {
4587 const intptr_t kWideCharsLen = 7;
4588 uint16_t wide_chars[kWideCharsLen] = {'H', 'e', 'l', 'l', 'o', 256, '!'};
4589 const String& two_str =
4590 String::Handle(String::FromUTF16(wide_chars, kWideCharsLen));
4591
4592 const String* data[3] = {&two_str, &Symbols::Dot(), &two_str};
4593 CheckConcatAll(data, 3);
4594 }
4595
4596 {
4597 uint8_t characters[] = {0xF6, 0xF1, 0xE9};
4598 intptr_t len = ARRAY_SIZE(characters);
4599
4600 const String& str = String::Handle(ExternalOneByteString::New(
4601 characters, len, NULL, 0, NoopFinalizer, Heap::kNew));
4602 const String* data[3] = {&str, &Symbols::Dot(), &str};
4603 CheckConcatAll(data, 3);
4604 }
4605
4606 {
4607 uint16_t characters[] = {'a', '\n', '\f', '\b', '\t',
4608 '\v', '\r', '\\', '$', 'z'};
4609 intptr_t len = ARRAY_SIZE(characters);
4610
4611 const String& str = String::Handle(ExternalTwoByteString::New(
4612 characters, len, NULL, 0, NoopFinalizer, Heap::kNew));
4613 const String* data[3] = {&str, &Symbols::Dot(), &str};
4614 CheckConcatAll(data, 3);
4615 }
4616
4617 {
4618 uint8_t characters1[] = {0xF6, 0xF1, 0xE9};
4619 intptr_t len1 = ARRAY_SIZE(characters1);
4620
4621 const String& str1 = String::Handle(ExternalOneByteString::New(
4622 characters1, len1, NULL, 0, NoopFinalizer, Heap::kNew));
4623
4624 uint16_t characters2[] = {'a', '\n', '\f', '\b', '\t',
4625 '\v', '\r', '\\', '$', 'z'};
4626 intptr_t len2 = ARRAY_SIZE(characters2);
4627
4628 const String& str2 = String::Handle(ExternalTwoByteString::New(
4629 characters2, len2, NULL, 0, NoopFinalizer, Heap::kNew));
4630 const String* data[3] = {&str1, &Symbols::Dot(), &str2};
4631 CheckConcatAll(data, 3);
4632 }
4633
4634 {
4635 const String& empty = String::Handle(String::New(""));
4636 const String* data[3] = {&Symbols::FallThroughError(), &empty,
4637 &Symbols::isPaused()};
4638 CheckConcatAll(data, 3);
4639 }
4640}
4641
4642struct TestResult {
4643 const char* in;
4644 const char* out;
4645};
4646
4647ISOLATE_UNIT_TEST_CASE(String_ScrubName) {
4648 TestResult tests[] = {
4649 {"(dynamic, dynamic) => void", "(dynamic, dynamic) => void"},
4650 {"_List@915557746", "_List"},
4651 {"_HashMap@600006304<K, V>(dynamic) => V",
4652 "_HashMap<K, V>(dynamic) => V"},
4653 {"set:foo", "foo="},
4654 {"get:foo", "foo"},
4655 {"_ReceivePortImpl@709387912", "_ReceivePortImpl"},
4656 {"_ReceivePortImpl@709387912._internal@709387912",
4657 "_ReceivePortImpl._internal"},
4658 {"_C@6328321&_E@6328321&_F@6328321", "_C&_E&_F"},
4659 {"List.", "List"},
4660 {"get:foo@6328321", "foo"},
4661 {"_MyClass@6328321.", "_MyClass"},
4662 {"_MyClass@6328321.named", "_MyClass.named"},
4663 };
4664 String& test = String::Handle();
4665 const char* result;
4666 for (size_t i = 0; i < ARRAY_SIZE(tests); i++) {
4667 test = String::New(tests[i].in);
4668 result = String::ScrubName(test);
4669 EXPECT_STREQ(tests[i].out, result);
4670 }
4671}
4672
4673ISOLATE_UNIT_TEST_CASE(String_EqualsUTF32) {
4674 // Regression test for Issue 27433. Checks that comparisons between Strings
4675 // and utf32 arrays happens after conversion to utf16 instead of utf32, as
4676 // required for proper canonicalization of string literals with a lossy
4677 // utf32->utf16 conversion.
4678 int32_t char_codes[] = {0, 0x0a, 0x0d, 0x7f, 0xff,
4679 0xffff, 0xd800, 0xdc00, 0xdbff, 0xdfff};
4680
4681 const String& str =
4682 String::Handle(String::FromUTF32(char_codes, ARRAY_SIZE(char_codes)));
4683 EXPECT(str.Equals(char_codes, ARRAY_SIZE(char_codes)));
4684}
4685
4686} // namespace dart
4687