| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "platform/assert.h" | 5 #include "platform/assert.h" |
| 6 #include "vm/globals.h" | 6 #include "vm/globals.h" |
| 7 | 7 |
| 8 #include "vm/ast.h" | 8 #include "vm/ast.h" |
| 9 #include "vm/assembler.h" | 9 #include "vm/assembler.h" |
| 10 #include "vm/code_descriptors.h" | 10 #include "vm/code_descriptors.h" |
| 11 #include "vm/compiler.h" | 11 #include "vm/compiler.h" |
| 12 #include "vm/dart_entry.h" | 12 #include "vm/dart_entry.h" |
| 13 #include "vm/native_entry.h" | 13 #include "vm/native_entry.h" |
| 14 #include "vm/parser.h" | 14 #include "vm/parser.h" |
| 15 #include "vm/symbols.h" | 15 #include "vm/symbols.h" |
| 16 #include "vm/thread.h" | 16 #include "vm/thread.h" |
| 17 #include "vm/unit_test.h" | 17 #include "vm/unit_test.h" |
| 18 | 18 |
| 19 namespace dart { | 19 namespace dart { |
| 20 | 20 |
| 21 static const TokenPosition kPos = TokenPosition::kNoSource; | 21 static const TokenPosition kPos = TokenPosition::kNoSource; |
| 22 | 22 |
| 23 | 23 |
| 24 CODEGEN_TEST_GENERATE(StackmapCodegen, test) { | 24 CODEGEN_TEST_GENERATE(StackMapCodegen, test) { |
| 25 ParsedFunction* parsed_function = | 25 ParsedFunction* parsed_function = |
| 26 new ParsedFunction(Thread::Current(), test->function()); | 26 new ParsedFunction(Thread::Current(), test->function()); |
| 27 LiteralNode* l = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(1))); | 27 LiteralNode* l = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(1))); |
| 28 test->node_sequence()->Add(new ReturnNode(kPos, l)); | 28 test->node_sequence()->Add(new ReturnNode(kPos, l)); |
| 29 l = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2))); | 29 l = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(2))); |
| 30 test->node_sequence()->Add(new ReturnNode(kPos, l)); | 30 test->node_sequence()->Add(new ReturnNode(kPos, l)); |
| 31 l = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3))); | 31 l = new LiteralNode(kPos, Smi::ZoneHandle(Smi::New(3))); |
| 32 test->node_sequence()->Add(new ReturnNode(kPos, l)); | 32 test->node_sequence()->Add(new ReturnNode(kPos, l)); |
| 33 parsed_function->SetNodeSequence(test->node_sequence()); | 33 parsed_function->SetNodeSequence(test->node_sequence()); |
| 34 parsed_function->set_instantiator(NULL); | 34 parsed_function->set_instantiator(NULL); |
| 35 parsed_function->EnsureExpressionTemp(); | 35 parsed_function->EnsureExpressionTemp(); |
| 36 test->node_sequence()->scope()->AddVariable( | 36 test->node_sequence()->scope()->AddVariable( |
| 37 parsed_function->expression_temp_var()); | 37 parsed_function->expression_temp_var()); |
| 38 test->node_sequence()->scope()->AddVariable( | 38 test->node_sequence()->scope()->AddVariable( |
| 39 parsed_function->current_context_var()); | 39 parsed_function->current_context_var()); |
| 40 parsed_function->AllocateVariables(); | 40 parsed_function->AllocateVariables(); |
| 41 bool retval; | 41 bool retval; |
| 42 Isolate* isolate = Isolate::Current(); | 42 Isolate* isolate = Isolate::Current(); |
| 43 EXPECT(isolate != NULL); | 43 EXPECT(isolate != NULL); |
| 44 LongJumpScope jump; | 44 LongJumpScope jump; |
| 45 if (setjmp(*jump.Set()) == 0) { | 45 if (setjmp(*jump.Set()) == 0) { |
| 46 // Build a stackmap table and some stackmap table entries. | 46 // Build a stackmap table and some stackmap table entries. |
| 47 const intptr_t kStackSlotCount = 11; | 47 const intptr_t kStackSlotCount = 11; |
| 48 StackmapTableBuilder* stackmap_table_builder = new StackmapTableBuilder(); | 48 StackMapTableBuilder* stackmap_table_builder = new StackMapTableBuilder(); |
| 49 EXPECT(stackmap_table_builder != NULL); | 49 EXPECT(stackmap_table_builder != NULL); |
| 50 | 50 |
| 51 BitmapBuilder* stack_bitmap = new BitmapBuilder(); | 51 BitmapBuilder* stack_bitmap = new BitmapBuilder(); |
| 52 EXPECT(stack_bitmap != NULL); | 52 EXPECT(stack_bitmap != NULL); |
| 53 EXPECT_EQ(0, stack_bitmap->Length()); | 53 EXPECT_EQ(0, stack_bitmap->Length()); |
| 54 stack_bitmap->Set(0, true); | 54 stack_bitmap->Set(0, true); |
| 55 EXPECT_EQ(1, stack_bitmap->Length()); | 55 EXPECT_EQ(1, stack_bitmap->Length()); |
| 56 stack_bitmap->SetLength(kStackSlotCount); | 56 stack_bitmap->SetLength(kStackSlotCount); |
| 57 EXPECT_EQ(kStackSlotCount, stack_bitmap->Length()); | 57 EXPECT_EQ(kStackSlotCount, stack_bitmap->Length()); |
| 58 | 58 |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 118 } | 118 } |
| 119 // Add a stack map entry at pc offset 3. | 119 // Add a stack map entry at pc offset 3. |
| 120 stackmap_table_builder->AddEntry(3, stack_bitmap, 0); | 120 stackmap_table_builder->AddEntry(3, stack_bitmap, 0); |
| 121 | 121 |
| 122 const Error& error = | 122 const Error& error = |
| 123 Error::Handle(Compiler::CompileParsedFunction(parsed_function)); | 123 Error::Handle(Compiler::CompileParsedFunction(parsed_function)); |
| 124 EXPECT(error.IsNull()); | 124 EXPECT(error.IsNull()); |
| 125 const Code& code = Code::Handle(test->function().CurrentCode()); | 125 const Code& code = Code::Handle(test->function().CurrentCode()); |
| 126 | 126 |
| 127 const Array& stack_maps = | 127 const Array& stack_maps = |
| 128 Array::Handle(stackmap_table_builder->FinalizeStackmaps(code)); | 128 Array::Handle(stackmap_table_builder->FinalizeStackMaps(code)); |
| 129 code.set_stackmaps(stack_maps); | 129 code.set_stackmaps(stack_maps); |
| 130 const Array& stack_map_list = Array::Handle(code.stackmaps()); | 130 const Array& stack_map_list = Array::Handle(code.stackmaps()); |
| 131 EXPECT(!stack_map_list.IsNull()); | 131 EXPECT(!stack_map_list.IsNull()); |
| 132 Stackmap& stack_map = Stackmap::Handle(); | 132 StackMap& stack_map = StackMap::Handle(); |
| 133 EXPECT_EQ(4, stack_map_list.Length()); | 133 EXPECT_EQ(4, stack_map_list.Length()); |
| 134 | 134 |
| 135 // Validate the first stack map entry. | 135 // Validate the first stack map entry. |
| 136 stack_map ^= stack_map_list.At(0); | 136 stack_map ^= stack_map_list.At(0); |
| 137 EXPECT_EQ(kStackSlotCount, stack_map.Length()); | 137 EXPECT_EQ(kStackSlotCount, stack_map.Length()); |
| 138 for (intptr_t i = 0; i < kStackSlotCount; ++i) { | 138 for (intptr_t i = 0; i < kStackSlotCount; ++i) { |
| 139 EXPECT_EQ(expectation0[i], stack_map.IsObject(i)); | 139 EXPECT_EQ(expectation0[i], stack_map.IsObject(i)); |
| 140 } | 140 } |
| 141 | 141 |
| 142 // Validate the second stack map entry. | 142 // Validate the second stack map entry. |
| (...skipping 15 matching lines...) Expand all Loading... |
| 158 EXPECT_EQ(kStackSlotCount, stack_map.Length()); | 158 EXPECT_EQ(kStackSlotCount, stack_map.Length()); |
| 159 for (intptr_t i = 0; i < kStackSlotCount; ++i) { | 159 for (intptr_t i = 0; i < kStackSlotCount; ++i) { |
| 160 EXPECT_EQ(expectation3[i], stack_map.IsObject(i)); | 160 EXPECT_EQ(expectation3[i], stack_map.IsObject(i)); |
| 161 } | 161 } |
| 162 retval = true; | 162 retval = true; |
| 163 } else { | 163 } else { |
| 164 retval = false; | 164 retval = false; |
| 165 } | 165 } |
| 166 EXPECT(retval); | 166 EXPECT(retval); |
| 167 } | 167 } |
| 168 CODEGEN_TEST_RUN(StackmapCodegen, Smi::New(1)) | 168 CODEGEN_TEST_RUN(StackMapCodegen, Smi::New(1)) |
| 169 | 169 |
| 170 | 170 |
| 171 static void NativeFunc(Dart_NativeArguments args) { | 171 static void NativeFunc(Dart_NativeArguments args) { |
| 172 Dart_Handle i = Dart_GetNativeArgument(args, 0); | 172 Dart_Handle i = Dart_GetNativeArgument(args, 0); |
| 173 Dart_Handle k = Dart_GetNativeArgument(args, 1); | 173 Dart_Handle k = Dart_GetNativeArgument(args, 1); |
| 174 int64_t value = -1; | 174 int64_t value = -1; |
| 175 EXPECT_VALID(Dart_IntegerToInt64(i, &value)); | 175 EXPECT_VALID(Dart_IntegerToInt64(i, &value)); |
| 176 EXPECT_EQ(10, value); | 176 EXPECT_EQ(10, value); |
| 177 EXPECT_VALID(Dart_IntegerToInt64(k, &value)); | 177 EXPECT_VALID(Dart_IntegerToInt64(k, &value)); |
| 178 EXPECT_EQ(20, value); | 178 EXPECT_EQ(20, value); |
| 179 { | 179 { |
| 180 TransitionNativeToVM transition(Thread::Current()); | 180 TransitionNativeToVM transition(Thread::Current()); |
| 181 Isolate::Current()->heap()->CollectAllGarbage(); | 181 Isolate::Current()->heap()->CollectAllGarbage(); |
| 182 } | 182 } |
| 183 } | 183 } |
| 184 | 184 |
| 185 | 185 |
| 186 static Dart_NativeFunction native_resolver(Dart_Handle name, | 186 static Dart_NativeFunction native_resolver(Dart_Handle name, |
| 187 int argument_count, | 187 int argument_count, |
| 188 bool* auto_setup_scope) { | 188 bool* auto_setup_scope) { |
| 189 ASSERT(auto_setup_scope); | 189 ASSERT(auto_setup_scope); |
| 190 *auto_setup_scope = false; | 190 *auto_setup_scope = false; |
| 191 return reinterpret_cast<Dart_NativeFunction>(&NativeFunc); | 191 return reinterpret_cast<Dart_NativeFunction>(&NativeFunc); |
| 192 } | 192 } |
| 193 | 193 |
| 194 | 194 |
| 195 TEST_CASE(StackmapGC) { | 195 TEST_CASE(StackMapGC) { |
| 196 const char* kScriptChars = | 196 const char* kScriptChars = |
| 197 "class A {" | 197 "class A {" |
| 198 " static void func(var i, var k) native 'NativeFunc';" | 198 " static void func(var i, var k) native 'NativeFunc';" |
| 199 " static foo() {" | 199 " static foo() {" |
| 200 " var i;" | 200 " var i;" |
| 201 " var s1;" | 201 " var s1;" |
| 202 " var k;" | 202 " var k;" |
| 203 " var s2;" | 203 " var s2;" |
| 204 " var s3;" | 204 " var s3;" |
| 205 " i = 10; s1 = 'abcd'; k = 20; s2 = 'B'; s3 = 'C';" | 205 " i = 10; s1 = 'abcd'; k = 20; s2 = 'B'; s3 = 'C';" |
| (...skipping 24 matching lines...) Expand all Loading... |
| 230 EXPECT(function_moo.HasCode()); | 230 EXPECT(function_moo.HasCode()); |
| 231 | 231 |
| 232 String& function_foo_name = String::Handle(String::New("foo")); | 232 String& function_foo_name = String::Handle(String::New("foo")); |
| 233 Function& function_foo = | 233 Function& function_foo = |
| 234 Function::Handle(cls.LookupStaticFunction(function_foo_name)); | 234 Function::Handle(cls.LookupStaticFunction(function_foo_name)); |
| 235 EXPECT(CompilerTest::TestCompileFunction(function_foo)); | 235 EXPECT(CompilerTest::TestCompileFunction(function_foo)); |
| 236 EXPECT(function_foo.HasCode()); | 236 EXPECT(function_foo.HasCode()); |
| 237 | 237 |
| 238 // Build and setup a stackmap for the call to 'func' in 'A.foo' in order | 238 // Build and setup a stackmap for the call to 'func' in 'A.foo' in order |
| 239 // to test the traversal of stack maps when a GC happens. | 239 // to test the traversal of stack maps when a GC happens. |
| 240 StackmapTableBuilder* stackmap_table_builder = new StackmapTableBuilder(); | 240 StackMapTableBuilder* stackmap_table_builder = new StackMapTableBuilder(); |
| 241 EXPECT(stackmap_table_builder != NULL); | 241 EXPECT(stackmap_table_builder != NULL); |
| 242 BitmapBuilder* stack_bitmap = new BitmapBuilder(); | 242 BitmapBuilder* stack_bitmap = new BitmapBuilder(); |
| 243 EXPECT(stack_bitmap != NULL); | 243 EXPECT(stack_bitmap != NULL); |
| 244 stack_bitmap->Set(0, false); // var i. | 244 stack_bitmap->Set(0, false); // var i. |
| 245 stack_bitmap->Set(1, true); // var s1. | 245 stack_bitmap->Set(1, true); // var s1. |
| 246 stack_bitmap->Set(2, false); // var k. | 246 stack_bitmap->Set(2, false); // var k. |
| 247 stack_bitmap->Set(3, true); // var s2. | 247 stack_bitmap->Set(3, true); // var s2. |
| 248 stack_bitmap->Set(4, true); // var s3. | 248 stack_bitmap->Set(4, true); // var s3. |
| 249 const Code& code = Code::Handle(function_foo.unoptimized_code()); | 249 const Code& code = Code::Handle(function_foo.unoptimized_code()); |
| 250 // Search for the pc of the call to 'func'. | 250 // Search for the pc of the call to 'func'. |
| 251 const PcDescriptors& descriptors = | 251 const PcDescriptors& descriptors = |
| 252 PcDescriptors::Handle(code.pc_descriptors()); | 252 PcDescriptors::Handle(code.pc_descriptors()); |
| 253 int call_count = 0; | 253 int call_count = 0; |
| 254 PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kUnoptStaticCall); | 254 PcDescriptors::Iterator iter(descriptors, RawPcDescriptors::kUnoptStaticCall); |
| 255 while (iter.MoveNext()) { | 255 while (iter.MoveNext()) { |
| 256 stackmap_table_builder->AddEntry(iter.PcOffset(), stack_bitmap, 0); | 256 stackmap_table_builder->AddEntry(iter.PcOffset(), stack_bitmap, 0); |
| 257 ++call_count; | 257 ++call_count; |
| 258 } | 258 } |
| 259 // We can't easily check that we put the stackmap at the correct pc, but | 259 // We can't easily check that we put the stackmap at the correct pc, but |
| 260 // we did if there was exactly one call seen. | 260 // we did if there was exactly one call seen. |
| 261 EXPECT(call_count == 1); | 261 EXPECT(call_count == 1); |
| 262 const Array& stack_maps = | 262 const Array& stack_maps = |
| 263 Array::Handle(stackmap_table_builder->FinalizeStackmaps(code)); | 263 Array::Handle(stackmap_table_builder->FinalizeStackMaps(code)); |
| 264 code.set_stackmaps(stack_maps); | 264 code.set_stackmaps(stack_maps); |
| 265 | 265 |
| 266 // Now invoke 'A.moo' and it will trigger a GC when the native function | 266 // Now invoke 'A.moo' and it will trigger a GC when the native function |
| 267 // is called, this should then cause the stack map of function 'A.foo' | 267 // is called, this should then cause the stack map of function 'A.foo' |
| 268 // to be traversed and the appropriate objects visited. | 268 // to be traversed and the appropriate objects visited. |
| 269 const Object& result = Object::Handle( | 269 const Object& result = Object::Handle( |
| 270 DartEntry::InvokeFunction(function_foo, Object::empty_array())); | 270 DartEntry::InvokeFunction(function_foo, Object::empty_array())); |
| 271 EXPECT(!result.IsError()); | 271 EXPECT(!result.IsError()); |
| 272 } | 272 } |
| 273 | 273 |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 361 if (token_positions[i] != it.TokenPos().value()) { | 361 if (token_positions[i] != it.TokenPos().value()) { |
| 362 OS::Print("[%" Pd "]: Expected: %" Pd " != %" Pd "\n", i, | 362 OS::Print("[%" Pd "]: Expected: %" Pd " != %" Pd "\n", i, |
| 363 token_positions[i], it.TokenPos().value()); | 363 token_positions[i], it.TokenPos().value()); |
| 364 } | 364 } |
| 365 EXPECT(token_positions[i] == it.TokenPos().value()); | 365 EXPECT(token_positions[i] == it.TokenPos().value()); |
| 366 i++; | 366 i++; |
| 367 } | 367 } |
| 368 } | 368 } |
| 369 | 369 |
| 370 } // namespace dart | 370 } // namespace dart |
| OLD | NEW |