|  | /* | 
|  | * Copyright (C) 2015 The Android Open Source Project | 
|  | * | 
|  | * Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | * you may not read this file except in compliance with the License. | 
|  | * You may obtain a copy of the License at | 
|  | * | 
|  | *      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | * | 
|  | * Unless required by applicable law or agreed to in writing, software | 
|  | * distributed under the License is distributed on an "AS IS" BASIS, | 
|  | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | * See the License for the specific language governing permissions and | 
|  | * limitations under the License. | 
|  | */ | 
|  |  | 
|  | #include <gtest/gtest.h> | 
|  |  | 
|  | #include "data_type.h" | 
|  | #include "nodes.h" | 
|  |  | 
|  | namespace art { | 
|  |  | 
|  | // Only runtime types other than void are allowed. | 
|  | static const DataType::Type kTestTypes[] = { | 
|  | DataType::Type::kReference, | 
|  | DataType::Type::kBool, | 
|  | DataType::Type::kInt8, | 
|  | DataType::Type::kUint16, | 
|  | DataType::Type::kInt16, | 
|  | DataType::Type::kInt32, | 
|  | DataType::Type::kInt64, | 
|  | DataType::Type::kFloat32, | 
|  | DataType::Type::kFloat64, | 
|  | }; | 
|  |  | 
|  | /** | 
|  | * Tests for the SideEffects class. | 
|  | */ | 
|  |  | 
|  | // | 
|  | // Helper methods. | 
|  | // | 
|  |  | 
|  | void testWriteAndReadSanity(SideEffects write, SideEffects read) { | 
|  | EXPECT_FALSE(write.DoesNothing()); | 
|  | EXPECT_FALSE(read.DoesNothing()); | 
|  |  | 
|  | EXPECT_TRUE(write.DoesAnyWrite()); | 
|  | EXPECT_FALSE(write.DoesAnyRead()); | 
|  | EXPECT_FALSE(read.DoesAnyWrite()); | 
|  | EXPECT_TRUE(read.DoesAnyRead()); | 
|  |  | 
|  | // All-dependences. | 
|  | SideEffects all = SideEffects::All(); | 
|  | EXPECT_TRUE(all.MayDependOn(write)); | 
|  | EXPECT_FALSE(write.MayDependOn(all)); | 
|  | EXPECT_FALSE(all.MayDependOn(read)); | 
|  | EXPECT_TRUE(read.MayDependOn(all)); | 
|  |  | 
|  | // None-dependences. | 
|  | SideEffects none = SideEffects::None(); | 
|  | EXPECT_FALSE(none.MayDependOn(write)); | 
|  | EXPECT_FALSE(write.MayDependOn(none)); | 
|  | EXPECT_FALSE(none.MayDependOn(read)); | 
|  | EXPECT_FALSE(read.MayDependOn(none)); | 
|  | } | 
|  |  | 
|  | void testWriteAndReadDependence(SideEffects write, SideEffects read) { | 
|  | testWriteAndReadSanity(write, read); | 
|  |  | 
|  | // Dependence only in one direction. | 
|  | EXPECT_FALSE(write.MayDependOn(read)); | 
|  | EXPECT_TRUE(read.MayDependOn(write)); | 
|  | } | 
|  |  | 
|  | void testNoWriteAndReadDependence(SideEffects write, SideEffects read) { | 
|  | testWriteAndReadSanity(write, read); | 
|  |  | 
|  | // No dependence in any direction. | 
|  | EXPECT_FALSE(write.MayDependOn(read)); | 
|  | EXPECT_FALSE(read.MayDependOn(write)); | 
|  | } | 
|  |  | 
|  | // | 
|  | // Actual tests. | 
|  | // | 
|  |  | 
|  | TEST(SideEffectsTest, All) { | 
|  | SideEffects all = SideEffects::All(); | 
|  | EXPECT_TRUE(all.DoesAnyWrite()); | 
|  | EXPECT_TRUE(all.DoesAnyRead()); | 
|  | EXPECT_FALSE(all.DoesNothing()); | 
|  | EXPECT_TRUE(all.DoesAllReadWrite()); | 
|  | } | 
|  |  | 
|  | TEST(SideEffectsTest, None) { | 
|  | SideEffects none = SideEffects::None(); | 
|  | EXPECT_FALSE(none.DoesAnyWrite()); | 
|  | EXPECT_FALSE(none.DoesAnyRead()); | 
|  | EXPECT_TRUE(none.DoesNothing()); | 
|  | EXPECT_FALSE(none.DoesAllReadWrite()); | 
|  | } | 
|  |  | 
|  | TEST(SideEffectsTest, DependencesAndNoDependences) { | 
|  | // Apply test to each individual data type. | 
|  | for (DataType::Type type : kTestTypes) { | 
|  | // Same data type and access type: proper write/read dep. | 
|  | testWriteAndReadDependence( | 
|  | SideEffects::FieldWriteOfType(type, false), | 
|  | SideEffects::FieldReadOfType(type, false)); | 
|  | testWriteAndReadDependence( | 
|  | SideEffects::ArrayWriteOfType(type), | 
|  | SideEffects::ArrayReadOfType(type)); | 
|  | // Same data type but different access type: no write/read dep. | 
|  | testNoWriteAndReadDependence( | 
|  | SideEffects::FieldWriteOfType(type, false), | 
|  | SideEffects::ArrayReadOfType(type)); | 
|  | testNoWriteAndReadDependence( | 
|  | SideEffects::ArrayWriteOfType(type), | 
|  | SideEffects::FieldReadOfType(type, false)); | 
|  | } | 
|  | } | 
|  |  | 
|  | TEST(SideEffectsTest, NoDependences) { | 
|  | // Different data type, same access type: no write/read dep. | 
|  | testNoWriteAndReadDependence( | 
|  | SideEffects::FieldWriteOfType(DataType::Type::kInt32, false), | 
|  | SideEffects::FieldReadOfType(DataType::Type::kFloat64, false)); | 
|  | testNoWriteAndReadDependence( | 
|  | SideEffects::ArrayWriteOfType(DataType::Type::kInt32), | 
|  | SideEffects::ArrayReadOfType(DataType::Type::kFloat64)); | 
|  | // Everything different: no write/read dep. | 
|  | testNoWriteAndReadDependence( | 
|  | SideEffects::FieldWriteOfType(DataType::Type::kInt32, false), | 
|  | SideEffects::ArrayReadOfType(DataType::Type::kFloat64)); | 
|  | testNoWriteAndReadDependence( | 
|  | SideEffects::ArrayWriteOfType(DataType::Type::kInt32), | 
|  | SideEffects::FieldReadOfType(DataType::Type::kFloat64, false)); | 
|  | } | 
|  |  | 
|  | TEST(SideEffectsTest, VolatileDependences) { | 
|  | SideEffects volatile_write = | 
|  | SideEffects::FieldWriteOfType(DataType::Type::kInt32, /* is_volatile */ true); | 
|  | SideEffects any_write = | 
|  | SideEffects::FieldWriteOfType(DataType::Type::kInt32, /* is_volatile */ false); | 
|  | SideEffects volatile_read = | 
|  | SideEffects::FieldReadOfType(DataType::Type::kInt8, /* is_volatile */ true); | 
|  | SideEffects any_read = | 
|  | SideEffects::FieldReadOfType(DataType::Type::kInt8, /* is_volatile */ false); | 
|  |  | 
|  | EXPECT_FALSE(volatile_write.MayDependOn(any_read)); | 
|  | EXPECT_TRUE(any_read.MayDependOn(volatile_write)); | 
|  | EXPECT_TRUE(volatile_write.MayDependOn(any_write)); | 
|  | EXPECT_FALSE(any_write.MayDependOn(volatile_write)); | 
|  |  | 
|  | EXPECT_FALSE(volatile_read.MayDependOn(any_read)); | 
|  | EXPECT_TRUE(any_read.MayDependOn(volatile_read)); | 
|  | EXPECT_TRUE(volatile_read.MayDependOn(any_write)); | 
|  | EXPECT_FALSE(any_write.MayDependOn(volatile_read)); | 
|  | } | 
|  |  | 
|  | TEST(SideEffectsTest, SameWidthTypesNoAlias) { | 
|  | // Type I/F. | 
|  | testNoWriteAndReadDependence( | 
|  | SideEffects::FieldWriteOfType(DataType::Type::kInt32, /* is_volatile */ false), | 
|  | SideEffects::FieldReadOfType(DataType::Type::kFloat32, /* is_volatile */ false)); | 
|  | testNoWriteAndReadDependence( | 
|  | SideEffects::ArrayWriteOfType(DataType::Type::kInt32), | 
|  | SideEffects::ArrayReadOfType(DataType::Type::kFloat32)); | 
|  | // Type L/D. | 
|  | testNoWriteAndReadDependence( | 
|  | SideEffects::FieldWriteOfType(DataType::Type::kInt64, /* is_volatile */ false), | 
|  | SideEffects::FieldReadOfType(DataType::Type::kFloat64, /* is_volatile */ false)); | 
|  | testNoWriteAndReadDependence( | 
|  | SideEffects::ArrayWriteOfType(DataType::Type::kInt64), | 
|  | SideEffects::ArrayReadOfType(DataType::Type::kFloat64)); | 
|  | } | 
|  |  | 
|  | TEST(SideEffectsTest, AllWritesAndReads) { | 
|  | SideEffects s = SideEffects::None(); | 
|  | // Keep taking the union of different writes and reads. | 
|  | for (DataType::Type type : kTestTypes) { | 
|  | s = s.Union(SideEffects::FieldWriteOfType(type, /* is_volatile */ false)); | 
|  | s = s.Union(SideEffects::ArrayWriteOfType(type)); | 
|  | s = s.Union(SideEffects::FieldReadOfType(type, /* is_volatile */ false)); | 
|  | s = s.Union(SideEffects::ArrayReadOfType(type)); | 
|  | } | 
|  | EXPECT_TRUE(s.DoesAllReadWrite()); | 
|  | } | 
|  |  | 
|  | TEST(SideEffectsTest, GC) { | 
|  | SideEffects can_trigger_gc = SideEffects::CanTriggerGC(); | 
|  | SideEffects depends_on_gc = SideEffects::DependsOnGC(); | 
|  | SideEffects all_changes = SideEffects::AllChanges(); | 
|  | SideEffects all_dependencies = SideEffects::AllDependencies(); | 
|  |  | 
|  | EXPECT_TRUE(depends_on_gc.MayDependOn(can_trigger_gc)); | 
|  | EXPECT_TRUE(depends_on_gc.Union(can_trigger_gc).MayDependOn(can_trigger_gc)); | 
|  | EXPECT_FALSE(can_trigger_gc.MayDependOn(depends_on_gc)); | 
|  |  | 
|  | EXPECT_TRUE(depends_on_gc.MayDependOn(all_changes)); | 
|  | EXPECT_TRUE(depends_on_gc.Union(can_trigger_gc).MayDependOn(all_changes)); | 
|  | EXPECT_FALSE(can_trigger_gc.MayDependOn(all_changes)); | 
|  |  | 
|  | EXPECT_TRUE(all_changes.Includes(can_trigger_gc)); | 
|  | EXPECT_FALSE(all_changes.Includes(depends_on_gc)); | 
|  | EXPECT_TRUE(all_dependencies.Includes(depends_on_gc)); | 
|  | EXPECT_FALSE(all_dependencies.Includes(can_trigger_gc)); | 
|  | } | 
|  |  | 
|  | TEST(SideEffectsTest, BitStrings) { | 
|  | EXPECT_STREQ( | 
|  | "|||||||", | 
|  | SideEffects::None().ToString().c_str()); | 
|  | EXPECT_STREQ( | 
|  | "|GC|DFJISCBZL|DFJISCBZL|GC|DFJISCBZL|DFJISCBZL|", | 
|  | SideEffects::All().ToString().c_str()); | 
|  | EXPECT_STREQ( | 
|  | "|||||DFJISCBZL|DFJISCBZL|", | 
|  | SideEffects::AllWrites().ToString().c_str()); | 
|  | EXPECT_STREQ( | 
|  | "||DFJISCBZL|DFJISCBZL||||", | 
|  | SideEffects::AllReads().ToString().c_str()); | 
|  | EXPECT_STREQ( | 
|  | "||||||L|", | 
|  | SideEffects::FieldWriteOfType(DataType::Type::kReference, false).ToString().c_str()); | 
|  | EXPECT_STREQ( | 
|  | "||DFJISCBZL|DFJISCBZL||DFJISCBZL|DFJISCBZL|", | 
|  | SideEffects::FieldWriteOfType(DataType::Type::kReference, true).ToString().c_str()); | 
|  | EXPECT_STREQ( | 
|  | "|||||Z||", | 
|  | SideEffects::ArrayWriteOfType(DataType::Type::kBool).ToString().c_str()); | 
|  | EXPECT_STREQ( | 
|  | "|||||C||", | 
|  | SideEffects::ArrayWriteOfType(DataType::Type::kUint16).ToString().c_str()); | 
|  | EXPECT_STREQ( | 
|  | "|||||S||", | 
|  | SideEffects::ArrayWriteOfType(DataType::Type::kInt16).ToString().c_str()); | 
|  | EXPECT_STREQ( | 
|  | "|||B||||", | 
|  | SideEffects::FieldReadOfType(DataType::Type::kInt8, false).ToString().c_str()); | 
|  | EXPECT_STREQ( | 
|  | "||D|||||", | 
|  | SideEffects::ArrayReadOfType(DataType::Type::kFloat64).ToString().c_str()); | 
|  | EXPECT_STREQ( | 
|  | "||J|||||", | 
|  | SideEffects::ArrayReadOfType(DataType::Type::kInt64).ToString().c_str()); | 
|  | EXPECT_STREQ( | 
|  | "||F|||||", | 
|  | SideEffects::ArrayReadOfType(DataType::Type::kFloat32).ToString().c_str()); | 
|  | EXPECT_STREQ( | 
|  | "||I|||||", | 
|  | SideEffects::ArrayReadOfType(DataType::Type::kInt32).ToString().c_str()); | 
|  | SideEffects s = SideEffects::None(); | 
|  | s = s.Union(SideEffects::FieldWriteOfType(DataType::Type::kUint16, /* is_volatile */ false)); | 
|  | s = s.Union(SideEffects::FieldWriteOfType(DataType::Type::kInt64, /* is_volatile */ false)); | 
|  | s = s.Union(SideEffects::ArrayWriteOfType(DataType::Type::kInt16)); | 
|  | s = s.Union(SideEffects::FieldReadOfType(DataType::Type::kInt32, /* is_volatile */ false)); | 
|  | s = s.Union(SideEffects::ArrayReadOfType(DataType::Type::kFloat32)); | 
|  | s = s.Union(SideEffects::ArrayReadOfType(DataType::Type::kFloat64)); | 
|  | EXPECT_STREQ("||DF|I||S|JC|", s.ToString().c_str()); | 
|  | } | 
|  |  | 
|  | }  // namespace art |