am e5426c99: Fix histogram memory issues.
* commit 'e5426c9995d28bcb19391d8dbf0ad70606cf1770':
Fix histogram memory issues.
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index 1ee29cb..60e638c 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -209,8 +209,8 @@
void DexCompiler::CompileReturnVoid(Instruction* inst, uint32_t dex_pc) {
DCHECK(inst->Opcode() == Instruction::RETURN_VOID);
- // Are we compiling a constructor ?
- if ((unit_.GetAccessFlags() & kAccConstructor) == 0) {
+ // Are we compiling a non-clinit constructor?
+ if (!unit_.IsConstructor() || unit_.IsStatic()) {
return;
}
// Do we need a constructor barrier ?
diff --git a/compiler/driver/dex_compilation_unit.h b/compiler/driver/dex_compilation_unit.h
index 5bf0086..465139b 100644
--- a/compiler/driver/dex_compilation_unit.h
+++ b/compiler/driver/dex_compilation_unit.h
@@ -80,6 +80,10 @@
return access_flags_;
}
+ bool IsConstructor() const {
+ return ((access_flags_ & kAccConstructor) != 0);
+ }
+
bool IsNative() const {
return ((access_flags_ & kAccNative) != 0);
}
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index cbdc430..aaff0fc 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -313,7 +313,6 @@
method_ids_ = reinterpret_cast<const MethodId*>(b + h->method_ids_off_);
proto_ids_ = reinterpret_cast<const ProtoId*>(b + h->proto_ids_off_);
class_defs_ = reinterpret_cast<const ClassDef*>(b + h->class_defs_off_);
- DCHECK_EQ(size_, header_->file_size_) << GetLocation();
}
bool DexFile::CheckMagicAndVersion() const {
diff --git a/runtime/stack.cc b/runtime/stack.cc
index aeb15f0..a74bcdb 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -266,7 +266,11 @@
// Frame sanity.
size_t frame_size = method->GetFrameSizeInBytes();
CHECK_NE(frame_size, 0u);
- CHECK_LT(frame_size, 1024u);
+ // A rough guess at an upper size we expect to see for a frame. The 256 is
+ // a dex register limit. The 16 incorporates callee save spills and
+ // outgoing argument set up.
+ const size_t kMaxExpectedFrameSize = 256 * sizeof(word) + 16;
+ CHECK_LE(frame_size, kMaxExpectedFrameSize);
size_t return_pc_offset = method->GetReturnPcOffsetInBytes();
CHECK_LT(return_pc_offset, frame_size);
}
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 9f0d911..95fda9d 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2507,8 +2507,8 @@
// Special instructions.
case Instruction::RETURN_VOID_BARRIER:
- DCHECK(Runtime::Current()->IsStarted());
- if (!IsConstructor()) {
+ DCHECK(Runtime::Current()->IsStarted()) << PrettyMethod(dex_method_idx_, *dex_file_);
+ if (!IsConstructor() || IsStatic()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "return-void-barrier not expected";
}
break;
@@ -2819,8 +2819,10 @@
dex_cache_->SetResolvedType(class_idx, result.GetClass());
}
// Check if access is allowed. Unresolved types use xxxWithAccessCheck to
- // check at runtime if access is allowed and so pass here.
- if (!result.IsUnresolvedTypes() && !referrer.IsUnresolvedTypes() && !referrer.CanAccess(result)) {
+ // check at runtime if access is allowed and so pass here. If result is
+ // primitive, skip the access check.
+ if (result.IsNonZeroReferenceTypes() && !result.IsUnresolvedTypes() &&
+ !referrer.IsUnresolvedTypes() && !referrer.CanAccess(result)) {
Fail(VERIFY_ERROR_ACCESS_CLASS) << "illegal class access: '"
<< referrer << "' -> '" << result << "'";
}
@@ -3297,6 +3299,43 @@
}
}
+void MethodVerifier::VerifyPrimitivePut(const RegType& target_type, const RegType& insn_type,
+ const uint32_t vregA) {
+ // Primitive assignability rules are weaker than regular assignability rules.
+ bool instruction_compatible;
+ bool value_compatible;
+ const RegType& value_type = work_line_->GetRegisterType(vregA);
+ if (target_type.IsIntegralTypes()) {
+ instruction_compatible = insn_type.IsIntegralTypes();
+ value_compatible = value_type.IsIntegralTypes();
+ } else if (target_type.IsFloat()) {
+ instruction_compatible = insn_type.IsInteger(); // no put-float, so expect put-int
+ value_compatible = value_type.IsFloatTypes();
+ } else if (target_type.IsLong()) {
+ instruction_compatible = insn_type.IsLong();
+ value_compatible = value_type.IsLongTypes();
+ } else if (target_type.IsDouble()) {
+ instruction_compatible = insn_type.IsLong(); // no put-double, so expect put-long
+ value_compatible = value_type.IsDoubleTypes();
+ } else {
+ instruction_compatible = false; // reference with primitive store
+ value_compatible = false; // unused
+ }
+ if (!instruction_compatible) {
+ // This is a global failure rather than a class change failure as the instructions and
+ // the descriptors for the type should have been consistent within the same file at
+ // compile time.
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "put insn has type '" << insn_type
+ << "' but expected type '" << target_type << "'";
+ return;
+ }
+ if (!value_compatible) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
+ << " of type " << value_type << " but expected " << target_type << " for put";
+ return;
+ }
+}
+
void MethodVerifier::VerifyAPut(const Instruction* inst,
const RegType& insn_type, bool is_primitive) {
const RegType& index_type = work_line_->GetRegisterType(inst->VRegC_23x());
@@ -3310,25 +3349,20 @@
} else if (!array_type.IsArrayTypes()) {
Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "not array type " << array_type << " with aput";
} else {
- /* verify the class */
const RegType& component_type = reg_types_.GetComponentType(array_type, class_loader_);
- if (!component_type.IsReferenceTypes() && !is_primitive) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "primitive array type " << array_type
- << " source for aput-object";
- } else if (component_type.IsNonZeroReferenceTypes() && is_primitive) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "reference array type " << array_type
- << " source for category 1 aput";
- } else if (is_primitive && !insn_type.Equals(component_type) &&
- !((insn_type.IsInteger() && component_type.IsFloat()) ||
- (insn_type.IsLong() && component_type.IsDouble()))) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array type " << array_type
- << " incompatible with aput of type " << insn_type;
+ const uint32_t vregA = inst->VRegA_23x();
+ if (is_primitive) {
+ VerifyPrimitivePut(component_type, insn_type, vregA);
} else {
- // The instruction agrees with the type of array, confirm the value to be stored does too
- // Note: we use the instruction type (rather than the component type) for aput-object as
- // incompatible classes will be caught at runtime as an array store exception
- work_line_->VerifyRegisterType(inst->VRegA_23x(),
- is_primitive ? component_type : insn_type);
+ if (!component_type.IsReferenceTypes()) {
+ Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "primitive array type " << array_type
+ << " source for aput-object";
+ } else {
+ // The instruction agrees with the type of array, confirm the value to be stored does too
+ // Note: we use the instruction type (rather than the component type) for aput-object as
+ // incompatible classes will be caught at runtime as an array store exception
+ work_line_->VerifyRegisterType(vregA, insn_type);
+ }
}
}
}
@@ -3518,43 +3552,7 @@
}
const uint32_t vregA = (is_static) ? inst->VRegA_21c() : inst->VRegA_22c();
if (is_primitive) {
- // Primitive field assignability rules are weaker than regular assignability rules
- bool instruction_compatible;
- bool value_compatible;
- const RegType& value_type = work_line_->GetRegisterType(vregA);
- if (field_type.IsIntegralTypes()) {
- instruction_compatible = insn_type.IsIntegralTypes();
- value_compatible = value_type.IsIntegralTypes();
- } else if (field_type.IsFloat()) {
- instruction_compatible = insn_type.IsInteger(); // no [is]put-float, so expect [is]put-int
- value_compatible = value_type.IsFloatTypes();
- } else if (field_type.IsLong()) {
- instruction_compatible = insn_type.IsLong();
- value_compatible = value_type.IsLongTypes();
- } else if (field_type.IsDouble()) {
- instruction_compatible = insn_type.IsLong(); // no [is]put-double, so expect [is]put-long
- value_compatible = value_type.IsDoubleTypes();
- } else {
- instruction_compatible = false; // reference field with primitive store
- value_compatible = false; // unused
- }
- if (!instruction_compatible) {
- // This is a global failure rather than a class change failure as the instructions and
- // the descriptors for the type should have been consistent within the same file at
- // compile time
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected field " << PrettyField(field)
- << " to be of type '" << insn_type
- << "' but found type '" << field_type
- << "' in put";
- return;
- }
- if (!value_compatible) {
- Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unexpected value in v" << vregA
- << " of type " << value_type
- << " but expected " << field_type
- << " for store to " << PrettyField(field) << " in put";
- return;
- }
+ VerifyPrimitivePut(field_type, insn_type, vregA);
} else {
if (!insn_type.IsAssignableFrom(field_type)) {
Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "expected field " << PrettyField(field)
@@ -3756,6 +3754,10 @@
if (!insn_flags_[next_insn].IsReturn()) {
target_line->CopyFromLine(merge_line);
} else {
+ // Verify that the monitor stack is empty on return.
+ if (!merge_line->VerifyMonitorStackEmpty()) {
+ return false;
+ }
// For returns we only care about the operand to the return, all other registers are dead.
// Initialize them as conflicts so they don't add to GC and deoptimization information.
const Instruction* ret_inst = Instruction::At(code_item_->insns_ + next_insn);
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index 3f98a00..ed64307 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -476,6 +476,10 @@
void VerifyNewArray(const Instruction* inst, bool is_filled, bool is_range)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // Helper to perform verification on puts of primitive type.
+ void VerifyPrimitivePut(const RegType& target_type, const RegType& insn_type,
+ const uint32_t vregA) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Perform verification of an aget instruction. The destination register's type will be set to
// be that of component type of the array unless the array type is unknown, in which case a
// bottom type inferred from the type of instruction is used. is_primitive is false for an
diff --git a/runtime/verifier/register_line.cc b/runtime/verifier/register_line.cc
index 7965c06..24a626b 100644
--- a/runtime/verifier/register_line.cc
+++ b/runtime/verifier/register_line.cc
@@ -38,7 +38,7 @@
bool RegisterLine::SetRegisterType(uint32_t vdst, const RegType& new_type) {
DCHECK_LT(vdst, num_regs_);
if (new_type.IsLowHalf() || new_type.IsHighHalf()) {
- verifier_->Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "Expected category1 register type not '"
+ verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Expected category1 register type not '"
<< new_type << "'";
return false;
} else if (new_type.IsConflict()) { // should only be set during a merge
@@ -448,7 +448,7 @@
}
}
-bool RegisterLine::VerifyMonitorStackEmpty() {
+bool RegisterLine::VerifyMonitorStackEmpty() const {
if (MonitorStackDepth() != 0) {
verifier_->Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "expected empty monitor stack";
return false;
diff --git a/runtime/verifier/register_line.h b/runtime/verifier/register_line.h
index f380877..f19dcca 100644
--- a/runtime/verifier/register_line.h
+++ b/runtime/verifier/register_line.h
@@ -268,7 +268,7 @@
// We expect no monitors to be held at certain points, such a method returns. Verify the stack
// is empty, failing and returning false if not.
- bool VerifyMonitorStackEmpty();
+ bool VerifyMonitorStackEmpty() const;
bool MergeRegisters(const RegisterLine* incoming_line)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);