diff options
69 files changed, 776 insertions, 790 deletions
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk index eec471e457..dc5385309a 100644 --- a/build/Android.common_build.mk +++ b/build/Android.common_build.mk @@ -318,6 +318,10 @@ ifeq ($(ART_USE_READ_BARRIER),true) art_cflags += -DART_READ_BARRIER_TYPE_IS_$(ART_READ_BARRIER_TYPE)=1 art_asflags += -DART_USE_READ_BARRIER=1 art_asflags += -DART_READ_BARRIER_TYPE_IS_$(ART_READ_BARRIER_TYPE)=1 + + # Temporarily override -fstack-protector-strong with -fstack-protector to avoid a major + # slowdown with the read barrier config. b/26744236. + art_cflags += -fstack-protector endif ifeq ($(ART_USE_TLAB),true) diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc index fe83ba9e14..dc2c9c954a 100644 --- a/cmdline/cmdline_parser_test.cc +++ b/cmdline/cmdline_parser_test.cc @@ -535,7 +535,7 @@ TEST_F(CmdlineParserTest, TestProfilerOptions) { /* -Xexperimental:_ */ TEST_F(CmdlineParserTest, TestExperimentalFlags) { - // Off by default + // Default EXPECT_SINGLE_PARSE_DEFAULT_VALUE(ExperimentalFlags::kNone, "", M::Experimental); @@ -549,16 +549,6 @@ TEST_F(CmdlineParserTest, TestExperimentalFlags) { EXPECT_SINGLE_PARSE_VALUE(ExperimentalFlags::kLambdas, "-Xexperimental:lambdas", M::Experimental); - // Enabled explicitly - EXPECT_SINGLE_PARSE_VALUE(ExperimentalFlags::kDefaultMethods, - "-Xexperimental:default-methods", - M::Experimental); - - // Enabled both - EXPECT_SINGLE_PARSE_VALUE(ExperimentalFlags::kDefaultMethods | ExperimentalFlags::kLambdas, - "-Xexperimental:default-methods " - "-Xexperimental:lambdas", - M::Experimental); } // -Xverify:_ diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h index 97c672c560..740199d541 100644 --- a/cmdline/cmdline_types.h +++ b/cmdline/cmdline_types.h @@ -847,11 +847,9 @@ template<> struct CmdlineType<ExperimentalFlags> : CmdlineTypeParser<ExperimentalFlags> { Result ParseAndAppend(const std::string& option, ExperimentalFlags& existing) { if (option == "none") { - existing = existing | ExperimentalFlags::kNone; + existing = ExperimentalFlags::kNone; } else if (option == "lambdas") { existing = existing | ExperimentalFlags::kLambdas; - } else if (option == "default-methods") { - existing = existing | ExperimentalFlags::kDefaultMethods; } else { return Result::Failure(std::string("Unknown option '") + option + "'"); } diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc index 3766093fa8..22b178ce7d 100644 --- a/compiler/dex/quick/dex_file_method_inliner.cc +++ b/compiler/dex/quick/dex_file_method_inliner.cc @@ -37,13 +37,21 @@ namespace { // anonymous namespace static constexpr bool kIntrinsicIsStatic[] = { true, // kIntrinsicDoubleCvt true, // kIntrinsicFloatCvt + true, // kIntrinsicFloatIsInfinite + true, // kIntrinsicDoubleIsInfinite + true, // kIntrinsicFloatIsNaN + true, // kIntrinsicDoubleIsNaN true, // kIntrinsicReverseBits true, // kIntrinsicReverseBytes true, // kIntrinsicBitCount + true, // kIntrinsicCompare, + true, // kIntrinsicHighestOneBit + true, // kIntrinsicLowestOneBit true, // kIntrinsicNumberOfLeadingZeros true, // kIntrinsicNumberOfTrailingZeros true, // kIntrinsicRotateRight true, // kIntrinsicRotateLeft + true, // kIntrinsicSignum true, // kIntrinsicAbsInt true, // kIntrinsicAbsLong true, // kIntrinsicAbsFloat @@ -98,15 +106,23 @@ static_assert(arraysize(kIntrinsicIsStatic) == kInlineOpNop, "arraysize of kIntrinsicIsStatic unexpected"); static_assert(kIntrinsicIsStatic[kIntrinsicDoubleCvt], "DoubleCvt must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicFloatCvt], "FloatCvt must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicFloatIsInfinite], "FloatIsInfinite must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicDoubleIsInfinite], "DoubleIsInfinite must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicFloatIsNaN], "FloatIsNaN must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicDoubleIsNaN], "DoubleIsNaN must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicReverseBits], "ReverseBits must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicReverseBytes], "ReverseBytes must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicBitCount], "BitCount must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicCompare], "Compare must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicHighestOneBit], "HighestOneBit must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicLowestOneBit], "LowestOneBit must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfLeadingZeros], "NumberOfLeadingZeros must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicNumberOfTrailingZeros], "NumberOfTrailingZeros must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicRotateRight], "RotateRight must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicRotateLeft], "RotateLeft must be static"); +static_assert(kIntrinsicIsStatic[kIntrinsicSignum], "Signum must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAbsInt], "AbsInt must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAbsLong], "AbsLong must be static"); static_assert(kIntrinsicIsStatic[kIntrinsicAbsFloat], "AbsFloat must be static"); @@ -261,6 +277,8 @@ const char* const DexFileMethodInliner::kNameCacheNames[] = { "equals", // kNameCacheEquals "getCharsNoCheck", // kNameCacheGetCharsNoCheck "isEmpty", // kNameCacheIsEmpty + "isInfinite", // kNameCacheIsInfinite + "isNaN", // kNameCacheIsNaN "indexOf", // kNameCacheIndexOf "length", // kNameCacheLength "<init>", // kNameCacheInit @@ -296,10 +314,14 @@ const char* const DexFileMethodInliner::kNameCacheNames[] = { "putOrderedObject", // kNameCachePutOrderedObject "arraycopy", // kNameCacheArrayCopy "bitCount", // kNameCacheBitCount + "compare", // kNameCacheCompare + "highestOneBit", // kNameCacheHighestOneBit + "lowestOneBit", // kNameCacheLowestOneBit "numberOfLeadingZeros", // kNameCacheNumberOfLeadingZeros "numberOfTrailingZeros", // kNameCacheNumberOfTrailingZeros "rotateRight", // kNameCacheRotateRight "rotateLeft", // kNameCacheRotateLeft + "signum", // kNameCacheSignum }; const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = { @@ -319,10 +341,14 @@ const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = { { kClassCacheFloat, 2, { kClassCacheFloat, kClassCacheFloat } }, // kProtoCacheD_J { kClassCacheLong, 1, { kClassCacheDouble } }, + // kProtoCacheD_Z + { kClassCacheBoolean, 1, { kClassCacheDouble } }, // kProtoCacheJ_D { kClassCacheDouble, 1, { kClassCacheLong } }, // kProtoCacheF_I { kClassCacheInt, 1, { kClassCacheFloat } }, + // kProtoCacheF_Z + { kClassCacheBoolean, 1, { kClassCacheFloat } }, // kProtoCacheI_F { kClassCacheFloat, 1, { kClassCacheInt } }, // kProtoCacheII_I @@ -351,6 +377,8 @@ const DexFileMethodInliner::ProtoDef DexFileMethodInliner::kProtoCacheDefs[] = { { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheInt } }, // kProtoCacheJJ_J { kClassCacheLong, 2, { kClassCacheLong, kClassCacheLong } }, + // kProtoCacheJJ_I + { kClassCacheInt, 2, { kClassCacheLong, kClassCacheLong } }, // kProtoCacheJJ_V { kClassCacheVoid, 2, { kClassCacheLong, kClassCacheLong } }, // kProtoCacheJS_V @@ -444,6 +472,11 @@ const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0), INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, kIntrinsicFlagToFloatingPoint), + INTRINSIC(JavaLangFloat, IsInfinite, F_Z, kIntrinsicFloatIsInfinite, 0), + INTRINSIC(JavaLangDouble, IsInfinite, D_Z, kIntrinsicDoubleIsInfinite, 0), + INTRINSIC(JavaLangFloat, IsNaN, F_Z, kIntrinsicFloatIsNaN, 0), + INTRINSIC(JavaLangDouble, IsNaN, D_Z, kIntrinsicDoubleIsNaN, 0), + INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, k32), INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, k64), INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf), @@ -452,10 +485,18 @@ const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods INTRINSIC(JavaLangInteger, BitCount, I_I, kIntrinsicBitCount, k32), INTRINSIC(JavaLangLong, BitCount, J_I, kIntrinsicBitCount, k64), + INTRINSIC(JavaLangInteger, Compare, II_I, kIntrinsicCompare, k32), + INTRINSIC(JavaLangLong, Compare, JJ_I, kIntrinsicCompare, k64), + INTRINSIC(JavaLangInteger, HighestOneBit, I_I, kIntrinsicHighestOneBit, k32), + INTRINSIC(JavaLangLong, HighestOneBit, J_J, kIntrinsicHighestOneBit, k64), + INTRINSIC(JavaLangInteger, LowestOneBit, I_I, kIntrinsicLowestOneBit, k32), + INTRINSIC(JavaLangLong, LowestOneBit, J_J, kIntrinsicLowestOneBit, k64), INTRINSIC(JavaLangInteger, NumberOfLeadingZeros, I_I, kIntrinsicNumberOfLeadingZeros, k32), INTRINSIC(JavaLangLong, NumberOfLeadingZeros, J_I, kIntrinsicNumberOfLeadingZeros, k64), INTRINSIC(JavaLangInteger, NumberOfTrailingZeros, I_I, kIntrinsicNumberOfTrailingZeros, k32), INTRINSIC(JavaLangLong, NumberOfTrailingZeros, J_I, kIntrinsicNumberOfTrailingZeros, k64), + INTRINSIC(JavaLangInteger, Signum, I_I, kIntrinsicSignum, k32), + INTRINSIC(JavaLangLong, Signum, J_I, kIntrinsicSignum, k64), INTRINSIC(JavaLangMath, Abs, I_I, kIntrinsicAbsInt, 0), INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0), @@ -750,11 +791,19 @@ bool DexFileMethodInliner::GenIntrinsic(Mir2Lir* backend, CallInfo* info) { intrinsic.d.data & kIntrinsicFlagIsOrdered); case kIntrinsicSystemArrayCopyCharArray: return backend->GenInlinedArrayCopyCharArray(info); + case kIntrinsicFloatIsInfinite: + case kIntrinsicDoubleIsInfinite: + case kIntrinsicFloatIsNaN: + case kIntrinsicDoubleIsNaN: case kIntrinsicBitCount: + case kIntrinsicCompare: + case kIntrinsicHighestOneBit: + case kIntrinsicLowestOneBit: case kIntrinsicNumberOfLeadingZeros: case kIntrinsicNumberOfTrailingZeros: case kIntrinsicRotateRight: case kIntrinsicRotateLeft: + case kIntrinsicSignum: case kIntrinsicSystemArrayCopy: return false; // not implemented in quick. default: diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h index 28036237d7..59b8a533ae 100644 --- a/compiler/dex/quick/dex_file_method_inliner.h +++ b/compiler/dex/quick/dex_file_method_inliner.h @@ -190,6 +190,8 @@ class DexFileMethodInliner { kNameCacheEquals, kNameCacheGetCharsNoCheck, kNameCacheIsEmpty, + kNameCacheIsInfinite, + kNameCacheIsNaN, kNameCacheIndexOf, kNameCacheLength, kNameCacheInit, @@ -225,10 +227,14 @@ class DexFileMethodInliner { kNameCachePutOrderedObject, kNameCacheArrayCopy, kNameCacheBitCount, + kNameCacheCompare, + kNameCacheHighestOneBit, + kNameCacheLowestOneBit, kNameCacheNumberOfLeadingZeros, kNameCacheNumberOfTrailingZeros, kNameCacheRotateRight, kNameCacheRotateLeft, + kNameCacheSignum, kNameCacheLast }; @@ -247,8 +253,10 @@ class DexFileMethodInliner { kProtoCacheF_F, kProtoCacheFF_F, kProtoCacheD_J, + kProtoCacheD_Z, kProtoCacheJ_D, kProtoCacheF_I, + kProtoCacheF_Z, kProtoCacheI_F, kProtoCacheII_I, kProtoCacheI_C, @@ -263,6 +271,7 @@ class DexFileMethodInliner { kProtoCacheJB_V, kProtoCacheJI_V, kProtoCacheJJ_J, + kProtoCacheJJ_I, kProtoCacheJJ_V, kProtoCacheJS_V, kProtoCacheObject_Z, diff --git a/compiler/dex/quick/quick_compiler.cc b/compiler/dex/quick/quick_compiler.cc index ebc9a2c9ea..027290f9b1 100644 --- a/compiler/dex/quick/quick_compiler.cc +++ b/compiler/dex/quick/quick_compiler.cc @@ -486,11 +486,6 @@ static const size_t kUnsupportedOpcodesSize[] = { static_assert(sizeof(kUnsupportedOpcodesSize) == 8 * sizeof(size_t), "kUnsupportedOpcodesSize unexpected"); -static bool IsUnsupportedExperimentalLambdasOnly(size_t i) { - DCHECK_LE(i, arraysize(kUnsupportedOpcodes)); - return kUnsupportedOpcodes[i] == kUnsupportedLambdaOpcodes; -} - // The maximum amount of Dalvik register in a method for which we will start compiling. Tries to // avoid an abort when we need to manage more SSA registers than we can. static constexpr size_t kMaxAllowedDalvikRegisters = INT16_MAX / 2; @@ -513,36 +508,6 @@ static bool CanCompileShorty(const char* shorty, InstructionSet instruction_set) return true; } -// If the ISA has unsupported opcodes, should we skip scanning over them? -// -// Most of the time we're compiling non-experimental files, so scanning just slows -// performance down by as much as 6% with 4 threads. -// In the rare cases we compile experimental opcodes, the runtime has an option to enable it, -// which will force scanning for any unsupported opcodes. -static bool SkipScanningUnsupportedOpcodes(InstructionSet instruction_set) { - Runtime* runtime = Runtime::Current(); - if (UNLIKELY(runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods))) { - // Always need to scan opcodes if we have default methods since invoke-super for interface - // methods is never going to be supported in the quick compiler. - return false; - } else if (UNLIKELY(kUnsupportedOpcodesSize[instruction_set] == 0U)) { - // All opcodes are supported no matter what. Usually not the case - // since experimental opcodes are not implemented in the quick compiler. - return true; - } else if (LIKELY(!Runtime::Current()-> - AreExperimentalFlagsEnabled(ExperimentalFlags::kLambdas))) { - // Experimental opcodes are disabled. - // - // If all unsupported opcodes are experimental we don't need to do scanning. - return IsUnsupportedExperimentalLambdasOnly(instruction_set); - } else { - // Experimental opcodes are enabled. - // - // Do the opcode scanning if the ISA has any unsupported opcodes. - return false; - } -} - bool QuickCompiler::CanCompileInstruction(const MIR* mir, const DexFile& dex_file) const { switch (mir->dalvikInsn.opcode) { @@ -572,11 +537,8 @@ bool QuickCompiler::CanCompileMethod(uint32_t method_idx, return false; } - // Check whether we do have limitations at all. - if (kSupportedTypes[cu->instruction_set] == nullptr && - SkipScanningUnsupportedOpcodes(cu->instruction_set)) { - return true; - } + // Since the quick compiler doesn't (and never will) support default methods we always need to + // scan opcodes. // Check if we can compile the prototype. const char* shorty = dex_file.GetMethodShorty(dex_file.GetMethodId(method_idx)); diff --git a/compiler/image_test.cc b/compiler/image_test.cc index b8416751c5..b65fb36167 100644 --- a/compiler/image_test.cc +++ b/compiler/image_test.cc @@ -181,7 +181,7 @@ void ImageTest::TestWriteRead(ImageHeader::StorageMode storage_mode) { ASSERT_NE(0U, bitmap_section.Size()); gc::Heap* heap = Runtime::Current()->GetHeap(); - ASSERT_TRUE(!heap->GetContinuousSpaces().empty()); + ASSERT_TRUE(heap->HaveContinuousSpaces()); gc::space::ContinuousSpace* space = heap->GetNonMovingSpace(); ASSERT_FALSE(space->IsImageSpace()); ASSERT_TRUE(space != nullptr); diff --git a/compiler/optimizing/bounds_check_elimination.h b/compiler/optimizing/bounds_check_elimination.h index b9df686ffd..6dc53207ea 100644 --- a/compiler/optimizing/bounds_check_elimination.h +++ b/compiler/optimizing/bounds_check_elimination.h @@ -29,13 +29,13 @@ class BoundsCheckElimination : public HOptimization { BoundsCheckElimination(HGraph* graph, const SideEffectsAnalysis& side_effects, HInductionVarAnalysis* induction_analysis) - : HOptimization(graph, kBoundsCheckEliminiationPassName), + : HOptimization(graph, kBoundsCheckEliminationPassName), side_effects_(side_effects), induction_analysis_(induction_analysis) {} void Run() OVERRIDE; - static constexpr const char* kBoundsCheckEliminiationPassName = "BCE"; + static constexpr const char* kBoundsCheckEliminationPassName = "BCE"; private: const SideEffectsAnalysis& side_effects_; diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 32c3a925e0..280516252b 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -21,6 +21,7 @@ #include <cctype> #include <sstream> +#include "bounds_check_elimination.h" #include "code_generator.h" #include "dead_code_elimination.h" #include "disassembler.h" @@ -505,6 +506,7 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { if (IsPass(LICM::kLoopInvariantCodeMotionPassName) || IsPass(HDeadCodeElimination::kFinalDeadCodeEliminationPassName) || IsPass(HDeadCodeElimination::kInitialDeadCodeEliminationPassName) + || IsPass(BoundsCheckElimination::kBoundsCheckEliminationPassName) || IsPass(SsaBuilder::kSsaBuilderPassName)) { HLoopInformation* info = instruction->GetBlock()->GetLoopInformation(); if (info == nullptr) { diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 5caf077858..a6be324730 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -131,6 +131,16 @@ static Intrinsics GetIntrinsic(InlineMethod method) { return ((method.d.data & kIntrinsicFlagToFloatingPoint) == 0) ? Intrinsics::kFloatFloatToRawIntBits : Intrinsics::kFloatIntBitsToFloat; + // Floating-point tests. + case kIntrinsicFloatIsInfinite: + return Intrinsics::kFloatIsInfinite; + case kIntrinsicDoubleIsInfinite: + return Intrinsics::kDoubleIsInfinite; + case kIntrinsicFloatIsNaN: + return Intrinsics::kFloatIsNaN; + case kIntrinsicDoubleIsNaN: + return Intrinsics::kDoubleIsNaN; + // Bit manipulations. case kIntrinsicReverseBits: switch (GetType(method.d.data, true)) { @@ -186,6 +196,36 @@ static Intrinsics GetIntrinsic(InlineMethod method) { LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; UNREACHABLE(); } + case kIntrinsicCompare: + switch (GetType(method.d.data, true)) { + case Primitive::kPrimInt: + return Intrinsics::kIntegerCompare; + case Primitive::kPrimLong: + return Intrinsics::kLongCompare; + default: + LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; + UNREACHABLE(); + } + case kIntrinsicHighestOneBit: + switch (GetType(method.d.data, true)) { + case Primitive::kPrimInt: + return Intrinsics::kIntegerHighestOneBit; + case Primitive::kPrimLong: + return Intrinsics::kLongHighestOneBit; + default: + LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; + UNREACHABLE(); + } + case kIntrinsicLowestOneBit: + switch (GetType(method.d.data, true)) { + case Primitive::kPrimInt: + return Intrinsics::kIntegerLowestOneBit; + case Primitive::kPrimLong: + return Intrinsics::kLongLowestOneBit; + default: + LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; + UNREACHABLE(); + } case kIntrinsicNumberOfLeadingZeros: switch (GetType(method.d.data, true)) { case Primitive::kPrimInt: @@ -206,6 +246,16 @@ static Intrinsics GetIntrinsic(InlineMethod method) { LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; UNREACHABLE(); } + case kIntrinsicSignum: + switch (GetType(method.d.data, true)) { + case Primitive::kPrimInt: + return Intrinsics::kIntegerSignum; + case Primitive::kPrimLong: + return Intrinsics::kLongSignum; + default: + LOG(FATAL) << "Unknown/unsupported op size " << method.d.data; + UNREACHABLE(); + } // Abs. case kIntrinsicAbsDouble: diff --git a/compiler/optimizing/intrinsics_arm.cc b/compiler/optimizing/intrinsics_arm.cc index e72f927e44..97fe5872bf 100644 --- a/compiler/optimizing/intrinsics_arm.cc +++ b/compiler/optimizing/intrinsics_arm.cc @@ -1580,13 +1580,9 @@ void IntrinsicCodeGeneratorARM::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) UNIMPLEMENTED_INTRINSIC(IntegerBitCount) UNIMPLEMENTED_INTRINSIC(IntegerReverse) UNIMPLEMENTED_INTRINSIC(IntegerReverseBytes) -UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft) -UNIMPLEMENTED_INTRINSIC(IntegerRotateRight) UNIMPLEMENTED_INTRINSIC(LongBitCount) UNIMPLEMENTED_INTRINSIC(LongReverse) UNIMPLEMENTED_INTRINSIC(LongReverseBytes) -UNIMPLEMENTED_INTRINSIC(LongRotateLeft) -UNIMPLEMENTED_INTRINSIC(LongRotateRight) UNIMPLEMENTED_INTRINSIC(ShortReverseBytes) UNIMPLEMENTED_INTRINSIC(MathMinDoubleDouble) UNIMPLEMENTED_INTRINSIC(MathMinFloatFloat) @@ -1621,6 +1617,26 @@ UNIMPLEMENTED_INTRINSIC(MathSinh) UNIMPLEMENTED_INTRINSIC(MathTan) UNIMPLEMENTED_INTRINSIC(MathTanh) +UNIMPLEMENTED_INTRINSIC(FloatIsInfinite) +UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite) +UNIMPLEMENTED_INTRINSIC(FloatIsNaN) +UNIMPLEMENTED_INTRINSIC(DoubleIsNaN) + +UNIMPLEMENTED_INTRINSIC(IntegerCompare) +UNIMPLEMENTED_INTRINSIC(LongCompare) +UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit) +UNIMPLEMENTED_INTRINSIC(LongHighestOneBit) +UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit) +UNIMPLEMENTED_INTRINSIC(LongLowestOneBit) +UNIMPLEMENTED_INTRINSIC(IntegerSignum) +UNIMPLEMENTED_INTRINSIC(LongSignum) + +// Rotate operations are handled as HRor instructions. +UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft) +UNIMPLEMENTED_INTRINSIC(IntegerRotateRight) +UNIMPLEMENTED_INTRINSIC(LongRotateLeft) +UNIMPLEMENTED_INTRINSIC(LongRotateRight) + #undef UNIMPLEMENTED_INTRINSIC #undef __ diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc index 8cf2d4f393..c888f01841 100644 --- a/compiler/optimizing/intrinsics_arm64.cc +++ b/compiler/optimizing/intrinsics_arm64.cc @@ -1465,11 +1465,7 @@ void IntrinsicCodeGeneratorARM64::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED } UNIMPLEMENTED_INTRINSIC(IntegerBitCount) -UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft) -UNIMPLEMENTED_INTRINSIC(IntegerRotateRight) UNIMPLEMENTED_INTRINSIC(LongBitCount) -UNIMPLEMENTED_INTRINSIC(LongRotateLeft) -UNIMPLEMENTED_INTRINSIC(LongRotateRight) UNIMPLEMENTED_INTRINSIC(SystemArrayCopyChar) UNIMPLEMENTED_INTRINSIC(SystemArrayCopy) UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) @@ -1493,6 +1489,26 @@ UNIMPLEMENTED_INTRINSIC(MathSinh) UNIMPLEMENTED_INTRINSIC(MathTan) UNIMPLEMENTED_INTRINSIC(MathTanh) +UNIMPLEMENTED_INTRINSIC(FloatIsInfinite) +UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite) +UNIMPLEMENTED_INTRINSIC(FloatIsNaN) +UNIMPLEMENTED_INTRINSIC(DoubleIsNaN) + +UNIMPLEMENTED_INTRINSIC(IntegerCompare) +UNIMPLEMENTED_INTRINSIC(LongCompare) +UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit) +UNIMPLEMENTED_INTRINSIC(LongHighestOneBit) +UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit) +UNIMPLEMENTED_INTRINSIC(LongLowestOneBit) +UNIMPLEMENTED_INTRINSIC(IntegerSignum) +UNIMPLEMENTED_INTRINSIC(LongSignum) + +// Rotate operations are handled as HRor instructions. +UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft) +UNIMPLEMENTED_INTRINSIC(IntegerRotateRight) +UNIMPLEMENTED_INTRINSIC(LongRotateLeft) +UNIMPLEMENTED_INTRINSIC(LongRotateRight) + #undef UNIMPLEMENTED_INTRINSIC #undef __ diff --git a/compiler/optimizing/intrinsics_list.h b/compiler/optimizing/intrinsics_list.h index ea380347da..88217b308e 100644 --- a/compiler/optimizing/intrinsics_list.h +++ b/compiler/optimizing/intrinsics_list.h @@ -23,23 +23,35 @@ #define INTRINSICS_LIST(V) \ V(DoubleDoubleToRawLongBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ + V(DoubleIsInfinite, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ + V(DoubleIsNaN, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(DoubleLongBitsToDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(FloatFloatToRawIntBits, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ + V(FloatIsInfinite, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ + V(FloatIsNaN, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(FloatIntBitsToFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(IntegerReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(IntegerReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(IntegerBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ + V(IntegerCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ + V(IntegerHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ + V(IntegerLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(IntegerNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(IntegerNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(IntegerRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(IntegerRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ + V(IntegerSignum, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(LongReverse, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(LongReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(LongBitCount, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ + V(LongCompare, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ + V(LongHighestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ + V(LongLowestOneBit, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(LongNumberOfLeadingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(LongNumberOfTrailingZeros, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(LongRotateRight, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(LongRotateLeft, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ + V(LongSignum, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(ShortReverseBytes, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(MathAbsDouble, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ V(MathAbsFloat, kStatic, kNeedsEnvironmentOrCache, kNoSideEffects, kNoThrow) \ diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc index 81112b1a34..0d9cf091cc 100644 --- a/compiler/optimizing/intrinsics_mips.cc +++ b/compiler/optimizing/intrinsics_mips.cc @@ -1013,6 +1013,21 @@ UNIMPLEMENTED_INTRINSIC(MathNextAfter) UNIMPLEMENTED_INTRINSIC(MathSinh) UNIMPLEMENTED_INTRINSIC(MathTan) UNIMPLEMENTED_INTRINSIC(MathTanh) + +UNIMPLEMENTED_INTRINSIC(FloatIsInfinite) +UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite) +UNIMPLEMENTED_INTRINSIC(FloatIsNaN) +UNIMPLEMENTED_INTRINSIC(DoubleIsNaN) + +UNIMPLEMENTED_INTRINSIC(IntegerCompare) +UNIMPLEMENTED_INTRINSIC(LongCompare) +UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit) +UNIMPLEMENTED_INTRINSIC(LongHighestOneBit) +UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit) +UNIMPLEMENTED_INTRINSIC(LongLowestOneBit) +UNIMPLEMENTED_INTRINSIC(IntegerSignum) +UNIMPLEMENTED_INTRINSIC(LongSignum) + #undef UNIMPLEMENTED_INTRINSIC #undef __ diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc index 769c4228c4..cba84fa3e3 100644 --- a/compiler/optimizing/intrinsics_mips64.cc +++ b/compiler/optimizing/intrinsics_mips64.cc @@ -1760,6 +1760,20 @@ UNIMPLEMENTED_INTRINSIC(MathSinh) UNIMPLEMENTED_INTRINSIC(MathTan) UNIMPLEMENTED_INTRINSIC(MathTanh) +UNIMPLEMENTED_INTRINSIC(FloatIsInfinite) +UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite) +UNIMPLEMENTED_INTRINSIC(FloatIsNaN) +UNIMPLEMENTED_INTRINSIC(DoubleIsNaN) + +UNIMPLEMENTED_INTRINSIC(IntegerCompare) +UNIMPLEMENTED_INTRINSIC(LongCompare) +UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit) +UNIMPLEMENTED_INTRINSIC(LongHighestOneBit) +UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit) +UNIMPLEMENTED_INTRINSIC(LongLowestOneBit) +UNIMPLEMENTED_INTRINSIC(IntegerSignum) +UNIMPLEMENTED_INTRINSIC(LongSignum) + #undef UNIMPLEMENTED_INTRINSIC #undef __ diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc index 3f5688b0db..acc40bc998 100644 --- a/compiler/optimizing/intrinsics_x86.cc +++ b/compiler/optimizing/intrinsics_x86.cc @@ -2593,11 +2593,27 @@ void IntrinsicCodeGeneratorX86::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSED) UNIMPLEMENTED_INTRINSIC(MathRoundDouble) UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) +UNIMPLEMENTED_INTRINSIC(SystemArrayCopy) + +UNIMPLEMENTED_INTRINSIC(FloatIsInfinite) +UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite) +UNIMPLEMENTED_INTRINSIC(FloatIsNaN) +UNIMPLEMENTED_INTRINSIC(DoubleIsNaN) + +UNIMPLEMENTED_INTRINSIC(IntegerCompare) +UNIMPLEMENTED_INTRINSIC(LongCompare) +UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit) +UNIMPLEMENTED_INTRINSIC(LongHighestOneBit) +UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit) +UNIMPLEMENTED_INTRINSIC(LongLowestOneBit) +UNIMPLEMENTED_INTRINSIC(IntegerSignum) +UNIMPLEMENTED_INTRINSIC(LongSignum) + +// Rotate operations are handled as HRor instructions. UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft) UNIMPLEMENTED_INTRINSIC(IntegerRotateRight) UNIMPLEMENTED_INTRINSIC(LongRotateRight) UNIMPLEMENTED_INTRINSIC(LongRotateLeft) -UNIMPLEMENTED_INTRINSIC(SystemArrayCopy) #undef UNIMPLEMENTED_INTRINSIC diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc index 23a628f243..6ccc5d1e01 100644 --- a/compiler/optimizing/intrinsics_x86_64.cc +++ b/compiler/optimizing/intrinsics_x86_64.cc @@ -2592,6 +2592,22 @@ void IntrinsicCodeGeneratorX86_64::Visit ## Name(HInvoke* invoke ATTRIBUTE_UNUSE } UNIMPLEMENTED_INTRINSIC(ReferenceGetReferent) + +UNIMPLEMENTED_INTRINSIC(FloatIsInfinite) +UNIMPLEMENTED_INTRINSIC(DoubleIsInfinite) +UNIMPLEMENTED_INTRINSIC(FloatIsNaN) +UNIMPLEMENTED_INTRINSIC(DoubleIsNaN) + +UNIMPLEMENTED_INTRINSIC(IntegerCompare) +UNIMPLEMENTED_INTRINSIC(LongCompare) +UNIMPLEMENTED_INTRINSIC(IntegerHighestOneBit) +UNIMPLEMENTED_INTRINSIC(LongHighestOneBit) +UNIMPLEMENTED_INTRINSIC(IntegerLowestOneBit) +UNIMPLEMENTED_INTRINSIC(LongLowestOneBit) +UNIMPLEMENTED_INTRINSIC(IntegerSignum) +UNIMPLEMENTED_INTRINSIC(LongSignum) + +// Rotate operations are handled as HRor instructions. UNIMPLEMENTED_INTRINSIC(IntegerRotateLeft) UNIMPLEMENTED_INTRINSIC(IntegerRotateRight) UNIMPLEMENTED_INTRINSIC(LongRotateLeft) diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index adf8734214..92f758d61d 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -2221,10 +2221,7 @@ void HInvoke::SetIntrinsic(Intrinsics intrinsic, SetSideEffects(GetSideEffects().Union(SideEffects::CanTriggerGC())); } // Adjust method's exception status from intrinsic table. - switch (exceptions) { - case kNoThrow: SetCanThrow(false); break; - case kCanThrow: SetCanThrow(true); break; - } + SetCanThrow(exceptions == kCanThrow); } bool HNewInstance::IsStringAlloc() const { diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 7b9ce5bd1b..57b52fcdd8 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -40,7 +40,7 @@ #include "gc/space/image_space.h" #include "gc/space/large_object_space.h" #include "gc/space/space-inl.h" -#include "image.h" +#include "image-inl.h" #include "indenter.h" #include "linker/buffered_output_stream.h" #include "linker/file_output_stream.h" diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc index 7e4ce917db..1668dc5f25 100644 --- a/patchoat/patchoat.cc +++ b/patchoat/patchoat.cc @@ -35,7 +35,7 @@ #include "elf_file.h" #include "elf_file_impl.h" #include "gc/space/image_space.h" -#include "image.h" +#include "image-inl.h" #include "mirror/abstract_method.h" #include "mirror/object-inl.h" #include "mirror/method.h" diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index ff38394038..bb709e8774 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -53,6 +53,7 @@ #include "gc/heap.h" #include "gc/space/image_space.h" #include "handle_scope-inl.h" +#include "image-inl.h" #include "intern_table.h" #include "interpreter/interpreter.h" #include "jit/jit.h" @@ -2926,19 +2927,19 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation(); // For app images, the dex cache location may be a suffix of the dex file location since the // dex file location is an absolute path. - const size_t dex_cache_length = dex_cache->GetLocation()->GetLength(); + const std::string dex_cache_location = dex_cache->GetLocation()->ToModifiedUtf8(); + const size_t dex_cache_length = dex_cache_location.length(); CHECK_GT(dex_cache_length, 0u) << dex_file.GetLocation(); std::string dex_file_location = dex_file.GetLocation(); CHECK_GE(dex_file_location.length(), dex_cache_length) - << dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation(); + << dex_cache_location << " " << dex_file.GetLocation(); // Take suffix. const std::string dex_file_suffix = dex_file_location.substr( dex_file_location.length() - dex_cache_length, dex_cache_length); // Example dex_cache location is SettingsProvider.apk and // dex file location is /system/priv-app/SettingsProvider/SettingsProvider.apk - CHECK(dex_cache->GetLocation()->Equals(dex_file_suffix)) - << dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation(); + CHECK_EQ(dex_cache_location, dex_file_suffix); // Clean up pass to remove null dex caches. // Null dex caches can occur due to class unloading and we are lazily removing null entries. JavaVMExt* const vm = self->GetJniEnv()->vm; @@ -5973,15 +5974,6 @@ bool ClassLinker::LinkInterfaceMethods( Runtime* const runtime = Runtime::Current(); const bool is_interface = klass->IsInterface(); - // TODO It might in the future prove useful to make interfaces have full iftables, allowing a - // faster invoke-super implementation in the interpreter/across dex-files. - // We will just skip doing any of this on non-debug builds for speed. - if (is_interface && - !kIsDebugBuild && - !runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) { - return true; - } - const bool has_superclass = klass->HasSuperClass(); const bool fill_tables = !is_interface; const size_t super_ifcount = has_superclass ? klass->GetSuperClass()->GetIfTableCount() : 0U; diff --git a/runtime/class_linker.h b/runtime/class_linker.h index d503dd4704..4975c29742 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -1063,8 +1063,8 @@ class ClassLinker { friend class ImageWriter; // for GetClassRoots friend class JniCompilerTest; // for GetRuntimeQuickGenericJniStub friend class JniInternalTest; // for GetRuntimeQuickGenericJniStub + ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName); // for DexLock, and RegisterDexFileLocked ART_FRIEND_TEST(mirror::DexCacheTest, Open); // for AllocDexCache - DISALLOW_COPY_AND_ASSIGN(ClassLinker); }; diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index 471d7ca5e6..40dfda9316 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -1201,4 +1201,42 @@ TEST_F(ClassLinkerTest, IsBootStrapClassLoaded) { EXPECT_FALSE(statics.Get()->IsBootStrapClassLoaded()); } +// Regression test for b/26799552. +TEST_F(ClassLinkerTest, RegisterDexFileName) { + ScopedObjectAccess soa(Thread::Current()); + StackHandleScope<2> hs(soa.Self()); + ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); + MutableHandle<mirror::DexCache> dex_cache(hs.NewHandle<mirror::DexCache>(nullptr)); + { + ReaderMutexLock mu(soa.Self(), *class_linker->DexLock()); + for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) { + dex_cache.Assign(down_cast<mirror::DexCache*>(soa.Self()->DecodeJObject(data.weak_root))); + if (dex_cache.Get() != nullptr) { + break; + } + } + ASSERT_TRUE(dex_cache.Get() != nullptr); + } + // Make a copy of the dex cache and change the name. + dex_cache.Assign(dex_cache->Clone(soa.Self())->AsDexCache()); + const uint16_t data[] = { 0x20AC, 0x20A1 }; + Handle<mirror::String> location(hs.NewHandle(mirror::String::AllocFromUtf16(soa.Self(), + arraysize(data), + data))); + dex_cache->SetLocation(location.Get()); + const DexFile* old_dex_file = dex_cache->GetDexFile(); + + DexFile* dex_file = new DexFile(old_dex_file->Begin(), + old_dex_file->Size(), + location->ToModifiedUtf8(), + 0u, + nullptr, + nullptr); + { + WriterMutexLock mu(soa.Self(), *class_linker->DexLock()); + // Check that inserting with a UTF16 name works. + class_linker->RegisterDexFileLocked(*dex_file, dex_cache); + } +} + } // namespace art diff --git a/runtime/dex_file.h b/runtime/dex_file.h index 968b37ba86..200121e61f 100644 --- a/runtime/dex_file.h +++ b/runtime/dex_file.h @@ -1260,6 +1260,7 @@ class DexFile { mutable std::unique_ptr<TypeLookupTable> lookup_table_; friend class DexFileVerifierTest; + ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName); // for constructor }; struct DexFileReference { diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc index 727f4fc659..7a852e216e 100644 --- a/runtime/dex_file_verifier.cc +++ b/runtime/dex_file_verifier.cc @@ -2538,20 +2538,6 @@ bool DexFileVerifier::CheckMethodAccessFlags(uint32_t method_index, return false; } - // Only the static initializer may have code in an interface. - // TODO We should have some way determine whether to allow this experimental flag without the - // runtime being started. - // We assume experimental flags are enabled when running without a runtime to enable tools like - // dexdump to handle dex files with these features. - if (((class_access_flags & kAccInterface) != 0) - && !is_clinit_by_name - && Runtime::Current() != nullptr - && !Runtime::Current()->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) { - *error_msg = StringPrintf("Non-clinit interface method %" PRIu32 " should not have code", - method_index); - return false; - } - // Instance constructors must not be synchronized and a few other flags. if (is_init_by_name) { static constexpr uint32_t kInitAllowed = diff --git a/runtime/experimental_flags.h b/runtime/experimental_flags.h index 2e674e95c6..198f3fa56e 100644 --- a/runtime/experimental_flags.h +++ b/runtime/experimental_flags.h @@ -27,7 +27,6 @@ struct ExperimentalFlags { enum { kNone = 0x0000, kLambdas = 0x0001, - kDefaultMethods = 0x0002, }; constexpr ExperimentalFlags() : value_(0x0000) {} @@ -69,10 +68,6 @@ inline std::ostream& operator<<(std::ostream& stream, const ExperimentalFlags& e stream << (started ? "|" : "") << "kLambdas"; started = true; } - if (e & ExperimentalFlags::kDefaultMethods) { - stream << (started ? "|" : "") << "kDefaultMethods"; - started = true; - } if (!started) { stream << "kNone"; } diff --git a/runtime/gc/accounting/mod_union_table_test.cc b/runtime/gc/accounting/mod_union_table_test.cc index edab1b0a60..349d6ffaa9 100644 --- a/runtime/gc/accounting/mod_union_table_test.cc +++ b/runtime/gc/accounting/mod_union_table_test.cc @@ -22,6 +22,7 @@ #include "mirror/array-inl.h" #include "space_bitmap-inl.h" #include "thread-inl.h" +#include "thread_list.h" namespace art { namespace gc { @@ -184,7 +185,11 @@ void ModUnionTableTest::RunTest(ModUnionTableFactory::TableType type) { std::unique_ptr<space::DlMallocSpace> other_space(space::DlMallocSpace::Create( "other space", 128 * KB, 4 * MB, 4 * MB, nullptr, false)); ASSERT_TRUE(other_space.get() != nullptr); - heap->AddSpace(other_space.get()); + { + ScopedThreadSuspension sts(self, kSuspended); + ScopedSuspendAll ssa("Add image space"); + heap->AddSpace(other_space.get()); + } std::unique_ptr<ModUnionTable> table(ModUnionTableFactory::Create( type, space, other_space.get())); ASSERT_TRUE(table.get() != nullptr); @@ -253,6 +258,8 @@ void ModUnionTableTest::RunTest(ModUnionTableFactory::TableType type) { std::ostringstream oss2; table->Dump(oss2); // Remove the space we added so it doesn't persist to the next test. + ScopedThreadSuspension sts(self, kSuspended); + ScopedSuspendAll ssa("Add image space"); heap->RemoveSpace(other_space.get()); } diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc index bcfcb89e62..9397c3585a 100644 --- a/runtime/gc/collector/concurrent_copying.cc +++ b/runtime/gc/collector/concurrent_copying.cc @@ -24,6 +24,7 @@ #include "gc/reference_processor.h" #include "gc/space/image_space.h" #include "gc/space/space-inl.h" +#include "image-inl.h" #include "intern_table.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" @@ -2066,8 +2067,9 @@ mirror::Object* ConcurrentCopying::MarkNonMoving(mirror::Object* ref) { } void ConcurrentCopying::FinishPhase() { + Thread* const self = Thread::Current(); { - MutexLock mu(Thread::Current(), mark_stack_lock_); + MutexLock mu(self, mark_stack_lock_); CHECK_EQ(pooled_mark_stacks_.size(), kMarkStackPoolSize); } region_space_ = nullptr; @@ -2075,7 +2077,8 @@ void ConcurrentCopying::FinishPhase() { MutexLock mu(Thread::Current(), skipped_blocks_lock_); skipped_blocks_map_.clear(); } - WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); + ReaderMutexLock mu(self, *Locks::mutator_lock_); + WriterMutexLock mu2(self, *Locks::heap_bitmap_lock_); heap_->ClearMarkedObjects(); } diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h index 954c80ec7b..580486aa68 100644 --- a/runtime/gc/collector/garbage_collector.h +++ b/runtime/gc/collector/garbage_collector.h @@ -153,7 +153,9 @@ class GarbageCollector : public RootVisitor, public IsMarkedVisitor, public Mark void ResetCumulativeStatistics() REQUIRES(!pause_histogram_lock_); // Swap the live and mark bitmaps of spaces that are active for the collector. For partial GC, // this is the allocation space, for full GC then we swap the zygote bitmaps too. - void SwapBitmaps() REQUIRES(Locks::heap_bitmap_lock_); + void SwapBitmaps() + REQUIRES(Locks::heap_bitmap_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); uint64_t GetTotalPausedTimeNs() REQUIRES(!pause_histogram_lock_); int64_t GetTotalFreedBytes() const { return total_freed_bytes_; diff --git a/runtime/gc/collector/mark_compact.h b/runtime/gc/collector/mark_compact.h index 8a12094168..48311570b5 100644 --- a/runtime/gc/collector/mark_compact.h +++ b/runtime/gc/collector/mark_compact.h @@ -106,7 +106,7 @@ class MarkCompact : public GarbageCollector { REQUIRES(Locks::mutator_lock_); // Sweeps unmarked objects to complete the garbage collection. - void Sweep(bool swap_bitmaps) REQUIRES(Locks::heap_bitmap_lock_); + void Sweep(bool swap_bitmaps) REQUIRES(Locks::heap_bitmap_lock_, Locks::mutator_lock_); // Sweeps unmarked objects to complete the garbage collection. void SweepLargeObjects(bool swap_bitmaps) REQUIRES(Locks::heap_bitmap_lock_); diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc index 5427f88563..64c8e9af04 100644 --- a/runtime/gc/collector/mark_sweep.cc +++ b/runtime/gc/collector/mark_sweep.cc @@ -1467,7 +1467,9 @@ void MarkSweep::FinishPhase() { } CHECK(mark_stack_->IsEmpty()); // Ensure that the mark stack is empty. mark_stack_->Reset(); - WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); + Thread* const self = Thread::Current(); + ReaderMutexLock mu(self, *Locks::mutator_lock_); + WriterMutexLock mu2(self, *Locks::heap_bitmap_lock_); heap_->ClearMarkedObjects(); } diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h index 245f96bdb3..b61bef7317 100644 --- a/runtime/gc/collector/mark_sweep.h +++ b/runtime/gc/collector/mark_sweep.h @@ -85,7 +85,7 @@ class MarkSweep : public GarbageCollector { void Init(); // Find the default mark bitmap. - void FindDefaultSpaceBitmap(); + void FindDefaultSpaceBitmap() SHARED_REQUIRES(Locks::mutator_lock_); // Marks all objects in the root set at the start of a garbage collection. void MarkRoots(Thread* self) diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h index a905904115..0199e1ae56 100644 --- a/runtime/gc/collector/semi_space.h +++ b/runtime/gc/collector/semi_space.h @@ -135,7 +135,9 @@ class SemiSpace : public GarbageCollector { REQUIRES(Locks::mutator_lock_); // Sweeps unmarked objects to complete the garbage collection. - virtual void Sweep(bool swap_bitmaps) REQUIRES(Locks::heap_bitmap_lock_); + virtual void Sweep(bool swap_bitmaps) + REQUIRES(Locks::heap_bitmap_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Sweeps unmarked objects to complete the garbage collection. void SweepLargeObjects(bool swap_bitmaps) REQUIRES(Locks::heap_bitmap_lock_); diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc index 8cd8d73ba5..137540afd2 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -801,6 +801,7 @@ bool Heap::IsCompilingBoot() const { if (!Runtime::Current()->IsAotCompiler()) { return false; } + ScopedObjectAccess soa(Thread::Current()); for (const auto& space : continuous_spaces_) { if (space->IsImageSpace() || space->IsZygoteSpace()) { return false; @@ -1381,15 +1382,18 @@ void Heap::TrimSpaces(Thread* self) { uint64_t total_alloc_space_allocated = 0; uint64_t total_alloc_space_size = 0; uint64_t managed_reclaimed = 0; - for (const auto& space : continuous_spaces_) { - if (space->IsMallocSpace()) { - gc::space::MallocSpace* malloc_space = space->AsMallocSpace(); - if (malloc_space->IsRosAllocSpace() || !CareAboutPauseTimes()) { - // Don't trim dlmalloc spaces if we care about pauses since this can hold the space lock - // for a long period of time. - managed_reclaimed += malloc_space->Trim(); + { + ScopedObjectAccess soa(self); + for (const auto& space : continuous_spaces_) { + if (space->IsMallocSpace()) { + gc::space::MallocSpace* malloc_space = space->AsMallocSpace(); + if (malloc_space->IsRosAllocSpace() || !CareAboutPauseTimes()) { + // Don't trim dlmalloc spaces if we care about pauses since this can hold the space lock + // for a long period of time. + managed_reclaimed += malloc_space->Trim(); + } + total_alloc_space_size += malloc_space->Size(); } - total_alloc_space_size += malloc_space->Size(); } } total_alloc_space_allocated = GetBytesAllocated(); @@ -1520,6 +1524,7 @@ std::string Heap::DumpSpaces() const { } void Heap::DumpSpaces(std::ostream& stream) const { + ScopedObjectAccess soa(Thread::Current()); for (const auto& space : continuous_spaces_) { accounting::ContinuousSpaceBitmap* live_bitmap = space->GetLiveBitmap(); accounting::ContinuousSpaceBitmap* mark_bitmap = space->GetMarkBitmap(); @@ -1598,6 +1603,9 @@ void Heap::RecordFreeRevoke() { } space::RosAllocSpace* Heap::GetRosAllocSpace(gc::allocator::RosAlloc* rosalloc) const { + if (rosalloc_space_ != nullptr && rosalloc_space_->GetRosAlloc() == rosalloc) { + return rosalloc_space_; + } for (const auto& space : continuous_spaces_) { if (space->AsContinuousSpace()->IsRosAllocSpace()) { if (space->AsContinuousSpace()->AsRosAllocSpace()->GetRosAlloc() == rosalloc) { @@ -3530,7 +3538,8 @@ void Heap::GrowForUtilization(collector::GarbageCollector* collector_ran, void Heap::ClampGrowthLimit() { // Use heap bitmap lock to guard against races with BindLiveToMarkBitmap. - WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_); + ScopedObjectAccess soa(Thread::Current()); + WriterMutexLock mu(soa.Self(), *Locks::heap_bitmap_lock_); capacity_ = growth_limit_; for (const auto& space : continuous_spaces_) { if (space->IsMallocSpace()) { @@ -3546,6 +3555,7 @@ void Heap::ClampGrowthLimit() { void Heap::ClearGrowthLimit() { growth_limit_ = capacity_; + ScopedObjectAccess soa(Thread::Current()); for (const auto& space : continuous_spaces_) { if (space->IsMallocSpace()) { gc::space::MallocSpace* malloc_space = space->AsMallocSpace(); diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h index 1b7e2c9f0d..c02e2d3864 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -308,7 +308,10 @@ class Heap { void ThreadFlipEnd(Thread* self) REQUIRES(!*thread_flip_lock_); // Clear all of the mark bits, doesn't clear bitmaps which have the same live bits as mark bits. - void ClearMarkedObjects() REQUIRES(Locks::heap_bitmap_lock_); + // Mutator lock is required for GetContinuousSpaces. + void ClearMarkedObjects() + REQUIRES(Locks::heap_bitmap_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Initiates an explicit garbage collection. void CollectGarbage(bool clear_soft_references) @@ -359,8 +362,12 @@ class Heap { // due to usage by tests. void SetSpaceAsDefault(space::ContinuousSpace* continuous_space) REQUIRES(!Locks::heap_bitmap_lock_); - void AddSpace(space::Space* space) REQUIRES(!Locks::heap_bitmap_lock_); - void RemoveSpace(space::Space* space) REQUIRES(!Locks::heap_bitmap_lock_); + void AddSpace(space::Space* space) + REQUIRES(!Locks::heap_bitmap_lock_) + REQUIRES(Locks::mutator_lock_); + void RemoveSpace(space::Space* space) + REQUIRES(!Locks::heap_bitmap_lock_) + REQUIRES(Locks::mutator_lock_); // Set target ideal heap utilization ratio, implements // dalvik.system.VMRuntime.setTargetHeapUtilization. @@ -378,7 +385,13 @@ class Heap { void UpdateProcessState(ProcessState process_state) REQUIRES(!*pending_task_lock_, !*gc_complete_lock_); - const std::vector<space::ContinuousSpace*>& GetContinuousSpaces() const { + bool HaveContinuousSpaces() const NO_THREAD_SAFETY_ANALYSIS { + // No lock since vector empty is thread safe. + return !continuous_spaces_.empty(); + } + + const std::vector<space::ContinuousSpace*>& GetContinuousSpaces() const + SHARED_REQUIRES(Locks::mutator_lock_) { return continuous_spaces_; } @@ -518,10 +531,13 @@ class Heap { // get the space that corresponds to an object's address. Current implementation searches all // spaces in turn. If fail_ok is false then failing to find a space will cause an abort. // TODO: consider using faster data structure like binary tree. - space::ContinuousSpace* FindContinuousSpaceFromObject(const mirror::Object*, bool fail_ok) const; + space::ContinuousSpace* FindContinuousSpaceFromObject(const mirror::Object*, bool fail_ok) const + SHARED_REQUIRES(Locks::mutator_lock_); space::DiscontinuousSpace* FindDiscontinuousSpaceFromObject(const mirror::Object*, - bool fail_ok) const; - space::Space* FindSpaceFromObject(const mirror::Object*, bool fail_ok) const; + bool fail_ok) const + SHARED_REQUIRES(Locks::mutator_lock_); + space::Space* FindSpaceFromObject(const mirror::Object*, bool fail_ok) const + SHARED_REQUIRES(Locks::mutator_lock_); void DumpForSigQuit(std::ostream& os) REQUIRES(!*gc_complete_lock_); @@ -577,7 +593,9 @@ class Heap { REQUIRES(Locks::heap_bitmap_lock_); // Unbind any bound bitmaps. - void UnBindBitmaps() REQUIRES(Locks::heap_bitmap_lock_); + void UnBindBitmaps() + REQUIRES(Locks::heap_bitmap_lock_) + SHARED_REQUIRES(Locks::mutator_lock_); // Returns the boot image spaces. There may be multiple boot image spaces. const std::vector<space::ImageSpace*>& GetBootImageSpaces() const { @@ -604,7 +622,8 @@ class Heap { } // Return the corresponding rosalloc space. - space::RosAllocSpace* GetRosAllocSpace(gc::allocator::RosAlloc* rosalloc) const; + space::RosAllocSpace* GetRosAllocSpace(gc::allocator::RosAlloc* rosalloc) const + SHARED_REQUIRES(Locks::mutator_lock_); space::MallocSpace* GetNonMovingSpace() const { return non_moving_space_; @@ -962,7 +981,8 @@ class Heap { void ProcessCards(TimingLogger* timings, bool use_rem_sets, bool process_alloc_space_cards, - bool clear_alloc_space_cards); + bool clear_alloc_space_cards) + SHARED_REQUIRES(Locks::mutator_lock_); // Push an object onto the allocation stack. void PushOnAllocationStack(Thread* self, mirror::Object** obj) @@ -1005,10 +1025,10 @@ class Heap { REQUIRES(!*gc_complete_lock_, !*pending_task_lock_, !*backtrace_lock_); // All-known continuous spaces, where objects lie within fixed bounds. - std::vector<space::ContinuousSpace*> continuous_spaces_; + std::vector<space::ContinuousSpace*> continuous_spaces_ GUARDED_BY(Locks::mutator_lock_); // All-known discontinuous spaces, where objects may be placed throughout virtual memory. - std::vector<space::DiscontinuousSpace*> discontinuous_spaces_; + std::vector<space::DiscontinuousSpace*> discontinuous_spaces_ GUARDED_BY(Locks::mutator_lock_); // All-known alloc spaces, where objects may be or have been allocated. std::vector<space::AllocSpace*> alloc_spaces_; diff --git a/runtime/gc/space/dlmalloc_space.cc b/runtime/gc/space/dlmalloc_space.cc index e754a52e7e..455d28e229 100644 --- a/runtime/gc/space/dlmalloc_space.cc +++ b/runtime/gc/space/dlmalloc_space.cc @@ -319,7 +319,7 @@ void DlMallocSpace::LogFragmentationAllocFailure(std::ostream& os, namespace allocator { // Implement the dlmalloc morecore callback. -void* ArtDlMallocMoreCore(void* mspace, intptr_t increment) { +void* ArtDlMallocMoreCore(void* mspace, intptr_t increment) SHARED_REQUIRES(Locks::mutator_lock_) { Runtime* runtime = Runtime::Current(); Heap* heap = runtime->GetHeap(); ::art::gc::space::DlMallocSpace* dlmalloc_space = heap->GetDlMallocSpace(); diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc index 9ff3d8db75..891e280ab2 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -30,6 +30,7 @@ #include "base/time_utils.h" #include "base/unix_file/fd_file.h" #include "gc/accounting/space_bitmap-inl.h" +#include "image-inl.h" #include "mirror/class-inl.h" #include "mirror/object-inl.h" #include "oat_file.h" @@ -1032,11 +1033,12 @@ static bool RelocateInPlace(ImageHeader& image_header, bitmap->VisitMarkedRange(objects_begin, objects_end, fixup_object_visitor); FixupObjectAdapter fixup_adapter(boot_image, boot_oat, app_image, app_oat); // Fixup image roots. - CHECK(app_image.ContainsSource(reinterpret_cast<uintptr_t>(image_header.GetImageRoots()))); + CHECK(app_image.ContainsSource(reinterpret_cast<uintptr_t>( + image_header.GetImageRoots<kWithoutReadBarrier>()))); image_header.RelocateImageObjects(app_image.Delta()); CHECK_EQ(image_header.GetImageBegin(), target_base); // Fix up dex cache DexFile pointers. - auto* dex_caches = image_header.GetImageRoot(ImageHeader::kDexCaches)-> + auto* dex_caches = image_header.GetImageRoot<kWithoutReadBarrier>(ImageHeader::kDexCaches)-> AsObjectArray<mirror::DexCache>(); for (int32_t i = 0, count = dex_caches->GetLength(); i < count; ++i) { mirror::DexCache* dex_cache = dex_caches->Get(i); diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc index 49126d2c02..fd4d0a1a47 100644 --- a/runtime/gc/space/rosalloc_space.cc +++ b/runtime/gc/space/rosalloc_space.cc @@ -247,7 +247,10 @@ size_t RosAllocSpace::FreeList(Thread* self, size_t num_ptrs, mirror::Object** p size_t RosAllocSpace::Trim() { VLOG(heap) << "RosAllocSpace::Trim() "; { - MutexLock mu(Thread::Current(), lock_); + Thread* const self = Thread::Current(); + // SOA required for Rosalloc::Trim() -> ArtRosAllocMoreCore() -> Heap::GetRosAllocSpace. + ScopedObjectAccess soa(self); + MutexLock mu(self, lock_); // Trim to release memory at the end of the space. rosalloc_->Trim(); } @@ -373,7 +376,8 @@ void RosAllocSpace::Clear() { namespace allocator { // Callback from rosalloc when it needs to increase the footprint. -void* ArtRosAllocMoreCore(allocator::RosAlloc* rosalloc, intptr_t increment) { +void* ArtRosAllocMoreCore(allocator::RosAlloc* rosalloc, intptr_t increment) + SHARED_REQUIRES(Locks::mutator_lock_) { Heap* heap = Runtime::Current()->GetHeap(); art::gc::space::RosAllocSpace* rosalloc_space = heap->GetRosAllocSpace(rosalloc); DCHECK(rosalloc_space != nullptr); diff --git a/runtime/gc/space/space_create_test.cc b/runtime/gc/space/space_create_test.cc index aea2d9f895..170f927e9b 100644 --- a/runtime/gc/space/space_create_test.cc +++ b/runtime/gc/space/space_create_test.cc @@ -170,7 +170,11 @@ TEST_P(SpaceCreateTest, ZygoteSpaceTestBody) { gc::Heap* heap = Runtime::Current()->GetHeap(); space::Space* old_space = space; - heap->RemoveSpace(old_space); + { + ScopedThreadSuspension sts(self, kSuspended); + ScopedSuspendAll ssa("Add image space"); + heap->RemoveSpace(old_space); + } heap->RevokeAllThreadLocalBuffers(); space::ZygoteSpace* zygote_space = space->CreateZygoteSpace("alloc space", heap->IsLowMemoryMode(), diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h index e588eb3efa..20ef44a77d 100644 --- a/runtime/gc/space/space_test.h +++ b/runtime/gc/space/space_test.h @@ -27,6 +27,7 @@ #include "mirror/class_loader.h" #include "mirror/object-inl.h" #include "scoped_thread_state_change.h" +#include "thread_list.h" #include "zygote_space.h" namespace art { @@ -43,7 +44,11 @@ class SpaceTest : public Super { if (revoke) { heap->RevokeAllThreadLocalBuffers(); } - heap->AddSpace(space); + { + ScopedThreadStateChange sts(Thread::Current(), kSuspended); + ScopedSuspendAll ssa("Add image space"); + heap->AddSpace(space); + } heap->SetSpaceAsDefault(space); } diff --git a/runtime/image-inl.h b/runtime/image-inl.h new file mode 100644 index 0000000000..e3307d87b6 --- /dev/null +++ b/runtime/image-inl.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use 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. + */ + +#ifndef ART_RUNTIME_IMAGE_INL_H_ +#define ART_RUNTIME_IMAGE_INL_H_ + +#include "image.h" + +namespace art { + +template <ReadBarrierOption kReadBarrierOption> +inline mirror::Object* ImageHeader::GetImageRoot(ImageRoot image_root) const { + mirror::ObjectArray<mirror::Object>* image_roots = GetImageRoots<kReadBarrierOption>(); + return image_roots->Get<kVerifyNone, kReadBarrierOption>(static_cast<int32_t>(image_root)); +} + +template <ReadBarrierOption kReadBarrierOption> +inline mirror::ObjectArray<mirror::Object>* ImageHeader::GetImageRoots() const { + // Need a read barrier as it's not visited during root scan. + // Pass in the address of the local variable to the read barrier + // rather than image_roots_ because it won't move (asserted below) + // and it's a const member. + mirror::ObjectArray<mirror::Object>* image_roots = + reinterpret_cast<mirror::ObjectArray<mirror::Object>*>(image_roots_); + mirror::ObjectArray<mirror::Object>* result = + ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Object>, kReadBarrierOption>( + &image_roots); + DCHECK_EQ(image_roots, result); + return image_roots; +} + +} // namespace art + +#endif // ART_RUNTIME_IMAGE_INL_H_ diff --git a/runtime/image.cc b/runtime/image.cc index 2fed4d3bd3..de00343451 100644 --- a/runtime/image.cc +++ b/runtime/image.cc @@ -128,24 +128,6 @@ const char* ImageHeader::GetMagic() const { return reinterpret_cast<const char*>(magic_); } -mirror::Object* ImageHeader::GetImageRoot(ImageRoot image_root) const { - return GetImageRoots()->Get(image_root); -} - -mirror::ObjectArray<mirror::Object>* ImageHeader::GetImageRoots() const { - // Need a read barrier as it's not visited during root scan. - // Pass in the address of the local variable to the read barrier - // rather than image_roots_ because it won't move (asserted below) - // and it's a const member. - mirror::ObjectArray<mirror::Object>* image_roots = - reinterpret_cast<mirror::ObjectArray<mirror::Object>*>(image_roots_); - mirror::ObjectArray<mirror::Object>* result = - ReadBarrier::BarrierForRoot<mirror::ObjectArray<mirror::Object>, kWithReadBarrier>( - &image_roots); - DCHECK_EQ(image_roots, result); - return result; -} - ArtMethod* ImageHeader::GetImageMethod(ImageMethod index) const { CHECK_LT(static_cast<size_t>(index), kImageMethodsCount); return reinterpret_cast<ArtMethod*>(image_methods_[index]); diff --git a/runtime/image.h b/runtime/image.h index b3f177bc8f..c449e43243 100644 --- a/runtime/image.h +++ b/runtime/image.h @@ -212,8 +212,11 @@ class PACKED(4) ImageHeader { return GetImageSection(kSectionArtMethods); } + template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier> mirror::Object* GetImageRoot(ImageRoot image_root) const SHARED_REQUIRES(Locks::mutator_lock_); + + template <ReadBarrierOption kReadBarrierOption = kWithReadBarrier> mirror::ObjectArray<mirror::Object>* GetImageRoots() const SHARED_REQUIRES(Locks::mutator_lock_); diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc index 96854dad0e..74a2532a5d 100644 --- a/runtime/intern_table.cc +++ b/runtime/intern_table.cc @@ -22,6 +22,7 @@ #include "gc/collector/garbage_collector.h" #include "gc/space/image_space.h" #include "gc/weak_root_state.h" +#include "image-inl.h" #include "mirror/dex_cache-inl.h" #include "mirror/object_array-inl.h" #include "mirror/object-inl.h" diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc index 7b058d0c92..692c6cb0c1 100644 --- a/runtime/mirror/dex_cache.cc +++ b/runtime/mirror/dex_cache.cc @@ -50,7 +50,7 @@ void DexCache::Init(const DexFile* dex_file, CHECK_EQ(num_resolved_fields != 0u, resolved_fields != nullptr); SetDexFile(dex_file); - SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location); + SetLocation(location); SetStrings(strings); SetResolvedTypes(resolved_types); SetResolvedMethods(resolved_methods); @@ -79,5 +79,9 @@ void DexCache::Fixup(ArtMethod* trampoline, size_t pointer_size) { } } +void DexCache::SetLocation(mirror::String* location) { + SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location); +} + } // namespace mirror } // namespace art diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h index 5ed061f6a4..0002076ce0 100644 --- a/runtime/mirror/dex_cache.h +++ b/runtime/mirror/dex_cache.h @@ -191,11 +191,12 @@ class MANAGED DexCache FINAL : public Object { return GetFieldPtr<const DexFile*>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_)); } - void SetDexFile(const DexFile* dex_file) SHARED_REQUIRES(Locks::mutator_lock_) - ALWAYS_INLINE { - return SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file); + void SetDexFile(const DexFile* dex_file) SHARED_REQUIRES(Locks::mutator_lock_) { + SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file); } + void SetLocation(mirror::String* location) SHARED_REQUIRES(Locks::mutator_lock_); + // NOTE: Get/SetElementPtrSize() are intended for working with ArtMethod** and ArtField** // provided by GetResolvedMethods/Fields() and ArtMethod::GetDexCacheResolvedMethods(), // so they need to be public. diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc index 8febb62a5f..8f108faa1f 100644 --- a/runtime/native/dalvik_system_VMDebug.cc +++ b/runtime/native/dalvik_system_VMDebug.cc @@ -314,32 +314,33 @@ static void VMDebug_getHeapSpaceStats(JNIEnv* env, jclass, jlongArray data) { size_t largeObjectsSize = 0; size_t largeObjectsUsed = 0; gc::Heap* heap = Runtime::Current()->GetHeap(); - for (gc::space::ContinuousSpace* space : heap->GetContinuousSpaces()) { - if (space->IsImageSpace()) { - // Currently don't include the image space. - } else if (space->IsZygoteSpace()) { - gc::space::ZygoteSpace* zygote_space = space->AsZygoteSpace(); - zygoteSize += zygote_space->Size(); - zygoteUsed += zygote_space->GetBytesAllocated(); - } else if (space->IsMallocSpace()) { - // This is a malloc space. - gc::space::MallocSpace* malloc_space = space->AsMallocSpace(); - allocSize += malloc_space->GetFootprint(); - allocUsed += malloc_space->GetBytesAllocated(); - } else if (space->IsBumpPointerSpace()) { - ScopedObjectAccess soa(env); - gc::space::BumpPointerSpace* bump_pointer_space = space->AsBumpPointerSpace(); - allocSize += bump_pointer_space->Size(); - allocUsed += bump_pointer_space->GetBytesAllocated(); + { + ScopedObjectAccess soa(env); + for (gc::space::ContinuousSpace* space : heap->GetContinuousSpaces()) { + if (space->IsImageSpace()) { + // Currently don't include the image space. + } else if (space->IsZygoteSpace()) { + gc::space::ZygoteSpace* zygote_space = space->AsZygoteSpace(); + zygoteSize += zygote_space->Size(); + zygoteUsed += zygote_space->GetBytesAllocated(); + } else if (space->IsMallocSpace()) { + // This is a malloc space. + gc::space::MallocSpace* malloc_space = space->AsMallocSpace(); + allocSize += malloc_space->GetFootprint(); + allocUsed += malloc_space->GetBytesAllocated(); + } else if (space->IsBumpPointerSpace()) { + gc::space::BumpPointerSpace* bump_pointer_space = space->AsBumpPointerSpace(); + allocSize += bump_pointer_space->Size(); + allocUsed += bump_pointer_space->GetBytesAllocated(); + } } - } - for (gc::space::DiscontinuousSpace* space : heap->GetDiscontinuousSpaces()) { - if (space->IsLargeObjectSpace()) { - largeObjectsSize += space->AsLargeObjectSpace()->GetBytesAllocated(); - largeObjectsUsed += largeObjectsSize; + for (gc::space::DiscontinuousSpace* space : heap->GetDiscontinuousSpaces()) { + if (space->IsLargeObjectSpace()) { + largeObjectsSize += space->AsLargeObjectSpace()->GetBytesAllocated(); + largeObjectsUsed += largeObjectsSize; + } } } - size_t allocFree = allocSize - allocUsed; size_t zygoteFree = zygoteSize - zygoteUsed; size_t largeObjectsFree = largeObjectsSize - largeObjectsUsed; diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index b34b5505eb..de90f0aa04 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -30,6 +30,7 @@ #include "oat_file_assistant.h" #include "scoped_thread_state_change.h" #include "thread-inl.h" +#include "thread_list.h" namespace art { @@ -376,7 +377,11 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( std::string temp_error_msg; // Add image space has a race condition since other threads could be reading from the // spaces array. - runtime->GetHeap()->AddSpace(image_space.get()); + { + ScopedThreadSuspension sts(self, kSuspended); + ScopedSuspendAll ssa("Add image space"); + runtime->GetHeap()->AddSpace(image_space.get()); + } added_image_space = true; if (!runtime->GetClassLinker()->AddImageSpace(image_space.get(), h_loader, @@ -386,7 +391,11 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( /*out*/&temp_error_msg)) { LOG(INFO) << "Failed to add image file " << temp_error_msg; dex_files.clear(); - runtime->GetHeap()->RemoveSpace(image_space.get()); + { + ScopedThreadSuspension sts(self, kSuspended); + ScopedSuspendAll ssa("Remove image space"); + runtime->GetHeap()->RemoveSpace(image_space.get()); + } added_image_space = false; // Non-fatal, don't update error_msg. } diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc index 341be9aab0..aa64ee3702 100644 --- a/runtime/parsed_options.cc +++ b/runtime/parsed_options.cc @@ -565,13 +565,6 @@ bool ParsedOptions::DoParse(const RuntimeOptions& options, args.Set(M::HeapGrowthLimit, args.GetOrDefault(M::MemoryMaximumSize)); } - if (args.GetOrDefault(M::Experimental) & ExperimentalFlags::kDefaultMethods) { - LOG(WARNING) << "Default method support has been enabled. The verifier will be less strict " - << "in some cases. All existing invoke opcodes have an unstable updated " - << "specification and are nearly guaranteed to change over time. Do not attempt " - << "to write shipping code against the invoke opcodes with this flag."; - } - if (args.GetOrDefault(M::Experimental) & ExperimentalFlags::kLambdas) { LOG(WARNING) << "Experimental lambdas have been enabled. All lambda opcodes have " << "an unstable specification and are nearly guaranteed to change over time. " @@ -698,8 +691,8 @@ void ParsedOptions::Usage(const char* fmt, ...) { UsageMessage(stream, " -X[no]image-dex2oat (Whether to create and use a boot image)\n"); UsageMessage(stream, " -Xno-dex-file-fallback " "(Don't fall back to dex files without oat files)\n"); - UsageMessage(stream, " -Xexperimental:{lambdas,default-methods} " - "(Enable new experimental dalvik opcodes and semantics, off by default)\n"); + UsageMessage(stream, " -Xexperimental:lambdas " + "(Enable new and experimental dalvik opcodes and semantics)\n"); UsageMessage(stream, "\n"); UsageMessage(stream, "The following previously supported Dalvik options are ignored:\n"); diff --git a/runtime/quick/inline_method_analyser.h b/runtime/quick/inline_method_analyser.h index ca456c2861..1bb816bb20 100644 --- a/runtime/quick/inline_method_analyser.h +++ b/runtime/quick/inline_method_analyser.h @@ -37,13 +37,21 @@ class MethodVerifier; enum InlineMethodOpcode : uint16_t { kIntrinsicDoubleCvt, kIntrinsicFloatCvt, + kIntrinsicFloatIsInfinite, + kIntrinsicDoubleIsInfinite, + kIntrinsicFloatIsNaN, + kIntrinsicDoubleIsNaN, kIntrinsicReverseBits, kIntrinsicReverseBytes, kIntrinsicBitCount, + kIntrinsicCompare, + kIntrinsicHighestOneBit, + kIntrinsicLowestOneBit, kIntrinsicNumberOfLeadingZeros, kIntrinsicNumberOfTrailingZeros, kIntrinsicRotateRight, kIntrinsicRotateLeft, + kIntrinsicSignum, kIntrinsicAbsInt, kIntrinsicAbsLong, kIntrinsicAbsFloat, diff --git a/runtime/runtime.cc b/runtime/runtime.cc index f138c811d7..0c06ca672c 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -71,7 +71,7 @@ #include "gc/space/image_space.h" #include "gc/space/space-inl.h" #include "handle_scope-inl.h" -#include "image.h" +#include "image-inl.h" #include "instrumentation.h" #include "intern_table.h" #include "interpreter/interpreter.h" diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def index c5b009d2cd..308f3bafc2 100644 --- a/runtime/runtime_options.def +++ b/runtime/runtime_options.def @@ -113,7 +113,7 @@ RUNTIME_OPTIONS_KEY (unsigned int, ZygoteMaxFailedBoots, 10) RUNTIME_OPTIONS_KEY (Unit, NoDexFileFallback) RUNTIME_OPTIONS_KEY (std::string, CpuAbiList) RUNTIME_OPTIONS_KEY (std::string, Fingerprint) -RUNTIME_OPTIONS_KEY (ExperimentalFlags, Experimental, ExperimentalFlags::kNone) // -Xexperimental:{, lambdas, default-methods} +RUNTIME_OPTIONS_KEY (ExperimentalFlags, Experimental, ExperimentalFlags::kNone) // -Xexperimental:{none, lambdas} // Not parse-able from command line, but can be provided explicitly. // (Do not add anything here that is defined in ParsedOptions::MakeParser) diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 7e0f3371bc..2890a9826e 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -608,7 +608,6 @@ SafeMap<uint32_t, std::set<uint32_t>>& MethodVerifier::FindStringInitMap() { bool MethodVerifier::Verify() { // Some older code doesn't correctly mark constructors as such. Test for this case by looking at // the name. - Runtime* runtime = Runtime::Current(); const DexFile::MethodId& method_id = dex_file_->GetMethodId(dex_method_idx_); const char* method_name = dex_file_->StringDataByIdx(method_id.name_idx_); bool instance_constructor_by_name = strcmp("<init>", method_name) == 0; @@ -678,12 +677,9 @@ bool MethodVerifier::Verify() { } if ((class_def_->GetJavaAccessFlags() & kAccInterface) != 0) { // Interface methods must be public and abstract (if default methods are disabled). - bool default_methods_supported = - runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods); - uint32_t kRequired = kAccPublic | (default_methods_supported ? 0 : kAccAbstract); + uint32_t kRequired = kAccPublic; if ((method_access_flags_ & kRequired) != kRequired) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be public" - << (default_methods_supported ? "" : " and abstract"); + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be public"; return false; } // In addition to the above, interface methods must not be protected. @@ -715,19 +711,14 @@ bool MethodVerifier::Verify() { // default methods enabled we also allow other public, static, non-final methods to have code. // Otherwise that is the only type of method allowed. if (!(IsConstructor() && IsStatic())) { - if (runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods)) { - if (IsInstanceConstructor()) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-static constructor"; - return false; - } else if (method_access_flags_ & kAccFinal) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have final methods"; - return false; - } else if (!(method_access_flags_ & kAccPublic)) { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-public members"; - return false; - } - } else { - Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interface methods must be abstract"; + if (IsInstanceConstructor()) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-static constructor"; + return false; + } else if (method_access_flags_ & kAccFinal) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have final methods"; + return false; + } else if (!(method_access_flags_ & kAccPublic)) { + Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "interfaces may not have non-public members"; return false; } } @@ -3713,12 +3704,10 @@ ArtMethod* MethodVerifier::ResolveMethodAndCheckAccess( // Note: this check must be after the initializer check, as those are required to fail a class, // while this check implies an IncompatibleClassChangeError. if (klass->IsInterface()) { - Runtime* runtime = Runtime::Current(); - const bool default_methods_supported = - runtime == nullptr || - runtime->AreExperimentalFlagsEnabled(ExperimentalFlags::kDefaultMethods); + // methods called on interfaces should be invoke-interface, invoke-super, or invoke-static. if (method_type != METHOD_INTERFACE && - (!default_methods_supported || method_type != METHOD_STATIC)) { + method_type != METHOD_STATIC && + method_type != METHOD_SUPER) { Fail(VERIFY_ERROR_CLASS_CHANGE) << "non-interface method " << PrettyMethod(dex_method_idx, *dex_file_) << " is in an interface class " << PrettyClass(klass); diff --git a/test/048-reflect-v8/run b/test/048-reflect-v8/run deleted file mode 100644 index ba3318a1fd..0000000000 --- a/test/048-reflect-v8/run +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2016 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use 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. - - -# Ensure that the default methods are turned on for dalvikvm and dex2oat -${RUN} "$@" --experimental default-methods diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java index 3e6d1f4d94..06cfd0a606 100644 --- a/test/449-checker-bce/src/Main.java +++ b/test/449-checker-bce/src/Main.java @@ -622,28 +622,39 @@ public class Main { static int[][] mA; /// CHECK-START: void Main.dynamicBCEAndIntrinsic(int) BCE (before) - /// CHECK-DAG: NullCheck - /// CHECK-DAG: ArrayLength - /// CHECK-DAG: BoundsCheck - /// CHECK-DAG: ArrayGet - /// CHECK-DAG: NullCheck - /// CHECK-DAG: ArrayLength - /// CHECK-DAG: BoundsCheck - /// CHECK-DAG: ArrayGet - /// CHECK-DAG: InvokeStaticOrDirect - /// CHECK-DAG: ArraySet - + // Array references mA[i] and ..[j] both in inner loop. + /// CHECK-DAG: <<Get1:l\d+>> ArrayGet [<<Array1:l\d+>>,<<Bounds1:i\d+>>] loop:<<InnerLoop:B\d+>> + /// CHECK-DAG: <<Array1>> NullCheck [<<Field1:l\d+>>] loop:<<InnerLoop>> + /// CHECK-DAG: <<Len1:i\d+>> ArrayLength [<<Array1>>] loop:<<InnerLoop>> + /// CHECK-DAG: <<Bounds1>> BoundsCheck [<<Index1:i\d+>>,<<Len1>>] loop:<<InnerLoop>> + /// CHECK-DAG: <<Get2:i\d+>> ArrayGet [<<Array2:l\d+>>,<<Bounds2:i\d+>>] loop:<<InnerLoop>> + /// CHECK-DAG: <<Array2>> NullCheck [<<Get1>>] loop:<<InnerLoop>> + /// CHECK-DAG: <<Len2:i\d+>> ArrayLength [<<Array2>>] loop:<<InnerLoop>> + /// CHECK-DAG: <<Bounds2>> BoundsCheck [<<Index2:i\d+>>,<<Len2>>] loop:<<InnerLoop>> + /// CHECK-DAG: InvokeStaticOrDirect [<<Get2>>] loop:<<InnerLoop>> + /// CHECK-DAG: <<Index2>> Phi loop:<<InnerLoop>> + /// CHECK-DAG: <<Index1>> Phi loop:<<OuterLoop:B\d+>> + /// CHECK-DAG: <<Field1>> StaticFieldGet loop:none + /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>" + // + /// CHECK-START: void Main.dynamicBCEAndIntrinsic(int) BCE (after) + // Array reference mA[i] hoisted to same level as deopt. + /// CHECK-DAG: Deoptimize loop:<<OuterLoop:B\d+>> + /// CHECK-DAG: ArrayLength loop:<<OuterLoop>> + /// CHECK-DAG: <<Get1:l\d+>> ArrayGet [<<Array1:l\d+>>,<<Index1:i\d+>>] loop:<<OuterLoop>> + // Array reference ..[j] still in inner loop, with a direct index. + /// CHECK-DAG: <<Get2:i\d+>> ArrayGet [<<Array2:l\d+>>,<<Index2:i\d+>>] loop:<<InnerLoop:B\d+>> + /// CHECK-DAG: InvokeStaticOrDirect [<<Get2>>] loop:<<InnerLoop>> + /// CHECK-DAG: <<Index2>> Phi loop:<<InnerLoop>> + /// CHECK-DAG: <<Index1>> Phi loop:<<OuterLoop>> + // Synthetic phi. + /// CHECK-DAG: <<Array2>> Phi loop:<<OuterLoop>> + /// CHECK-DAG: <<Array1>> StaticFieldGet loop:none + /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>" + // /// CHECK-START: void Main.dynamicBCEAndIntrinsic(int) BCE (after) /// CHECK-NOT: NullCheck - /// CHECK-NOT: ArrayLength /// CHECK-NOT: BoundsCheck - /// CHECK-DAG: ArrayGet - /// CHECK-NOT: ArrayGet - /// CHECK-DAG: InvokeStaticOrDirect - /// CHECK-DAG: ArraySet - /// CHECK-DAG: Exit - /// CHECK-DAG: Deoptimize - static void dynamicBCEAndIntrinsic(int n) { for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { diff --git a/test/530-checker-loops/src/Main.java b/test/530-checker-loops/src/Main.java index f1d9a37c88..deff279f77 100644 --- a/test/530-checker-loops/src/Main.java +++ b/test/530-checker-loops/src/Main.java @@ -26,7 +26,7 @@ public class Main { // /// CHECK-START: int Main.linear(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linear(int[]) BCE (after) /// CHECK-NOT: BoundsCheck @@ -40,7 +40,7 @@ public class Main { } /// CHECK-START: int Main.linearDown(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearDown(int[]) BCE (after) /// CHECK-NOT: BoundsCheck @@ -54,7 +54,7 @@ public class Main { } /// CHECK-START: int Main.linearObscure(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearObscure(int[]) BCE (after) /// CHECK-NOT: BoundsCheck @@ -69,7 +69,7 @@ public class Main { } /// CHECK-START: int Main.linearVeryObscure(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearVeryObscure(int[]) BCE (after) /// CHECK-NOT: BoundsCheck @@ -84,7 +84,7 @@ public class Main { } /// CHECK-START: int Main.hiddenStride(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.hiddenStride(int[]) BCE (after) /// CHECK-NOT: BoundsCheck @@ -101,7 +101,7 @@ public class Main { } /// CHECK-START: int Main.linearWhile(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearWhile(int[]) BCE (after) /// CHECK-NOT: BoundsCheck @@ -116,7 +116,7 @@ public class Main { } /// CHECK-START: int Main.linearThreeWayPhi(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearThreeWayPhi(int[]) BCE (after) /// CHECK-NOT: BoundsCheck @@ -134,7 +134,7 @@ public class Main { } /// CHECK-START: int Main.linearFourWayPhi(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearFourWayPhi(int[]) BCE (after) /// CHECK-NOT: BoundsCheck @@ -156,7 +156,7 @@ public class Main { } /// CHECK-START: int Main.wrapAroundThenLinear(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.wrapAroundThenLinear(int[]) BCE (after) /// CHECK-NOT: BoundsCheck @@ -173,7 +173,7 @@ public class Main { } /// CHECK-START: int Main.wrapAroundThenLinearThreeWayPhi(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.wrapAroundThenLinearThreeWayPhi(int[]) BCE (after) /// CHECK-NOT: BoundsCheck @@ -194,7 +194,7 @@ public class Main { } /// CHECK-START: int[] Main.linearWithParameter(int) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int[] Main.linearWithParameter(int) BCE (after) /// CHECK-NOT: BoundsCheck @@ -208,7 +208,7 @@ public class Main { } /// CHECK-START: int[] Main.linearCopy(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int[] Main.linearCopy(int[]) BCE (after) /// CHECK-NOT: BoundsCheck @@ -223,8 +223,8 @@ public class Main { } /// CHECK-START: int Main.linearByTwo(int[]) BCE (before) - /// CHECK: BoundsCheck - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearByTwo(int[]) BCE (after) /// CHECK-NOT: BoundsCheck @@ -241,7 +241,7 @@ public class Main { } /// CHECK-START: int Main.linearByTwoSkip1(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearByTwoSkip1(int[]) BCE (after) /// CHECK-NOT: BoundsCheck @@ -255,10 +255,12 @@ public class Main { } /// CHECK-START: int Main.linearByTwoSkip2(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.linearByTwoSkip2(int[]) BCE (after) + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearByTwoSkip2(int[]) BCE (after) - /// CHECK: BoundsCheck /// CHECK-NOT: Deoptimize private static int linearByTwoSkip2(int x[]) { int result = 0; @@ -270,7 +272,7 @@ public class Main { } /// CHECK-START: int Main.linearWithCompoundStride() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearWithCompoundStride() BCE (after) /// CHECK-NOT: BoundsCheck @@ -287,7 +289,7 @@ public class Main { } /// CHECK-START: int Main.linearWithLargePositiveStride() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearWithLargePositiveStride() BCE (after) /// CHECK-NOT: BoundsCheck @@ -305,10 +307,12 @@ public class Main { } /// CHECK-START: int Main.linearWithVeryLargePositiveStride() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.linearWithVeryLargePositiveStride() BCE (after) + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearWithVeryLargePositiveStride() BCE (after) - /// CHECK: BoundsCheck /// CHECK-NOT: Deoptimize private static int linearWithVeryLargePositiveStride() { int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; @@ -323,7 +327,7 @@ public class Main { } /// CHECK-START: int Main.linearWithLargeNegativeStride() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearWithLargeNegativeStride() BCE (after) /// CHECK-NOT: BoundsCheck @@ -341,10 +345,12 @@ public class Main { } /// CHECK-START: int Main.linearWithVeryLargeNegativeStride() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.linearWithVeryLargeNegativeStride() BCE (after) + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearWithVeryLargeNegativeStride() BCE (after) - /// CHECK: BoundsCheck /// CHECK-NOT: Deoptimize private static int linearWithVeryLargeNegativeStride() { int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 }; @@ -359,7 +365,7 @@ public class Main { } /// CHECK-START: int Main.linearForNEUp() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearForNEUp() BCE (after) /// CHECK-NOT: BoundsCheck @@ -374,7 +380,7 @@ public class Main { } /// CHECK-START: int Main.linearForNEDown() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearForNEDown() BCE (after) /// CHECK-NOT: BoundsCheck @@ -389,7 +395,7 @@ public class Main { } /// CHECK-START: int Main.linearDoWhileUp() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearDoWhileUp() BCE (after) /// CHECK-NOT: BoundsCheck @@ -405,7 +411,7 @@ public class Main { } /// CHECK-START: int Main.linearDoWhileDown() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearDoWhileDown() BCE (after) /// CHECK-NOT: BoundsCheck @@ -421,10 +427,12 @@ public class Main { } /// CHECK-START: int Main.linearShort() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.linearShort() BCE (after) + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.linearShort() BCE (after) - /// CHECK: BoundsCheck /// CHECK-NOT: Deoptimize private static int linearShort() { int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; @@ -437,7 +445,7 @@ public class Main { } /// CHECK-START: int Main.invariantFromPreLoop(int[], int) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.invariantFromPreLoop(int[], int) BCE (after) /// CHECK-NOT: BoundsCheck @@ -458,20 +466,11 @@ public class Main { } /// CHECK-START: void Main.linearTriangularOnTwoArrayLengths(int) BCE (before) - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: void Main.linearTriangularOnTwoArrayLengths(int) BCE (after) /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet - /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet /// CHECK-NOT: Deoptimize private static void linearTriangularOnTwoArrayLengths(int n) { int[] a = new int[n]; @@ -488,20 +487,11 @@ public class Main { } /// CHECK-START: void Main.linearTriangularOnOneArrayLength(int) BCE (before) - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: void Main.linearTriangularOnOneArrayLength(int) BCE (after) /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet - /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet /// CHECK-NOT: Deoptimize private static void linearTriangularOnOneArrayLength(int n) { int[] a = new int[n]; @@ -518,20 +508,11 @@ public class Main { } /// CHECK-START: void Main.linearTriangularOnParameter(int) BCE (before) - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: void Main.linearTriangularOnParameter(int) BCE (after) /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet - /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet /// CHECK-NOT: Deoptimize private static void linearTriangularOnParameter(int n) { int[] a = new int[n]; @@ -548,32 +529,13 @@ public class Main { } /// CHECK-START: void Main.linearTriangularVariations(int) BCE (before) - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: void Main.linearTriangularVariations(int) BCE (after) /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet - /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet - /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet - /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet /// CHECK-NOT: Deoptimize private static void linearTriangularVariations(int n) { int[] a = new int[n]; @@ -616,22 +578,11 @@ public class Main { } /// CHECK-START: void Main.bubble(int[]) BCE (before) - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: If - /// CHECK: ArraySet - /// CHECK: ArraySet + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: void Main.bubble(int[]) BCE (after) /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: If - /// CHECK: ArraySet - /// CHECK: ArraySet /// CHECK-NOT: Deoptimize private static void bubble(int[] a) { for (int i = a.length; --i >= 0;) { @@ -646,7 +597,7 @@ public class Main { } /// CHECK-START: int Main.periodicIdiom(int) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.periodicIdiom(int) BCE (after) /// CHECK-NOT: BoundsCheck @@ -664,7 +615,7 @@ public class Main { } /// CHECK-START: int Main.periodicSequence2(int) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.periodicSequence2(int) BCE (after) /// CHECK-NOT: BoundsCheck @@ -685,10 +636,10 @@ public class Main { } /// CHECK-START: int Main.periodicSequence4(int) BCE (before) - /// CHECK: BoundsCheck - /// CHECK: BoundsCheck - /// CHECK: BoundsCheck - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.periodicSequence4(int) BCE (after) /// CHECK-NOT: BoundsCheck @@ -713,7 +664,7 @@ public class Main { } /// CHECK-START: int Main.justRightUp1() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.justRightUp1() BCE (after) /// CHECK-NOT: BoundsCheck @@ -728,7 +679,7 @@ public class Main { } /// CHECK-START: int Main.justRightUp2() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.justRightUp2() BCE (after) /// CHECK-NOT: BoundsCheck @@ -743,7 +694,7 @@ public class Main { } /// CHECK-START: int Main.justRightUp3() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.justRightUp3() BCE (after) /// CHECK-NOT: BoundsCheck @@ -758,10 +709,12 @@ public class Main { } /// CHECK-START: int Main.justOOBUp() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.justOOBUp() BCE (after) + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.justOOBUp() BCE (after) - /// CHECK: BoundsCheck /// CHECK-NOT: Deoptimize private static int justOOBUp() { int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; @@ -774,7 +727,7 @@ public class Main { } /// CHECK-START: int Main.justRightDown1() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.justRightDown1() BCE (after) /// CHECK-NOT: BoundsCheck @@ -789,7 +742,7 @@ public class Main { } /// CHECK-START: int Main.justRightDown2() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.justRightDown2() BCE (after) /// CHECK-NOT: BoundsCheck @@ -804,7 +757,7 @@ public class Main { } /// CHECK-START: int Main.justRightDown3() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.justRightDown3() BCE (after) /// CHECK-NOT: BoundsCheck @@ -819,10 +772,12 @@ public class Main { } /// CHECK-START: int Main.justOOBDown() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.justOOBDown() BCE (after) + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int Main.justOOBDown() BCE (after) - /// CHECK: BoundsCheck /// CHECK-NOT: Deoptimize private static int justOOBDown() { int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; @@ -835,66 +790,74 @@ public class Main { } /// CHECK-START: void Main.lowerOOB(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.lowerOOB(int[]) BCE (after) + /// CHECK-DAG: BoundsCheck // /// CHECK-START: void Main.lowerOOB(int[]) BCE (after) - /// CHECK: BoundsCheck /// CHECK-NOT: Deoptimize private static void lowerOOB(int[] x) { + // OOB! for (int i = -1; i < x.length; i++) { sResult += x[i]; } } /// CHECK-START: void Main.upperOOB(int[]) BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.upperOOB(int[]) BCE (after) + /// CHECK-DAG: BoundsCheck // /// CHECK-START: void Main.upperOOB(int[]) BCE (after) - /// CHECK: BoundsCheck /// CHECK-NOT: Deoptimize private static void upperOOB(int[] x) { + // OOB! for (int i = 0; i <= x.length; i++) { sResult += x[i]; } } /// CHECK-START: void Main.doWhileUpOOB() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.doWhileUpOOB() BCE (after) + /// CHECK-DAG: BoundsCheck // /// CHECK-START: void Main.doWhileUpOOB() BCE (after) - /// CHECK: BoundsCheck /// CHECK-NOT: Deoptimize private static void doWhileUpOOB() { int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int i = 0; + // OOB! do { sResult += x[i++]; } while (i <= x.length); } /// CHECK-START: void Main.doWhileDownOOB() BCE (before) - /// CHECK: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.doWhileDownOOB() BCE (after) + /// CHECK-DAG: BoundsCheck // /// CHECK-START: void Main.doWhileDownOOB() BCE (after) - /// CHECK: BoundsCheck /// CHECK-NOT: Deoptimize private static void doWhileDownOOB() { int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; int i = x.length - 1; + // OOB! do { sResult += x[i--]; } while (-1 <= i); } /// CHECK-START: int[] Main.multiply1() BCE (before) - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int[] Main.multiply1() BCE (after) /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet /// CHECK-NOT: Deoptimize private static int[] multiply1() { int[] a = new int[10]; @@ -912,21 +875,20 @@ public class Main { } /// CHECK-START: int[] Main.multiply2() BCE (before) - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int[] Main.multiply2() BCE (after) + /// CHECK-DAG: BoundsCheck // /// CHECK-START: int[] Main.multiply2() BCE (after) - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: ArraySet + /// CHECK-NOT: Deoptimize static int[] multiply2() { int[] a = new int[10]; try { for (int i = -3; i <= 3; i++) { for (int j = -3; j <= 3; j++) { // Range [-9,9]: unsafe. - a[i * j] += 1; + a[i * j] += 1; } } } catch (Exception e) { @@ -936,24 +898,19 @@ public class Main { } /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (before) - /// CHECK: StaticFieldGet - /// CHECK: NullCheck - /// CHECK: ArrayLength - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: StaticFieldSet + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> // /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after) - /// CHECK: StaticFieldGet - /// CHECK-NOT: NullCheck - /// CHECK-NOT: ArrayLength - /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: StaticFieldSet - /// CHECK: Exit - /// CHECK: Deoptimize - /// CHECK: Deoptimize - /// CHECK: Deoptimize + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: Deoptimize loop:none + // + /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after) + /// CHECK-NOT: NullCheck loop:{{B\d+}} + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} private static int linearDynamicBCE1(int[] x, int lo, int hi) { int result = 0; for (int i = lo; i < hi; i++) { @@ -963,24 +920,19 @@ public class Main { } /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (before) - /// CHECK: StaticFieldGet - /// CHECK: NullCheck - /// CHECK: ArrayLength - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: StaticFieldSet + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> // /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after) - /// CHECK: StaticFieldGet - /// CHECK-NOT: NullCheck - /// CHECK-NOT: ArrayLength - /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: StaticFieldSet - /// CHECK: Exit - /// CHECK: Deoptimize - /// CHECK: Deoptimize - /// CHECK: Deoptimize + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: Deoptimize loop:none + // + /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after) + /// CHECK-NOT: NullCheck loop:{{B\d+}} + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} private static int linearDynamicBCE2(int[] x, int lo, int hi, int offset) { int result = 0; for (int i = lo; i < hi; i++) { @@ -990,19 +942,19 @@ public class Main { } /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (before) - /// CHECK: NullCheck - /// CHECK: ArrayLength - /// CHECK: BoundsCheck - /// CHECK: ArrayGet + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> // /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after) - /// CHECK: Deoptimize - /// CHECK: Deoptimize - /// CHECK: Deoptimize - /// CHECK-NOT: NullCheck - /// CHECK-NOT: ArrayLength - /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: Deoptimize loop:none + // + /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after) + /// CHECK-NOT: NullCheck loop:{{B\d+}} + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} private static int wrapAroundDynamicBCE(int[] x) { int w = 9; int result = 0; @@ -1014,19 +966,19 @@ public class Main { } /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (before) - /// CHECK: NullCheck - /// CHECK: ArrayLength - /// CHECK: BoundsCheck - /// CHECK: ArrayGet + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> // /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after) - /// CHECK: Deoptimize - /// CHECK: Deoptimize - /// CHECK: Deoptimize - /// CHECK-NOT: NullCheck - /// CHECK-NOT: ArrayLength - /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: Deoptimize loop:none + // + /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after) + /// CHECK-NOT: NullCheck loop:{{B\d+}} + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} private static int periodicDynamicBCE(int[] x) { int k = 0; int result = 0; @@ -1038,20 +990,19 @@ public class Main { } /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before) - /// CHECK: NullCheck - /// CHECK: ArrayLength - /// CHECK: BoundsCheck - /// CHECK: ArrayGet + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> // /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) - /// CHECK-NOT: NullCheck - /// CHECK-NOT: ArrayLength - /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: Exit - /// CHECK: Deoptimize - /// CHECK: Deoptimize - /// CHECK: Deoptimize + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: Deoptimize loop:none + // + /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) + /// CHECK-NOT: NullCheck loop:{{B\d+}} + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} static int dynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) { // This loop could be infinite for hi = max int. Since i is also used // as subscript, however, dynamic bce can proceed. @@ -1063,16 +1014,14 @@ public class Main { } /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before) - /// CHECK: NullCheck - /// CHECK: ArrayLength - /// CHECK: BoundsCheck - /// CHECK: ArrayGet + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> // /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) - /// CHECK: NullCheck - /// CHECK: ArrayLength - /// CHECK: BoundsCheck - /// CHECK: ArrayGet /// CHECK-NOT: Deoptimize static int noDynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) { // As above, but now the index is not used as subscript, @@ -1085,16 +1034,14 @@ public class Main { } /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (before) - /// CHECK: NullCheck - /// CHECK: ArrayLength - /// CHECK: BoundsCheck - /// CHECK: ArrayGet + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> // /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after) - /// CHECK: NullCheck - /// CHECK: ArrayLength - /// CHECK: BoundsCheck - /// CHECK: ArrayGet /// CHECK-NOT: Deoptimize static int noDynamicBCEMixedInductionTypes(int[] x, long lo, long hi) { int result = 0; @@ -1107,42 +1054,21 @@ public class Main { } /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (before) - /// CHECK: NullCheck - /// CHECK: ArrayLength - /// CHECK: NotEqual - /// CHECK: If - /// CHECK: If - /// CHECK: NullCheck - /// CHECK: ArrayLength - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: If - /// CHECK: BoundsCheck - /// CHECK: BoundsCheck - /// CHECK: BoundsCheck - /// CHECK: BoundsCheck - /// CHECK: BoundsCheck - /// CHECK: BoundsCheck + /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> + /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> // /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after) - /// CHECK: NullCheck - /// CHECK: ArrayLength - /// CHECK: NotEqual - /// CHECK: If - /// CHECK: If - /// CHECK-NOT: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: If - /// CHECK: Deoptimize - /// CHECK: BoundsCheck - /// CHECK: BoundsCheck - /// CHECK: BoundsCheck - /// CHECK-NOT: BoundsCheck - /// CHECK: Exit - /// CHECK: Deoptimize - /// CHECK: Deoptimize - /// CHECK: Deoptimize - /// CHECK-NOT: ArrayGet + // Order matters: + /// CHECK: Deoptimize loop:<<Loop:B\d+>> + // CHECK-NOT: Goto loop:<<Loop>> + /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> + /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> + /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> + /// CHECK: Goto loop:<<Loop>> + // + /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after) + /// CHECK-DAG: Deoptimize loop:none static int dynamicBCEAndConstantIndices(int[] x, int[][] a, int lo, int hi) { // Deliberately test array length on a before the loop so that only bounds checks // on constant subscripts remain, making them a viable candidate for hoisting. @@ -1166,80 +1092,73 @@ public class Main { return result; } - /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], java.lang.Integer[], int, int) BCE (before) - /// CHECK: If - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - /// CHECK: BoundsCheck - /// CHECK: ArrayGet - // - /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], java.lang.Integer[], int, int) BCE (after) - /// CHECK-DAG: If - /// CHECK-NOT: BoundsCheck - /// CHECK-DAG: ArrayGet - /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: ArrayGet - /// CHECK-DAG: Exit - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: ArrayGet - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: ArrayGet - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: ArrayGet - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: ArrayGet - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: ArrayGet - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: ArrayGet - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: ArrayGet - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: ArrayGet - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: Deoptimize - /// CHECK-DAG: ArrayGet - static int dynamicBCEAndConstantIndicesAllTypes(int[] q, - boolean[] r, - byte[] s, - char[] t, - short[] u, - int[] v, - long[] w, - float[] x, - double[] y, - Integer[] z, int lo, int hi) { + /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (before) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + // For brevity, just test occurrence of at least one of each in the loop: + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-NOT: ArrayGet loop:<<Loop>> + // + /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after) + /// CHECK-NOT: NullCheck loop:{{B\d+}} + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} + // + /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after) + /// CHECK-DAG: Deoptimize loop:none + static int dynamicBCEAndConstantIndicesAllPrimTypes(int[] q, + boolean[] r, + byte[] s, + char[] t, + short[] u, + int[] v, + long[] w, + float[] x, + double[] y, int lo, int hi) { int result = 0; for (int i = lo; i < hi; i++) { + // All constant index array references can be hoisted out of the loop during BCE on q[i]. result += q[i] + (r[0] ? 1 : 0) + (int) s[0] + (int) t[0] + (int) u[0] + (int) v[0] + - (int) w[0] + (int) x[0] + (int) y[0] + (int) z[0]; + (int) w[0] + (int) x[0] + (int) y[0]; + } + return result; + } + + /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (before) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: Deoptimize loop:none + // + /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after) + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} + static int dynamicBCEAndConstantIndexRefType(int[] q, Integer[] z, int lo, int hi) { + int result = 0; + for (int i = lo; i < hi; i++) { + // Similar to above, but now implicit call to intValue() may prevent hoisting + // z[0] itself during BCE on q[i]. Therefore, we just check BCE on q[i]. + result += q[i] + z[0]; } return result; } @@ -1501,9 +1420,10 @@ public class Main { long[] x6 = { 6 }; float[] x7 = { 7 }; double[] x8 = { 8 }; + expectEquals(415, + dynamicBCEAndConstantIndicesAllPrimTypes(x, x1, x2, x3, x4, x5, x6, x7, x8, 0, 10)); Integer[] x9 = { 9 }; - expectEquals(505, - dynamicBCEAndConstantIndicesAllTypes(x, x1, x2, x3, x4, x5, x6, x7, x8, x9, 0, 10)); + expectEquals(145, dynamicBCEAndConstantIndexRefType(x, x9, 0, 10)); } private static void expectEquals(int expected, int result) { diff --git a/test/960-default-smali/run b/test/960-default-smali/run deleted file mode 100755 index 22f68006e7..0000000000 --- a/test/960-default-smali/run +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use 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. - -${RUN} --experimental default-methods "$@" diff --git a/test/961-default-iface-resolution-generated/run b/test/961-default-iface-resolution-generated/run deleted file mode 100755 index 22f68006e7..0000000000 --- a/test/961-default-iface-resolution-generated/run +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use 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. - -${RUN} --experimental default-methods "$@" diff --git a/test/962-iface-static/run b/test/962-iface-static/run deleted file mode 100755 index d37737f3da..0000000000 --- a/test/962-iface-static/run +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use 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. - -${RUN} --experimental default-methods "$@" diff --git a/test/963-default-range-smali/run b/test/963-default-range-smali/run deleted file mode 100755 index d37737f3da..0000000000 --- a/test/963-default-range-smali/run +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use 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. - -${RUN} --experimental default-methods "$@" diff --git a/test/964-default-iface-init-generated/run b/test/964-default-iface-init-generated/run deleted file mode 100755 index 22f68006e7..0000000000 --- a/test/964-default-iface-init-generated/run +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use 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. - -${RUN} --experimental default-methods "$@" diff --git a/test/965-default-verify/run b/test/965-default-verify/run deleted file mode 100755 index 8944ea92d3..0000000000 --- a/test/965-default-verify/run +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use 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. - -${RUN} "$@" --experimental default-methods diff --git a/test/966-default-conflict/run b/test/966-default-conflict/run deleted file mode 100755 index 8944ea92d3..0000000000 --- a/test/966-default-conflict/run +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use 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. - -${RUN} "$@" --experimental default-methods diff --git a/test/967-default-ame/run b/test/967-default-ame/run deleted file mode 100755 index 8944ea92d3..0000000000 --- a/test/967-default-ame/run +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use 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. - -${RUN} "$@" --experimental default-methods diff --git a/test/968-default-partial-compile-generated/run b/test/968-default-partial-compile-generated/run deleted file mode 100755 index 6d2930d463..0000000000 --- a/test/968-default-partial-compile-generated/run +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use 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. - -${RUN} "$@" --experimental default-methods diff --git a/test/969-iface-super/run b/test/969-iface-super/run deleted file mode 100755 index 8944ea92d3..0000000000 --- a/test/969-iface-super/run +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Copyright (C) 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use 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. - -${RUN} "$@" --experimental default-methods diff --git a/test/970-iface-super-resolution-generated/run b/test/970-iface-super-resolution-generated/run deleted file mode 100755 index 6d2930d463..0000000000 --- a/test/970-iface-super-resolution-generated/run +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use 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. - -${RUN} "$@" --experimental default-methods diff --git a/test/971-iface-super/run b/test/971-iface-super/run deleted file mode 100755 index 6d2930d463..0000000000 --- a/test/971-iface-super/run +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash -# -# Copyright 2015 The Android Open Source Project -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use 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. - -${RUN} "$@" --experimental default-methods diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt index 351e99e8d4..6d67f8477d 100644 --- a/tools/libcore_failures.txt +++ b/tools/libcore_failures.txt @@ -260,6 +260,7 @@ "dalvik.system.JniTest#testPassingShorts", "dalvik.system.JniTest#testPassingThis", "libcore.util.NativeAllocationRegistryTest#testBadSize", + "libcore.util.NativeAllocationRegistryTest#testEarlyFree", "libcore.util.NativeAllocationRegistryTest#testNativeAllocationAllocatorAndNoSharedRegistry", "libcore.util.NativeAllocationRegistryTest#testNativeAllocationAllocatorAndSharedRegistry", "libcore.util.NativeAllocationRegistryTest#testNativeAllocationNoAllocatorAndNoSharedRegistry", |