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 "platform/assert.h" |
6 | #include "vm/globals.h" |
7 | |
8 | #include "vm/code_descriptors.h" |
9 | #include "vm/compiler/assembler/assembler.h" |
10 | #include "vm/compiler/jit/compiler.h" |
11 | #include "vm/dart_entry.h" |
12 | #include "vm/native_entry.h" |
13 | #include "vm/parser.h" |
14 | #include "vm/symbols.h" |
15 | #include "vm/thread.h" |
16 | #include "vm/unit_test.h" |
17 | |
18 | namespace dart { |
19 | |
20 | static void NativeFunc(Dart_NativeArguments args) { |
21 | Dart_Handle i = Dart_GetNativeArgument(args, 0); |
22 | Dart_Handle k = Dart_GetNativeArgument(args, 1); |
23 | int64_t value = -1; |
24 | EXPECT_VALID(Dart_IntegerToInt64(i, &value)); |
25 | EXPECT_EQ(10, value); |
26 | EXPECT_VALID(Dart_IntegerToInt64(k, &value)); |
27 | EXPECT_EQ(20, value); |
28 | { |
29 | TransitionNativeToVM transition(Thread::Current()); |
30 | Isolate::Current()->heap()->CollectAllGarbage(); |
31 | } |
32 | } |
33 | |
34 | static Dart_NativeFunction native_resolver(Dart_Handle name, |
35 | int argument_count, |
36 | bool* auto_setup_scope) { |
37 | ASSERT(auto_setup_scope); |
38 | *auto_setup_scope = false; |
39 | return reinterpret_cast<Dart_NativeFunction>(&NativeFunc); |
40 | } |
41 | |
42 | TEST_CASE(StackMapGC) { |
43 | const char* kScriptChars = |
44 | "class A {" |
45 | " static void func(var i, var k) native 'NativeFunc';" |
46 | " static foo() {" |
47 | " var i;" |
48 | " var s1;" |
49 | " var k;" |
50 | " var s2;" |
51 | " var s3;" |
52 | " i = 10; s1 = 'abcd'; k = 20; s2 = 'B'; s3 = 'C';" |
53 | " func(i, k);" |
54 | " return i + k; }" |
55 | " static void moo() {" |
56 | " var i = A.foo();" |
57 | " if (i != 30) throw '$i != 30';" |
58 | " }\n" |
59 | "}\n" ; |
60 | // First setup the script and compile the script. |
61 | TestCase::LoadTestScript(kScriptChars, native_resolver); |
62 | TransitionNativeToVM transition(thread); |
63 | |
64 | EXPECT(ClassFinalizer::ProcessPendingClasses()); |
65 | const String& name = String::Handle(String::New(TestCase::url())); |
66 | const Library& lib = Library::Handle(Library::LookupLibrary(thread, name)); |
67 | EXPECT(!lib.IsNull()); |
68 | Class& cls = |
69 | Class::Handle(lib.LookupClass(String::Handle(Symbols::New(thread, "A" )))); |
70 | EXPECT(!cls.IsNull()); |
71 | |
72 | // Now compile the two functions 'A.foo' and 'A.moo' |
73 | String& function_moo_name = String::Handle(String::New("moo" )); |
74 | Function& function_moo = |
75 | Function::Handle(cls.LookupStaticFunction(function_moo_name)); |
76 | EXPECT(CompilerTest::TestCompileFunction(function_moo)); |
77 | EXPECT(function_moo.HasCode()); |
78 | |
79 | String& function_foo_name = String::Handle(String::New("foo" )); |
80 | Function& function_foo = |
81 | Function::Handle(cls.LookupStaticFunction(function_foo_name)); |
82 | EXPECT(CompilerTest::TestCompileFunction(function_foo)); |
83 | EXPECT(function_foo.HasCode()); |
84 | |
85 | // Build and setup a stackmap for the call to 'func' in 'A.foo' in order |
86 | // to test the traversal of stack maps when a GC happens. |
87 | BitmapBuilder* stack_bitmap = new BitmapBuilder(); |
88 | EXPECT(stack_bitmap != nullptr); |
89 | stack_bitmap->Set(0, false); // var i. |
90 | stack_bitmap->Set(1, true); // var s1. |
91 | stack_bitmap->Set(2, false); // var k. |
92 | stack_bitmap->Set(3, true); // var s2. |
93 | stack_bitmap->Set(4, true); // var s3. |
94 | const Code& code = Code::Handle(function_foo.unoptimized_code()); |
95 | // Search for the pc of the call to 'func'. |
96 | const PcDescriptors& descriptors = |
97 | PcDescriptors::Handle(code.pc_descriptors()); |
98 | int call_count = 0; |
99 | PcDescriptors::Iterator iter(descriptors, |
100 | PcDescriptorsLayout::kUnoptStaticCall); |
101 | CompressedStackMapsBuilder compressed_maps_builder; |
102 | while (iter.MoveNext()) { |
103 | compressed_maps_builder.AddEntry(iter.PcOffset(), stack_bitmap, 0); |
104 | ++call_count; |
105 | } |
106 | // We can't easily check that we put the stackmap at the correct pc, but |
107 | // we did if there was exactly one call seen. |
108 | EXPECT(call_count == 1); |
109 | const auto& compressed_maps = |
110 | CompressedStackMaps::Handle(compressed_maps_builder.Finalize()); |
111 | code.set_compressed_stackmaps(compressed_maps); |
112 | |
113 | // Now invoke 'A.moo' and it will trigger a GC when the native function |
114 | // is called, this should then cause the stack map of function 'A.foo' |
115 | // to be traversed and the appropriate objects visited. |
116 | const Object& result = Object::Handle( |
117 | DartEntry::InvokeFunction(function_foo, Object::empty_array())); |
118 | EXPECT(!result.IsError()); |
119 | } |
120 | |
121 | ISOLATE_UNIT_TEST_CASE(DescriptorList_TokenPositions) { |
122 | DescriptorList* descriptors = new DescriptorList(64); |
123 | ASSERT(descriptors != NULL); |
124 | const intptr_t token_positions[] = { |
125 | kMinInt32, |
126 | 5, |
127 | 13, |
128 | 13, |
129 | 13, |
130 | 13, |
131 | 31, |
132 | 23, |
133 | 23, |
134 | 23, |
135 | 33, |
136 | 33, |
137 | 5, |
138 | 5, |
139 | TokenPosition::kMinSourcePos, |
140 | TokenPosition::kMaxSourcePos, |
141 | }; |
142 | const intptr_t num_token_positions = |
143 | sizeof(token_positions) / sizeof(token_positions[0]); |
144 | |
145 | for (intptr_t i = 0; i < num_token_positions; i++) { |
146 | descriptors->AddDescriptor(PcDescriptorsLayout::kRuntimeCall, 0, 0, |
147 | TokenPosition(token_positions[i]), 0, 1); |
148 | } |
149 | |
150 | const PcDescriptors& finalized_descriptors = |
151 | PcDescriptors::Handle(descriptors->FinalizePcDescriptors(0)); |
152 | |
153 | ASSERT(!finalized_descriptors.IsNull()); |
154 | PcDescriptors::Iterator it(finalized_descriptors, |
155 | PcDescriptorsLayout::kRuntimeCall); |
156 | |
157 | intptr_t i = 0; |
158 | while (it.MoveNext()) { |
159 | if (token_positions[i] != it.TokenPos().value()) { |
160 | OS::PrintErr("[%" Pd "]: Expected: %" Pd " != %" Pd "\n" , i, |
161 | token_positions[i], it.TokenPos().value()); |
162 | } |
163 | EXPECT(token_positions[i] == it.TokenPos().value()); |
164 | i++; |
165 | } |
166 | } |
167 | |
168 | } // namespace dart |
169 | |