summaryrefslogtreecommitdiffstats
path: root/runtime/interpreter/interpreter_common.h
diff options
context:
space:
mode:
authorSebastien Hertz <shertz@google.com>2014-01-15 10:20:56 +0100
committerSebastien Hertz <shertz@google.com>2014-02-17 11:32:15 +0100
commitd2fe10a3a34af171bf1631219cd2d6ff6b7778b5 (patch)
treeb6b7eb8eba23a5c2723518da99c03bf47b97f58a /runtime/interpreter/interpreter_common.h
parent5a3f55ad9519e87c0d3bbddaf3d8a186a887a79b (diff)
downloadart-d2fe10a3a34af171bf1631219cd2d6ff6b7778b5.zip
art-d2fe10a3a34af171bf1631219cd2d6ff6b7778b5.tar.gz
art-d2fe10a3a34af171bf1631219cd2d6ff6b7778b5.tar.bz2
Remove blacklist
Removes the class initialization blacklist and use transaction to detect and revert class initialization attempting to invoke native method. This only concerns class initialization happening at compilation time when generating an image (like boot.art for the system). In transactional mode, we log every object's field assignment and array update. Therefore we're able to abort a transaction to restore values of fields and array as they were before the transaction starts. We also log changes to the intern string table so we can restore its state prior to transaction start. Since transactional mode only happens at compilation time, we don't need to log all these changes at runtime. In order to reduce the overhead of testing if transactional mode is on/off, we templatize interfaces of mirror::Object and mirror::Array, respectively responsible for setting a field and setting an array element. For various reasons, we skip some specific fields from transaction: - Object's class and array's length must remain unchanged so garbage collector can compute object's size. - Immutable fields only set during class loading: list of fields, method, dex caches, vtables, ... as all classes have been loaded and verified before a transaction occurs. - Object's monitor for performance reason. Before generating the image, we browse the heap to collect objects that need to be written into it. Since the heap may still holds references to unreachable objects due to aborted transactions, we trigger one collection at the end of the class preinitialization phase. Since the transaction is held by the runtime and all compilation threads share the same runtime, we need to ensure only one compilation thread has exclusive access to the runtime. To workaround this issue, we force class initialization phase to run with only one thread. Note this is only done when generating image so application compilation is not impacted. This issue will be addressed in a separate CL. Bug: 9676614 Change-Id: I221910a9183a5ba6c2b99a277f5a5a68bc69b5f9
Diffstat (limited to 'runtime/interpreter/interpreter_common.h')
-rw-r--r--runtime/interpreter/interpreter_common.h69
1 files changed, 41 insertions, 28 deletions
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 768ca33..a03e420 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -65,12 +65,12 @@ namespace interpreter {
// External references to both interpreter implementations.
-template<bool do_access_check>
+template<bool do_access_check, bool transaction_active>
extern JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh,
const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
-template<bool do_access_check>
+template<bool do_access_check, bool transaction_active>
extern JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh,
const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register);
@@ -83,6 +83,9 @@ static inline void DoMonitorExit(Thread* self, Object* ref) NO_THREAD_SAFETY_ANA
ref->MonitorExit(self);
}
+void RecordArrayElementsInTransaction(mirror::Array* array, int32_t count)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Invokes the given method. This is part of the invocation support and is used by DoInvoke and
// DoInvokeVirtualQuick functions.
// Returns true on success, otherwise throws an exception and returns false.
@@ -228,7 +231,7 @@ static inline bool DoIGetQuick(ShadowFrame& shadow_frame, const Instruction* ins
// Handles iput-XXX and sput-XXX instructions.
// Returns true on success, otherwise throws an exception and returns false.
-template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check>
+template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check, bool transaction_active>
static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
const Instruction* inst, uint16_t inst_data) {
bool do_assignability_check = do_access_check;
@@ -254,22 +257,22 @@ static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
switch (field_type) {
case Primitive::kPrimBoolean:
- f->SetBoolean(obj, shadow_frame.GetVReg(vregA));
+ f->SetBoolean<transaction_active>(obj, shadow_frame.GetVReg(vregA));
break;
case Primitive::kPrimByte:
- f->SetByte(obj, shadow_frame.GetVReg(vregA));
+ f->SetByte<transaction_active>(obj, shadow_frame.GetVReg(vregA));
break;
case Primitive::kPrimChar:
- f->SetChar(obj, shadow_frame.GetVReg(vregA));
+ f->SetChar<transaction_active>(obj, shadow_frame.GetVReg(vregA));
break;
case Primitive::kPrimShort:
- f->SetShort(obj, shadow_frame.GetVReg(vregA));
+ f->SetShort<transaction_active>(obj, shadow_frame.GetVReg(vregA));
break;
case Primitive::kPrimInt:
- f->SetInt(obj, shadow_frame.GetVReg(vregA));
+ f->SetInt<transaction_active>(obj, shadow_frame.GetVReg(vregA));
break;
case Primitive::kPrimLong:
- f->SetLong(obj, shadow_frame.GetVRegLong(vregA));
+ f->SetLong<transaction_active>(obj, shadow_frame.GetVRegLong(vregA));
break;
case Primitive::kPrimNot: {
Object* reg = shadow_frame.GetVRegReference(vregA);
@@ -286,7 +289,7 @@ static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
return false;
}
}
- f->SetObj(obj, reg);
+ f->SetObj<transaction_active>(obj, reg);
break;
}
default:
@@ -297,7 +300,7 @@ static inline bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame,
// Handles iput-quick, iput-wide-quick and iput-object-quick instructions.
// Returns true on success, otherwise throws an exception and returns false.
-template<Primitive::Type field_type>
+template<Primitive::Type field_type, bool transaction_active>
static inline bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instruction* inst, uint16_t inst_data) {
Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
if (UNLIKELY(obj == nullptr)) {
@@ -311,13 +314,15 @@ static inline bool DoIPutQuick(const ShadowFrame& shadow_frame, const Instructio
const uint32_t vregA = inst->VRegA_22c(inst_data);
switch (field_type) {
case Primitive::kPrimInt:
- obj->SetField32(field_offset, shadow_frame.GetVReg(vregA), is_volatile);
+ obj->SetField32<transaction_active>(field_offset, shadow_frame.GetVReg(vregA), is_volatile);
break;
case Primitive::kPrimLong:
- obj->SetField64(field_offset, shadow_frame.GetVRegLong(vregA), is_volatile);
+ obj->SetField64<transaction_active>(field_offset, shadow_frame.GetVRegLong(vregA),
+ is_volatile);
break;
case Primitive::kPrimNot:
- obj->SetFieldObject(field_offset, shadow_frame.GetVRegReference(vregA), is_volatile);
+ obj->SetFieldObject<transaction_active>(field_offset, shadow_frame.GetVRegReference(vregA),
+ is_volatile);
break;
default:
LOG(FATAL) << "Unreachable: " << field_type;
@@ -416,7 +421,7 @@ static inline bool DoLongRemainder(ShadowFrame& shadow_frame, size_t result_reg,
// Handles filled-new-array and filled-new-array-range instructions.
// Returns true on success, otherwise throws an exception and returns false.
-template <bool is_range, bool do_access_check>
+template <bool is_range, bool do_access_check, bool transaction_active>
bool DoFilledNewArray(const Instruction* inst, const ShadowFrame& shadow_frame,
Thread* self, JValue* result);
@@ -604,14 +609,16 @@ EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(StaticObjectRead, Primitive::kPrimNot);
#undef EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL
// Explicitly instantiate all DoFieldPut functions.
-#define EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, _do_check) \
+#define EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, _do_check, _transaction_active) \
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
- bool DoFieldPut<_find_type, _field_type, _do_check>(Thread* self, const ShadowFrame& shadow_frame, \
- const Instruction* inst, uint16_t inst_data)
+ bool DoFieldPut<_find_type, _field_type, _do_check, _transaction_active>(Thread* self, const ShadowFrame& shadow_frame, \
+ const Instruction* inst, uint16_t inst_data)
#define EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(_find_type, _field_type) \
- EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false); \
- EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, true);
+ EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false, false); \
+ EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, true, false); \
+ EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false, true); \
+ EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, true, true);
// iput-XXX
EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(InstancePrimitiveWrite, Primitive::kPrimBoolean);
@@ -657,14 +664,20 @@ EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimNot); // iget-object-qui
#undef EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL
// Explicitly instantiate all DoIPutQuick functions.
-#define EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type) \
- template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
- bool DoIPutQuick<_field_type>(const ShadowFrame& shadow_frame, const Instruction* inst, \
- uint16_t inst_data)
-
-EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(Primitive::kPrimInt); // iget-quick.
-EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(Primitive::kPrimLong); // iget-wide-quick.
-EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(Primitive::kPrimNot); // iget-object-quick.
+#define EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, _transaction_active) \
+ template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
+ bool DoIPutQuick<_field_type, _transaction_active>(const ShadowFrame& shadow_frame, \
+ const Instruction* inst, \
+ uint16_t inst_data)
+
+#define EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(_field_type) \
+ EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, false); \
+ EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type, true);
+
+EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimInt); // iget-quick.
+EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimLong); // iget-wide-quick.
+EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL(Primitive::kPrimNot); // iget-object-quick.
+#undef EXPLICIT_DO_IPUT_QUICK_ALL_TEMPLATE_DECL
#undef EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL
} // namespace interpreter