summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/optimizing/builder.cc10
-rw-r--r--compiler/optimizing/code_generator_arm.cc43
-rw-r--r--compiler/optimizing/code_generator_x86.cc64
-rw-r--r--compiler/optimizing/code_generator_x86_64.cc68
-rw-r--r--compiler/utils/x86_64/assembler_x86_64.cc12
-rw-r--r--compiler/utils/x86_64/assembler_x86_64.h1
-rw-r--r--runtime/base/logging.cc2
-rw-r--r--runtime/base/logging.h5
-rw-r--r--runtime/base/mutex-inl.h8
-rw-r--r--runtime/base/mutex.cc4
-rw-r--r--runtime/base/mutex.h12
-rw-r--r--runtime/runtime.cc56
-rw-r--r--runtime/runtime.h11
-rw-r--r--runtime/runtime_android.cc1
-rw-r--r--runtime/runtime_linux.cc1
-rw-r--r--runtime/thread-inl.h8
-rw-r--r--runtime/thread.cc2
-rw-r--r--runtime/thread_list.cc6
-rw-r--r--runtime/utils.cc8
-rw-r--r--test/422-type-conversion/src/Main.java70
-rw-r--r--tools/art25
-rw-r--r--tools/libcore_failures.txt15
22 files changed, 309 insertions, 123 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index 9561054b69..ca72f3f242 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -1306,6 +1306,16 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32
break;
}
+ case Instruction::DOUBLE_TO_INT: {
+ Conversion_12x(instruction, Primitive::kPrimDouble, Primitive::kPrimInt, dex_pc);
+ break;
+ }
+
+ case Instruction::DOUBLE_TO_LONG: {
+ Conversion_12x(instruction, Primitive::kPrimDouble, Primitive::kPrimLong, dex_pc);
+ break;
+ }
+
case Instruction::DOUBLE_TO_FLOAT: {
Conversion_12x(instruction, Primitive::kPrimDouble, Primitive::kPrimFloat, dex_pc);
break;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 5076c85885..36af393e3b 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -44,7 +44,7 @@ static constexpr int kCurrentMethodStackOffset = 0;
static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2, R3 };
static constexpr size_t kRuntimeParameterCoreRegistersLength =
arraysize(kRuntimeParameterCoreRegisters);
-static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0 };
+static constexpr SRegister kRuntimeParameterFpuRegisters[] = { S0, S1 };
static constexpr size_t kRuntimeParameterFpuRegistersLength =
arraysize(kRuntimeParameterFpuRegisters);
@@ -1365,9 +1365,11 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
Primitive::Type input_type = conversion->GetInputType();
DCHECK_NE(result_type, input_type);
- // Float-to-long conversions invoke the runtime.
+ // The float-to-long and double-to-long type conversions rely on a
+ // call to the runtime.
LocationSummary::CallKind call_kind =
- (input_type == Primitive::kPrimFloat && result_type == Primitive::kPrimLong)
+ ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
+ && result_type == Primitive::kPrimLong)
? LocationSummary::kCall
: LocationSummary::kNoCall;
LocationSummary* locations =
@@ -1422,8 +1424,10 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
break;
case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type
- << " to " << result_type << " not yet implemented";
+ // Processing a Dex `double-to-int' instruction.
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresFpuRegister());
break;
default:
@@ -1452,10 +1456,15 @@ void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) {
break;
}
- case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type << " to "
- << result_type << " not yet implemented";
+ case Primitive::kPrimDouble: {
+ // Processing a Dex `double-to-long' instruction.
+ InvokeRuntimeCallingConvention calling_convention;
+ locations->SetInAt(0, Location::FpuRegisterPairLocation(
+ calling_convention.GetFpuRegisterAt(0),
+ calling_convention.GetFpuRegisterAt(1)));
+ locations->SetOut(Location::RegisterPairLocation(R0, R1));
break;
+ }
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
@@ -1614,10 +1623,15 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio
break;
}
- case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type
- << " to " << result_type << " not yet implemented";
+ case Primitive::kPrimDouble: {
+ // Processing a Dex `double-to-int' instruction.
+ SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>();
+ DRegister temp_d = FromLowSToD(temp_s);
+ __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>()));
+ __ vcvtid(temp_s, temp_d);
+ __ vmovrs(out.AsRegister<Register>(), temp_s);
break;
+ }
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
@@ -1643,15 +1657,16 @@ void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversio
case Primitive::kPrimFloat:
// Processing a Dex `float-to-long' instruction.
- // This call does not actually record PC information.
codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
conversion,
conversion->GetDexPc());
break;
case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type << " to "
- << result_type << " not yet implemented";
+ // Processing a Dex `double-to-long' instruction.
+ codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
+ conversion,
+ conversion->GetDexPc());
break;
default:
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 2aa121d04b..2fd712f7e2 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -1330,9 +1330,11 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
Primitive::Type input_type = conversion->GetInputType();
DCHECK_NE(result_type, input_type);
- // Float-to-long conversions invoke the runtime.
+ // The float-to-long and double-to-long type conversions rely on a
+ // call to the runtime.
LocationSummary::CallKind call_kind =
- (input_type == Primitive::kPrimFloat && result_type == Primitive::kPrimLong)
+ ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
+ && result_type == Primitive::kPrimLong)
? LocationSummary::kCall
: LocationSummary::kNoCall;
LocationSummary* locations =
@@ -1387,8 +1389,10 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
break;
case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type
- << " to " << result_type << " not yet implemented";
+ // Processing a Dex `double-to-int' instruction.
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresFpuRegister());
break;
default:
@@ -1411,15 +1415,27 @@ void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
case Primitive::kPrimFloat: {
// Processing a Dex `float-to-long' instruction.
InvokeRuntimeCallingConvention calling_convention;
- locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
+ // Note that on x86 floating-point parameters are passed
+ // through core registers (here, EAX).
+ locations->SetInAt(0, Location::RegisterLocation(
+ calling_convention.GetRegisterAt(0)));
// The runtime helper puts the result in EAX, EDX.
locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
break;
}
- case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type << " to "
- << result_type << " not yet implemented";
+ case Primitive::kPrimDouble: {
+ // Processing a Dex `double-to-long' instruction.
+ InvokeRuntimeCallingConvention calling_convention;
+ // Note that on x86 floating-point parameters are passed
+ // through core registers (here, EAX and ECX).
+ locations->SetInAt(0, Location::RegisterPairLocation(
+ calling_convention.GetRegisterAt(0),
+ calling_convention.GetRegisterAt(1)));
+ // The runtime helper puts the result in EAX, EDX.
+ locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
+ break;
+ }
break;
default:
@@ -1607,10 +1623,30 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
break;
}
- case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type
- << " to " << result_type << " not yet implemented";
+ case Primitive::kPrimDouble: {
+ // Processing a Dex `double-to-int' instruction.
+ XmmRegister input = in.AsFpuRegister<XmmRegister>();
+ Register output = out.AsRegister<Register>();
+ XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+ Label done, nan;
+
+ __ movl(output, Immediate(kPrimIntMax));
+ // temp = int-to-double(output)
+ __ cvtsi2sd(temp, output);
+ // if input >= temp goto done
+ __ comisd(input, temp);
+ __ j(kAboveEqual, &done);
+ // if input == NaN goto nan
+ __ j(kUnordered, &nan);
+ // output = double-to-int-truncate(input)
+ __ cvttsd2si(output, input);
+ __ jmp(&done);
+ __ Bind(&nan);
+ // output = 0
+ __ xorl(output, output);
+ __ Bind(&done);
break;
+ }
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
@@ -1634,13 +1670,13 @@ void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversio
case Primitive::kPrimFloat:
// Processing a Dex `float-to-long' instruction.
__ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pF2l)));
- // This call does not actually record PC information.
codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
break;
case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type << " to "
- << result_type << " not yet implemented";
+ // Processing a Dex `double-to-long' instruction.
+ __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pD2l)));
+ codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
break;
default:
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 5761fb1bda..39a97661c9 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -1370,8 +1370,10 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
break;
case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type
- << " to " << result_type << " not yet implemented";
+ // Processing a Dex `double-to-int' instruction.
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresFpuRegister());
break;
default:
@@ -1401,8 +1403,10 @@ void LocationsBuilderX86_64::VisitTypeConversion(HTypeConversion* conversion) {
break;
case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type << " to "
- << result_type << " not yet implemented";
+ // Processing a Dex `double-to-long' instruction.
+ locations->SetInAt(0, Location::RequiresFpuRegister());
+ locations->SetOut(Location::RequiresRegister());
+ locations->AddTemp(Location::RequiresFpuRegister());
break;
default:
@@ -1589,10 +1593,30 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
break;
}
- case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type
- << " to " << result_type << " not yet implemented";
+ case Primitive::kPrimDouble: {
+ // Processing a Dex `double-to-int' instruction.
+ XmmRegister input = in.AsFpuRegister<XmmRegister>();
+ CpuRegister output = out.AsRegister<CpuRegister>();
+ XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+ Label done, nan;
+
+ __ movl(output, Immediate(kPrimIntMax));
+ // temp = int-to-double(output)
+ __ cvtsi2sd(temp, output);
+ // if input >= temp goto done
+ __ comisd(input, temp);
+ __ j(kAboveEqual, &done);
+ // if input == NaN goto nan
+ __ j(kUnordered, &nan);
+ // output = double-to-int-truncate(input)
+ __ cvttsd2si(output, input);
+ __ jmp(&done);
+ __ Bind(&nan);
+ // output = 0
+ __ xorl(output, output);
+ __ Bind(&done);
break;
+ }
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
@@ -1620,14 +1644,14 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
Label done, nan;
__ movq(output, Immediate(kPrimLongMax));
- // temp = int-to-float(output)
+ // temp = long-to-float(output)
__ cvtsi2ss(temp, output, true);
// if input >= temp goto done
__ comiss(input, temp);
__ j(kAboveEqual, &done);
// if input == NaN goto nan
__ j(kUnordered, &nan);
- // output = float-to-int-truncate(input)
+ // output = float-to-long-truncate(input)
__ cvttss2si(output, input, true);
__ jmp(&done);
__ Bind(&nan);
@@ -1637,10 +1661,30 @@ void InstructionCodeGeneratorX86_64::VisitTypeConversion(HTypeConversion* conver
break;
}
- case Primitive::kPrimDouble:
- LOG(FATAL) << "Type conversion from " << input_type << " to "
- << result_type << " not yet implemented";
+ case Primitive::kPrimDouble: {
+ // Processing a Dex `double-to-long' instruction.
+ XmmRegister input = in.AsFpuRegister<XmmRegister>();
+ CpuRegister output = out.AsRegister<CpuRegister>();
+ XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
+ Label done, nan;
+
+ __ movq(output, Immediate(kPrimLongMax));
+ // temp = long-to-double(output)
+ __ cvtsi2sd(temp, output, true);
+ // if input >= temp goto done
+ __ comisd(input, temp);
+ __ j(kAboveEqual, &done);
+ // if input == NaN goto nan
+ __ j(kUnordered, &nan);
+ // output = double-to-long-truncate(input)
+ __ cvttsd2si(output, input, true);
+ __ jmp(&done);
+ __ Bind(&nan);
+ // output = 0
+ __ xorq(output, output);
+ __ Bind(&done);
break;
+ }
default:
LOG(FATAL) << "Unexpected type conversion from " << input_type
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 3c21236a8a..2a6c58e128 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -683,9 +683,19 @@ void X86_64Assembler::cvttss2si(CpuRegister dst, XmmRegister src, bool is64bit)
void X86_64Assembler::cvttsd2si(CpuRegister dst, XmmRegister src) {
+ cvttsd2si(dst, src, false);
+}
+
+
+void X86_64Assembler::cvttsd2si(CpuRegister dst, XmmRegister src, bool is64bit) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
- EmitOptionalRex32(dst, src);
+ if (is64bit) {
+ // Emit a REX.W prefix if the operand size is 64 bits.
+ EmitRex64(dst, src);
+ } else {
+ EmitOptionalRex32(dst, src);
+ }
EmitUint8(0x0F);
EmitUint8(0x2C);
EmitXmmRegisterOperand(dst.LowBits(), src);
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 4c2836665d..51d1de2c0f 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -342,6 +342,7 @@ class X86_64Assembler FINAL : public Assembler {
void cvttss2si(CpuRegister dst, XmmRegister src); // Note: this is the r32 version.
void cvttss2si(CpuRegister dst, XmmRegister src, bool is64bit);
void cvttsd2si(CpuRegister dst, XmmRegister src); // Note: this is the r32 version.
+ void cvttsd2si(CpuRegister dst, XmmRegister src, bool is64bit);
void cvtdq2pd(XmmRegister dst, XmmRegister src);
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index b781d6008c..bdc4cf6399 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -35,8 +35,6 @@ namespace art {
LogVerbosity gLogVerbosity;
-unsigned int gAborting = 0;
-
static LogSeverity gMinimumLogSeverity = INFO;
static std::unique_ptr<std::string> gCmdLine;
static std::unique_ptr<std::string> gProgramInvocationName;
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index ae83e331fd..a9cc99b085 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -55,11 +55,6 @@ struct LogVerbosity {
// Global log verbosity setting, initialized by InitLogging.
extern LogVerbosity gLogVerbosity;
-// 0 if not abort, non-zero if an abort is in progress. Used on fatal exit to prevents recursive
-// aborts. Global declaration allows us to disable some error checking to ensure fatal shutdown
-// makes forward progress.
-extern unsigned int gAborting;
-
// Configure logging based on ANDROID_LOG_TAGS environment variable.
// We need to parse a string that looks like
//
diff --git a/runtime/base/mutex-inl.h b/runtime/base/mutex-inl.h
index cb698175df..020634122e 100644
--- a/runtime/base/mutex-inl.h
+++ b/runtime/base/mutex-inl.h
@@ -97,9 +97,7 @@ inline void BaseMutex::RegisterAsLocked(Thread* self) {
}
}
}
- if (gAborting == 0) { // Avoid recursive aborts.
- CHECK(!bad_mutexes_held);
- }
+ CHECK(!bad_mutexes_held);
}
// Don't record monitors as they are outside the scope of analysis. They may be inspected off of
// the monitor list.
@@ -114,7 +112,7 @@ inline void BaseMutex::RegisterAsUnlocked(Thread* self) {
return;
}
if (level_ != kMonitorLock) {
- if (kDebugLocking && gAborting == 0) { // Avoid recursive aborts.
+ if (kDebugLocking) {
CHECK(self->GetHeldMutex(level_) == this) << "Unlocking on unacquired mutex: " << name_;
}
self->SetHeldMutex(level_, NULL);
@@ -178,7 +176,7 @@ inline bool Mutex::IsExclusiveHeld(const Thread* self) const {
bool result = (GetExclusiveOwnerTid() == SafeGetTid(self));
if (kDebugLocking) {
// Sanity debug check that if we think it is locked we have it in our held mutexes.
- if (result && self != NULL && level_ != kMonitorLock && !gAborting) {
+ if (result && self != NULL && level_ != kMonitorLock) {
CHECK_EQ(self->GetHeldMutex(level_), this);
}
}
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index aa2aefc318..49579886fd 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -209,9 +209,7 @@ void BaseMutex::CheckSafeToWait(Thread* self) {
}
}
}
- if (gAborting == 0) { // Avoid recursive aborts.
- CHECK(!bad_mutexes_held);
- }
+ CHECK(!bad_mutexes_held);
}
}
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 9c93cc624d..41b5f12fdb 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -220,7 +220,7 @@ class LOCKABLE Mutex : public BaseMutex {
// Assert that the Mutex is exclusively held by the current thread.
void AssertExclusiveHeld(const Thread* self) {
- if (kDebugLocking && (gAborting == 0)) {
+ if (kDebugLocking) {
CHECK(IsExclusiveHeld(self)) << *this;
}
}
@@ -228,7 +228,7 @@ class LOCKABLE Mutex : public BaseMutex {
// Assert that the Mutex is not held by the current thread.
void AssertNotHeldExclusive(const Thread* self) {
- if (kDebugLocking && (gAborting == 0)) {
+ if (kDebugLocking) {
CHECK(!IsExclusiveHeld(self)) << *this;
}
}
@@ -318,7 +318,7 @@ class LOCKABLE ReaderWriterMutex : public BaseMutex {
// Assert the current thread has exclusive access to the ReaderWriterMutex.
void AssertExclusiveHeld(const Thread* self) {
- if (kDebugLocking && (gAborting == 0)) {
+ if (kDebugLocking) {
CHECK(IsExclusiveHeld(self)) << *this;
}
}
@@ -326,7 +326,7 @@ class LOCKABLE ReaderWriterMutex : public BaseMutex {
// Assert the current thread doesn't have exclusive access to the ReaderWriterMutex.
void AssertNotExclusiveHeld(const Thread* self) {
- if (kDebugLocking && (gAborting == 0)) {
+ if (kDebugLocking) {
CHECK(!IsExclusiveHeld(self)) << *this;
}
}
@@ -337,7 +337,7 @@ class LOCKABLE ReaderWriterMutex : public BaseMutex {
// Assert the current thread has shared access to the ReaderWriterMutex.
void AssertSharedHeld(const Thread* self) {
- if (kDebugLocking && (gAborting == 0)) {
+ if (kDebugLocking) {
// TODO: we can only assert this well when self != NULL.
CHECK(IsSharedHeld(self) || self == NULL) << *this;
}
@@ -347,7 +347,7 @@ class LOCKABLE ReaderWriterMutex : public BaseMutex {
// Assert the current thread doesn't hold this ReaderWriterMutex either in shared or exclusive
// mode.
void AssertNotHeld(const Thread* self) {
- if (kDebugLocking && (gAborting == 0)) {
+ if (kDebugLocking) {
CHECK(!IsSharedHeld(self)) << *this;
}
}
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 078e7d24e1..e79203198e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -126,6 +126,8 @@ namespace art {
static constexpr bool kEnableJavaStackTraceHandler = false;
Runtime* Runtime::instance_ = nullptr;
+volatile unsigned int gAborting = 0;
+
Runtime::Runtime()
: instruction_set_(kNone),
compiler_callbacks_(nullptr),
@@ -236,13 +238,8 @@ Runtime::~Runtime() {
struct AbortState {
void Dump(std::ostream& os) const {
- if (gAborting > 1) {
- os << "Runtime aborting --- recursively, so no thread-specific detail!\n";
- return;
- }
- gAborting++;
os << "Runtime aborting...\n";
- if (Runtime::Current() == NULL) {
+ if (Runtime::Current() == nullptr) {
os << "(Runtime does not yet exist!)\n";
return;
}
@@ -300,13 +297,18 @@ struct AbortState {
void Runtime::Abort() {
gAborting++; // set before taking any locks
+ if (gAborting > 1) {
+ LogMessage::LogLine(__FILE__, __LINE__, INTERNAL_FATAL,
+ "Runtime aborting --- recursively, so no thread-specific detail!\n");
+ return;
+ }
// Ensure that we don't have multiple threads trying to abort at once,
// which would result in significantly worse diagnostics.
MutexLock mu(Thread::Current(), *Locks::abort_lock_);
// Get any pending output out of the way.
- fflush(NULL);
+ fflush(nullptr);
// Many people have difficulty distinguish aborts from crashes,
// so be explicit.
@@ -314,7 +316,7 @@ void Runtime::Abort() {
LOG(INTERNAL_FATAL) << Dumpable<AbortState>(state);
// Call the abort hook if we have one.
- if (Runtime::Current() != NULL && Runtime::Current()->abort_ != NULL) {
+ if (Runtime::Current() != nullptr && Runtime::Current()->abort_ != nullptr) {
LOG(INTERNAL_FATAL) << "Calling abort hook...";
Runtime::Current()->abort_();
// notreached
@@ -342,7 +344,7 @@ void Runtime::PreZygoteFork() {
}
void Runtime::CallExitHook(jint status) {
- if (exit_ != NULL) {
+ if (exit_ != nullptr) {
ScopedThreadStateChange tsc(Thread::Current(), kNative);
exit_(status);
LOG(WARNING) << "Exit hook returned instead of exiting!";
@@ -357,14 +359,14 @@ void Runtime::SweepSystemWeaks(IsMarkedCallback* visitor, void* arg) {
bool Runtime::Create(const RuntimeOptions& options, bool ignore_unrecognized) {
// TODO: acquire a static mutex on Runtime to avoid racing.
- if (Runtime::instance_ != NULL) {
+ if (Runtime::instance_ != nullptr) {
return false;
}
- InitLogging(NULL); // Calls Locks::Init() as a side effect.
+ InitLogging(nullptr); // Calls Locks::Init() as a side effect.
instance_ = new Runtime;
if (!instance_->Init(options, ignore_unrecognized)) {
delete instance_;
- instance_ = NULL;
+ instance_ = nullptr;
return false;
}
return true;
@@ -372,7 +374,7 @@ bool Runtime::Create(const RuntimeOptions& options, bool ignore_unrecognized) {
static jobject CreateSystemClassLoader() {
if (Runtime::Current()->UseCompileTimeClassPath()) {
- return NULL;
+ return nullptr;
}
ScopedObjectAccess soa(Thread::Current());
@@ -385,7 +387,7 @@ static jobject CreateSystemClassLoader() {
mirror::ArtMethod* getSystemClassLoader =
class_loader_class->FindDirectMethod("getSystemClassLoader", "()Ljava/lang/ClassLoader;");
- CHECK(getSystemClassLoader != NULL);
+ CHECK(getSystemClassLoader != nullptr);
JValue result = InvokeWithJValues(soa, nullptr, soa.EncodeMethod(getSystemClassLoader), nullptr);
JNIEnv* env = soa.Self()->GetJniEnv();
@@ -401,7 +403,7 @@ static jobject CreateSystemClassLoader() {
mirror::ArtField* contextClassLoader =
thread_class->FindDeclaredInstanceField("contextClassLoader", "Ljava/lang/ClassLoader;");
- CHECK(contextClassLoader != NULL);
+ CHECK(contextClassLoader != nullptr);
// We can't run in a transaction yet.
contextClassLoader->SetObject<false>(soa.Self()->GetPeer(),
@@ -527,7 +529,7 @@ bool Runtime::InitZygote() {
// Mark rootfs as being a slave so that changes from default
// namespace only flow into our children.
- if (mount("rootfs", "/", NULL, (MS_SLAVE | MS_REC), NULL) == -1) {
+ if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) {
PLOG(WARNING) << "Failed to mount() rootfs as MS_SLAVE";
return false;
}
@@ -536,7 +538,7 @@ bool Runtime::InitZygote() {
// bind mount storage into their respective private namespaces, which
// are isolated from each other.
const char* target_base = getenv("EMULATED_STORAGE_TARGET");
- if (target_base != NULL) {
+ if (target_base != nullptr) {
if (mount("tmpfs", target_base, "tmpfs", MS_NOSUID | MS_NODEV,
"uid=0,gid=1028,mode=0751") == -1) {
LOG(WARNING) << "Failed to mount tmpfs to " << target_base;
@@ -893,14 +895,14 @@ bool Runtime::Init(const RuntimeOptions& raw_options, bool ignore_unrecognized)
self->ThrowNewException(ThrowLocation(), "Ljava/lang/OutOfMemoryError;",
"OutOfMemoryError thrown while trying to throw OutOfMemoryError; "
"no stack trace available");
- pre_allocated_OutOfMemoryError_ = GcRoot<mirror::Throwable>(self->GetException(NULL));
+ pre_allocated_OutOfMemoryError_ = GcRoot<mirror::Throwable>(self->GetException(nullptr));
self->ClearException();
// Pre-allocate a NoClassDefFoundError for the common case of failing to find a system class
// ahead of checking the application's class loader.
self->ThrowNewException(ThrowLocation(), "Ljava/lang/NoClassDefFoundError;",
"Class not found using the boot class loader; no stack trace available");
- pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>(self->GetException(NULL));
+ pre_allocated_NoClassDefFoundError_ = GcRoot<mirror::Throwable>(self->GetException(nullptr));
self->ClearException();
// Look for a native bridge.
@@ -976,26 +978,26 @@ void Runtime::InitThreadGroups(Thread* self) {
env->NewGlobalRef(env->GetStaticObjectField(
WellKnownClasses::java_lang_ThreadGroup,
WellKnownClasses::java_lang_ThreadGroup_mainThreadGroup));
- CHECK(main_thread_group_ != NULL || IsCompiler());
+ CHECK(main_thread_group_ != nullptr || IsCompiler());
system_thread_group_ =
env->NewGlobalRef(env->GetStaticObjectField(
WellKnownClasses::java_lang_ThreadGroup,
WellKnownClasses::java_lang_ThreadGroup_systemThreadGroup));
- CHECK(system_thread_group_ != NULL || IsCompiler());
+ CHECK(system_thread_group_ != nullptr || IsCompiler());
}
jobject Runtime::GetMainThreadGroup() const {
- CHECK(main_thread_group_ != NULL || IsCompiler());
+ CHECK(main_thread_group_ != nullptr || IsCompiler());
return main_thread_group_;
}
jobject Runtime::GetSystemThreadGroup() const {
- CHECK(system_thread_group_ != NULL || IsCompiler());
+ CHECK(system_thread_group_ != nullptr || IsCompiler());
return system_thread_group_;
}
jobject Runtime::GetSystemClassLoader() const {
- CHECK(system_class_loader_ != NULL || IsCompiler());
+ CHECK(system_class_loader_ != nullptr || IsCompiler());
return system_class_loader_;
}
@@ -1121,12 +1123,12 @@ void Runtime::BlockSignals() {
bool Runtime::AttachCurrentThread(const char* thread_name, bool as_daemon, jobject thread_group,
bool create_peer) {
- return Thread::Attach(thread_name, as_daemon, thread_group, create_peer) != NULL;
+ return Thread::Attach(thread_name, as_daemon, thread_group, create_peer) != nullptr;
}
void Runtime::DetachCurrentThread() {
Thread* self = Thread::Current();
- if (self == NULL) {
+ if (self == nullptr) {
LOG(FATAL) << "attempting to detach thread that is not attached";
}
if (self->HasManagedStack()) {
@@ -1351,7 +1353,7 @@ void Runtime::SetCalleeSaveMethod(mirror::ArtMethod* method, CalleeSaveType type
}
const std::vector<const DexFile*>& Runtime::GetCompileTimeClassPath(jobject class_loader) {
- if (class_loader == NULL) {
+ if (class_loader == nullptr) {
return GetClassLinker()->GetBootClassPath();
}
CHECK(UseCompileTimeClassPath());
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 39fd910893..e334764daa 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -71,6 +71,11 @@ class ThreadList;
class Trace;
class Transaction;
+// 0 if not abort, non-zero if an abort is in progress. Used on fatal exit to prevents recursive
+// aborts. Global declaration allows us to disable some error checking to ensure fatal shutdown
+// makes forward progress.
+extern volatile unsigned int gAborting;
+
typedef std::vector<std::pair<std::string, const void*>> RuntimeOptions;
// Not all combinations of flags are valid. You may not visit all roots as well as the new roots
@@ -175,9 +180,9 @@ class Runtime {
return instance_;
}
- // Aborts semi-cleanly. Used in the implementation of LOG(FATAL), which most
- // callers should prefer.
- [[noreturn]] static void Abort() LOCKS_EXCLUDED(Locks::abort_lock_);
+ // Aborts semi-cleanly. Used in the implementation of LOG(FATAL), which most callers should
+ // prefer. Not [[noreturn]] due to returning early in the case of recursive aborts.
+ static void Abort() LOCKS_EXCLUDED(Locks::abort_lock_);
// Returns the "main" ThreadGroup, used when attaching user threads.
jobject GetMainThreadGroup() const;
diff --git a/runtime/runtime_android.cc b/runtime/runtime_android.cc
index 33600ddba5..33641edb50 100644
--- a/runtime/runtime_android.cc
+++ b/runtime/runtime_android.cc
@@ -38,7 +38,6 @@ void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_contex
_exit(1);
}
handling_unexpected_signal = true;
- gAborting++; // set before taking any locks
MutexLock mu(Thread::Current(), *Locks::unexpected_signal_lock_);
Runtime* runtime = Runtime::Current();
diff --git a/runtime/runtime_linux.cc b/runtime/runtime_linux.cc
index 1de035c0d5..927309177a 100644
--- a/runtime/runtime_linux.cc
+++ b/runtime/runtime_linux.cc
@@ -284,7 +284,6 @@ void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_contex
}
handlingUnexpectedSignal = true;
- gAborting++; // set before taking any locks
MutexLock mu(Thread::Current(), *Locks::unexpected_signal_lock_);
bool has_address = (signal_number == SIGILL || signal_number == SIGBUS ||
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 7aed8b033c..49b7be9edd 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -83,9 +83,7 @@ inline ThreadState Thread::SetState(ThreadState new_state) {
inline void Thread::AssertThreadSuspensionIsAllowable(bool check_locks) const {
if (kIsDebugBuild) {
- if (gAborting == 0) {
- CHECK_EQ(0u, tls32_.no_thread_suspension) << tlsPtr_.last_no_thread_suspension_cause;
- }
+ CHECK_EQ(0u, tls32_.no_thread_suspension) << tlsPtr_.last_no_thread_suspension_cause;
if (check_locks) {
bool bad_mutexes_held = false;
for (int i = kLockLevelCount - 1; i >= 0; --i) {
@@ -99,9 +97,7 @@ inline void Thread::AssertThreadSuspensionIsAllowable(bool check_locks) const {
}
}
}
- if (gAborting == 0) {
- CHECK(!bad_mutexes_held);
- }
+ CHECK(!bad_mutexes_held);
}
}
}
diff --git a/runtime/thread.cc b/runtime/thread.cc
index f7c710695a..a6e5b0c18b 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -742,7 +742,7 @@ void Thread::DumpState(std::ostream& os, const Thread* thread, pid_t tid) {
// Don't do this if we are aborting since the GC may have all the threads suspended. This will
// cause ScopedObjectAccessUnchecked to deadlock.
- if (gAborting == 0 && self != nullptr && thread != nullptr && thread->tlsPtr_.opeer != nullptr) {
+ if (self != nullptr && thread != nullptr && thread->tlsPtr_.opeer != nullptr) {
ScopedObjectAccessUnchecked soa(self);
priority = soa.DecodeField(WellKnownClasses::java_lang_Thread_priority)
->GetInt(thread->tlsPtr_.opeer);
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index beafcda8f2..71325a5350 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -168,9 +168,7 @@ class DumpCheckpoint FINAL : public Closure {
const uint32_t kWaitTimeoutMs = 10000;
bool timed_out = barrier_.Increment(self, threads_running_checkpoint, kWaitTimeoutMs);
if (timed_out) {
- // Avoid a recursive abort.
- LOG((kIsDebugBuild && (gAborting == 0)) ? FATAL : ERROR)
- << "Unexpected time out during dump checkpoint.";
+ LOG(kIsDebugBuild ? FATAL : ERROR) << "Unexpected time out during dump checkpoint.";
}
}
@@ -243,7 +241,7 @@ size_t ThreadList::RunCheckpoint(Closure* checkpoint_function) {
Locks::mutator_lock_->AssertNotExclusiveHeld(self);
Locks::thread_list_lock_->AssertNotHeld(self);
Locks::thread_suspend_count_lock_->AssertNotHeld(self);
- if (kDebugLocking && gAborting == 0) {
+ if (kDebugLocking) {
CHECK_NE(self->GetState(), kRunnable);
}
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 1211547a51..d9782f3fee 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1125,14 +1125,6 @@ void DumpNativeStack(std::ostream& os, pid_t tid, const char* prefix,
return;
}
-#if !defined(HAVE_ANDROID_OS)
- if (GetTid() != tid) {
- // TODO: dumping of other threads is disabled to avoid crashes during stress testing.
- // b/15446488.
- return;
- }
-#endif
-
std::unique_ptr<Backtrace> backtrace(Backtrace::Create(BACKTRACE_CURRENT_PROCESS, tid));
if (!backtrace->Unwind(0)) {
os << prefix << "(backtrace::Unwind failed for thread " << tid << ")\n";
diff --git a/test/422-type-conversion/src/Main.java b/test/422-type-conversion/src/Main.java
index 91618fc341..7ce2868283 100644
--- a/test/422-type-conversion/src/Main.java
+++ b/test/422-type-conversion/src/Main.java
@@ -112,6 +112,12 @@ public class Main {
// Generate, compile and check float-to-double Dex instructions.
floatToDouble();
+ // Generate, compile and check double-to-int Dex instructions.
+ doubleToInt();
+
+ // Generate, compile and check double-to-long Dex instructions.
+ doubleToLong();
+
// Generate, compile and check double-to-float Dex instructions.
doubleToFloat();
@@ -415,6 +421,58 @@ public class Main {
assertDoubleEquals(Double.NEGATIVE_INFINITY, $opt$FloatToDouble(Float.NEGATIVE_INFINITY));
}
+ private static void doubleToInt() {
+ assertIntEquals(1, $opt$DoubleToInt(1D));
+ assertIntEquals(0, $opt$DoubleToInt(0D));
+ assertIntEquals(0, $opt$DoubleToInt(-0D));
+ assertIntEquals(-1, $opt$DoubleToInt(-1D));
+ assertIntEquals(51, $opt$DoubleToInt(51D));
+ assertIntEquals(-51, $opt$DoubleToInt(-51D));
+ assertIntEquals(0, $opt$DoubleToInt(0.5D));
+ assertIntEquals(0, $opt$DoubleToInt(0.4999999D));
+ assertIntEquals(0, $opt$DoubleToInt(-0.4999999D));
+ assertIntEquals(0, $opt$DoubleToInt(-0.5D));
+ assertIntEquals(42, $opt$DoubleToInt(42.199D));
+ assertIntEquals(-42, $opt$DoubleToInt(-42.199D));
+ assertIntEquals(2147483647, $opt$DoubleToInt(2147483647D)); // 2^31 - 1
+ assertIntEquals(-2147483647, $opt$DoubleToInt(-2147483647D)); // -(2^31 - 1)
+ assertIntEquals(-2147483648, $opt$DoubleToInt(-2147483648D)); // -(2^31)
+ assertIntEquals(2147483647, $opt$DoubleToInt(2147483648D)); // (2^31)
+ assertIntEquals(-2147483648, $opt$DoubleToInt(-2147483649D)); // -(2^31 + 1)
+ assertIntEquals(2147483647, $opt$DoubleToInt(9223372036854775807D)); // 2^63 - 1
+ assertIntEquals(-2147483648, $opt$DoubleToInt(-9223372036854775807D)); // -(2^63 - 1)
+ assertIntEquals(-2147483648, $opt$DoubleToInt(-9223372036854775808D)); // -(2^63)
+ assertIntEquals(0, $opt$DoubleToInt(Double.NaN));
+ assertIntEquals(2147483647, $opt$DoubleToInt(Double.POSITIVE_INFINITY));
+ assertIntEquals(-2147483648, $opt$DoubleToInt(Double.NEGATIVE_INFINITY));
+ }
+
+ private static void doubleToLong() {
+ assertLongEquals(1L, $opt$DoubleToLong(1D));
+ assertLongEquals(0L, $opt$DoubleToLong(0D));
+ assertLongEquals(0L, $opt$DoubleToLong(-0D));
+ assertLongEquals(-1L, $opt$DoubleToLong(-1D));
+ assertLongEquals(51L, $opt$DoubleToLong(51D));
+ assertLongEquals(-51L, $opt$DoubleToLong(-51D));
+ assertLongEquals(0L, $opt$DoubleToLong(0.5D));
+ assertLongEquals(0L, $opt$DoubleToLong(0.4999999D));
+ assertLongEquals(0L, $opt$DoubleToLong(-0.4999999D));
+ assertLongEquals(0L, $opt$DoubleToLong(-0.5D));
+ assertLongEquals(42L, $opt$DoubleToLong(42.199D));
+ assertLongEquals(-42L, $opt$DoubleToLong(-42.199D));
+ assertLongEquals(2147483647L, $opt$DoubleToLong(2147483647D)); // 2^31 - 1
+ assertLongEquals(-2147483647L, $opt$DoubleToLong(-2147483647D)); // -(2^31 - 1)
+ assertLongEquals(-2147483648L, $opt$DoubleToLong(-2147483648D)); // -(2^31)
+ assertLongEquals(2147483648L, $opt$DoubleToLong(2147483648D)); // (2^31)
+ assertLongEquals(-2147483649L, $opt$DoubleToLong(-2147483649D)); // -(2^31 + 1)
+ assertLongEquals(9223372036854775807L, $opt$DoubleToLong(9223372036854775807D)); // 2^63 - 1
+ assertLongEquals(-9223372036854775808L, $opt$DoubleToLong(-9223372036854775807D)); // -(2^63 - 1)
+ assertLongEquals(-9223372036854775808L, $opt$DoubleToLong(-9223372036854775808D)); // -(2^63)
+ assertLongEquals(0L, $opt$DoubleToLong(Double.NaN));
+ assertLongEquals(9223372036854775807L, $opt$DoubleToLong(Double.POSITIVE_INFINITY));
+ assertLongEquals(-9223372036854775808L, $opt$DoubleToLong(Double.NEGATIVE_INFINITY));
+ }
+
private static void doubleToFloat() {
assertFloatEquals(1F, $opt$DoubleToFloat(1D));
assertFloatEquals(0F, $opt$DoubleToFloat(0D));
@@ -599,15 +657,21 @@ public class Main {
// This method produces a float-to-int Dex instruction.
static int $opt$FloatToInt(float a) { return (int)a; }
+ // This method produces a float-to-long Dex instruction.
+ static long $opt$FloatToLong(float a){ return (long)a; }
+
// This method produces a float-to-double Dex instruction.
static double $opt$FloatToDouble(float a) { return (double)a; }
+ // This method produces a double-to-int Dex instruction.
+ static int $opt$DoubleToInt(double a){ return (int)a; }
+
+ // This method produces a double-to-long Dex instruction.
+ static long $opt$DoubleToLong(double a){ return (long)a; }
+
// This method produces a double-to-float Dex instruction.
static float $opt$DoubleToFloat(double a) { return (float)a; }
- // This method produces a float-to-long Dex instruction.
- static long $opt$FloatToLong(float a){ return (long)a; }
-
// These methods produce int-to-byte Dex instructions.
static byte $opt$ShortToByte(short a) { return (byte)a; }
static byte $opt$IntToByte(int a) { return (byte)a; }
diff --git a/tools/art b/tools/art
index af96b47fad..d5d546b4ad 100644
--- a/tools/art
+++ b/tools/art
@@ -1,5 +1,3 @@
-#!/bin/bash
-#
# Copyright (C) 2011 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,6 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+# This script is used on host and device. It uses a common subset
+# shell dialect that should work on the host (e.g. bash), and
+# Android (e.g. mksh).
+
function follow_links() {
if [ z"$BASH_SOURCE" != z ]; then
file="$BASH_SOURCE"
@@ -28,7 +30,8 @@ function follow_links() {
}
function find_libdir() {
- if [ "$(readlink "$ANDROID_ROOT/bin/$DALVIKVM")" = "dalvikvm64" ]; then
+ # Use realpath instead of readlink because Android does not have a readlink.
+ if [ "$(realpath "$ANDROID_ROOT/bin/$DALVIKVM")" = "$(realpath "$ANDROID_ROOT/bin/dalvikvm64")" ]; then
echo "lib64"
else
echo "lib"
@@ -70,16 +73,22 @@ done
PROG_NAME="$(follow_links)"
PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
ANDROID_ROOT=$PROG_DIR/..
-ANDROID_DATA=$PWD/android-data$$
LIBDIR=$(find_libdir)
LD_LIBRARY_PATH=$ANDROID_ROOT/$LIBDIR
-
if [ z"$PERF" != z ]; then
invoke_with="perf record -o $ANDROID_DATA/perf.data -e cycles:u $invoke_with"
fi
-mkdir -p $ANDROID_DATA/dalvik-cache/{arm,arm64,x86,x86_64}
+DELETE_ANDROID_DATA=false
+# If ANDROID_DATA is the system ANDROID_DATA or is not set, use our own,
+# and ensure we delete it at the end.
+if [ "$ANDROID_DATA" = "/data" ] || [ "$ANDROID_DATA" = "" ]; then
+ ANDROID_DATA=$PWD/android-data$$
+ mkdir -p $ANDROID_DATA/dalvik-cache/{arm,arm64,x86,x86_64}
+ DELETE_ANDROID_DATA=true
+fi
+
ANDROID_DATA=$ANDROID_DATA \
ANDROID_ROOT=$ANDROID_ROOT \
LD_LIBRARY_PATH=$LD_LIBRARY_PATH \
@@ -97,7 +106,9 @@ if [ z"$PERF" != z ]; then
fi
echo "Perf data saved in: $ANDROID_DATA/perf.data"
else
- rm -rf $ANDROID_DATA
+ if [ "$DELETE_ANDROID_DATA" = "true" ]; then
+ rm -rf $ANDROID_DATA
+ fi
fi
exit $EXIT_STATUS
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 8eac1d3a23..febc48c526 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -11,11 +11,26 @@
{
description: "Assert.java differences between vogar and junit.",
result: EXEC_FAILED,
+ modes: [host],
name: "libcore.java.math.RunCSVTests#test_csv"
},
{
description: "Test is currently being updated.",
result: EXEC_FAILED,
name: "libcore.java.util.OldTimeZoneTest#test_getDisplayNameZILjava_util_Locale"
+},
+{
+ description: "Differences between vogar and cts in user directory",
+ result: EXEC_FAILED,
+ modes: [device],
+ name: "libcore.java.lang.SystemTest#testSystemProperties_mutable"
+},
+{
+ description: "Differences between vogar and cts",
+ result: EXEC_FAILED,
+ modes: [device],
+ names: ["libcore.java.lang.OldSystemTest#test_getProperties",
+ "org.apache.harmony.tests.java.lang.Process2Test#test_getErrorStream",
+ "org.apache.harmony.tests.java.lang.ProcessTest#test_exitValue"]
}
]