Merge "GenSpecialCase support for x86"
diff --git a/Android.mk b/Android.mk
index 62d40bb..6ad5606 100644
--- a/Android.mk
+++ b/Android.mk
@@ -143,7 +143,7 @@
@echo test-art-host-interpreter PASSED
.PHONY: test-art-host-dependencies
-test-art-host-dependencies: $(ART_HOST_TEST_DEPENDENCIES) $(HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) $(HOST_CORE_DEX_LOCATIONS)
+test-art-host-dependencies: $(ART_HOST_TEST_DEPENDENCIES) $(HOST_OUT_SHARED_LIBRARIES)/libarttest$(ART_HOST_SHLIB_EXTENSION) $(HOST_CORE_DEX_LOCATIONS) $(HOST_OUT_EXECUTABLES)/jasmin
.PHONY: test-art-host-gtest
test-art-host-gtest: $(ART_HOST_TEST_TARGETS)
@@ -209,7 +209,7 @@
@echo test-art-target PASSED
.PHONY: test-art-target-dependencies
-test-art-target-dependencies: $(ART_TARGET_TEST_DEPENDENCIES) $(ART_TEST_OUT)/libarttest.so
+test-art-target-dependencies: $(ART_TARGET_TEST_DEPENDENCIES) $(ART_TEST_OUT)/libarttest.so $(HOST_OUT_EXECUTABLES)/jasmin
.PHONY: test-art-target-sync
test-art-target-sync: test-art-target-dependencies
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index acaa0f8..66a16b6 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -59,6 +59,7 @@
runtime/reference_table_test.cc \
runtime/runtime_test.cc \
runtime/thread_pool_test.cc \
+ runtime/transaction_test.cc \
runtime/utils_test.cc \
runtime/verifier/method_verifier_test.cc \
runtime/verifier/reg_type_test.cc \
diff --git a/compiler/Android.mk b/compiler/Android.mk
index c6662c2..27bc3a3 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -90,6 +90,7 @@
utils/x86/assembler_x86.cc \
utils/x86/managed_register_x86.cc \
buffered_output_stream.cc \
+ compiler_backend.cc \
elf_fixup.cc \
elf_stripper.cc \
elf_writer.cc \
diff --git a/compiler/compiler_backend.cc b/compiler/compiler_backend.cc
new file mode 100644
index 0000000..b8f21a9
--- /dev/null
+++ b/compiler/compiler_backend.cc
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "compiler_backend.h"
+#include "elf_writer_quick.h"
+#include "dex/quick/mir_to_lir.h"
+#include "dex/mir_graph.h"
+#include "driver/compiler_driver.h"
+#include "mirror/art_method-inl.h"
+
+#ifdef ART_USE_PORTABLE_COMPILER
+#include "dex/portable/mir_to_gbc.h"
+#include "elf_writer_mclinker.h"
+#endif
+
+namespace art {
+
+#ifdef ART_SEA_IR_MODE
+extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& compiler,
+ const art::DexFile::CodeItem* code_item,
+ uint32_t access_flags,
+ art::InvokeType invoke_type,
+ uint16_t class_def_idx,
+ uint32_t method_idx,
+ jobject class_loader,
+ const art::DexFile& dex_file);
+#endif
+
+extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& driver);
+extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& driver);
+extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver& compiler,
+ const art::DexFile::CodeItem* code_item,
+ uint32_t access_flags,
+ art::InvokeType invoke_type,
+ uint16_t class_def_idx,
+ uint32_t method_idx,
+ jobject class_loader,
+ const art::DexFile& dex_file);
+
+extern "C" art::CompiledMethod* ArtQuickJniCompileMethod(art::CompilerDriver& compiler,
+ uint32_t access_flags, uint32_t method_idx,
+ const art::DexFile& dex_file);
+
+
+static CompiledMethod* TryCompileWithSeaIR(art::CompilerDriver& compiler,
+ const art::DexFile::CodeItem* code_item,
+ uint32_t access_flags,
+ art::InvokeType invoke_type,
+ uint16_t class_def_idx,
+ uint32_t method_idx,
+ jobject class_loader,
+ const art::DexFile& dex_file) {
+#ifdef ART_SEA_IR_MODE
+ bool use_sea = Runtime::Current()->IsSeaIRMode();
+ use_sea = use_sea &&
+ (std::string::npos != PrettyMethod(method_idx, dex_file).find("fibonacci"));
+ if (use_sea) {
+ LOG(INFO) << "Using SEA IR to compile..." << std::endl;
+ return SeaIrCompileMethod(compiler,
+ code_item,
+ access_flags,
+ invoke_type,
+ class_def_idx,
+ method_idx,
+ class_loader,
+ dex_file);
+ }
+#endif
+ return nullptr;
+}
+
+
+class QuickBackend : public CompilerBackend {
+ public:
+ QuickBackend() : CompilerBackend(100) {}
+
+ void Init(CompilerDriver& driver) const {
+ ArtInitQuickCompilerContext(driver);
+ }
+
+ void UnInit(CompilerDriver& driver) const {
+ ArtUnInitQuickCompilerContext(driver);
+ }
+
+ CompiledMethod* Compile(CompilerDriver& compiler,
+ const DexFile::CodeItem* code_item,
+ uint32_t access_flags,
+ InvokeType invoke_type,
+ uint16_t class_def_idx,
+ uint32_t method_idx,
+ jobject class_loader,
+ const DexFile& dex_file) const {
+ CompiledMethod* method = TryCompileWithSeaIR(compiler,
+ code_item,
+ access_flags,
+ invoke_type,
+ class_def_idx,
+ method_idx,
+ class_loader,
+ dex_file);
+ if (method != nullptr) return method;
+
+ return ArtQuickCompileMethod(compiler,
+ code_item,
+ access_flags,
+ invoke_type,
+ class_def_idx,
+ method_idx,
+ class_loader,
+ dex_file);
+ }
+
+ CompiledMethod* JniCompile(CompilerDriver& driver,
+ uint32_t access_flags,
+ uint32_t method_idx,
+ const DexFile& dex_file) const {
+ return ArtQuickJniCompileMethod(driver, access_flags, method_idx, dex_file);
+ }
+
+ uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const {
+ return reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode());
+ }
+
+ bool WriteElf(art::File* file,
+ OatWriter& oat_writer,
+ const std::vector<const art::DexFile*>& dex_files,
+ const std::string& android_root,
+ bool is_host, const CompilerDriver& driver) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host, driver);
+ }
+
+ Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
+ Mir2Lir* mir_to_lir = nullptr;
+ switch (cu->instruction_set) {
+ case kThumb2:
+ mir_to_lir = ArmCodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
+ break;
+ case kMips:
+ mir_to_lir = MipsCodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
+ break;
+ case kX86:
+ mir_to_lir = X86CodeGenerator(cu, cu->mir_graph.get(), &cu->arena);
+ break;
+ default:
+ LOG(FATAL) << "Unexpected instruction set: " << cu->instruction_set;
+ }
+
+ /* The number of compiler temporaries depends on backend so set it up now if possible */
+ if (mir_to_lir) {
+ size_t max_temps = mir_to_lir->GetMaxPossibleCompilerTemps();
+ bool set_max = cu->mir_graph->SetMaxAvailableNonSpecialCompilerTemps(max_temps);
+ CHECK(set_max);
+ }
+ return mir_to_lir;;
+ }
+
+ void InitCompilationUnit(CompilationUnit& cu) const {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(QuickBackend);
+};
+
+#ifdef ART_USE_PORTABLE_COMPILER
+
+extern "C" void ArtInitCompilerContext(art::CompilerDriver& driver);
+extern "C" void ArtUnInitCompilerContext(art::CompilerDriver& driver);
+extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver,
+ const art::DexFile::CodeItem* code_item,
+ uint32_t access_flags,
+ art::InvokeType invoke_type,
+ uint16_t class_def_idx,
+ uint32_t method_idx,
+ jobject class_loader,
+ const art::DexFile& dex_file);
+extern "C" art::CompiledMethod* ArtLLVMJniCompileMethod(art::CompilerDriver& driver,
+ uint32_t access_flags, uint32_t method_idx,
+ const art::DexFile& dex_file);
+
+
+class LLVMBackend : public CompilerBackend {
+ public:
+ LLVMBackend() : CompilerBackend(1000) {}
+
+ void Init(CompilerDriver& driver) const {
+ ArtInitCompilerContext(driver);
+ }
+
+ void UnInit(CompilerDriver& driver) const {
+ ArtUnInitCompilerContext(driver);
+ }
+
+ CompiledMethod* Compile(CompilerDriver& compiler,
+ const DexFile::CodeItem* code_item,
+ uint32_t access_flags,
+ InvokeType invoke_type,
+ uint16_t class_def_idx,
+ uint32_t method_idx,
+ jobject class_loader,
+ const DexFile& dex_file) const {
+ CompiledMethod* method = TryCompileWithSeaIR(compiler,
+ code_item,
+ access_flags,
+ invoke_type,
+ class_def_idx,
+ method_idx,
+ class_loader,
+ dex_file);
+ if (method != nullptr) return method;
+
+ return ArtCompileMethod(compiler,
+ code_item,
+ access_flags,
+ invoke_type,
+ class_def_idx,
+ method_idx,
+ class_loader,
+ dex_file);
+ }
+
+ CompiledMethod* JniCompile(CompilerDriver& driver,
+ uint32_t access_flags,
+ uint32_t method_idx,
+ const DexFile& dex_file) const {
+ return ArtLLVMJniCompileMethod(driver, access_flags, method_idx, dex_file);
+ }
+
+ uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const {
+ return reinterpret_cast<uintptr_t>(method->GetEntryPointFromPortableCompiledCode());
+ }
+
+ bool WriteElf(art::File* file,
+ OatWriter& oat_writer,
+ const std::vector<const art::DexFile*>& dex_files,
+ const std::string& android_root,
+ bool is_host, const CompilerDriver& driver) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ return art::ElfWriterMclinker::Create(
+ file, oat_writer, dex_files, android_root, is_host, driver);
+ }
+
+ Backend* GetCodeGenerator(CompilationUnit* cu, void* compilation_unit) const {
+ return PortableCodeGenerator(
+ cu, cu->mir_graph.get(), &cu->arena,
+ reinterpret_cast<art::llvm::LlvmCompilationUnit*>(compilation_unit));
+ }
+
+ void InitCompilationUnit(CompilationUnit& cu) const {
+ // Fused long branches not currently useful in bitcode.
+ cu.disable_opt |=
+ (1 << kBranchFusing) |
+ (1 << kSuppressExceptionEdges);
+ }
+
+ bool isPortable() const { return true; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LLVMBackend);
+};
+#endif
+
+CompilerBackend* CompilerBackend::Create(CompilerBackend::Kind kind) {
+ switch (kind) {
+ case kQuick:
+ return new QuickBackend();
+ break;
+ case kPortable:
+#ifdef ART_USE_PORTABLE_COMPILER
+ return new LLVMBackend();
+#else
+ LOG(FATAL) << "Portable compiler not compiled";
+#endif
+ break;
+ default:
+ LOG(FATAL) << "UNREACHABLE";
+ }
+ return nullptr;
+}
+
+} // namespace art
diff --git a/compiler/compiler_backend.h b/compiler/compiler_backend.h
new file mode 100644
index 0000000..b20c125
--- /dev/null
+++ b/compiler/compiler_backend.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2014 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_COMPILER_COMPILER_BACKEND_H_
+#define ART_COMPILER_COMPILER_BACKEND_H_
+
+#include "dex_file.h"
+#include "os.h"
+
+namespace art {
+
+class Backend;
+class CompilationUnit;
+class CompilerDriver;
+class CompiledMethod;
+class MIRGraph;
+class OatWriter;
+
+namespace mirror {
+ class ArtMethod;
+}
+
+class CompilerBackend {
+ public:
+ enum Kind {
+ kQuick,
+ kPortable
+ };
+
+ explicit CompilerBackend(int warning)
+ : maximum_compilation_time_before_warning_(warning) {}
+
+ static CompilerBackend* Create(Kind kind);
+
+ virtual void Init(CompilerDriver& driver) const = 0;
+
+ virtual void UnInit(CompilerDriver& driver) const = 0;
+
+ virtual CompiledMethod* Compile(CompilerDriver& compiler,
+ const DexFile::CodeItem* code_item,
+ uint32_t access_flags,
+ InvokeType invoke_type,
+ uint16_t class_def_idx,
+ uint32_t method_idx,
+ jobject class_loader,
+ const DexFile& dex_file) const = 0;
+
+ virtual CompiledMethod* JniCompile(CompilerDriver& driver,
+ uint32_t access_flags,
+ uint32_t method_idx,
+ const DexFile& dex_file) const = 0;
+
+ virtual uintptr_t GetEntryPointOf(mirror::ArtMethod* method) const = 0;
+
+ virtual bool WriteElf(art::File* file,
+ OatWriter& oat_writer,
+ const std::vector<const art::DexFile*>& dex_files,
+ const std::string& android_root,
+ bool is_host, const CompilerDriver& driver) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) = 0;
+
+ virtual Backend* GetCodeGenerator(CompilationUnit* cu,
+ void* compilation_unit) const = 0;
+
+ uint64_t GetMaximumCompilationTimeBeforeWarning() const {
+ return maximum_compilation_time_before_warning_;
+ }
+
+ virtual bool IsPortable() const { return false; }
+
+ virtual void InitCompilationUnit(CompilationUnit& cu) const = 0;
+
+ virtual ~CompilerBackend() {}
+
+ private:
+ uint64_t maximum_compilation_time_before_warning_;
+
+ DISALLOW_COPY_AND_ASSIGN(CompilerBackend);
+};
+
+} // namespace art
+
+#endif // ART_COMPILER_COMPILER_BACKEND_H_
diff --git a/compiler/dex/compiler_ir.h b/compiler/dex/compiler_ir.h
index 32fd79b..ea8eb1c 100644
--- a/compiler/dex/compiler_ir.h
+++ b/compiler/dex/compiler_ir.h
@@ -68,7 +68,7 @@
uint32_t disable_opt; // opt_control_vector flags.
uint32_t enable_debug; // debugControlVector flags.
bool verbose;
- CompilerBackend compiler_backend;
+ const CompilerBackend* compiler_backend;
InstructionSet instruction_set;
const InstructionSetFeatures& GetInstructionSetFeatures() {
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 8f83cd0..591d92a 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#include <llvm/Support/Threading.h>
-
+#include "compiler_backend.h"
#include "compiler_internals.h"
#include "driver/compiler_driver.h"
#include "dataflow_iterator-inl.h"
@@ -27,42 +26,9 @@
#include "base/logging.h"
#include "base/timing_logger.h"
-#if defined(ART_USE_PORTABLE_COMPILER)
-#include "dex/portable/mir_to_gbc.h"
-#include "llvm/llvm_compilation_unit.h"
-#endif
-
#include "dex/quick/dex_file_to_method_inliner_map.h"
-namespace {
-#if !defined(ART_USE_PORTABLE_COMPILER)
- pthread_once_t llvm_multi_init = PTHREAD_ONCE_INIT;
-#endif
- void InitializeLLVMForQuick() {
- ::llvm::llvm_start_multithreaded();
- }
-}
-
namespace art {
-namespace llvm {
-::llvm::Module* makeLLVMModuleContents(::llvm::Module* module);
-}
-
-LLVMInfo::LLVMInfo() {
-#if !defined(ART_USE_PORTABLE_COMPILER)
- pthread_once(&llvm_multi_init, InitializeLLVMForQuick);
-#endif
- // Create context, module, intrinsic helper & ir builder
- llvm_context_.reset(new ::llvm::LLVMContext());
- llvm_module_ = new ::llvm::Module("art", *llvm_context_);
- ::llvm::StructType::create(*llvm_context_, "JavaObject");
- art::llvm::makeLLVMModuleContents(llvm_module_);
- intrinsic_helper_.reset(new art::llvm::IntrinsicHelper(*llvm_context_, *llvm_module_));
- ir_builder_.reset(new art::llvm::IRBuilder(*llvm_context_, *llvm_module_, *intrinsic_helper_));
-}
-
-LLVMInfo::~LLVMInfo() {
-}
extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& driver) {
CHECK(driver.GetCompilerContext() == NULL);
@@ -123,7 +89,7 @@
disable_opt(0),
enable_debug(0),
verbose(false),
- compiler_backend(kNoBackend),
+ compiler_backend(NULL),
instruction_set(kNone),
num_dalvik_registers(0),
insns(NULL),
@@ -163,15 +129,12 @@
}
static CompiledMethod* CompileMethod(CompilerDriver& compiler,
- const CompilerBackend compiler_backend,
+ CompilerBackend* compiler_backend,
const DexFile::CodeItem* code_item,
uint32_t access_flags, InvokeType invoke_type,
uint16_t class_def_idx, uint32_t method_idx,
- jobject class_loader, const DexFile& dex_file
-#if defined(ART_USE_PORTABLE_COMPILER)
- , llvm::LlvmCompilationUnit* llvm_compilation_unit
-#endif
-) {
+ jobject class_loader, const DexFile& dex_file,
+ void* llvm_compilation_unit) {
VLOG(compiler) << "Compiling " << PrettyMethod(method_idx, dex_file) << "...";
if (code_item->insns_size_in_code_units_ >= 0x10000) {
LOG(INFO) << "Method size exceeds compiler limits: " << code_item->insns_size_in_code_units_
@@ -211,12 +174,7 @@
* MIR and backend flags? Need command-line setting as well.
*/
- if (compiler_backend == kPortable) {
- // Fused long branches not currently useful in bitcode.
- cu.disable_opt |=
- (1 << kBranchFusing) |
- (1 << kSuppressExceptionEdges);
- }
+ compiler_backend->InitCompilationUnit(cu);
if (cu.instruction_set == kMips) {
// Disable some optimizations for mips for now
@@ -241,37 +199,7 @@
* The reason we do this is that optimizations on the MIR graph may need to get information
* that is only available if a CG exists.
*/
-#if defined(ART_USE_PORTABLE_COMPILER)
- if (compiler_backend == kPortable) {
- cu.cg.reset(PortableCodeGenerator(&cu, cu.mir_graph.get(), &cu.arena, llvm_compilation_unit));
- } else {
-#endif
- Mir2Lir* mir_to_lir = nullptr;
- switch (compiler.GetInstructionSet()) {
- case kThumb2:
- mir_to_lir = ArmCodeGenerator(&cu, cu.mir_graph.get(), &cu.arena);
- break;
- case kMips:
- mir_to_lir = MipsCodeGenerator(&cu, cu.mir_graph.get(), &cu.arena);
- break;
- case kX86:
- mir_to_lir = X86CodeGenerator(&cu, cu.mir_graph.get(), &cu.arena);
- break;
- default:
- LOG(FATAL) << "Unexpected instruction set: " << compiler.GetInstructionSet();
- }
-
- cu.cg.reset(mir_to_lir);
-
- /* The number of compiler temporaries depends on backend so set it up now if possible */
- if (mir_to_lir) {
- size_t max_temps = mir_to_lir->GetMaxPossibleCompilerTemps();
- bool set_max = cu.mir_graph->SetMaxAvailableNonSpecialCompilerTemps(max_temps);
- CHECK(set_max);
- }
-#if defined(ART_USE_PORTABLE_COMPILER)
- }
-#endif
+ cu.cg.reset(compiler_backend->GetCodeGenerator(&cu, llvm_compilation_unit));
/* Gathering opcode stats? */
if (kCompilerDebugFlags & (1 << kDebugCountOpcodes)) {
@@ -283,11 +211,9 @@
class_loader, dex_file);
cu.NewTimingSplit("MIROpt:CheckFilters");
-#if !defined(ART_USE_PORTABLE_COMPILER)
if (cu.mir_graph->SkipCompilation(Runtime::Current()->GetCompilerFilter())) {
return NULL;
}
-#endif
/* Create the pass driver and launch it */
PassDriver driver(&cu);
@@ -338,7 +264,7 @@
}
CompiledMethod* CompileOneMethod(CompilerDriver& compiler,
- const CompilerBackend backend,
+ CompilerBackend* backend,
const DexFile::CodeItem* code_item,
uint32_t access_flags,
InvokeType invoke_type,
@@ -346,13 +272,9 @@
uint32_t method_idx,
jobject class_loader,
const DexFile& dex_file,
- llvm::LlvmCompilationUnit* llvm_compilation_unit) {
+ void* compilation_unit) {
return CompileMethod(compiler, backend, code_item, access_flags, invoke_type, class_def_idx,
- method_idx, class_loader, dex_file
-#if defined(ART_USE_PORTABLE_COMPILER)
- , llvm_compilation_unit
-#endif
- ); // NOLINT(whitespace/parens)
+ method_idx, class_loader, dex_file, compilation_unit);
}
} // namespace art
@@ -364,7 +286,7 @@
uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
const art::DexFile& dex_file) {
// TODO: check method fingerprint here to determine appropriate backend type. Until then, use build default
- art::CompilerBackend backend = compiler.GetCompilerBackend();
+ art::CompilerBackend* backend = compiler.GetCompilerBackend();
return art::CompileOneMethod(compiler, backend, code_item, access_flags, invoke_type,
class_def_idx, method_idx, class_loader, dex_file,
NULL /* use thread llvm_info */);
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 209ed3d..b91ef28 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -406,7 +406,7 @@
// Is this the select pattern?
// TODO: flesh out support for Mips. NOTE: llvm's select op doesn't quite work here.
// TUNING: expand to support IF_xx compare & branches
- if ((cu_->compiler_backend != kPortable) &&
+ if (cu_->compiler_backend->IsPortable() &&
(cu_->instruction_set == kThumb2 || cu_->instruction_set == kX86) &&
((mir->dalvikInsn.opcode == Instruction::IF_EQZ) ||
(mir->dalvikInsn.opcode == Instruction::IF_NEZ))) {
diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc
index e6cc2de..3187fbb 100644
--- a/compiler/dex/portable/mir_to_gbc.cc
+++ b/compiler/dex/portable/mir_to_gbc.cc
@@ -41,6 +41,22 @@
const char kCatchBlock = 'C';
namespace art {
+namespace llvm {
+::llvm::Module* makeLLVMModuleContents(::llvm::Module* module);
+}
+
+LLVMInfo::LLVMInfo() {
+ // Create context, module, intrinsic helper & ir builder
+ llvm_context_.reset(new ::llvm::LLVMContext());
+ llvm_module_ = new ::llvm::Module("art", *llvm_context_);
+ ::llvm::StructType::create(*llvm_context_, "JavaObject");
+ art::llvm::makeLLVMModuleContents(llvm_module_);
+ intrinsic_helper_.reset(new art::llvm::IntrinsicHelper(*llvm_context_, *llvm_module_));
+ ir_builder_.reset(new art::llvm::IRBuilder(*llvm_context_, *llvm_module_, *intrinsic_helper_));
+}
+
+LLVMInfo::~LLVMInfo() {
+}
::llvm::BasicBlock* MirConverter::GetLLVMBlock(int id) {
return id_to_block_map_.Get(id);
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 9eb112b..5f04b7d 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -463,10 +463,20 @@
RegLocation rl_result = {kLocPhysReg, 0, 0, 0, 0, 0, 0, 0, 1, kVectorNotUsed,
r2, INVALID_REG, INVALID_SREG, INVALID_SREG};
- // handle 0x80000000 / -1 special case.
- LIR *minint_branch = 0;
- if (imm == -1) {
+ // handle div/rem by 1 special case.
+ if (imm == 1) {
if (is_div) {
+ // x / 1 == x.
+ StoreValue(rl_result, rl_src);
+ } else {
+ // x % 1 == 0.
+ LoadConstantNoClobber(r0, 0);
+ // For this case, return the result in EAX.
+ rl_result.low_reg = r0;
+ }
+ } else if (imm == -1) { // handle 0x80000000 / -1 special case.
+ if (is_div) {
+ LIR *minint_branch = 0;
LoadValueDirectFixed(rl_src, r0);
OpRegImm(kOpCmp, r0, 0x80000000);
minint_branch = NewLIR2(kX86Jcc8, 0, kX86CondEq);
@@ -486,7 +496,7 @@
// For this case, return the result in EAX.
rl_result.low_reg = r0;
} else {
- DCHECK(imm <= -2 || imm >= 2);
+ CHECK(imm <= -2 || imm >= 2);
// Use H.S.Warren's Hacker's Delight Chapter 10 and
// T,Grablund, P.L.Montogomery's Division by invariant integers using multiplication.
int magic, shift;
@@ -975,6 +985,10 @@
}
// Nope. Do it the hard way
+ // Check for V*V. We can eliminate a multiply in that case, as 2L*1H == 2H*1L.
+ bool is_square = mir_graph_->SRegToVReg(rl_src1.s_reg_low) ==
+ mir_graph_->SRegToVReg(rl_src2.s_reg_low);
+
FlushAllRegs();
LockCallTemps(); // Prepare for explicit register usage.
rl_src1 = UpdateLocWide(rl_src1);
@@ -992,36 +1006,52 @@
kWord, GetSRegHi(rl_src1.s_reg_low));
}
- // EAX <- 2H
- if (src2_in_reg) {
- NewLIR2(kX86Mov32RR, r0, rl_src2.high_reg);
- } else {
- LoadBaseDisp(rX86_SP, SRegOffset(rl_src2.s_reg_low) + HIWORD_OFFSET, r0,
- kWord, GetSRegHi(rl_src2.s_reg_low));
- }
+ if (is_square) {
+ // Take advantage of the fact that the values are the same.
+ // ECX <- ECX * 2L (1H * 2L)
+ if (src2_in_reg) {
+ NewLIR2(kX86Imul32RR, r1, rl_src2.low_reg);
+ } else {
+ int displacement = SRegOffset(rl_src2.s_reg_low);
+ LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET);
+ AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
+ true /* is_load */, true /* is_64bit */);
+ }
- // EAX <- EAX * 1L (2H * 1L)
- if (src1_in_reg) {
- NewLIR2(kX86Imul32RR, r0, rl_src1.low_reg);
+ // ECX <- 2*ECX (2H * 1L) + (1H * 2L)
+ NewLIR2(kX86Add32RR, r1, r1);
} else {
- int displacement = SRegOffset(rl_src1.s_reg_low);
- LIR *m = NewLIR3(kX86Imul32RM, r0, rX86_SP, displacement + LOWORD_OFFSET);
- AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
- true /* is_load */, true /* is_64bit */);
- }
+ // EAX <- 2H
+ if (src2_in_reg) {
+ NewLIR2(kX86Mov32RR, r0, rl_src2.high_reg);
+ } else {
+ LoadBaseDisp(rX86_SP, SRegOffset(rl_src2.s_reg_low) + HIWORD_OFFSET, r0,
+ kWord, GetSRegHi(rl_src2.s_reg_low));
+ }
- // ECX <- ECX * 2L (1H * 2L)
- if (src2_in_reg) {
- NewLIR2(kX86Imul32RR, r1, rl_src2.low_reg);
- } else {
- int displacement = SRegOffset(rl_src2.s_reg_low);
- LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET);
- AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
- true /* is_load */, true /* is_64bit */);
- }
+ // EAX <- EAX * 1L (2H * 1L)
+ if (src1_in_reg) {
+ NewLIR2(kX86Imul32RR, r0, rl_src1.low_reg);
+ } else {
+ int displacement = SRegOffset(rl_src1.s_reg_low);
+ LIR *m = NewLIR3(kX86Imul32RM, r0, rX86_SP, displacement + LOWORD_OFFSET);
+ AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
+ true /* is_load */, true /* is_64bit */);
+ }
- // ECX <- ECX + EAX (2H * 1L) + (1H * 2L)
- NewLIR2(kX86Add32RR, r1, r0);
+ // ECX <- ECX * 2L (1H * 2L)
+ if (src2_in_reg) {
+ NewLIR2(kX86Imul32RR, r1, rl_src2.low_reg);
+ } else {
+ int displacement = SRegOffset(rl_src2.s_reg_low);
+ LIR *m = NewLIR3(kX86Imul32RM, r1, rX86_SP, displacement + LOWORD_OFFSET);
+ AnnotateDalvikRegAccess(m, (displacement + LOWORD_OFFSET) >> 2,
+ true /* is_load */, true /* is_64bit */);
+ }
+
+ // ECX <- ECX + EAX (2H * 1L) + (1H * 2L)
+ NewLIR2(kX86Add32RR, r1, r0);
+ }
// EAX <- 2L
if (src2_in_reg) {
@@ -1651,6 +1681,8 @@
X86OpCode x86op = GetOpcode(op, rl_dest, true, val_hi);
NewLIR2(x86op, rl_dest.high_reg, val_hi);
}
+
+ StoreFinalValueWide(rl_dest, rl_dest);
return;
}
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 5b22817..c72c1c5 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -25,6 +25,7 @@
#include "base/stl_util.h"
#include "base/timing_logger.h"
#include "class_linker.h"
+#include "compiler_backend.h"
#include "dex_compilation_unit.h"
#include "dex_file-inl.h"
#include "dex/verification_results.h"
@@ -49,15 +50,10 @@
#include "thread.h"
#include "thread_pool.h"
#include "trampolines/trampoline_compiler.h"
+#include "transaction.h"
#include "verifier/method_verifier.h"
#include "verifier/method_verifier-inl.h"
-#if defined(ART_USE_PORTABLE_COMPILER)
-#include "elf_writer_mclinker.h"
-#else
-#include "elf_writer_quick.h"
-#endif
-
namespace art {
static double Percentage(size_t x, size_t y) {
@@ -287,28 +283,6 @@
DISALLOW_COPY_AND_ASSIGN(AOTCompilationStats);
};
-extern "C" void ArtInitCompilerContext(art::CompilerDriver& driver);
-extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& driver);
-
-extern "C" void ArtUnInitCompilerContext(art::CompilerDriver& driver);
-extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& driver);
-
-extern "C" art::CompiledMethod* ArtCompileMethod(art::CompilerDriver& driver,
- const art::DexFile::CodeItem* code_item,
- uint32_t access_flags,
- art::InvokeType invoke_type,
- uint16_t class_def_idx,
- uint32_t method_idx,
- jobject class_loader,
- const art::DexFile& dex_file);
-extern "C" art::CompiledMethod* ArtQuickCompileMethod(art::CompilerDriver& compiler,
- const art::DexFile::CodeItem* code_item,
- uint32_t access_flags,
- art::InvokeType invoke_type,
- uint16_t class_def_idx,
- uint32_t method_idx,
- jobject class_loader,
- const art::DexFile& dex_file);
extern "C" art::CompiledMethod* ArtCompileDEX(art::CompilerDriver& compiler,
const art::DexFile::CodeItem* code_item,
@@ -318,36 +292,20 @@
uint32_t method_idx,
jobject class_loader,
const art::DexFile& dex_file);
-#ifdef ART_SEA_IR_MODE
-extern "C" art::CompiledMethod* SeaIrCompileMethod(art::CompilerDriver& compiler,
- const art::DexFile::CodeItem* code_item,
- uint32_t access_flags,
- art::InvokeType invoke_type,
- uint16_t class_def_idx,
- uint32_t method_idx,
- jobject class_loader,
- const art::DexFile& dex_file);
-#endif
-extern "C" art::CompiledMethod* ArtLLVMJniCompileMethod(art::CompilerDriver& driver,
- uint32_t access_flags, uint32_t method_idx,
- const art::DexFile& dex_file);
-
-extern "C" art::CompiledMethod* ArtQuickJniCompileMethod(art::CompilerDriver& compiler,
- uint32_t access_flags, uint32_t method_idx,
- const art::DexFile& dex_file);
extern "C" void compilerLLVMSetBitcodeFileName(art::CompilerDriver& driver,
std::string const& filename);
CompilerDriver::CompilerDriver(VerificationResults* verification_results,
DexFileToMethodInlinerMap* method_inliner_map,
- CompilerBackend compiler_backend, InstructionSet instruction_set,
+ CompilerBackend::Kind compiler_backend_kind,
+ InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
bool image, DescriptorSet* image_classes, size_t thread_count,
bool dump_stats, bool dump_passes, CumulativeLogger* timer)
: verification_results_(verification_results),
method_inliner_map_(method_inliner_map),
- compiler_backend_(compiler_backend),
+ compiler_backend_(CompilerBackend::Create(compiler_backend_kind)),
instruction_set_(instruction_set),
instruction_set_features_(instruction_set_features),
freezing_constructor_lock_("freezing constructor lock"),
@@ -362,9 +320,7 @@
dump_passes_(dump_passes),
timings_logger_(timer),
compiler_library_(NULL),
- compiler_(NULL),
compiler_context_(NULL),
- jni_compiler_(NULL),
compiler_enable_auto_elf_loading_(NULL),
compiler_get_method_code_addr_(NULL),
support_boot_image_fixup_(instruction_set != kMips),
@@ -375,34 +331,9 @@
CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, NULL), "compiler tls key");
- // TODO: more work needed to combine initializations and allow per-method backend selection
- typedef void (*InitCompilerContextFn)(CompilerDriver&);
- InitCompilerContextFn init_compiler_context;
- if (compiler_backend_ == kPortable) {
- // Initialize compiler_context_
- init_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtInitCompilerContext);
- compiler_ = reinterpret_cast<CompilerFn>(ArtCompileMethod);
- } else {
- init_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtInitQuickCompilerContext);
- compiler_ = reinterpret_cast<CompilerFn>(ArtQuickCompileMethod);
- }
-
dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX);
-#ifdef ART_SEA_IR_MODE
- sea_ir_compiler_ = NULL;
- if (Runtime::Current()->IsSeaIRMode()) {
- sea_ir_compiler_ = reinterpret_cast<CompilerFn>(SeaIrCompileMethod);
- }
-#endif
-
- init_compiler_context(*this);
-
- if (compiler_backend_ == kPortable) {
- jni_compiler_ = reinterpret_cast<JniCompilerFn>(ArtLLVMJniCompileMethod);
- } else {
- jni_compiler_ = reinterpret_cast<JniCompilerFn>(ArtQuickJniCompileMethod);
- }
+ compiler_backend_->Init(*this);
CHECK(!Runtime::Current()->IsStarted());
if (!image_) {
@@ -449,16 +380,7 @@
STLDeleteElements(&classes_to_patch_);
}
CHECK_PTHREAD_CALL(pthread_key_delete, (tls_key_), "delete tls key");
- typedef void (*UninitCompilerContextFn)(CompilerDriver&);
- UninitCompilerContextFn uninit_compiler_context;
- // Uninitialize compiler_context_
- // TODO: rework to combine initialization/uninitialization
- if (compiler_backend_ == kPortable) {
- uninit_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtUnInitCompilerContext);
- } else {
- uninit_compiler_context = reinterpret_cast<void (*)(CompilerDriver&)>(ArtUnInitQuickCompilerContext);
- }
- uninit_compiler_context(*this);
+ compiler_backend_->UnInit(*this);
}
CompilerTls* CompilerDriver::GetTls() {
@@ -1153,7 +1075,7 @@
*direct_method = 0;
bool use_dex_cache = false;
const bool compiling_boot = Runtime::Current()->GetHeap()->IsCompilingBoot();
- if (compiler_backend_ == kPortable) {
+ if (compiler_backend_->IsPortable()) {
if (sharp_type != kStatic && sharp_type != kDirect) {
return;
}
@@ -1230,23 +1152,13 @@
CHECK(!method->IsAbstract());
*type = sharp_type;
*direct_method = reinterpret_cast<uintptr_t>(method);
- if (compiler_backend_ == kQuick) {
- *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode());
- } else {
- CHECK_EQ(compiler_backend_, kPortable);
- *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromPortableCompiledCode());
- }
+ *direct_code = compiler_backend_->GetEntryPointOf(method);
target_method->dex_file = method->GetDeclaringClass()->GetDexCache()->GetDexFile();
target_method->dex_method_index = method->GetDexMethodIndex();
} else if (!must_use_direct_pointers) {
// Set the code and rely on the dex cache for the method.
*type = sharp_type;
- if (compiler_backend_ == kQuick) {
- *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromQuickCompiledCode());
- } else {
- CHECK_EQ(compiler_backend_, kPortable);
- *direct_code = reinterpret_cast<uintptr_t>(method->GetEntryPointFromPortableCompiledCode());
- }
+ *direct_code = compiler_backend_->GetEntryPointOf(method);
} else {
// Direct pointers were required but none were available.
VLOG(compiler) << "Dex cache devirtualization failed for: " << PrettyMethod(method);
@@ -1795,425 +1707,6 @@
context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_);
}
-static const char* class_initializer_black_list[] = {
- "Landroid/app/ActivityThread;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/bluetooth/BluetoothAudioGateway;", // Calls android.bluetooth.BluetoothAudioGateway.classInitNative().
- "Landroid/bluetooth/HeadsetBase;", // Calls android.bluetooth.HeadsetBase.classInitNative().
- "Landroid/content/res/CompatibilityInfo;", // Requires android.util.DisplayMetrics -..-> android.os.SystemProperties.native_get_int.
- "Landroid/content/res/CompatibilityInfo$1;", // Requires android.util.DisplayMetrics -..-> android.os.SystemProperties.native_get_int.
- "Landroid/content/UriMatcher;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/database/CursorWindow;", // Requires android.util.DisplayMetrics -..-> android.os.SystemProperties.native_get_int.
- "Landroid/database/sqlite/SQLiteConnection;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/database/sqlite/SQLiteConnection$Operation;", // Requires SimpleDateFormat -> java.util.Locale.
- "Landroid/database/sqlite/SQLiteDatabaseConfiguration;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/database/sqlite/SQLiteDebug;", // Calls android.util.Log.isLoggable.
- "Landroid/database/sqlite/SQLiteOpenHelper;", // Calls Class.getSimpleName -> Class.isAnonymousClass -> Class.getDex.
- "Landroid/database/sqlite/SQLiteQueryBuilder;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/drm/DrmManagerClient;", // Calls System.loadLibrary.
- "Landroid/graphics/drawable/AnimatedRotateDrawable;", // Sub-class of Drawable.
- "Landroid/graphics/drawable/AnimationDrawable;", // Sub-class of Drawable.
- "Landroid/graphics/drawable/BitmapDrawable;", // Sub-class of Drawable.
- "Landroid/graphics/drawable/ClipDrawable;", // Sub-class of Drawable.
- "Landroid/graphics/drawable/ColorDrawable;", // Sub-class of Drawable.
- "Landroid/graphics/drawable/Drawable;", // Requires android.graphics.Rect.
- "Landroid/graphics/drawable/DrawableContainer;", // Sub-class of Drawable.
- "Landroid/graphics/drawable/GradientDrawable;", // Sub-class of Drawable.
- "Landroid/graphics/drawable/LayerDrawable;", // Sub-class of Drawable.
- "Landroid/graphics/drawable/NinePatchDrawable;", // Sub-class of Drawable.
- "Landroid/graphics/drawable/RotateDrawable;", // Sub-class of Drawable.
- "Landroid/graphics/drawable/ScaleDrawable;", // Sub-class of Drawable.
- "Landroid/graphics/drawable/ShapeDrawable;", // Sub-class of Drawable.
- "Landroid/graphics/drawable/StateListDrawable;", // Sub-class of Drawable.
- "Landroid/graphics/drawable/TransitionDrawable;", // Sub-class of Drawable.
- "Landroid/graphics/Matrix;", // Calls android.graphics.Matrix.native_create.
- "Landroid/graphics/Matrix$1;", // Requires Matrix.
- "Landroid/graphics/PixelFormat;", // Calls android.graphics.PixelFormat.nativeClassInit().
- "Landroid/graphics/Rect;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/graphics/SurfaceTexture;", // Calls android.graphics.SurfaceTexture.nativeClassInit().
- "Landroid/graphics/Typeface;", // Calls android.graphics.Typeface.nativeCreate.
- "Landroid/inputmethodservice/ExtractEditText;", // Requires android.widget.TextView.
- "Landroid/media/AmrInputStream;", // Calls OsConstants.initConstants.
- "Landroid/media/CamcorderProfile;", // Calls OsConstants.initConstants.
- "Landroid/media/CameraProfile;", // Calls System.loadLibrary.
- "Landroid/media/DecoderCapabilities;", // Calls System.loadLibrary.
- "Landroid/media/EncoderCapabilities;", // Calls OsConstants.initConstants.
- "Landroid/media/ExifInterface;", // Calls OsConstants.initConstants.
- "Landroid/media/MediaCodec;", // Calls OsConstants.initConstants.
- "Landroid/media/MediaCodecList;", // Calls OsConstants.initConstants.
- "Landroid/media/MediaCrypto;", // Calls OsConstants.initConstants.
- "Landroid/media/MediaDrm;", // Calls OsConstants.initConstants.
- "Landroid/media/MediaExtractor;", // Calls OsConstants.initConstants.
- "Landroid/media/MediaFile;", // Requires DecoderCapabilities.
- "Landroid/media/MediaMetadataRetriever;", // Calls OsConstants.initConstants.
- "Landroid/media/MediaMuxer;", // Calls OsConstants.initConstants.
- "Landroid/media/MediaPlayer;", // Calls System.loadLibrary.
- "Landroid/media/MediaRecorder;", // Calls System.loadLibrary.
- "Landroid/media/MediaScanner;", // Calls System.loadLibrary.
- "Landroid/media/ResampleInputStream;", // Calls OsConstants.initConstants.
- "Landroid/media/SoundPool;", // Calls OsConstants.initConstants.
- "Landroid/media/videoeditor/MediaArtistNativeHelper;", // Calls OsConstants.initConstants.
- "Landroid/media/videoeditor/VideoEditorProfile;", // Calls OsConstants.initConstants.
- "Landroid/mtp/MtpDatabase;", // Calls OsConstants.initConstants.
- "Landroid/mtp/MtpDevice;", // Calls OsConstants.initConstants.
- "Landroid/mtp/MtpServer;", // Calls OsConstants.initConstants.
- "Landroid/net/NetworkInfo;", // Calls java.util.EnumMap.<init> -> java.lang.Enum.getSharedConstants -> System.identityHashCode.
- "Landroid/net/Proxy;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/net/SSLCertificateSocketFactory;", // Requires javax.net.ssl.HttpsURLConnection.
- "Landroid/net/Uri$AbstractHierarchicalUri;", // Requires Uri.
- "Landroid/net/Uri$HierarchicalUri;", // Requires Uri.
- "Landroid/net/Uri$OpaqueUri;", // Requires Uri.
- "Landroid/net/Uri$StringUri;", // Requires Uri.
- "Landroid/net/Uri;", // Calls Class.getSimpleName -> Class.isAnonymousClass -> Class.getDex.
- "Landroid/net/WebAddress;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/net/wifi/WifiNative;", // Calls new LocalLog -> new Time -> TimeZone -> Pattern.compile.
- "Landroid/nfc/NdefRecord;", // Calls String.getBytes -> java.nio.charset.Charset.
- "Landroid/opengl/EGL14;", // Calls android.opengl.EGL14._nativeClassInit.
- "Landroid/opengl/GLES10;", // Calls android.opengl.GLES10._nativeClassInit.
- "Landroid/opengl/GLES10Ext;", // Calls android.opengl.GLES10Ext._nativeClassInit.
- "Landroid/opengl/GLES11;", // Requires GLES10.
- "Landroid/opengl/GLES11Ext;", // Calls android.opengl.GLES11Ext._nativeClassInit.
- "Landroid/opengl/GLES20;", // Calls android.opengl.GLES20._nativeClassInit.
- "Landroid/opengl/GLUtils;", // Calls android.opengl.GLUtils.nativeClassInit.
- "Landroid/os/Build;", // Calls -..-> android.os.SystemProperties.native_get.
- "Landroid/os/Build$VERSION;", // Requires Build.
- "Landroid/os/Bundle;", // Calls android.os.Parcel.obtain -..> Parcel.nativeCreate.
- "Landroid/os/Debug;", // Requires android.os.Environment.
- "Landroid/os/Environment;", // Calls System.getenv.
- "Landroid/os/FileUtils;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/os/StrictMode;", // Calls android.util.Log.isLoggable.
- "Landroid/os/StrictMode$VmPolicy;", // Requires StrictMode.
- "Landroid/os/Trace;", // Calls android.os.Trace.nativeGetEnabledTags.
- "Landroid/os/UEventObserver;", // Calls Class.getSimpleName -> Class.isAnonymousClass -> Class.getDex.
- "Landroid/provider/ContactsContract;", // Calls OsConstants.initConstants.
- "Landroid/provider/Settings$Global;", // Calls OsConstants.initConstants.
- "Landroid/provider/Settings$Secure;", // Requires android.net.Uri.
- "Landroid/provider/Settings$System;", // Requires android.net.Uri.
- "Landroid/renderscript/RenderScript;", // Calls System.loadLibrary.
- "Landroid/server/BluetoothService;", // Calls android.server.BluetoothService.classInitNative.
- "Landroid/server/BluetoothEventLoop;", // Calls android.server.BluetoothEventLoop.classInitNative.
- "Landroid/telephony/PhoneNumberUtils;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/telephony/TelephonyManager;", // Calls OsConstants.initConstants.
- "Landroid/text/AutoText;", // Requires android.util.DisplayMetrics -..-> android.os.SystemProperties.native_get_int.
- "Landroid/text/Layout;", // Calls com.android.internal.util.ArrayUtils.emptyArray -> System.identityHashCode.
- "Landroid/text/BoringLayout;", // Requires Layout.
- "Landroid/text/DynamicLayout;", // Requires Layout.
- "Landroid/text/Html$HtmlParser;", // Calls -..-> String.toLowerCase -> java.util.Locale.
- "Landroid/text/StaticLayout;", // Requires Layout.
- "Landroid/text/TextUtils;", // Requires android.util.DisplayMetrics.
- "Landroid/util/DisplayMetrics;", // Calls SystemProperties.native_get_int.
- "Landroid/util/Patterns;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/view/Choreographer;", // Calls SystemProperties.native_get_boolean.
- "Landroid/util/Patterns;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/view/GLES20Canvas;", // Calls GLES20Canvas.nIsAvailable().
- "Landroid/view/GLES20RecordingCanvas;", // Requires android.view.GLES20Canvas.
- "Landroid/view/GestureDetector;", // Calls android.view.GLES20Canvas.nIsAvailable.
- "Landroid/view/HardwareRenderer$Gl20Renderer;", // Requires SystemProperties.native_get.
- "Landroid/view/HardwareRenderer$GlRenderer;", // Requires SystemProperties.native_get.
- "Landroid/view/InputEventConsistencyVerifier;", // Requires android.os.Build.
- "Landroid/view/Surface;", // Requires SystemProperties.native_get.
- "Landroid/view/SurfaceControl;", // Calls OsConstants.initConstants.
- "Landroid/view/animation/AlphaAnimation;", // Requires Animation.
- "Landroid/view/animation/Animation;", // Calls SystemProperties.native_get_boolean.
- "Landroid/view/animation/AnimationSet;", // Calls OsConstants.initConstants.
- "Landroid/view/textservice/SpellCheckerSubtype;", // Calls Class.getDex().
- "Landroid/webkit/JniUtil;", // Calls System.loadLibrary.
- "Landroid/webkit/PluginManager;", // // Calls OsConstants.initConstants.
- "Landroid/webkit/WebViewCore;", // Calls System.loadLibrary.
- "Landroid/webkit/WebViewFactory;", // Calls -..-> android.os.SystemProperties.native_get.
- "Landroid/webkit/WebViewFactory$Preloader;", // Calls to Class.forName.
- "Landroid/webkit/WebViewInputDispatcher;", // Calls Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/webkit/URLUtil;", // Calls Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Landroid/widget/AutoCompleteTextView;", // Requires TextView.
- "Landroid/widget/Button;", // Requires TextView.
- "Landroid/widget/CheckBox;", // Requires TextView.
- "Landroid/widget/CheckedTextView;", // Requires TextView.
- "Landroid/widget/CompoundButton;", // Requires TextView.
- "Landroid/widget/EditText;", // Requires TextView.
- "Landroid/widget/NumberPicker;", // Requires java.util.Locale.
- "Landroid/widget/ScrollBarDrawable;", // Sub-class of Drawable.
- "Landroid/widget/SearchView$SearchAutoComplete;", // Requires TextView.
- "Landroid/widget/Switch;", // Requires TextView.
- "Landroid/widget/TextView;", // Calls Paint.<init> -> Paint.native_init.
- "Lcom/android/i18n/phonenumbers/AsYouTypeFormatter;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Lcom/android/i18n/phonenumbers/MetadataManager;", // Calls OsConstants.initConstants.
- "Lcom/android/i18n/phonenumbers/PhoneNumberMatcher;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Lcom/android/i18n/phonenumbers/PhoneNumberUtil;", // Requires java.util.logging.LogManager.
- "Lcom/android/i18n/phonenumbers/geocoding/AreaCodeMap;", // Calls OsConstants.initConstants.
- "Lcom/android/i18n/phonenumbers/geocoding/PhoneNumberOfflineGeocoder;", // Calls OsConstants.initConstants.
- "Lcom/android/internal/os/SamplingProfilerIntegration;", // Calls SystemProperties.native_get_int.
- "Lcom/android/internal/policy/impl/PhoneWindow;", // Calls android.os.Binder.init.
- "Lcom/android/internal/view/menu/ActionMenuItemView;", // Requires TextView.
- "Lcom/android/internal/widget/DialogTitle;", // Requires TextView.
- "Lcom/android/org/bouncycastle/asn1/StreamUtil;", // Calls Runtime.getRuntime().maxMemory().
- "Lcom/android/org/bouncycastle/asn1/pkcs/MacData;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/asn1/pkcs/RSASSAPSSparams;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/asn1/cms/SignedData;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/asn1/x509/GeneralSubtree;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/asn1/x9/X9ECParameters;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/crypto/digests/OpenSSLDigest$MD5;", // Requires com.android.org.conscrypt.NativeCrypto.
- "Lcom/android/org/bouncycastle/crypto/digests/OpenSSLDigest$SHA1;", // Requires com.android.org.conscrypt.NativeCrypto.
- "Lcom/android/org/bouncycastle/crypto/digests/OpenSSLDigest$SHA256;", // Requires com.android.org.conscrypt.NativeCrypto.
- "Lcom/android/org/bouncycastle/crypto/digests/OpenSSLDigest$SHA384;", // Requires com.android.org.conscrypt.NativeCrypto.
- "Lcom/android/org/bouncycastle/crypto/digests/OpenSSLDigest$SHA512;", // Requires com.android.org.conscrypt.NativeCrypto.
- "Lcom/android/org/bouncycastle/crypto/engines/RSABlindedEngine;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/crypto/generators/DHParametersGenerator;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/crypto/generators/DHParametersHelper;", // Calls System.getenv -> OsConstants.initConstants.
- "Lcom/android/org/bouncycastle/crypto/generators/DSAKeyPairGenerator;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/crypto/generators/DSAParametersGenerator;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/crypto/generators/RSAKeyPairGenerator;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/dh/KeyPairGeneratorSpi;", // Calls OsConstants.initConstants.
- "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyPairGeneratorSpi;", // Calls OsConstants.initConstants.
- "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi$EC;", // Calls OsConstants.initConstants.
- "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi$ECDH;", // Calls OsConstants.initConstants.
- "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi$ECDHC;", // Calls OsConstants.initConstants.
- "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi$ECDSA;", // Calls OsConstants.initConstants.
- "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi$ECMQV;", // Calls OsConstants.initConstants.
- "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi;", // Calls OsConstants.initConstants.
- "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyPairGeneratorSpi;", // Calls OsConstants.initConstants.
- "Lcom/android/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi$BCPKCS12KeyStore;", // Calls Thread.currentThread.
- "Lcom/android/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi;", // Calls Thread.currentThread.
- "Lcom/android/org/bouncycastle/jce/PKCS10CertificationRequest;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/jce/provider/CertBlacklist;", // Calls System.getenv -> OsConstants.initConstants.
- "Lcom/android/org/bouncycastle/jce/provider/JCERSAPrivateCrtKey;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/jce/provider/JCERSAPrivateKey;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi;", // Calls System.getenv -> OsConstants.initConstants.
- "Lcom/android/org/bouncycastle/math/ec/ECConstants;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/math/ec/Tnaf;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/util/BigIntegers;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/bouncycastle/x509/X509Util;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lcom/android/org/conscrypt/CipherSuite;", // Calls OsConstants.initConstants.
- "Lcom/android/org/conscrypt/FileClientSessionCache$CacheFile;", // Calls OsConstants.initConstants.
- "Lcom/android/org/conscrypt/HandshakeIODataStream;", // Calls OsConstants.initConstants.
- "Lcom/android/org/conscrypt/Logger;", // Calls OsConstants.initConstants.
- "Lcom/android/org/conscrypt/NativeCrypto;", // Calls native NativeCrypto.clinit().
- "Lcom/android/org/conscrypt/OpenSSLECKeyPairGenerator;", // Calls OsConstants.initConstants.
- "Lcom/android/org/conscrypt/OpenSSLEngine;", // Requires com.android.org.conscrypt.NativeCrypto.
- "Lcom/android/org/conscrypt/OpenSSLMac$HmacMD5;", // Calls native NativeCrypto.clinit().
- "Lcom/android/org/conscrypt/OpenSSLMac$HmacSHA1;", // Calls native NativeCrypto.clinit().
- "Lcom/android/org/conscrypt/OpenSSLMac$HmacSHA256;", // Calls native NativeCrypto.clinit().
- "Lcom/android/org/conscrypt/OpenSSLMac$HmacSHA384;", // Calls native NativeCrypto.clinit().
- "Lcom/android/org/conscrypt/OpenSSLMac$HmacSHA512;", // Calls native NativeCrypto.clinit().
- "Lcom/android/org/conscrypt/OpenSSLMessageDigestJDK$MD5;", // Requires com.android.org.conscrypt.NativeCrypto.
- "Lcom/android/org/conscrypt/OpenSSLMessageDigestJDK$SHA1;", // Requires com.android.org.conscrypt.NativeCrypto.
- "Lcom/android/org/conscrypt/OpenSSLMessageDigestJDK$SHA256;", // Requires com.android.org.conscrypt.NativeCrypto.
- "Lcom/android/org/conscrypt/OpenSSLMessageDigestJDK$SHA384;", // Requires com.android.org.conscrypt.NativeCrypto.
- "Lcom/android/org/conscrypt/OpenSSLMessageDigestJDK$SHA512;", // Requires com.android.org.conscrypt.NativeCrypto.
- "Lcom/android/org/conscrypt/OpenSSLX509CertPath;", // Calls OsConstants.initConstants.
- "Lcom/android/org/conscrypt/OpenSSLX509CertificateFactory;", // Calls OsConstants.initConstants.
- "Lcom/android/org/conscrypt/PRF;", // Calls OsConstants.initConstants.
- "Lcom/android/org/conscrypt/SSLSessionImpl;", // Calls OsConstants.initConstants.
- "Lcom/android/org/conscrypt/TrustedCertificateStore;", // Calls System.getenv -> OsConstants.initConstants.
- "Lcom/android/okhttp/ConnectionPool;", // Calls OsConstants.initConstants.
- "Lcom/android/okhttp/OkHttpClient;", // Calls OsConstants.initConstants.
- "Lcom/android/okhttp/internal/DiskLruCache;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Lcom/android/okhttp/internal/Util;", // Calls OsConstants.initConstants.
- "Lcom/android/okhttp/internal/http/HttpsURLConnectionImpl;", // Calls VMClassLoader.getBootClassPathSize.
- "Lcom/android/okhttp/internal/spdy/SpdyConnection;", // Calls OsConstants.initConstants.
- "Lcom/android/okhttp/internal/spdy/SpdyReader;", // Calls OsConstants.initConstants.
- "Lcom/android/okhttp/internal/tls/OkHostnameVerifier;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Lcom/google/android/gles_jni/EGLContextImpl;", // Calls com.google.android.gles_jni.EGLImpl._nativeClassInit.
- "Lcom/google/android/gles_jni/EGLImpl;", // Calls com.google.android.gles_jni.EGLImpl._nativeClassInit.
- "Lcom/google/android/gles_jni/GLImpl;", // Calls com.google.android.gles_jni.GLImpl._nativeClassInit.
- "Lgov/nist/core/GenericObject;", // Calls OsConstants.initConstants.
- "Lgov/nist/core/Host;", // Calls OsConstants.initConstants.
- "Lgov/nist/core/HostPort;", // Calls OsConstants.initConstants.
- "Lgov/nist/core/NameValue;", // Calls OsConstants.initConstants.
- "Lgov/nist/core/net/DefaultNetworkLayer;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/Utils;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/address/AddressImpl;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/address/Authority;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/address/GenericURI;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/address/NetObject;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/address/SipUri;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/address/TelephoneNumber;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/address/UserInfo;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/Accept;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/AcceptEncoding;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/AcceptLanguage;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/AddressParametersHeader;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/AlertInfoList;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/AllowEvents;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/AllowEventsList;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/AuthenticationInfo;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/Authorization;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/CSeq;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/CallIdentifier;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/Challenge;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ContactList;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ContentEncoding;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ContentEncodingList;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ContentLanguageList;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ContentType;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/Credentials;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ErrorInfoList;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/Expires;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/From;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/MimeVersion;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/NameMap;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/Priority;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/Protocol;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ProxyAuthenticate;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ProxyAuthenticateList;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ProxyAuthorizationList;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ProxyRequire;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ProxyRequireList;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/RSeq;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/RecordRoute;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ReferTo;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/RequestLine;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/Require;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/RetryAfter;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/SIPETag;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/SIPHeader;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/SIPHeaderNamesCache;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/StatusLine;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/SubscriptionState;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/TimeStamp;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/UserAgent;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/Unsupported;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/Warning;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ViaList;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/extensions/Join;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/extensions/References;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/extensions/Replaces;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ims/PAccessNetworkInfo;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ims/PAssertedIdentity;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ims/PAssertedIdentityList;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ims/PAssociatedURI;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ims/PCalledPartyID;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ims/PChargingVector;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ims/PPreferredIdentity;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ims/PVisitedNetworkIDList;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ims/PathList;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ims/SecurityAgree;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ims/SecurityClient;", // Calls OsConstants.initConstants.
- "Lgov/nist/javax/sip/header/ims/ServiceRoute;", // Calls OsConstants.initConstants.
- "Ljava/io/Console;", // Has FileDescriptor(s).
- "Ljava/io/File;", // Calls to Random.<init> -> System.currentTimeMillis -> OsConstants.initConstants.
- "Ljava/io/FileDescriptor;", // Requires libcore.io.OsConstants.
- "Ljava/io/ObjectInputStream;", // Requires java.lang.ClassLoader$SystemClassLoader.
- "Ljava/io/ObjectStreamClass;", // Calls to Class.forName -> java.io.FileDescriptor.
- "Ljava/io/ObjectStreamConstants;", // Instance of non-image class SerializablePermission.
- "Ljava/lang/ClassLoader$SystemClassLoader;", // Calls System.getProperty -> OsConstants.initConstants.
- "Ljava/lang/HexStringParser;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Ljava/lang/ProcessManager;", // Calls Thread.currentThread.
- "Ljava/lang/Runtime;", // Calls System.getProperty -> OsConstants.initConstants.
- "Ljava/lang/System;", // Calls OsConstants.initConstants.
- "Ljava/math/BigDecimal;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Ljava/math/BigInteger;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Ljava/math/Primality;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Ljava/math/Multiplication;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Ljava/net/InetAddress;", // Requires libcore.io.OsConstants.
- "Ljava/net/Inet4Address;", // Sub-class of InetAddress.
- "Ljava/net/Inet6Address;", // Sub-class of InetAddress.
- "Ljava/net/InetUnixAddress;", // Sub-class of InetAddress.
- "Ljava/net/NetworkInterface;", // Calls to Random.<init> -> System.currentTimeMillis -> OsConstants.initConstants.
- "Ljava/net/StandardSocketOptions;", // Call System.identityHashCode.
- "Ljava/nio/charset/Charset;", // Calls Charset.getDefaultCharset -> System.getProperty -> OsConstants.initConstants.
- "Ljava/nio/charset/CharsetICU;", // Sub-class of Charset.
- "Ljava/nio/charset/Charsets;", // Calls Charset.forName.
- "Ljava/nio/charset/StandardCharsets;", // Calls OsConstants.initConstants.
- "Ljava/security/AlgorithmParameterGenerator;", // Calls OsConstants.initConstants.
- "Ljava/security/KeyPairGenerator$KeyPairGeneratorImpl;", // Calls OsConstants.initConstants.
- "Ljava/security/KeyPairGenerator;", // Calls OsConstants.initConstants.
- "Ljava/security/Security;", // Tries to do disk IO for "security.properties".
- "Ljava/security/spec/RSAKeyGenParameterSpec;", // java.math.NativeBN.BN_new()
- "Ljava/sql/Date;", // Calls OsConstants.initConstants.
- "Ljava/sql/DriverManager;", // Calls OsConstants.initConstants.
- "Ljava/sql/Time;", // Calls OsConstants.initConstants.
- "Ljava/sql/Timestamp;", // Calls OsConstants.initConstants.
- "Ljava/util/Date;", // Calls Date.<init> -> System.currentTimeMillis -> OsConstants.initConstants.
- "Ljava/util/ListResourceBundle;", // Calls OsConstants.initConstants.
- "Ljava/util/Locale;", // Calls System.getProperty -> OsConstants.initConstants.
- "Ljava/util/PropertyResourceBundle;", // Calls OsConstants.initConstants.
- "Ljava/util/ResourceBundle;", // Calls OsConstants.initConstants.
- "Ljava/util/ResourceBundle$MissingBundle;", // Calls OsConstants.initConstants.
- "Ljava/util/Scanner;", // regex.Pattern.compileImpl.
- "Ljava/util/SimpleTimeZone;", // Sub-class of TimeZone.
- "Ljava/util/TimeZone;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
- "Ljava/util/concurrent/ConcurrentHashMap;", // Calls Runtime.getRuntime().availableProcessors().
- "Ljava/util/concurrent/ConcurrentHashMap$Segment;", // Calls Runtime.getRuntime().availableProcessors().
- "Ljava/util/concurrent/ConcurrentSkipListMap;", // Calls Random() -> OsConstants.initConstants.
- "Ljava/util/concurrent/Exchanger;", // Calls Runtime.getRuntime().availableProcessors().
- "Ljava/util/concurrent/ForkJoinPool;", // Makes a thread pool ..-> calls OsConstants.initConstants.
- "Ljava/util/concurrent/LinkedTransferQueue;", // Calls Runtime.getRuntime().availableProcessors().
- "Ljava/util/concurrent/Phaser;", // Calls Runtime.getRuntime().availableProcessors().
- "Ljava/util/concurrent/ScheduledThreadPoolExecutor;", // Calls AtomicLong.VMSupportsCS8()
- "Ljava/util/concurrent/SynchronousQueue;", // Calls Runtime.getRuntime().availableProcessors().
- "Ljava/util/concurrent/atomic/AtomicLong;", // Calls AtomicLong.VMSupportsCS8()
- "Ljava/util/logging/LogManager;", // Calls System.getProperty -> OsConstants.initConstants.
- "Ljava/util/prefs/AbstractPreferences;", // Calls OsConstants.initConstants.
- "Ljava/util/prefs/FilePreferencesImpl;", // Calls OsConstants.initConstants.
- "Ljava/util/prefs/FilePreferencesFactoryImpl;", // Calls OsConstants.initConstants.
- "Ljava/util/prefs/Preferences;", // Calls OsConstants.initConstants.
- "Ljavax/crypto/KeyAgreement;", // Calls OsConstants.initConstants.
- "Ljavax/crypto/KeyGenerator;", // Calls OsConstants.initConstants.
- "Ljavax/security/cert/X509Certificate;", // Calls VMClassLoader.getBootClassPathSize.
- "Ljavax/security/cert/X509Certificate$1;", // Calls VMClassLoader.getBootClassPathSize.
- "Ljavax/microedition/khronos/egl/EGL10;", // Requires EGLContext.
- "Ljavax/microedition/khronos/egl/EGLContext;", // Requires com.google.android.gles_jni.EGLImpl.
- "Ljavax/xml/datatype/DatatypeConstants;", // Calls OsConstants.initConstants.
- "Ljavax/xml/datatype/FactoryFinder;", // Calls OsConstants.initConstants.
- "Ljavax/xml/namespace/QName;", // Calls OsConstants.initConstants.
- "Ljavax/xml/validation/SchemaFactoryFinder;", // Calls OsConstants.initConstants.
- "Ljavax/xml/xpath/XPathConstants;", // Calls OsConstants.initConstants.
- "Ljavax/xml/xpath/XPathFactoryFinder;", // Calls OsConstants.initConstants.
- "Llibcore/icu/LocaleData;", // Requires java.util.Locale.
- "Llibcore/icu/TimeZoneNames;", // Requires java.util.TimeZone.
- "Llibcore/io/IoUtils;", // Calls Random.<init> -> System.currentTimeMillis -> FileDescriptor -> OsConstants.initConstants.
- "Llibcore/io/OsConstants;", // Platform specific.
- "Llibcore/net/MimeUtils;", // Calls libcore.net.MimeUtils.getContentTypesPropertiesStream -> System.getProperty.
- "Llibcore/reflect/Types;", // Calls OsConstants.initConstants.
- "Llibcore/util/ZoneInfo;", // Sub-class of TimeZone.
- "Llibcore/util/ZoneInfoDB;", // Calls System.getenv -> OsConstants.initConstants.
- "Lorg/apache/commons/logging/LogFactory;", // Calls System.getProperty.
- "Lorg/apache/commons/logging/impl/LogFactoryImpl;", // Calls OsConstants.initConstants.
- "Lorg/apache/harmony/security/fortress/Services;", // Calls ClassLoader.getSystemClassLoader -> System.getProperty.
- "Lorg/apache/harmony/security/provider/cert/X509CertFactoryImpl;", // Requires java.nio.charsets.Charsets.
- "Lorg/apache/harmony/security/provider/crypto/RandomBitsSupplier;", // Requires java.io.File.
- "Lorg/apache/harmony/security/utils/AlgNameMapper;", // Requires java.util.Locale.
- "Lorg/apache/harmony/security/pkcs10/CertificationRequest;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/pkcs10/CertificationRequestInfo;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/pkcs7/AuthenticatedAttributes;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/pkcs7/SignedData;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/pkcs7/SignerInfo;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/pkcs8/PrivateKeyInfo;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/provider/crypto/SHA1PRNG_SecureRandomImpl;", // Calls OsConstants.initConstants.
- "Lorg/apache/harmony/security/x501/AttributeTypeAndValue;", // Calls IntegralToString.convertInt -> Thread.currentThread.
- "Lorg/apache/harmony/security/x501/DirectoryString;", // Requires BigInteger.
- "Lorg/apache/harmony/security/x501/Name;", // Requires org.apache.harmony.security.x501.AttributeTypeAndValue.
- "Lorg/apache/harmony/security/x509/AccessDescription;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/x509/AuthorityKeyIdentifier;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/x509/CRLDistributionPoints;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/x509/Certificate;", // Requires org.apache.harmony.security.x509.TBSCertificate.
- "Lorg/apache/harmony/security/x509/CertificateIssuer;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/x509/CertificateList;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/x509/DistributionPoint;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/x509/DistributionPointName;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/x509/EDIPartyName;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lorg/apache/harmony/security/x509/GeneralName;", // Requires org.apache.harmony.security.x501.Name.
- "Lorg/apache/harmony/security/x509/GeneralNames;", // Requires GeneralName.
- "Lorg/apache/harmony/security/x509/GeneralSubtree;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/x509/GeneralSubtrees;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/x509/InfoAccessSyntax;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/x509/IssuingDistributionPoint;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/x509/NameConstraints;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/x509/TBSCertList$RevokedCertificate;", // Calls NativeBN.BN_new().
- "Lorg/apache/harmony/security/x509/TBSCertList;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/security/x509/TBSCertificate;", // Requires org.apache.harmony.security.x501.Name.
- "Lorg/apache/harmony/security/x509/Time;", // Calls native ... -> java.math.NativeBN.BN_new().
- "Lorg/apache/harmony/security/x509/Validity;", // Requires x509.Time.
- "Lorg/apache/harmony/security/x509/tsp/TSTInfo;", // Calls Thread.currentThread.
- "Lorg/apache/harmony/xml/ExpatParser;", // Calls native ExpatParser.staticInitialize.
- "Lorg/apache/harmony/xml/ExpatParser$EntityParser;", // Calls ExpatParser.staticInitialize.
- "Lorg/apache/http/conn/params/ConnRouteParams;", // Requires java.util.Locale.
- "Lorg/apache/http/conn/ssl/SSLSocketFactory;", // Calls java.security.Security.getProperty.
- "Lorg/apache/http/conn/util/InetAddressUtils;", // Calls regex.Pattern.compile -..-> regex.Pattern.compileImpl.
-};
-
static void InitializeClass(const ParallelCompilationManager* manager, size_t class_def_index)
LOCKS_EXCLUDED(Locks::mutator_lock_) {
ATRACE_CALL();
@@ -2251,33 +1744,49 @@
manager->GetClassLinker()->EnsureInitialized(klass, false, true);
if (!klass->IsInitialized()) {
// We need to initialize static fields, we only do this for image classes that aren't
- // black listed or marked with the $NoPreloadHolder.
+ // marked with the $NoPreloadHolder (which implies this should not be initialized early).
bool can_init_static_fields = manager->GetCompiler()->IsImage() &&
- manager->GetCompiler()->IsImageClass(descriptor);
+ manager->GetCompiler()->IsImageClass(descriptor) &&
+ !StringPiece(descriptor).ends_with("$NoPreloadHolder;");
if (can_init_static_fields) {
- // NoPreloadHolder inner class implies this should not be initialized early.
- bool is_black_listed = StringPiece(descriptor).ends_with("$NoPreloadHolder;");
- if (!is_black_listed) {
- for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) {
- if (strcmp(descriptor, class_initializer_black_list[i]) == 0) {
- is_black_listed = true;
- break;
- }
+ VLOG(compiler) << "Initializing: " << descriptor;
+ if (strcmp("Ljava/lang/Void;", descriptor) == 0) {
+ // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
+ ObjectLock<mirror::Class> lock(soa.Self(), &klass);
+ mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
+ CHECK_EQ(fields->GetLength(), 1);
+ fields->Get(0)->SetObj<false>(klass.get(),
+ manager->GetClassLinker()->FindPrimitiveClass('V'));
+ klass->SetStatus(mirror::Class::kStatusInitialized, soa.Self());
+ } else {
+ // TODO multithreading support. We should ensure the current compilation thread has
+ // exclusive access to the runtime and the transaction. To achieve this, we could use
+ // a ReaderWriterMutex but we're holding the mutator lock so we fail mutex sanity
+ // checks in Thread::AssertThreadSuspensionIsAllowable.
+ Runtime* const runtime = Runtime::Current();
+ Transaction transaction;
+
+ // Run the class initializer in transaction mode.
+ runtime->EnterTransactionMode(&transaction);
+ const mirror::Class::Status old_status = klass->GetStatus();
+ bool success = manager->GetClassLinker()->EnsureInitialized(klass, true, true);
+ // TODO we detach transaction from runtime to indicate we quit the transactional
+ // mode which prevents the GC from visiting objects modified during the transaction.
+ // Ensure GC is not run so don't access freed objects when aborting transaction.
+ const char* old_casue = soa.Self()->StartAssertNoThreadSuspension("Transaction end");
+ runtime->ExitTransactionMode();
+
+ if (!success) {
+ CHECK(soa.Self()->IsExceptionPending());
+ ThrowLocation throw_location;
+ mirror::Throwable* exception = soa.Self()->GetException(&throw_location);
+ VLOG(compiler) << "Initialization of " << descriptor << " aborted because of "
+ << exception->Dump();
+ soa.Self()->ClearException();
+ transaction.Abort();
+ CHECK_EQ(old_status, klass->GetStatus()) << "Previous class status not restored";
}
- }
- if (!is_black_listed) {
- VLOG(compiler) << "Initializing: " << descriptor;
- if (strcmp("Ljava/lang/Void;", descriptor) == 0) {
- // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
- ObjectLock<mirror::Class> lock(soa.Self(), &klass);
- mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
- CHECK_EQ(fields->GetLength(), 1);
- fields->Get(0)->SetObj(klass.get(),
- manager->GetClassLinker()->FindPrimitiveClass('V'));
- klass->SetStatus(mirror::Class::kStatusInitialized, soa.Self());
- } else {
- manager->GetClassLinker()->EnsureInitialized(klass, true, true);
- }
+ soa.Self()->EndAssertNoThreadSuspension(old_casue);
}
}
}
@@ -2295,18 +1804,20 @@
void CompilerDriver::InitializeClasses(jobject jni_class_loader, const DexFile& dex_file,
ThreadPool& thread_pool, TimingLogger& timings) {
timings.NewSplit("InitializeNoClinit");
-#ifndef NDEBUG
- // Sanity check blacklist descriptors.
- if (IsImage()) {
- for (size_t i = 0; i < arraysize(class_initializer_black_list); ++i) {
- const char* descriptor = class_initializer_black_list[i];
- CHECK(IsValidDescriptor(descriptor)) << descriptor;
- }
- }
-#endif
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
ParallelCompilationManager context(class_linker, jni_class_loader, this, &dex_file, thread_pool);
- context.ForAll(0, dex_file.NumClassDefs(), InitializeClass, thread_count_);
+ size_t thread_count;
+ if (IsImage()) {
+ // TODO: remove this when transactional mode supports multithreading.
+ thread_count = 1U;
+ } else {
+ thread_count = thread_count_;
+ }
+ context.ForAll(0, dex_file.NumClassDefs(), InitializeClass, thread_count);
+ if (IsImage()) {
+ // Prune garbage objects created during aborted transactions.
+ Runtime::Current()->GetHeap()->CollectGarbage(true);
+ }
}
void CompilerDriver::InitializeClasses(jobject class_loader,
@@ -2417,7 +1928,7 @@
uint64_t start_ns = NanoTime();
if ((access_flags & kAccNative) != 0) {
- compiled_method = (*jni_compiler_)(*this, access_flags, method_idx, dex_file);
+ compiled_method = compiler_backend_->JniCompile(*this, access_flags, method_idx, dex_file);
CHECK(compiled_method != NULL);
} else if ((access_flags & kAccAbstract) != 0) {
} else {
@@ -2425,19 +1936,10 @@
bool compile = VerificationResults::IsCandidateForCompilation(method_ref, access_flags);
if (compile) {
- CompilerFn compiler = compiler_;
-#ifdef ART_SEA_IR_MODE
- bool use_sea = Runtime::Current()->IsSeaIRMode();
- use_sea = use_sea &&
- (std::string::npos != PrettyMethod(method_idx, dex_file).find("fibonacci"));
- if (use_sea) {
- compiler = sea_ir_compiler_;
- LOG(INFO) << "Using SEA IR to compile..." << std::endl;
- }
-#endif
// NOTE: if compiler declines to compile this method, it will return NULL.
- compiled_method = (*compiler)(*this, code_item, access_flags, invoke_type, class_def_idx,
- method_idx, class_loader, dex_file);
+ compiled_method = compiler_backend_->Compile(
+ *this, code_item, access_flags, invoke_type, class_def_idx,
+ method_idx, class_loader, dex_file);
} else if (dex_to_dex_compilation_level != kDontDexToDexCompile) {
// TODO: add a mode to disable DEX-to-DEX compilation ?
(*dex_to_dex_compiler_)(*this, code_item, access_flags,
@@ -2447,12 +1949,7 @@
}
}
uint64_t duration_ns = NanoTime() - start_ns;
-#ifdef ART_USE_PORTABLE_COMPILER
- const uint64_t kWarnMilliSeconds = 1000;
-#else
- const uint64_t kWarnMilliSeconds = 100;
-#endif
- if (duration_ns > MsToNs(kWarnMilliSeconds)) {
+ if (duration_ns > MsToNs(compiler_backend_->GetMaximumCompilationTimeBeforeWarning())) {
LOG(WARNING) << "Compilation of " << PrettyMethod(method_idx, dex_file)
<< " took " << PrettyDuration(duration_ns);
}
@@ -2549,11 +2046,7 @@
OatWriter& oat_writer,
art::File* file)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-#if defined(ART_USE_PORTABLE_COMPILER)
- return art::ElfWriterMclinker::Create(file, oat_writer, dex_files, android_root, is_host, *this);
-#else
- return art::ElfWriterQuick::Create(file, oat_writer, dex_files, android_root, is_host, *this);
-#endif
+ return compiler_backend_->WriteElf(file, oat_writer, dex_files, android_root, is_host, *this);
}
void CompilerDriver::InstructionSetToLLVMTarget(InstructionSet instruction_set,
std::string& target_triple,
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index c4ac9db..a9e029d 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -26,6 +26,7 @@
#include "class_reference.h"
#include "compiled_class.h"
#include "compiled_method.h"
+#include "compiler_backend.h"
#include "dex_file.h"
#include "dex/arena_allocator.h"
#include "instruction_set.h"
@@ -44,21 +45,15 @@
} // namespace verifier
class AOTCompilationStats;
-class ParallelCompilationManager;
class DexCompilationUnit;
class DexFileToMethodInlinerMap;
class InlineIGetIPutData;
class OatWriter;
+class ParallelCompilationManager;
class TimingLogger;
class VerificationResults;
class VerifiedMethod;
-enum CompilerBackend {
- kQuick,
- kPortable,
- kNoBackend
-};
-
enum EntryPointCallingConvention {
// ABI of invocations to a method's interpreter entry point.
kInterpreterAbi,
@@ -101,7 +96,8 @@
// classes.
explicit CompilerDriver(VerificationResults* verification_results,
DexFileToMethodInlinerMap* method_inliner_map,
- CompilerBackend compiler_backend, InstructionSet instruction_set,
+ CompilerBackend::Kind compiler_backend_kind,
+ InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
bool image, DescriptorSet* image_classes,
size_t thread_count, bool dump_stats, bool dump_passes,
@@ -133,8 +129,8 @@
return instruction_set_features_;
}
- CompilerBackend GetCompilerBackend() const {
- return compiler_backend_;
+ CompilerBackend* GetCompilerBackend() const {
+ return compiler_backend_.get();
}
// Are we compiling and creating an image file?
@@ -560,7 +556,7 @@
VerificationResults* verification_results_;
DexFileToMethodInlinerMap* method_inliner_map_;
- CompilerBackend compiler_backend_;
+ UniquePtr<CompilerBackend> compiler_backend_;
const InstructionSet instruction_set_;
const InstructionSetFeatures instruction_set_features_;
@@ -601,32 +597,16 @@
void* compiler_library_;
- typedef CompiledMethod* (*CompilerFn)(CompilerDriver& driver,
- const DexFile::CodeItem* code_item,
- uint32_t access_flags, InvokeType invoke_type,
- uint32_t class_dex_idx, uint32_t method_idx,
- jobject class_loader, const DexFile& dex_file);
-
typedef void (*DexToDexCompilerFn)(CompilerDriver& driver,
const DexFile::CodeItem* code_item,
uint32_t access_flags, InvokeType invoke_type,
uint32_t class_dex_idx, uint32_t method_idx,
jobject class_loader, const DexFile& dex_file,
DexToDexCompilationLevel dex_to_dex_compilation_level);
- CompilerFn compiler_;
-#ifdef ART_SEA_IR_MODE
- CompilerFn sea_ir_compiler_;
-#endif
-
DexToDexCompilerFn dex_to_dex_compiler_;
void* compiler_context_;
- typedef CompiledMethod* (*JniCompilerFn)(CompilerDriver& driver,
- uint32_t access_flags, uint32_t method_idx,
- const DexFile& dex_file);
- JniCompilerFn jni_compiler_;
-
pthread_key_t tls_key_;
// Arena pool used by the compiler.
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index e5dfb9d..60beebb 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -408,25 +408,25 @@
class_linker->GetDexCaches().size());
int i = 0;
for (DexCache* dex_cache : class_linker->GetDexCaches()) {
- dex_caches->Set(i++, dex_cache);
+ dex_caches->Set<false>(i++, dex_cache);
}
// build an Object[] of the roots needed to restore the runtime
SirtRef<ObjectArray<Object> > image_roots(
self, ObjectArray<Object>::Alloc(self, object_array_class.get(), ImageHeader::kImageRootsMax));
- image_roots->Set(ImageHeader::kResolutionMethod, runtime->GetResolutionMethod());
- image_roots->Set(ImageHeader::kImtConflictMethod, runtime->GetImtConflictMethod());
- image_roots->Set(ImageHeader::kDefaultImt, runtime->GetDefaultImt());
- image_roots->Set(ImageHeader::kCalleeSaveMethod,
- runtime->GetCalleeSaveMethod(Runtime::kSaveAll));
- image_roots->Set(ImageHeader::kRefsOnlySaveMethod,
- runtime->GetCalleeSaveMethod(Runtime::kRefsOnly));
- image_roots->Set(ImageHeader::kRefsAndArgsSaveMethod,
- runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
- image_roots->Set(ImageHeader::kOatLocation,
- String::AllocFromModifiedUtf8(self, oat_file_->GetLocation().c_str()));
- image_roots->Set(ImageHeader::kDexCaches, dex_caches);
- image_roots->Set(ImageHeader::kClassRoots, class_linker->GetClassRoots());
+ image_roots->Set<false>(ImageHeader::kResolutionMethod, runtime->GetResolutionMethod());
+ image_roots->Set<false>(ImageHeader::kImtConflictMethod, runtime->GetImtConflictMethod());
+ image_roots->Set<false>(ImageHeader::kDefaultImt, runtime->GetDefaultImt());
+ image_roots->Set<false>(ImageHeader::kCalleeSaveMethod,
+ runtime->GetCalleeSaveMethod(Runtime::kSaveAll));
+ image_roots->Set<false>(ImageHeader::kRefsOnlySaveMethod,
+ runtime->GetCalleeSaveMethod(Runtime::kRefsOnly));
+ image_roots->Set<false>(ImageHeader::kRefsAndArgsSaveMethod,
+ runtime->GetCalleeSaveMethod(Runtime::kRefsAndArgs));
+ image_roots->Set<false>(ImageHeader::kOatLocation,
+ String::AllocFromModifiedUtf8(self, oat_file_->GetLocation().c_str()));
+ image_roots->Set<false>(ImageHeader::kDexCaches, dex_caches);
+ image_roots->Set<false>(ImageHeader::kClassRoots, class_linker->GetClassRoots());
for (int i = 0; i < ImageHeader::kImageRootsMax; i++) {
CHECK(image_roots->Get(i) != NULL);
}
@@ -663,7 +663,7 @@
void ImageWriter::FixupObjectArray(ObjectArray<Object>* orig, ObjectArray<Object>* copy) {
for (int32_t i = 0; i < orig->GetLength(); ++i) {
Object* element = orig->Get(i);
- copy->SetWithoutChecksAndWriteBarrier(i, GetImageAddress(element));
+ copy->SetWithoutChecksAndWriteBarrier<false>(i, GetImageAddress(element));
}
}
@@ -693,7 +693,7 @@
Object* ref = orig->GetFieldObject<Object>(byte_offset, false);
// Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
// image.
- copy->SetFieldObjectWithoutWriteBarrier(byte_offset, GetImageAddress(ref), false);
+ copy->SetFieldObjectWithoutWriteBarrier<false>(byte_offset, GetImageAddress(ref), false);
ref_offsets &= ~(CLASS_HIGH_BIT >> right_shift);
}
} else {
@@ -715,7 +715,7 @@
Object* ref = orig->GetFieldObject<Object>(field_offset, false);
// Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
// image.
- copy->SetFieldObjectWithoutWriteBarrier(field_offset, GetImageAddress(ref), false);
+ copy->SetFieldObjectWithoutWriteBarrier<false>(field_offset, GetImageAddress(ref), false);
}
}
}
@@ -726,7 +726,7 @@
Object* ref = orig->GetFieldObject<Object>(field_offset, false);
// Use SetFieldObjectWithoutWriteBarrier to avoid card marking since we are writing to the
// image.
- copy->SetFieldObjectWithoutWriteBarrier(field_offset, GetImageAddress(ref), false);
+ copy->SetFieldObjectWithoutWriteBarrier<false>(field_offset, GetImageAddress(ref), false);
}
}
diff --git a/compiler/llvm/compiler_llvm.cc b/compiler/llvm/compiler_llvm.cc
index 6563eb5..a5acd2a 100644
--- a/compiler/llvm/compiler_llvm.cc
+++ b/compiler/llvm/compiler_llvm.cc
@@ -39,12 +39,12 @@
namespace art {
void CompileOneMethod(CompilerDriver& driver,
- const CompilerBackend compilerBackend,
+ CompilerBackend* compilerBackend,
const DexFile::CodeItem* code_item,
uint32_t access_flags, InvokeType invoke_type,
uint16_t class_def_idx, uint32_t method_idx, jobject class_loader,
const DexFile& dex_file,
- llvm::LlvmCompilationUnit* llvm_info);
+ void* llvm_info);
}
namespace llvm {
@@ -142,7 +142,7 @@
cunit->SetCompilerDriver(compiler_driver_);
// TODO: consolidate ArtCompileMethods
CompileOneMethod(*compiler_driver_,
- kPortable,
+ compiler_driver_->GetCompilerBackend(),
dex_compilation_unit->GetCodeItem(),
dex_compilation_unit->GetAccessFlags(),
invoke_type,
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index f6b511c..10d2c5c 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -15,6 +15,7 @@
*/
#include "compiler/oat_writer.h"
+#include "compiler/compiler_backend.h"
#include "mirror/art_method-inl.h"
#include "mirror/class-inl.h"
#include "mirror/object_array-inl.h"
@@ -84,12 +85,14 @@
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
// TODO: make selectable.
- CompilerBackend compiler_backend = kUsePortableCompiler ? kPortable : kQuick;
+ CompilerBackend::Kind compiler_backend = kUsePortableCompiler
+ ? CompilerBackend::kPortable
+ : CompilerBackend::kQuick;
InstructionSet insn_set = kIsTargetBuild ? kThumb2 : kX86;
InstructionSetFeatures insn_features;
verification_results_.reset(new VerificationResults);
- method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr);
+ method_inliner_map_.reset(new DexFileToMethodInlinerMap);
callbacks_.Reset(verification_results_.get(), method_inliner_map_.get());
timer_.reset(new CumulativeLogger("Compilation times"));
compiler_driver_.reset(new CompilerDriver(verification_results_.get(),
diff --git a/compiler/sea_ir/frontend.cc b/compiler/sea_ir/frontend.cc
index 6c779c8..b57007b 100644
--- a/compiler/sea_ir/frontend.cc
+++ b/compiler/sea_ir/frontend.cc
@@ -38,15 +38,12 @@
namespace art {
static CompiledMethod* CompileMethodWithSeaIr(CompilerDriver& compiler,
- const CompilerBackend compiler_backend,
+ CompilerBackend* compiler_backend,
const DexFile::CodeItem* code_item,
uint32_t method_access_flags, InvokeType invoke_type,
uint16_t class_def_idx, uint32_t method_idx,
- jobject class_loader, const DexFile& dex_file
-#if defined(ART_USE_PORTABLE_COMPILER)
- , llvm::LlvmCompilationUnit* llvm_compilation_unit
-#endif
-) {
+ jobject class_loader, const DexFile& dex_file,
+ void* llvm_compilation_unit) {
LOG(INFO) << "Compiling " << PrettyMethod(method_idx, dex_file) << ".";
sea_ir::SeaGraph* ir_graph = sea_ir::SeaGraph::GetGraph(dex_file);
std::string symbol = "dex_" + MangleForJni(PrettyMethod(method_idx, dex_file));
@@ -65,7 +62,7 @@
}
CompiledMethod* SeaIrCompileOneMethod(CompilerDriver& compiler,
- const CompilerBackend backend,
+ CompilerBackend* backend,
const DexFile::CodeItem* code_item,
uint32_t method_access_flags,
InvokeType invoke_type,
@@ -73,13 +70,9 @@
uint32_t method_idx,
jobject class_loader,
const DexFile& dex_file,
- llvm::LlvmCompilationUnit* llvm_compilation_unit) {
+ void* llvm_compilation_unit) {
return CompileMethodWithSeaIr(compiler, backend, code_item, method_access_flags, invoke_type,
- class_def_idx, method_idx, class_loader, dex_file
-#if defined(ART_USE_PORTABLE_COMPILER)
- , llvm_compilation_unit
-#endif
- ); // NOLINT
+ class_def_idx, method_idx, class_loader, dex_file, llvm_compilation_unit);
}
extern "C" art::CompiledMethod*
@@ -90,7 +83,7 @@
const art::DexFile& dex_file) {
// TODO: Check method fingerprint here to determine appropriate backend type.
// Until then, use build default
- art::CompilerBackend backend = compiler.GetCompilerBackend();
+ art::CompilerBackend* backend = compiler.GetCompilerBackend();
return art::SeaIrCompileOneMethod(compiler, backend, code_item, method_access_flags, invoke_type,
class_def_idx, method_idx, class_loader, dex_file,
NULL /* use thread llvm_info */);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 98c64aa..7f88471 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -30,6 +30,7 @@
#include "base/timing_logger.h"
#include "base/unix_file/fd_file.h"
#include "class_linker.h"
+#include "compiler_backend.h"
#include "compiler_callbacks.h"
#include "dex_file-inl.h"
#include "dex/verification_results.h"
@@ -163,7 +164,7 @@
public:
static bool Create(Dex2Oat** p_dex2oat,
Runtime::Options& options,
- CompilerBackend compiler_backend,
+ CompilerBackend::Kind compiler_backend,
InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
size_t thread_count)
@@ -286,7 +287,7 @@
dump_passes,
&compiler_phases_timings));
- if (compiler_backend_ == kPortable) {
+ if (compiler_backend_ == CompilerBackend::kPortable) {
driver->SetBitcodeFileName(bitcode_filename);
}
@@ -365,7 +366,7 @@
virtual bool MethodVerified(verifier::MethodVerifier* verifier)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
bool result = verification_results_->ProcessVerifiedMethod(verifier);
- if (result && method_inliner_map_ != nullptr) {
+ if (result) {
MethodReference ref = verifier->GetMethodReference();
method_inliner_map_->GetMethodInliner(ref.dex_file)
->AnalyseMethodCode(verifier);
@@ -381,7 +382,7 @@
DexFileToMethodInlinerMap* method_inliner_map_;
};
- explicit Dex2Oat(CompilerBackend compiler_backend,
+ explicit Dex2Oat(CompilerBackend::Kind compiler_backend,
InstructionSet instruction_set,
InstructionSetFeatures instruction_set_features,
size_t thread_count)
@@ -389,7 +390,7 @@
instruction_set_(instruction_set),
instruction_set_features_(instruction_set_features),
verification_results_(new VerificationResults),
- method_inliner_map_(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr),
+ method_inliner_map_(new DexFileToMethodInlinerMap),
callbacks_(verification_results_.get(), method_inliner_map_.get()),
runtime_(nullptr),
thread_count_(thread_count),
@@ -449,7 +450,7 @@
return false;
}
- const CompilerBackend compiler_backend_;
+ const CompilerBackend::Kind compiler_backend_;
const InstructionSet instruction_set_;
const InstructionSetFeatures instruction_set_features_;
@@ -688,7 +689,9 @@
std::string android_root;
std::vector<const char*> runtime_args;
int thread_count = sysconf(_SC_NPROCESSORS_CONF);
- CompilerBackend compiler_backend = kUsePortableCompiler ? kPortable : kQuick;
+ CompilerBackend::Kind compiler_backend = kUsePortableCompiler
+ ? CompilerBackend::kPortable
+ : CompilerBackend::kQuick;
// Take the default set of instruction features from the build.
InstructionSetFeatures instruction_set_features =
@@ -788,9 +791,9 @@
} else if (option.starts_with("--compiler-backend=")) {
StringPiece backend_str = option.substr(strlen("--compiler-backend=")).data();
if (backend_str == "Quick") {
- compiler_backend = kQuick;
+ compiler_backend = CompilerBackend::kQuick;
} else if (backend_str == "Portable") {
- compiler_backend = kPortable;
+ compiler_backend = CompilerBackend::kPortable;
}
} else if (option == "--host") {
is_host = true;
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 223ae7c..b6b4ff9 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -136,6 +136,7 @@
thread_pool.cc \
throw_location.cc \
trace.cc \
+ transaction.cc \
profiler.cc \
utf.cc \
utils.cc \
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index fac1e14..3863ee5 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2832,8 +2832,8 @@
return nullptr;
}
- interfaces_sfield->SetObject(klass.get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
- throws_sfield->SetObject(klass.get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
+ interfaces_sfield->SetObject<false>(klass.get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
+ throws_sfield->SetObject<false>(klass.get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
klass->SetStatus(mirror::Class::kStatusInitialized, self);
}
@@ -3144,7 +3144,11 @@
SafeMap<uint32_t, mirror::ArtField*> field_map;
ConstructFieldMap(dex_file, *dex_class_def, klass.get(), field_map);
for (size_t i = 0; it.HasNext(); i++, it.Next()) {
- it.ReadValueToField(field_map.Get(i));
+ if (Runtime::Current()->IsActiveTransaction()) {
+ it.ReadValueToField<true>(field_map.Get(i));
+ } else {
+ it.ReadValueToField<false>(field_map.Get(i));
+ }
}
}
}
@@ -3530,7 +3534,7 @@
super_mh.GetDeclaringClassDescriptor());
return false;
}
- vtable->Set(j, local_method);
+ vtable->Set<false>(j, local_method);
local_method->SetMethodIndex(j);
break;
} else {
@@ -3542,7 +3546,7 @@
}
if (j == actual_count) {
// Not overriding, append.
- vtable->Set(actual_count, local_method);
+ vtable->Set<false>(actual_count, local_method);
local_method->SetMethodIndex(actual_count);
actual_count += 1;
}
@@ -3576,7 +3580,7 @@
}
for (size_t i = 0; i < num_virtual_methods; ++i) {
mirror::ArtMethod* virtual_method = klass->GetVirtualMethodDuringLinking(i);
- vtable->Set(i, virtual_method);
+ vtable->Set<false>(i, virtual_method);
virtual_method->SetMethodIndex(i & 0xFFFF);
}
klass->SetVTable(vtable.get());
@@ -3745,14 +3749,14 @@
PrettyMethod(interface_method).c_str());
return false;
}
- method_array->Set(j, vtable_method);
+ method_array->Set<false>(j, vtable_method);
// Place method in imt if entry is empty, place conflict otherwise.
uint32_t imt_index = interface_method->GetDexMethodIndex() % kImtSize;
if (imtable->Get(imt_index) == NULL) {
- imtable->Set(imt_index, vtable_method);
+ imtable->Set<false>(imt_index, vtable_method);
imtable_changed = true;
} else {
- imtable->Set(imt_index, Runtime::Current()->GetImtConflictMethod());
+ imtable->Set<false>(imt_index, Runtime::Current()->GetImtConflictMethod());
}
break;
}
@@ -3777,7 +3781,7 @@
// TODO: If a methods move then the miranda_list may hold stale references.
miranda_list.push_back(miranda_method.get());
}
- method_array->Set(j, miranda_method.get());
+ method_array->Set<false>(j, miranda_method.get());
}
}
}
@@ -3787,7 +3791,7 @@
mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod();
for (size_t i = 0; i < kImtSize; i++) {
if (imtable->Get(i) == NULL) {
- imtable->Set(i, imt_conflict_method);
+ imtable->Set<false>(i, imt_conflict_method);
}
}
klass->SetImTable(imtable.get());
@@ -3823,7 +3827,7 @@
method->SetAccessFlags(method->GetAccessFlags() | kAccMiranda);
method->SetMethodIndex(0xFFFF & (old_vtable_count + i));
klass->SetVirtualMethod(old_method_count + i, method);
- vtable->Set(old_vtable_count + i, method);
+ vtable->Set<false>(old_vtable_count + i, method);
}
// TODO: do not assign to the vtable field until it is fully constructed.
klass->SetVTable(vtable.get());
@@ -3929,7 +3933,7 @@
}
grouped_and_sorted_fields.pop_front();
num_reference_fields++;
- fields->Set(current_field, field);
+ fields->Set<false>(current_field, field);
field->SetOffset(field_offset);
field_offset = MemberOffset(field_offset.Uint32Value() + sizeof(uint32_t));
}
@@ -3946,7 +3950,7 @@
if (type == Primitive::kPrimLong || type == Primitive::kPrimDouble) {
continue;
}
- fields->Set(current_field++, field);
+ fields->Set<false>(current_field++, field);
field->SetOffset(field_offset);
// drop the consumed field
grouped_and_sorted_fields.erase(grouped_and_sorted_fields.begin() + i);
@@ -3965,7 +3969,7 @@
FieldHelper fh(field);
Primitive::Type type = fh.GetTypeAsPrimitiveType();
CHECK(type != Primitive::kPrimNot); // should only be working on primitive types
- fields->Set(current_field, field);
+ fields->Set<false>(current_field, field);
field->SetOffset(field_offset);
field_offset = MemberOffset(field_offset.Uint32Value() +
((type == Primitive::kPrimLong || type == Primitive::kPrimDouble)
@@ -4418,7 +4422,7 @@
DCHECK(class_roots_ != NULL);
DCHECK(class_roots_->Get(class_root) == NULL);
- class_roots_->Set(class_root, klass);
+ class_roots_->Set<false>(class_root, klass);
}
} // namespace art
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index d9ef0c1..28ed6c4 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -867,55 +867,56 @@
EXPECT_STREQ(ClassHelper(s0->GetClass()).GetDescriptor(), "Ljava/lang/reflect/ArtField;");
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimBoolean);
EXPECT_EQ(true, s0->GetBoolean(statics.get()));
- s0->SetBoolean(statics.get(), false);
+ s0->SetBoolean<false>(statics.get(), false);
mirror::ArtField* s1 = statics->FindStaticField("s1", "B");
fh.ChangeField(s1);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimByte);
EXPECT_EQ(5, s1->GetByte(statics.get()));
- s1->SetByte(statics.get(), 6);
+ s1->SetByte<false>(statics.get(), 6);
mirror::ArtField* s2 = statics->FindStaticField("s2", "C");
fh.ChangeField(s2);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimChar);
EXPECT_EQ('a', s2->GetChar(statics.get()));
- s2->SetChar(statics.get(), 'b');
+ s2->SetChar<false>(statics.get(), 'b');
mirror::ArtField* s3 = statics->FindStaticField("s3", "S");
fh.ChangeField(s3);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimShort);
EXPECT_EQ(-536, s3->GetShort(statics.get()));
- s3->SetShort(statics.get(), -535);
+ s3->SetShort<false>(statics.get(), -535);
mirror::ArtField* s4 = statics->FindStaticField("s4", "I");
fh.ChangeField(s4);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimInt);
EXPECT_EQ(2000000000, s4->GetInt(statics.get()));
- s4->SetInt(statics.get(), 2000000001);
+ s4->SetInt<false>(statics.get(), 2000000001);
mirror::ArtField* s5 = statics->FindStaticField("s5", "J");
fh.ChangeField(s5);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimLong);
EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(statics.get()));
- s5->SetLong(statics.get(), 0x34567890abcdef12LL);
+ s5->SetLong<false>(statics.get(), 0x34567890abcdef12LL);
mirror::ArtField* s6 = statics->FindStaticField("s6", "F");
fh.ChangeField(s6);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimFloat);
EXPECT_EQ(0.5, s6->GetFloat(statics.get()));
- s6->SetFloat(statics.get(), 0.75);
+ s6->SetFloat<false>(statics.get(), 0.75);
mirror::ArtField* s7 = statics->FindStaticField("s7", "D");
fh.ChangeField(s7);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimDouble);
EXPECT_EQ(16777217, s7->GetDouble(statics.get()));
- s7->SetDouble(statics.get(), 16777219);
+ s7->SetDouble<false>(statics.get(), 16777219);
mirror::ArtField* s8 = statics->FindStaticField("s8", "Ljava/lang/String;");
fh.ChangeField(s8);
EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimNot);
EXPECT_TRUE(s8->GetObject(statics.get())->AsString()->Equals("android"));
- s8->SetObject(s8->GetDeclaringClass(), mirror::String::AllocFromModifiedUtf8(soa.Self(), "robot"));
+ s8->SetObject<false>(s8->GetDeclaringClass(),
+ mirror::String::AllocFromModifiedUtf8(soa.Self(), "robot"));
// TODO: Remove EXPECT_FALSE when GCC can handle EXPECT_EQ
// http://code.google.com/p/googletest/issues/detail?id=322
diff --git a/runtime/common_test.h b/runtime/common_test.h
index f7859ea..a94cbfc 100644
--- a/runtime/common_test.h
+++ b/runtime/common_test.h
@@ -25,6 +25,7 @@
#include <fstream>
#include "../../external/icu4c/common/unicode/uvernum.h"
+#include "../compiler/compiler_backend.h"
#include "../compiler/dex/quick/dex_file_to_method_inliner_map.h"
#include "../compiler/dex/verification_results.h"
#include "../compiler/driver/compiler_driver.h"
@@ -439,10 +440,12 @@
std::string max_heap_string(StringPrintf("-Xmx%zdm", gc::Heap::kDefaultMaximumSize / MB));
// TODO: make selectable
- CompilerBackend compiler_backend = kUsePortableCompiler ? kPortable : kQuick;
+ CompilerBackend::Kind compiler_backend = kUsePortableCompiler
+ ? CompilerBackend::kPortable
+ : CompilerBackend::kQuick;
verification_results_.reset(new VerificationResults);
- method_inliner_map_.reset(compiler_backend == kQuick ? new DexFileToMethodInlinerMap : nullptr);
+ method_inliner_map_.reset(new DexFileToMethodInlinerMap);
callbacks_.Reset(verification_results_.get(), method_inliner_map_.get());
Runtime::Options options;
options.push_back(std::make_pair("compilercallbacks", static_cast<CompilerCallbacks*>(&callbacks_)));
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 733e843..20ad372 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -1149,7 +1149,7 @@
if (o == ObjectRegistry::kInvalidObject) {
return JDWP::ERR_INVALID_OBJECT;
}
- oa->Set(offset + i, o);
+ oa->Set<false>(offset + i, o);
}
}
@@ -1582,10 +1582,12 @@
if (IsPrimitiveTag(tag)) {
if (tag == JDWP::JT_DOUBLE || tag == JDWP::JT_LONG) {
CHECK_EQ(width, 8);
- f->Set64(o, value);
+ // Debugging can't use transactional mode (runtime only).
+ f->Set64<false>(o, value);
} else {
CHECK_LE(width, 4);
- f->Set32(o, value);
+ // Debugging can't use transactional mode (runtime only).
+ f->Set32<false>(o, value);
}
} else {
mirror::Object* v = gRegistry->Get<mirror::Object*>(value);
@@ -1598,7 +1600,8 @@
return JDWP::ERR_INVALID_OBJECT;
}
}
- f->SetObject(o, v);
+ // Debugging can't use transactional mode (runtime only).
+ f->SetObject<false>(o, v);
}
return JDWP::ERR_NONE;
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index eaba7eb..5e2b9ff 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -1082,33 +1082,36 @@
ptr_ += width;
}
+template<bool kTransactionActive>
void EncodedStaticFieldValueIterator::ReadValueToField(mirror::ArtField* field) const {
switch (type_) {
- case kBoolean: field->SetBoolean(field->GetDeclaringClass(), jval_.z); break;
- case kByte: field->SetByte(field->GetDeclaringClass(), jval_.b); break;
- case kShort: field->SetShort(field->GetDeclaringClass(), jval_.s); break;
- case kChar: field->SetChar(field->GetDeclaringClass(), jval_.c); break;
- case kInt: field->SetInt(field->GetDeclaringClass(), jval_.i); break;
- case kLong: field->SetLong(field->GetDeclaringClass(), jval_.j); break;
- case kFloat: field->SetFloat(field->GetDeclaringClass(), jval_.f); break;
- case kDouble: field->SetDouble(field->GetDeclaringClass(), jval_.d); break;
- case kNull: field->SetObject(field->GetDeclaringClass(), NULL); break;
+ case kBoolean: field->SetBoolean<kTransactionActive>(field->GetDeclaringClass(), jval_.z); break;
+ case kByte: field->SetByte<kTransactionActive>(field->GetDeclaringClass(), jval_.b); break;
+ case kShort: field->SetShort<kTransactionActive>(field->GetDeclaringClass(), jval_.s); break;
+ case kChar: field->SetChar<kTransactionActive>(field->GetDeclaringClass(), jval_.c); break;
+ case kInt: field->SetInt<kTransactionActive>(field->GetDeclaringClass(), jval_.i); break;
+ case kLong: field->SetLong<kTransactionActive>(field->GetDeclaringClass(), jval_.j); break;
+ case kFloat: field->SetFloat<kTransactionActive>(field->GetDeclaringClass(), jval_.f); break;
+ case kDouble: field->SetDouble<kTransactionActive>(field->GetDeclaringClass(), jval_.d); break;
+ case kNull: field->SetObject<kTransactionActive>(field->GetDeclaringClass(), NULL); break;
case kString: {
CHECK(!kMovingFields);
mirror::String* resolved = linker_->ResolveString(dex_file_, jval_.i, *dex_cache_);
- field->SetObject(field->GetDeclaringClass(), resolved);
+ field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
break;
}
case kType: {
CHECK(!kMovingFields);
mirror::Class* resolved = linker_->ResolveType(dex_file_, jval_.i, *dex_cache_,
*class_loader_);
- field->SetObject(field->GetDeclaringClass(), resolved);
+ field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
break;
}
default: UNIMPLEMENTED(FATAL) << ": type " << type_;
}
}
+template void EncodedStaticFieldValueIterator::ReadValueToField<true>(mirror::ArtField* field) const;
+template void EncodedStaticFieldValueIterator::ReadValueToField<false>(mirror::ArtField* field) const;
CatchHandlerIterator::CatchHandlerIterator(const DexFile::CodeItem& code_item, uint32_t address) {
handler_.address_ = -1;
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 46df455..e9d18b5 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -1142,6 +1142,7 @@
ClassLinker* linker, const DexFile::ClassDef& class_def)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void ReadValueToField(mirror::ArtField* field) const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
bool HasNext() { return pos_ < array_size_; }
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 4e58a72..4078cac 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -162,7 +162,7 @@
CHECK(soa.Self()->IsExceptionPending());
return zero;
}
- soa.Decode<mirror::ObjectArray<mirror::Object>* >(args_jobj)->Set(i, val);
+ soa.Decode<mirror::ObjectArray<mirror::Object>* >(args_jobj)->Set<false>(i, val);
}
}
}
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 20532f4..8b94b5a 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -136,6 +136,7 @@
gc::Heap* heap = Runtime::Current()->GetHeap();
return klass->Alloc<kInstrumented>(self, heap->GetCurrentAllocator());
}
+ DCHECK(klass != nullptr);
return klass->Alloc<kInstrumented>(self, allocator_type);
}
@@ -377,10 +378,11 @@
#undef EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL
template<InvokeType type, bool access_check>
-static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx, mirror::Object* this_object,
+static inline mirror::ArtMethod* FindMethodFromCode(uint32_t method_idx,
+ mirror::Object* this_object,
mirror::ArtMethod* referrer, Thread* self) {
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
- SirtRef<mirror::Object> sirt_this(self, this_object);
+ SirtRef<mirror::Object> sirt_this(self, type == kStatic ? nullptr : this_object);
mirror::ArtMethod* resolved_method = class_linker->ResolveMethod(method_idx, referrer, type);
if (UNLIKELY(resolved_method == nullptr)) {
DCHECK(self->IsExceptionPending()); // Throw exception and unwind.
diff --git a/runtime/entrypoints/portable/portable_field_entrypoints.cc b/runtime/entrypoints/portable/portable_field_entrypoints.cc
index 0b54b9c..f48f1a9 100644
--- a/runtime/entrypoints/portable/portable_field_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_field_entrypoints.cc
@@ -30,13 +30,15 @@
StaticPrimitiveWrite,
sizeof(uint32_t));
if (LIKELY(field != NULL)) {
- field->Set32(field->GetDeclaringClass(), new_value);
+ // Compiled code can't use transactional mode.
+ field->Set32<false>(field->GetDeclaringClass(), new_value);
return 0;
}
field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, Thread::Current(),
sizeof(uint32_t));
if (LIKELY(field != NULL)) {
- field->Set32(field->GetDeclaringClass(), new_value);
+ // Compiled code can't use transactional mode.
+ field->Set32<false>(field->GetDeclaringClass(), new_value);
return 0;
}
return -1;
@@ -48,13 +50,15 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite, sizeof(uint64_t));
if (LIKELY(field != NULL)) {
- field->Set64(field->GetDeclaringClass(), new_value);
+ // Compiled code can't use transactional mode.
+ field->Set64<false>(field->GetDeclaringClass(), new_value);
return 0;
}
field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, Thread::Current(),
sizeof(uint64_t));
if (LIKELY(field != NULL)) {
- field->Set64(field->GetDeclaringClass(), new_value);
+ // Compiled code can't use transactional mode.
+ field->Set64<false>(field->GetDeclaringClass(), new_value);
return 0;
}
return -1;
@@ -67,13 +71,15 @@
mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticObjectWrite,
sizeof(mirror::HeapReference<mirror::Object>));
if (LIKELY(field != NULL)) {
- field->SetObj(field->GetDeclaringClass(), new_value);
+ // Compiled code can't use transactional mode.
+ field->SetObj<false>(field->GetDeclaringClass(), new_value);
return 0;
}
field = FindFieldFromCode<StaticObjectWrite, true>(field_idx, referrer, Thread::Current(),
sizeof(mirror::HeapReference<mirror::Object>));
if (LIKELY(field != NULL)) {
- field->SetObj(field->GetDeclaringClass(), new_value);
+ // Compiled code can't use transactional mode.
+ field->SetObj<false>(field->GetDeclaringClass(), new_value);
return 0;
}
return -1;
@@ -131,13 +137,15 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint32_t));
if (LIKELY(field != NULL)) {
- field->Set32(obj, new_value);
+ // Compiled code can't use transactional mode.
+ field->Set32<false>(obj, new_value);
return 0;
}
field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, Thread::Current(),
sizeof(uint32_t));
if (LIKELY(field != NULL)) {
- field->Set32(obj, new_value);
+ // Compiled code can't use transactional mode.
+ field->Set32<false>(obj, new_value);
return 0;
}
return -1;
@@ -149,13 +157,15 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite, sizeof(uint64_t));
if (LIKELY(field != NULL)) {
- field->Set64(obj, new_value);
+ // Compiled code can't use transactional mode.
+ field->Set64<false>(obj, new_value);
return 0;
}
field = FindFieldFromCode<InstancePrimitiveWrite, true>(field_idx, referrer, Thread::Current(),
sizeof(uint64_t));
if (LIKELY(field != NULL)) {
- field->Set64(obj, new_value);
+ // Compiled code can't use transactional mode.
+ field->Set64<false>(obj, new_value);
return 0;
}
return -1;
@@ -169,13 +179,15 @@
mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
sizeof(mirror::HeapReference<mirror::Object>));
if (LIKELY(field != NULL)) {
- field->SetObj(obj, new_value);
+ // Compiled code can't use transactional mode.
+ field->SetObj<false>(obj, new_value);
return 0;
}
field = FindFieldFromCode<InstanceObjectWrite, true>(field_idx, referrer, Thread::Current(),
sizeof(mirror::HeapReference<mirror::Object>));
if (LIKELY(field != NULL)) {
- field->SetObj(obj, new_value);
+ // Compiled code can't use transactional mode.
+ field->SetObj<false>(obj, new_value);
return 0;
}
return -1;
diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc
index 93ff7aa..2d5c07d 100644
--- a/runtime/entrypoints/quick/quick_field_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc
@@ -154,13 +154,15 @@
mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite,
sizeof(int32_t));
if (LIKELY(field != NULL)) {
- field->Set32(field->GetDeclaringClass(), new_value);
+ // Compiled code can't use transactional mode.
+ field->Set32<false>(field->GetDeclaringClass(), new_value);
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int32_t));
if (LIKELY(field != NULL)) {
- field->Set32(field->GetDeclaringClass(), new_value);
+ // Compiled code can't use transactional mode.
+ field->Set32<false>(field->GetDeclaringClass(), new_value);
return 0; // success
}
return -1; // failure
@@ -172,13 +174,15 @@
mirror::ArtField* field = FindFieldFast(field_idx, referrer, StaticPrimitiveWrite,
sizeof(int64_t));
if (LIKELY(field != NULL)) {
- field->Set64(field->GetDeclaringClass(), new_value);
+ // Compiled code can't use transactional mode.
+ field->Set64<false>(field->GetDeclaringClass(), new_value);
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
field = FindFieldFromCode<StaticPrimitiveWrite, true>(field_idx, referrer, self, sizeof(int64_t));
if (LIKELY(field != NULL)) {
- field->Set64(field->GetDeclaringClass(), new_value);
+ // Compiled code can't use transactional mode.
+ field->Set64<false>(field->GetDeclaringClass(), new_value);
return 0; // success
}
return -1; // failure
@@ -192,7 +196,8 @@
sizeof(mirror::HeapReference<mirror::Object>));
if (LIKELY(field != NULL)) {
if (LIKELY(!FieldHelper(field).IsPrimitiveType())) {
- field->SetObj(field->GetDeclaringClass(), new_value);
+ // Compiled code can't use transactional mode.
+ field->SetObj<false>(field->GetDeclaringClass(), new_value);
return 0; // success
}
}
@@ -200,7 +205,8 @@
field = FindFieldFromCode<StaticObjectWrite, true>(field_idx, referrer, self,
sizeof(mirror::HeapReference<mirror::Object>));
if (LIKELY(field != NULL)) {
- field->SetObj(field->GetDeclaringClass(), new_value);
+ // Compiled code can't use transactional mode.
+ field->SetObj<false>(field->GetDeclaringClass(), new_value);
return 0; // success
}
return -1; // failure
@@ -213,7 +219,8 @@
mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
sizeof(int32_t));
if (LIKELY(field != NULL && obj != NULL)) {
- field->Set32(obj, new_value);
+ // Compiled code can't use transactional mode.
+ field->Set32<false>(obj, new_value);
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
@@ -224,7 +231,8 @@
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
ThrowNullPointerExceptionForFieldAccess(throw_location, field, false);
} else {
- field->Set32(obj, new_value);
+ // Compiled code can't use transactional mode.
+ field->Set32<false>(obj, new_value);
return 0; // success
}
}
@@ -240,7 +248,8 @@
mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstancePrimitiveWrite,
sizeof(int64_t));
if (LIKELY(field != NULL && obj != NULL)) {
- field->Set64(obj, new_value);
+ // Compiled code can't use transactional mode.
+ field->Set64<false>(obj, new_value);
return 0; // success
}
*sp = callee_save;
@@ -252,7 +261,8 @@
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
ThrowNullPointerExceptionForFieldAccess(throw_location, field, false);
} else {
- field->Set64(obj, new_value);
+ // Compiled code can't use transactional mode.
+ field->Set64<false>(obj, new_value);
return 0; // success
}
}
@@ -267,7 +277,8 @@
mirror::ArtField* field = FindFieldFast(field_idx, referrer, InstanceObjectWrite,
sizeof(mirror::HeapReference<mirror::Object>));
if (LIKELY(field != NULL && obj != NULL)) {
- field->SetObj(obj, new_value);
+ // Compiled code can't use transactional mode.
+ field->SetObj<false>(obj, new_value);
return 0; // success
}
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsOnly);
@@ -278,7 +289,8 @@
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
ThrowNullPointerExceptionForFieldAccess(throw_location, field, false);
} else {
- field->SetObj(obj, new_value);
+ // Compiled code can't use transactional mode.
+ field->SetObj<false>(obj, new_value);
return 0; // success
}
}
diff --git a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
index c081768..e024a90 100644
--- a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
@@ -147,8 +147,8 @@
uint64_t artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
mirror::ArtMethod* caller_method,
Thread* self, mirror::ArtMethod** sp) {
- mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method,
- access_check, type);
+ mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method, access_check,
+ type);
if (UNLIKELY(method == NULL)) {
FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
method = FindMethodFromCode<type, access_check>(method_idx, this_object, caller_method, self);
diff --git a/runtime/entrypoints/quick/quick_lock_entrypoints.cc b/runtime/entrypoints/quick/quick_lock_entrypoints.cc
index 540abb3..5bc7f4c 100644
--- a/runtime/entrypoints/quick/quick_lock_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_lock_entrypoints.cc
@@ -30,10 +30,8 @@
return -1; // Failure.
} else {
if (kIsDebugBuild) {
- // GC may move the obj, need Sirt for the following DCHECKs.
- SirtRef<mirror::Object> sirt_obj(self, obj);
- obj->MonitorEnter(self); // May block
- CHECK(self->HoldsLock(sirt_obj.get()));
+ obj = obj->MonitorEnter(self); // May block
+ CHECK(self->HoldsLock(obj));
CHECK(!self->IsExceptionPending());
} else {
obj->MonitorEnter(self); // May block
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index f9486c3..012dabb 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -558,7 +558,7 @@
// We came here because of sharpening. Ensure the dex cache is up-to-date on the method index
// of the sharpened method.
if (called->GetDexCacheResolvedMethods() == caller->GetDexCacheResolvedMethods()) {
- caller->GetDexCacheResolvedMethods()->Set(called->GetDexMethodIndex(), called);
+ caller->GetDexCacheResolvedMethods()->Set<false>(called->GetDexMethodIndex(), called);
} else {
// Calling from one dex file to another, need to compute the method index appropriate to
// the caller's dex file. Since we get here only if the original called was a runtime
@@ -567,7 +567,7 @@
uint32_t method_index =
MethodHelper(called).FindDexMethodIndexInOtherDexFile(*dex_file, dex_method_idx);
if (method_index != DexFile::kDexNoIndex) {
- caller->GetDexCacheResolvedMethods()->Set(method_index, called);
+ caller->GetDexCacheResolvedMethods()->Set<false>(method_index, called);
}
}
}
diff --git a/runtime/gc/accounting/atomic_stack.h b/runtime/gc/accounting/atomic_stack.h
index ea8f89c..d6f3228 100644
--- a/runtime/gc/accounting/atomic_stack.h
+++ b/runtime/gc/accounting/atomic_stack.h
@@ -73,6 +73,41 @@
return true;
}
+ // Atomically bump the back index by the given number of
+ // slots. Returns false if we overflowed the stack.
+ bool AtomicBumpBack(size_t num_slots, T** start_address, T** end_address) {
+ if (kIsDebugBuild) {
+ debug_is_sorted_ = false;
+ }
+ int32_t index;
+ int32_t new_index;
+ do {
+ index = back_index_;
+ new_index = index + num_slots;
+ if (UNLIKELY(static_cast<size_t>(new_index) >= capacity_)) {
+ // Stack overflow.
+ return false;
+ }
+ } while (!back_index_.CompareAndSwap(index, new_index));
+ *start_address = &begin_[index];
+ *end_address = &begin_[new_index];
+ if (kIsDebugBuild) {
+ // Sanity check that the memory is zero.
+ for (int32_t i = index; i < new_index; ++i) {
+ DCHECK_EQ(begin_[i], static_cast<T>(0)) << "i=" << i << " index=" << index << " new_index=" << new_index;
+ }
+ }
+ return true;
+ }
+
+ void AssertAllZero() {
+ if (kIsDebugBuild) {
+ for (size_t i = 0; i < capacity_; ++i) {
+ DCHECK_EQ(begin_[i], static_cast<T>(0)) << "i=" << i;
+ }
+ }
+ }
+
void PushBack(const T& value) {
if (kIsDebugBuild) {
debug_is_sorted_ = false;
diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc
index aad214a..6258070 100644
--- a/runtime/gc/accounting/mod_union_table.cc
+++ b/runtime/gc/accounting/mod_union_table.cc
@@ -84,7 +84,11 @@
if (new_ref != ref) {
// Use SetFieldObjectWithoutWriteBarrier to avoid card mark as an optimization which
// reduces dirtied pages and improves performance.
- obj->SetFieldObjectWithoutWriteBarrier(offset, new_ref, true);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ obj->SetFieldObjectWithoutWriteBarrier<true>(offset, new_ref, true);
+ } else {
+ obj->SetFieldObjectWithoutWriteBarrier<false>(offset, new_ref, true);
+ }
}
}
}
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index 65d4c441..d02b851 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -1560,7 +1560,8 @@
void RosAlloc::RevokeAllThreadLocalRuns() {
// This is called when a mutator thread won't allocate such as at
// the Zygote creation time or during the GC pause.
- MutexLock mu(Thread::Current(), *Locks::thread_list_lock_);
+ MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
+ MutexLock mu2(Thread::Current(), *Locks::thread_list_lock_);
std::list<Thread*> thread_list = Runtime::Current()->GetThreadList()->GetList();
for (auto it = thread_list.begin(); it != thread_list.end(); ++it) {
Thread* t = *it;
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index de9f59e..dbbc115 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -206,6 +206,10 @@
// This second sweep makes sure that we don't have any objects in the live stack which point to
// freed objects. These cause problems since their references may be previously freed objects.
SweepArray(GetHeap()->allocation_stack_.get(), false);
+ // Since SweepArray() above resets the (active) allocation
+ // stack. Need to revoke the thread-local allocation stacks that
+ // point into it.
+ GetHeap()->RevokeAllThreadLocalAllocationStacks(self);
}
timings_.StartSplit("PreSweepingGcVerification");
@@ -241,12 +245,15 @@
// Need to do this before the checkpoint since we don't want any threads to add references to
// the live stack during the recursive mark.
timings_.NewSplit("SwapStacks");
- heap_->SwapStacks();
+ heap_->SwapStacks(self);
WriterMutexLock mu(self, *Locks::heap_bitmap_lock_);
if (Locks::mutator_lock_->IsExclusiveHeld(self)) {
// If we exclusively hold the mutator lock, all threads must be suspended.
MarkRoots();
+ if (kUseThreadLocalAllocationStack) {
+ heap_->RevokeAllThreadLocalAllocationStacks(self);
+ }
} else {
MarkThreadRoots(self);
// At this point the live stack should no longer have any mutators which push into it.
@@ -995,6 +1002,9 @@
<< thread->GetState() << " thread " << thread << " self " << self;
thread->VisitRoots(MarkSweep::MarkRootParallelCallback, mark_sweep_);
ATRACE_END();
+ if (kUseThreadLocalAllocationStack) {
+ thread->RevokeThreadLocalAllocationStack();
+ }
mark_sweep_->GetBarrier().Pass(self);
}
@@ -1062,6 +1072,9 @@
Object** out = objects;
for (size_t i = 0; i < count; ++i) {
Object* obj = objects[i];
+ if (kUseThreadLocalAllocationStack && obj == nullptr) {
+ continue;
+ }
if (space->HasAddress(obj)) {
// This object is in the space, remove it from the array and add it to the sweep buffer
// if needed.
@@ -1100,6 +1113,9 @@
for (size_t i = 0; i < count; ++i) {
Object* obj = objects[i];
// Handle large objects.
+ if (kUseThreadLocalAllocationStack && obj == nullptr) {
+ continue;
+ }
if (!large_mark_objects->Test(obj)) {
++freed_large_objects;
freed_large_object_bytes += large_object_space->Free(self, obj);
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index ac33cc7..6d9496e 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -210,7 +210,10 @@
// Need to do this before the checkpoint since we don't want any threads to add references to
// the live stack during the recursive mark.
timings_.NewSplit("SwapStacks");
- heap_->SwapStacks();
+ if (kUseThreadLocalAllocationStack) {
+ heap_->RevokeAllThreadLocalAllocationStacks(self_);
+ }
+ heap_->SwapStacks(self_);
WriterMutexLock mu(self_, *Locks::heap_bitmap_lock_);
MarkRoots();
// Mark roots of immune spaces.
@@ -659,7 +662,9 @@
// Don't need to mark the card since we updating the object address and not changing the
// actual objects its pointing to. Using SetFieldObjectWithoutWriteBarrier is better in this
// case since it does not dirty cards and use additional memory.
- obj->SetFieldObjectWithoutWriteBarrier(offset, new_address, false);
+ // Since we do not change the actual object, we can safely use non-transactional mode. Also
+ // disable check as we could run inside a transaction.
+ obj->SetFieldObjectWithoutWriteBarrier<false, false>(offset, new_address, false);
}
}, kMovingClasses);
mirror::Class* klass = obj->GetClass();
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 5e1136b..9c91b0e 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -82,11 +82,7 @@
DCHECK(!Runtime::Current()->HasStatsEnabled());
}
if (AllocatorHasAllocationStack(allocator)) {
- // This is safe to do since the GC will never free objects which are neither in the allocation
- // stack or the live bitmap.
- while (!allocation_stack_->AtomicPushBack(obj)) {
- CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseForAlloc, false);
- }
+ PushOnAllocationStack(self, obj);
}
if (kInstrumented) {
if (Dbg::IsAllocTrackingEnabled()) {
@@ -111,6 +107,35 @@
return obj;
}
+// The size of a thread-local allocation stack in the number of references.
+static constexpr size_t kThreadLocalAllocationStackSize = 128;
+
+inline void Heap::PushOnAllocationStack(Thread* self, mirror::Object* obj) {
+ if (kUseThreadLocalAllocationStack) {
+ bool success = self->PushOnThreadLocalAllocationStack(obj);
+ if (UNLIKELY(!success)) {
+ // Slow path. Allocate a new thread-local allocation stack.
+ mirror::Object** start_address;
+ mirror::Object** end_address;
+ while (!allocation_stack_->AtomicBumpBack(kThreadLocalAllocationStackSize,
+ &start_address, &end_address)) {
+ CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseForAlloc, false);
+ }
+ self->SetThreadLocalAllocationStack(start_address, end_address);
+ // Retry on the new thread-local allocation stack.
+ success = self->PushOnThreadLocalAllocationStack(obj);
+ // Must succeed.
+ CHECK(success);
+ }
+ } else {
+ // This is safe to do since the GC will never free objects which are neither in the allocation
+ // stack or the live bitmap.
+ while (!allocation_stack_->AtomicPushBack(obj)) {
+ CollectGarbageInternal(collector::kGcTypeSticky, kGcCauseForAlloc, false);
+ }
+ }
+}
+
template <bool kInstrumented, typename PreFenceVisitor>
inline mirror::Object* Heap::AllocLargeObject(Thread* self, mirror::Class* klass,
size_t byte_count,
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 5c174f8..7613a31 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -383,7 +383,8 @@
mirror::Object* obj = *it;
if (obj != nullptr && obj->GetClass() != nullptr) {
// Avoid the race condition caused by the object not yet being written into the allocation
- // stack or the class not yet being written in the object.
+ // stack or the class not yet being written in the object. Or, if kUseThreadLocalAllocationStack,
+ // there can be nulls on the allocation stack.
callback(obj, arg);
}
}
@@ -1533,13 +1534,14 @@
mirror::Object** limit = stack->End();
for (mirror::Object** it = stack->Begin(); it != limit; ++it) {
const mirror::Object* obj = *it;
- DCHECK(obj != nullptr);
- if (bitmap1->HasAddress(obj)) {
- bitmap1->Set(obj);
- } else if (bitmap2->HasAddress(obj)) {
- bitmap2->Set(obj);
- } else {
- large_objects->Set(obj);
+ if (!kUseThreadLocalAllocationStack || obj != nullptr) {
+ if (bitmap1->HasAddress(obj)) {
+ bitmap1->Set(obj);
+ } else if (bitmap2->HasAddress(obj)) {
+ bitmap2->Set(obj);
+ } else {
+ large_objects->Set(obj);
+ }
}
}
}
@@ -2004,7 +2006,9 @@
// We can verify objects in the live stack since none of these should reference dead objects.
for (mirror::Object** it = live_stack_->Begin(); it != live_stack_->End(); ++it) {
- visitor(*it);
+ if (!kUseThreadLocalAllocationStack || *it != nullptr) {
+ visitor(*it);
+ }
}
if (visitor.Failed()) {
@@ -2014,10 +2018,30 @@
return true;
}
-void Heap::SwapStacks() {
+void Heap::SwapStacks(Thread* self) {
+ if (kUseThreadLocalAllocationStack) {
+ live_stack_->AssertAllZero();
+ }
allocation_stack_.swap(live_stack_);
}
+void Heap::RevokeAllThreadLocalAllocationStacks(Thread* self) {
+ if (!Runtime::Current()->IsStarted()) {
+ // There's no thread list if the runtime hasn't started (eg
+ // dex2oat or a test). Just revoke for self.
+ self->RevokeThreadLocalAllocationStack();
+ return;
+ }
+ // This must be called only during the pause.
+ CHECK(Locks::mutator_lock_->IsExclusiveHeld(self));
+ MutexLock mu(self, *Locks::runtime_shutdown_lock_);
+ MutexLock mu2(self, *Locks::thread_list_lock_);
+ std::list<Thread*> thread_list = Runtime::Current()->GetThreadList()->GetList();
+ for (Thread* t : thread_list) {
+ t->RevokeThreadLocalAllocationStack();
+ }
+}
+
accounting::ModUnionTable* Heap::FindModUnionTableFromSpace(space::Space* space) {
auto it = mod_union_tables_.find(space);
if (it == mod_union_tables_.end()) {
@@ -2072,12 +2096,12 @@
thread_list->SuspendAll();
{
ReaderMutexLock mu(self, *Locks::heap_bitmap_lock_);
- SwapStacks();
+ SwapStacks(self);
// Sort the live stack so that we can quickly binary search it later.
if (!VerifyMissingCardMarks()) {
LOG(FATAL) << "Pre " << gc->GetName() << " missing card mark verification failed";
}
- SwapStacks();
+ SwapStacks(self);
}
thread_list->ResumeAll();
}
@@ -2311,7 +2335,7 @@
void Heap::SetReferenceReferent(mirror::Object* reference, mirror::Object* referent) {
DCHECK(reference != NULL);
DCHECK_NE(reference_referent_offset_.Uint32Value(), 0U);
- reference->SetFieldObject(reference_referent_offset_, referent, true);
+ reference->SetFieldObject<false, false>(reference_referent_offset_, referent, true);
}
mirror::Object* Heap::GetReferenceReferent(mirror::Object* reference) {
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index e416c0e..80a5a1a 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -111,6 +111,9 @@
// If true, use rosalloc/RosAllocSpace instead of dlmalloc/DlMallocSpace
static constexpr bool kUseRosAlloc = true;
+// If true, use thread-local allocation stack.
+static constexpr bool kUseThreadLocalAllocationStack = true;
+
// The process state passed in from the activity manager, used to determine when to do trimming
// and compaction.
enum ProcessState {
@@ -665,11 +668,17 @@
SHARED_LOCKS_REQUIRED(GlobalSychronization::heap_bitmap_lock_);
// Swap the allocation stack with the live stack.
- void SwapStacks();
+ void SwapStacks(Thread* self);
+
+ // Revoke all the thread-local allocation stacks.
+ void RevokeAllThreadLocalAllocationStacks(Thread* self);
// Clear cards and update the mod union table.
void ProcessCards(TimingLogger& timings);
+ // Push an object onto the allocation stack.
+ void PushOnAllocationStack(Thread* self, mirror::Object* obj);
+
// All-known continuous spaces, where objects lie within fixed bounds.
std::vector<space::ContinuousSpace*> continuous_spaces_;
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index 8af2725..b02b8bb 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -50,7 +50,7 @@
for (size_t j = 0; j < 2048; ++j) {
mirror::String* string = mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!");
// SIRT operator -> deferences the SIRT before running the method.
- array->Set(j, string);
+ array->Set<false>(j, string);
}
}
}
diff --git a/runtime/gc/reference_queue.cc b/runtime/gc/reference_queue.cc
index fae4cac..203701f 100644
--- a/runtime/gc/reference_queue.cc
+++ b/runtime/gc/reference_queue.cc
@@ -49,12 +49,21 @@
DCHECK_NE(pending_next_offset.Uint32Value(), 0U);
if (IsEmpty()) {
// 1 element cyclic queue, ie: Reference ref = ..; ref.pendingNext = ref;
- ref->SetFieldObject(pending_next_offset, ref, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ ref->SetFieldObject<true>(pending_next_offset, ref, false);
+ } else {
+ ref->SetFieldObject<false>(pending_next_offset, ref, false);
+ }
list_ = ref;
} else {
mirror::Object* head = list_->GetFieldObject<mirror::Object>(pending_next_offset, false);
- ref->SetFieldObject(pending_next_offset, head, false);
- list_->SetFieldObject(pending_next_offset, ref, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ ref->SetFieldObject<true>(pending_next_offset, head, false);
+ list_->SetFieldObject<true>(pending_next_offset, ref, false);
+ } else {
+ ref->SetFieldObject<false>(pending_next_offset, head, false);
+ list_->SetFieldObject<false>(pending_next_offset, ref, false);
+ }
}
}
@@ -71,10 +80,18 @@
list_ = nullptr;
} else {
mirror::Object* next = head->GetFieldObject<mirror::Object>(pending_next_offset, false);
- list_->SetFieldObject(pending_next_offset, next, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ list_->SetFieldObject<true>(pending_next_offset, next, false);
+ } else {
+ list_->SetFieldObject<false>(pending_next_offset, next, false);
+ }
ref = head;
}
- ref->SetFieldObject(pending_next_offset, nullptr, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ ref->SetFieldObject<true>(pending_next_offset, nullptr, false);
+ } else {
+ ref->SetFieldObject<false>(pending_next_offset, nullptr, false);
+ }
return ref;
}
@@ -131,7 +148,11 @@
// If the referent is non-null the reference must queuable.
DCHECK(heap_->IsEnqueuable(ref));
// Move the updated referent to the zombie field.
- ref->SetFieldObject(heap_->GetFinalizerReferenceZombieOffset(), forward_address, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ ref->SetFieldObject<true>(heap_->GetFinalizerReferenceZombieOffset(), forward_address, false);
+ } else {
+ ref->SetFieldObject<false>(heap_->GetFinalizerReferenceZombieOffset(), forward_address, false);
+ }
heap_->ClearReferenceReferent(ref);
cleared_references.EnqueueReference(ref);
} else if (referent != forward_address) {
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index 5693747..cc49d67 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -28,24 +28,24 @@
namespace art {
InternTable::InternTable()
- : intern_table_lock_("InternTable lock"), is_dirty_(false), allow_new_interns_(true),
- new_intern_condition_("New intern condition", intern_table_lock_) {
+ : is_dirty_(false), allow_new_interns_(true),
+ new_intern_condition_("New intern condition", *Locks::intern_table_lock_) {
}
size_t InternTable::Size() const {
- MutexLock mu(Thread::Current(), intern_table_lock_);
+ MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
return strong_interns_.size() + weak_interns_.size();
}
void InternTable::DumpForSigQuit(std::ostream& os) const {
- MutexLock mu(Thread::Current(), intern_table_lock_);
+ MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
os << "Intern table: " << strong_interns_.size() << " strong; "
<< weak_interns_.size() << " weak\n";
}
void InternTable::VisitRoots(RootCallback* callback, void* arg,
bool only_dirty, bool clean_dirty) {
- MutexLock mu(Thread::Current(), intern_table_lock_);
+ MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
if (!only_dirty || is_dirty_) {
for (auto& strong_intern : strong_interns_) {
strong_intern.second =
@@ -61,7 +61,7 @@
}
mirror::String* InternTable::Lookup(Table& table, mirror::String* s, uint32_t hash_code) {
- intern_table_lock_.AssertHeld(Thread::Current());
+ Locks::intern_table_lock_->AssertHeld(Thread::Current());
for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) {
mirror::String* existing_string = it->second;
if (existing_string->Equals(s)) {
@@ -71,15 +71,38 @@
return NULL;
}
+mirror::String* InternTable::InsertStrong(mirror::String* s, uint32_t hash_code) {
+ Runtime* runtime = Runtime::Current();
+ if (runtime->IsActiveTransaction()) {
+ runtime->RecordStrongStringInsertion(s, hash_code);
+ }
+ return Insert(strong_interns_, s, hash_code);
+}
+
+mirror::String* InternTable::InsertWeak(mirror::String* s, uint32_t hash_code) {
+ Runtime* runtime = Runtime::Current();
+ if (runtime->IsActiveTransaction()) {
+ runtime->RecordWeakStringInsertion(s, hash_code);
+ }
+ return Insert(weak_interns_, s, hash_code);
+}
+
mirror::String* InternTable::Insert(Table& table, mirror::String* s, uint32_t hash_code) {
- intern_table_lock_.AssertHeld(Thread::Current());
+ Locks::intern_table_lock_->AssertHeld(Thread::Current());
table.insert(std::make_pair(hash_code, s));
return s;
}
-void InternTable::Remove(Table& table, const mirror::String* s,
- uint32_t hash_code) {
- intern_table_lock_.AssertHeld(Thread::Current());
+void InternTable::RemoveWeak(mirror::String* s, uint32_t hash_code) {
+ Runtime* runtime = Runtime::Current();
+ if (runtime->IsActiveTransaction()) {
+ runtime->RecordWeakStringRemoval(s, hash_code);
+ }
+ Remove(weak_interns_, s, hash_code);
+}
+
+void InternTable::Remove(Table& table, mirror::String* s, uint32_t hash_code) {
+ Locks::intern_table_lock_->AssertHeld(Thread::Current());
for (auto it = table.find(hash_code), end = table.end(); it != end; ++it) {
if (it->second == s) {
table.erase(it);
@@ -88,6 +111,24 @@
}
}
+// Insert/remove methods used to undo changes made during an aborted transaction.
+mirror::String* InternTable::InsertStrongFromTransaction(mirror::String* s, uint32_t hash_code) {
+ DCHECK(!Runtime::Current()->IsActiveTransaction());
+ return InsertStrong(s, hash_code);
+}
+mirror::String* InternTable::InsertWeakFromTransaction(mirror::String* s, uint32_t hash_code) {
+ DCHECK(!Runtime::Current()->IsActiveTransaction());
+ return InsertWeak(s, hash_code);
+}
+void InternTable::RemoveStrongFromTransaction(mirror::String* s, uint32_t hash_code) {
+ DCHECK(!Runtime::Current()->IsActiveTransaction());
+ Remove(strong_interns_, s, hash_code);
+}
+void InternTable::RemoveWeakFromTransaction(mirror::String* s, uint32_t hash_code) {
+ DCHECK(!Runtime::Current()->IsActiveTransaction());
+ Remove(weak_interns_, s, hash_code);
+}
+
static mirror::String* LookupStringFromImage(mirror::String* s)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
gc::space::ImageSpace* image = Runtime::Current()->GetHeap()->GetImageSpace();
@@ -115,20 +156,20 @@
void InternTable::AllowNewInterns() {
Thread* self = Thread::Current();
- MutexLock mu(self, intern_table_lock_);
+ MutexLock mu(self, *Locks::intern_table_lock_);
allow_new_interns_ = true;
new_intern_condition_.Broadcast(self);
}
void InternTable::DisallowNewInterns() {
Thread* self = Thread::Current();
- MutexLock mu(self, intern_table_lock_);
+ MutexLock mu(self, *Locks::intern_table_lock_);
allow_new_interns_ = false;
}
mirror::String* InternTable::Insert(mirror::String* s, bool is_strong) {
Thread* self = Thread::Current();
- MutexLock mu(self, intern_table_lock_);
+ MutexLock mu(self, *Locks::intern_table_lock_);
DCHECK(s != NULL);
uint32_t hash_code = s->GetHashCode();
@@ -150,20 +191,20 @@
// Check the image for a match.
mirror::String* image = LookupStringFromImage(s);
if (image != NULL) {
- return Insert(strong_interns_, image, hash_code);
+ return InsertStrong(image, hash_code);
}
// There is no match in the strong table, check the weak table.
mirror::String* weak = Lookup(weak_interns_, s, hash_code);
if (weak != NULL) {
// A match was found in the weak table. Promote to the strong table.
- Remove(weak_interns_, weak, hash_code);
- return Insert(strong_interns_, weak, hash_code);
+ RemoveWeak(weak, hash_code);
+ return InsertStrong(weak, hash_code);
}
// No match in the strong table or the weak table. Insert into the strong
// table.
- return Insert(strong_interns_, s, hash_code);
+ return InsertStrong(s, hash_code);
}
// Check the strong table for a match.
@@ -174,7 +215,7 @@
// Check the image for a match.
mirror::String* image = LookupStringFromImage(s);
if (image != NULL) {
- return Insert(weak_interns_, image, hash_code);
+ return InsertWeak(image, hash_code);
}
// Check the weak table for a match.
mirror::String* weak = Lookup(weak_interns_, s, hash_code);
@@ -182,7 +223,7 @@
return weak;
}
// Insert into the weak table.
- return Insert(weak_interns_, s, hash_code);
+ return InsertWeak(s, hash_code);
}
mirror::String* InternTable::InternStrong(int32_t utf16_length,
@@ -211,13 +252,13 @@
}
bool InternTable::ContainsWeak(mirror::String* s) {
- MutexLock mu(Thread::Current(), intern_table_lock_);
+ MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
const mirror::String* found = Lookup(weak_interns_, s, s->GetHashCode());
return found == s;
}
void InternTable::SweepInternTableWeaks(IsMarkedCallback* callback, void* arg) {
- MutexLock mu(Thread::Current(), intern_table_lock_);
+ MutexLock mu(Thread::Current(), *Locks::intern_table_lock_);
for (auto it = weak_interns_.begin(), end = weak_interns_.end(); it != end;) {
mirror::Object* object = it->second;
mirror::Object* new_object = callback(object, arg);
diff --git a/runtime/intern_table.h b/runtime/intern_table.h
index 9f09fb9..cc48480 100644
--- a/runtime/intern_table.h
+++ b/runtime/intern_table.h
@@ -18,6 +18,7 @@
#define ART_RUNTIME_INTERN_TABLE_H_
#include "base/mutex.h"
+#include "locks.h"
#include "object_callbacks.h"
#include <map>
@@ -26,6 +27,7 @@
namespace mirror {
class String;
} // namespace mirror
+class Transaction;
/**
* Used to intern strings.
@@ -72,19 +74,38 @@
typedef std::multimap<int32_t, mirror::String*> Table;
mirror::String* Insert(mirror::String* s, bool is_strong)
+ LOCKS_EXCLUDED(Locks::intern_table_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
mirror::String* Lookup(Table& table, mirror::String* s, uint32_t hash_code)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- mirror::String* Insert(Table& table, mirror::String* s, uint32_t hash_code);
- void Remove(Table& table, const mirror::String* s, uint32_t hash_code);
+ mirror::String* InsertStrong(mirror::String* s, uint32_t hash_code)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+ mirror::String* InsertWeak(mirror::String* s, uint32_t hash_code)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+ mirror::String* Insert(Table& table, mirror::String* s, uint32_t hash_code)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+ void RemoveWeak(mirror::String* s, uint32_t hash_code)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+ void Remove(Table& table, mirror::String* s, uint32_t hash_code)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
- mutable Mutex intern_table_lock_;
- bool is_dirty_ GUARDED_BY(intern_table_lock_);
- bool allow_new_interns_ GUARDED_BY(intern_table_lock_);
- ConditionVariable new_intern_condition_ GUARDED_BY(intern_table_lock_);
- Table strong_interns_ GUARDED_BY(intern_table_lock_);
- Table weak_interns_ GUARDED_BY(intern_table_lock_);
+ // Transaction rollback access.
+ mirror::String* InsertStrongFromTransaction(mirror::String* s, uint32_t hash_code)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+ mirror::String* InsertWeakFromTransaction(mirror::String* s, uint32_t hash_code)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+ void RemoveStrongFromTransaction(mirror::String* s, uint32_t hash_code)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+ void RemoveWeakFromTransaction(mirror::String* s, uint32_t hash_code)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+ friend class Transaction;
+
+ bool is_dirty_ GUARDED_BY(Locks::intern_table_lock_);
+ bool allow_new_interns_ GUARDED_BY(Locks::intern_table_lock_);
+ ConditionVariable new_intern_condition_ GUARDED_BY(Locks::intern_table_lock_);
+ Table strong_interns_ GUARDED_BY(Locks::intern_table_lock_);
+ Table weak_interns_ GUARDED_BY(Locks::intern_table_lock_);
};
} // namespace art
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index c6faf44..a674571 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -15,6 +15,7 @@
*/
#include "interpreter_common.h"
+#include <limits>
namespace art {
namespace interpreter {
@@ -23,6 +24,10 @@
static void UnstartedRuntimeJni(Thread* self, ArtMethod* method,
Object* receiver, uint32_t* args, JValue* result)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(Runtime::Current()->IsActiveTransaction()) << "Calling native method "
+ << PrettyMethod(method)
+ << " in unstarted runtime should only happen"
+ << " in a transaction";
std::string name(PrettyMethod(method));
if (name == "java.lang.ClassLoader dalvik.system.VMStack.getCallingClassLoader()") {
result->SetL(NULL);
@@ -73,13 +78,18 @@
jint newValue = args[4];
byte* raw_addr = reinterpret_cast<byte*>(obj) + offset;
volatile int32_t* address = reinterpret_cast<volatile int32_t*>(raw_addr);
+ // Check offset is 32bits to fit in MemberOffset.
+ CHECK_GE(offset, static_cast<jlong>(std::numeric_limits<int32_t>::min()));
+ CHECK_LE(offset, static_cast<jlong>(std::numeric_limits<int32_t>::max()));
+ Runtime::Current()->RecordWriteField32(obj, MemberOffset(offset), *address, true);
// Note: android_atomic_release_cas() returns 0 on success, not failure.
int r = android_atomic_release_cas(expectedValue, newValue, address);
result->SetZ(r == 0);
} else if (name == "void sun.misc.Unsafe.putObject(java.lang.Object, long, java.lang.Object)") {
Object* obj = reinterpret_cast<Object*>(args[0]);
Object* newValue = reinterpret_cast<Object*>(args[3]);
- obj->SetFieldObject(MemberOffset((static_cast<uint64_t>(args[2]) << 32) | args[1]), newValue, false);
+ obj->SetFieldObject<true>(MemberOffset((static_cast<uint64_t>(args[2]) << 32) | args[1]),
+ newValue, false);
} else if (name == "int sun.misc.Unsafe.getArrayBaseOffsetForComponentType(java.lang.Class)") {
mirror::Class* component = reinterpret_cast<Object*>(args[0])->AsClass();
Primitive::Type primitive_type = component->GetPrimitiveType();
@@ -89,7 +99,11 @@
Primitive::Type primitive_type = component->GetPrimitiveType();
result->SetI(Primitive::ComponentSize(primitive_type));
} else {
- LOG(FATAL) << "Attempt to invoke native method in non-started runtime: " << name;
+ // Throw an exception so we can abort the transaction and undo every change.
+ ThrowLocation throw_location;
+ self->ThrowNewExceptionF(throw_location, "Ljava/lang/InternalError;",
+ "Attempt to invoke native method in non-started runtime: %s",
+ name.c_str());
}
}
@@ -293,21 +307,38 @@
DCHECK(!shadow_frame.GetMethod()->IsAbstract());
DCHECK(!shadow_frame.GetMethod()->IsNative());
+ bool transaction_active = Runtime::Current()->IsActiveTransaction();
if (LIKELY(shadow_frame.GetMethod()->IsPreverified())) {
// Enter the "without access check" interpreter.
if (kInterpreterImplKind == kSwitchImpl) {
- return ExecuteSwitchImpl<false>(self, mh, code_item, shadow_frame, result_register);
+ if (transaction_active) {
+ return ExecuteSwitchImpl<false, true>(self, mh, code_item, shadow_frame, result_register);
+ } else {
+ return ExecuteSwitchImpl<false, false>(self, mh, code_item, shadow_frame, result_register);
+ }
} else {
DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind);
- return ExecuteGotoImpl<false>(self, mh, code_item, shadow_frame, result_register);
+ if (transaction_active) {
+ return ExecuteGotoImpl<false, true>(self, mh, code_item, shadow_frame, result_register);
+ } else {
+ return ExecuteGotoImpl<false, false>(self, mh, code_item, shadow_frame, result_register);
+ }
}
} else {
// Enter the "with access check" interpreter.
if (kInterpreterImplKind == kSwitchImpl) {
- return ExecuteSwitchImpl<true>(self, mh, code_item, shadow_frame, result_register);
+ if (transaction_active) {
+ return ExecuteSwitchImpl<true, true>(self, mh, code_item, shadow_frame, result_register);
+ } else {
+ return ExecuteSwitchImpl<true, false>(self, mh, code_item, shadow_frame, result_register);
+ }
} else {
DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind);
- return ExecuteGotoImpl<true>(self, mh, code_item, shadow_frame, result_register);
+ if (transaction_active) {
+ return ExecuteGotoImpl<true, true>(self, mh, code_item, shadow_frame, result_register);
+ } else {
+ return ExecuteGotoImpl<true, false>(self, mh, code_item, shadow_frame, result_register);
+ }
}
}
}
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 0b959fb..e37fb61 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -15,6 +15,7 @@
*/
#include "interpreter_common.h"
+#include "mirror/array-inl.h"
namespace art {
namespace interpreter {
@@ -161,7 +162,7 @@
return !self->IsExceptionPending();
}
-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) {
DCHECK(inst->Opcode() == Instruction::FILLED_NEW_ARRAY ||
@@ -212,9 +213,9 @@
for (int32_t i = 0; i < length; ++i) {
size_t src_reg = is_range ? vregC + i : arg[i];
if (is_primitive_int_component) {
- newArray->AsIntArray()->SetWithoutChecks(i, shadow_frame.GetVReg(src_reg));
+ newArray->AsIntArray()->SetWithoutChecks<transaction_active>(i, shadow_frame.GetVReg(src_reg));
} else {
- newArray->AsObjectArray<Object>()->SetWithoutChecks(i, shadow_frame.GetVRegReference(src_reg));
+ newArray->AsObjectArray<Object>()->SetWithoutChecks<transaction_active>(i, shadow_frame.GetVRegReference(src_reg));
}
}
@@ -222,6 +223,50 @@
return true;
}
+// TODO fix thread analysis: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+template<typename T>
+static void RecordArrayElementsInTransactionImpl(mirror::PrimitiveArray<T>* array, int32_t count)
+ NO_THREAD_SAFETY_ANALYSIS {
+ Runtime* runtime = Runtime::Current();
+ for (int32_t i = 0; i < count; ++i) {
+ runtime->RecordWriteArray(array, i, array->GetWithoutChecks(i));
+ }
+}
+
+void RecordArrayElementsInTransaction(mirror::Array* array, int32_t count)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ DCHECK(Runtime::Current()->IsActiveTransaction());
+ DCHECK(array != nullptr);
+ DCHECK_LE(count, array->GetLength());
+ Primitive::Type primitive_component_type = array->GetClass()->GetComponentType()->GetPrimitiveType();
+ switch (primitive_component_type) {
+ case Primitive::kPrimBoolean:
+ RecordArrayElementsInTransactionImpl(array->AsBooleanArray(), count);
+ break;
+ case Primitive::kPrimByte:
+ RecordArrayElementsInTransactionImpl(array->AsByteArray(), count);
+ break;
+ case Primitive::kPrimChar:
+ RecordArrayElementsInTransactionImpl(array->AsCharArray(), count);
+ break;
+ case Primitive::kPrimShort:
+ RecordArrayElementsInTransactionImpl(array->AsShortArray(), count);
+ break;
+ case Primitive::kPrimInt:
+ case Primitive::kPrimFloat:
+ RecordArrayElementsInTransactionImpl(array->AsIntArray(), count);
+ break;
+ case Primitive::kPrimLong:
+ case Primitive::kPrimDouble:
+ RecordArrayElementsInTransactionImpl(array->AsLongArray(), count);
+ break;
+ default:
+ LOG(FATAL) << "Unsupported primitive type " << primitive_component_type
+ << " in fill-array-data";
+ break;
+ }
+}
+
static void UnstartedRuntimeInvoke(Thread* self, MethodHelper& mh,
const DexFile::CodeItem* code_item, ShadowFrame* shadow_frame,
JValue* result, size_t arg_offset) {
@@ -341,15 +386,19 @@
#undef EXPLICIT_DO_CALL_TEMPLATE_DECL
// Explicit DoFilledNewArray template function declarations.
-#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _check) \
- template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) \
- bool DoFilledNewArray<_is_range_, _check>(const Instruction* inst, \
- const ShadowFrame& shadow_frame, \
- Thread* self, JValue* result)
-EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, false);
-EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, true);
-EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, false);
-EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, true);
+#define EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(_is_range_, _check, _transaction_active) \
+ template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) \
+ bool DoFilledNewArray<_is_range_, _check, _transaction_active>(const Instruction* inst, \
+ const ShadowFrame& shadow_frame, \
+ Thread* self, JValue* result)
+#define EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(_transaction_active) \
+ EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, false, _transaction_active); \
+ EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(false, true, _transaction_active); \
+ EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, false, _transaction_active); \
+ EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL(true, true, _transaction_active)
+EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(false);
+EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL(true);
+#undef EXPLICIT_DO_FILLED_NEW_ARRAY_ALL_TEMPLATE_DECL
#undef EXPLICIT_DO_FILLED_NEW_ARRAY_TEMPLATE_DECL
} // namespace interpreter
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 @@
// 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 @@
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 @@
// 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 @@
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 @@
return false;
}
}
- f->SetObj(obj, reg);
+ f->SetObj<transaction_active>(obj, reg);
break;
}
default:
@@ -297,7 +300,7 @@
// 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 @@
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 @@
// 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 @@
#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 @@
#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)
+#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)
-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_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
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
index e8504b7..d0bb001 100644
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ b/runtime/interpreter/interpreter_goto_table_impl.cc
@@ -109,7 +109,7 @@
* ---------------------+---------------+
*
*/
-template<bool do_access_check>
+template<bool do_access_check, bool transaction_active>
JValue ExecuteGotoImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register) {
// Define handler tables:
@@ -536,15 +536,17 @@
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(FILLED_NEW_ARRAY) {
- bool success = DoFilledNewArray<false, do_access_check>(inst, shadow_frame,
- self, &result_register);
+ bool success =
+ DoFilledNewArray<false, do_access_check, transaction_active>(inst, shadow_frame,
+ self, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(FILLED_NEW_ARRAY_RANGE) {
- bool success = DoFilledNewArray<true, do_access_check>(inst, shadow_frame,
- self, &result_register);
+ bool success =
+ DoFilledNewArray<true, do_access_check, transaction_active>(inst, shadow_frame,
+ self, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
}
HANDLE_INSTRUCTION_END();
@@ -567,6 +569,9 @@
array->GetLength(), payload->element_count);
HANDLE_PENDING_EXCEPTION();
} else {
+ if (transaction_active) {
+ RecordArrayElementsInTransaction(array, payload->element_count);
+ }
uint32_t size_in_bytes = payload->element_count * payload->element_width;
memcpy(array->GetRawData(payload->element_width, 0), payload->data, size_in_bytes);
ADVANCE(3);
@@ -1060,7 +1065,7 @@
int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
BooleanArray* array = a->AsBooleanArray();
if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
ADVANCE(2);
} else {
HANDLE_PENDING_EXCEPTION();
@@ -1079,7 +1084,7 @@
int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
ByteArray* array = a->AsByteArray();
if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
ADVANCE(2);
} else {
HANDLE_PENDING_EXCEPTION();
@@ -1098,7 +1103,7 @@
int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
CharArray* array = a->AsCharArray();
if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
ADVANCE(2);
} else {
HANDLE_PENDING_EXCEPTION();
@@ -1117,7 +1122,7 @@
int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
ShortArray* array = a->AsShortArray();
if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
ADVANCE(2);
} else {
HANDLE_PENDING_EXCEPTION();
@@ -1136,7 +1141,7 @@
int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
IntArray* array = a->AsIntArray();
if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
ADVANCE(2);
} else {
HANDLE_PENDING_EXCEPTION();
@@ -1155,7 +1160,7 @@
int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
LongArray* array = a->AsLongArray();
if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
ADVANCE(2);
} else {
HANDLE_PENDING_EXCEPTION();
@@ -1174,7 +1179,7 @@
Object* val = shadow_frame.GetVRegReference(inst->VRegA_23x(inst_data));
ObjectArray<Object>* array = a->AsObjectArray<Object>();
if (LIKELY(array->CheckIsValidIndex(index) && array->CheckAssignable(val))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
ADVANCE(2);
} else {
HANDLE_PENDING_EXCEPTION();
@@ -1286,103 +1291,103 @@
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(IPUT_BOOLEAN) {
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(IPUT_BYTE) {
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(IPUT_CHAR) {
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(IPUT_SHORT) {
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(IPUT) {
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(IPUT_WIDE) {
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(IPUT_OBJECT) {
- bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(IPUT_QUICK) {
- bool success = DoIPutQuick<Primitive::kPrimInt>(shadow_frame, inst, inst_data);
+ bool success = DoIPutQuick<Primitive::kPrimInt, transaction_active>(shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(IPUT_WIDE_QUICK) {
- bool success = DoIPutQuick<Primitive::kPrimLong>(shadow_frame, inst, inst_data);
+ bool success = DoIPutQuick<Primitive::kPrimLong, transaction_active>(shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(IPUT_OBJECT_QUICK) {
- bool success = DoIPutQuick<Primitive::kPrimNot>(shadow_frame, inst, inst_data);
+ bool success = DoIPutQuick<Primitive::kPrimNot, transaction_active>(shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(SPUT_BOOLEAN) {
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(SPUT_BYTE) {
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(SPUT_CHAR) {
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(SPUT_SHORT) {
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(SPUT) {
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(SPUT_WIDE) {
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
HANDLE_INSTRUCTION_START(SPUT_OBJECT) {
- bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
}
HANDLE_INSTRUCTION_END();
@@ -2390,13 +2395,21 @@
// Explicit definitions of ExecuteGotoImpl.
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteGotoImpl<true>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
+JValue ExecuteGotoImpl<true, false>(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteGotoImpl<false>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
+JValue ExecuteGotoImpl<false, false>(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<true, true>(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteGotoImpl<false, true>(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
} // namespace interpreter
} // namespace art
diff --git a/runtime/interpreter/interpreter_switch_impl.cc b/runtime/interpreter/interpreter_switch_impl.cc
index e5d15b1..abee1db 100644
--- a/runtime/interpreter/interpreter_switch_impl.cc
+++ b/runtime/interpreter/interpreter_switch_impl.cc
@@ -50,7 +50,7 @@
// Code to run before each dex instruction.
#define PREAMBLE()
-template<bool do_access_check>
+template<bool do_access_check, bool transaction_active>
JValue ExecuteSwitchImpl(Thread* self, MethodHelper& mh, const DexFile::CodeItem* code_item,
ShadowFrame& shadow_frame, JValue result_register) {
bool do_assignability_check = do_access_check;
@@ -449,15 +449,17 @@
}
case Instruction::FILLED_NEW_ARRAY: {
PREAMBLE();
- bool success = DoFilledNewArray<false, do_access_check>(inst, shadow_frame,
- self, &result_register);
+ bool success =
+ DoFilledNewArray<false, do_access_check, transaction_active>(inst, shadow_frame, self,
+ &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
break;
}
case Instruction::FILLED_NEW_ARRAY_RANGE: {
PREAMBLE();
- bool success = DoFilledNewArray<true, do_access_check>(inst, shadow_frame,
- self, &result_register);
+ bool success =
+ DoFilledNewArray<true, do_access_check, transaction_active>(inst, shadow_frame,
+ self, &result_register);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
break;
}
@@ -482,6 +484,9 @@
HANDLE_PENDING_EXCEPTION();
break;
}
+ if (transaction_active) {
+ RecordArrayElementsInTransaction(array, payload->element_count);
+ }
uint32_t size_in_bytes = payload->element_count * payload->element_width;
memcpy(array->GetRawData(payload->element_width, 0), payload->data, size_in_bytes);
inst = inst->Next_3xx();
@@ -958,7 +963,7 @@
int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
BooleanArray* array = a->AsBooleanArray();
if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
inst = inst->Next_2xx();
} else {
HANDLE_PENDING_EXCEPTION();
@@ -977,7 +982,7 @@
int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
ByteArray* array = a->AsByteArray();
if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
inst = inst->Next_2xx();
} else {
HANDLE_PENDING_EXCEPTION();
@@ -996,7 +1001,7 @@
int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
CharArray* array = a->AsCharArray();
if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
inst = inst->Next_2xx();
} else {
HANDLE_PENDING_EXCEPTION();
@@ -1015,7 +1020,7 @@
int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
ShortArray* array = a->AsShortArray();
if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
inst = inst->Next_2xx();
} else {
HANDLE_PENDING_EXCEPTION();
@@ -1034,7 +1039,7 @@
int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
IntArray* array = a->AsIntArray();
if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
inst = inst->Next_2xx();
} else {
HANDLE_PENDING_EXCEPTION();
@@ -1053,7 +1058,7 @@
int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
LongArray* array = a->AsLongArray();
if (LIKELY(array->CheckIsValidIndex(index))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
inst = inst->Next_2xx();
} else {
HANDLE_PENDING_EXCEPTION();
@@ -1072,7 +1077,7 @@
Object* val = shadow_frame.GetVRegReference(inst->VRegA_23x(inst_data));
ObjectArray<Object>* array = a->AsObjectArray<Object>();
if (LIKELY(array->CheckIsValidIndex(index) && array->CheckAssignable(val))) {
- array->SetWithoutChecks(index, val);
+ array->SetWithoutChecks<transaction_active>(index, val);
inst = inst->Next_2xx();
} else {
HANDLE_PENDING_EXCEPTION();
@@ -1183,103 +1188,103 @@
}
case Instruction::IPUT_BOOLEAN: {
PREAMBLE();
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::IPUT_BYTE: {
PREAMBLE();
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::IPUT_CHAR: {
PREAMBLE();
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::IPUT_SHORT: {
PREAMBLE();
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::IPUT: {
PREAMBLE();
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::IPUT_WIDE: {
PREAMBLE();
- bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::IPUT_OBJECT: {
PREAMBLE();
- bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::IPUT_QUICK: {
PREAMBLE();
- bool success = DoIPutQuick<Primitive::kPrimInt>(shadow_frame, inst, inst_data);
+ bool success = DoIPutQuick<Primitive::kPrimInt, transaction_active>(shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::IPUT_WIDE_QUICK: {
PREAMBLE();
- bool success = DoIPutQuick<Primitive::kPrimLong>(shadow_frame, inst, inst_data);
+ bool success = DoIPutQuick<Primitive::kPrimLong, transaction_active>(shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::IPUT_OBJECT_QUICK: {
PREAMBLE();
- bool success = DoIPutQuick<Primitive::kPrimNot>(shadow_frame, inst, inst_data);
+ bool success = DoIPutQuick<Primitive::kPrimNot, transaction_active>(shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::SPUT_BOOLEAN: {
PREAMBLE();
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::SPUT_BYTE: {
PREAMBLE();
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::SPUT_CHAR: {
PREAMBLE();
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::SPUT_SHORT: {
PREAMBLE();
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::SPUT: {
PREAMBLE();
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::SPUT_WIDE: {
PREAMBLE();
- bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
case Instruction::SPUT_OBJECT: {
PREAMBLE();
- bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check>(self, shadow_frame, inst, inst_data);
+ bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check, transaction_active>(self, shadow_frame, inst, inst_data);
POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
break;
}
@@ -2137,13 +2142,21 @@
// Explicit definitions of ExecuteSwitchImpl.
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteSwitchImpl<true>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
+JValue ExecuteSwitchImpl<true, false>(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) HOT_ATTR
-JValue ExecuteSwitchImpl<false>(Thread* self, MethodHelper& mh,
- const DexFile::CodeItem* code_item,
- ShadowFrame& shadow_frame, JValue result_register);
+JValue ExecuteSwitchImpl<false, false>(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteSwitchImpl<true, true>(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
+template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+JValue ExecuteSwitchImpl<false, true>(Thread* self, MethodHelper& mh,
+ const DexFile::CodeItem* code_item,
+ ShadowFrame& shadow_frame, JValue result_register);
} // namespace interpreter
} // namespace art
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 6f31ca7..876de05 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -50,24 +50,6 @@
#include "UniquePtr.h"
#include "well_known_classes.h"
-using ::art::mirror::ArtField;
-using ::art::mirror::ArtMethod;
-using ::art::mirror::Array;
-using ::art::mirror::BooleanArray;
-using ::art::mirror::ByteArray;
-using ::art::mirror::CharArray;
-using ::art::mirror::Class;
-using ::art::mirror::ClassLoader;
-using ::art::mirror::DoubleArray;
-using ::art::mirror::FloatArray;
-using ::art::mirror::IntArray;
-using ::art::mirror::LongArray;
-using ::art::mirror::Object;
-using ::art::mirror::ObjectArray;
-using ::art::mirror::ShortArray;
-using ::art::mirror::String;
-using ::art::mirror::Throwable;
-
namespace art {
static const size_t kMonitorsInitial = 32; // Arbitrary.
@@ -85,7 +67,7 @@
static const size_t kWeakGlobalsInitial = 16; // Arbitrary.
static const size_t kWeakGlobalsMax = 51200; // Arbitrary sanity check. (Must fit in 16 bits.)
-static jweak AddWeakGlobalReference(ScopedObjectAccess& soa, Object* obj)
+static jweak AddWeakGlobalReference(ScopedObjectAccess& soa, mirror::Object* obj)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return soa.Vm()->AddWeakGlobalReference(soa.Self(), obj);
}
@@ -95,11 +77,10 @@
return version != JNI_VERSION_1_2 && version != JNI_VERSION_1_4 && version != JNI_VERSION_1_6;
}
-static void CheckMethodArguments(ArtMethod* m, uint32_t* args)
+static void CheckMethodArguments(mirror::ArtMethod* m, uint32_t* args)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- MethodHelper mh(m);
- const DexFile::TypeList* params = mh.GetParameterTypeList();
- if (params == NULL) {
+ const DexFile::TypeList* params = MethodHelper(m).GetParameterTypeList();
+ if (params == nullptr) {
return; // No arguments so nothing to check.
}
uint32_t offset = 0;
@@ -110,19 +91,19 @@
}
for (uint32_t i = 0; i < num_params; i++) {
uint16_t type_idx = params->GetTypeItem(i).type_idx_;
- Class* param_type = mh.GetClassFromTypeIdx(type_idx);
- if (param_type == NULL) {
+ mirror::Class* param_type = MethodHelper(m).GetClassFromTypeIdx(type_idx);
+ if (param_type == nullptr) {
Thread* self = Thread::Current();
CHECK(self->IsExceptionPending());
LOG(ERROR) << "Internal error: unresolvable type for argument type in JNI invoke: "
- << mh.GetTypeDescriptorFromTypeIdx(type_idx) << "\n"
- << self->GetException(NULL)->Dump();
+ << MethodHelper(m).GetTypeDescriptorFromTypeIdx(type_idx) << "\n"
+ << self->GetException(nullptr)->Dump();
self->ClearException();
++error_count;
} else if (!param_type->IsPrimitive()) {
// TODO: check primitives are in range.
- Object* argument = reinterpret_cast<Object*>(args[i + offset]);
- if (argument != NULL && !argument->InstanceOf(param_type)) {
+ mirror::Object* argument = reinterpret_cast<mirror::Object*>(args[i + offset]);
+ if (argument != nullptr && !argument->InstanceOf(param_type)) {
LOG(ERROR) << "JNI ERROR (app bug): attempt to pass an instance of "
<< PrettyTypeOf(argument) << " as argument " << (i + 1) << " to " << PrettyMethod(m);
++error_count;
@@ -134,11 +115,11 @@
if (error_count > 0) {
// TODO: pass the JNI function name (such as "CallVoidMethodV") through so we can call JniAbort
// with an argument.
- JniAbortF(NULL, "bad arguments passed to %s (see above for details)", PrettyMethod(m).c_str());
+ JniAbortF(nullptr, "bad arguments passed to %s (see above for details)", PrettyMethod(m).c_str());
}
}
-void InvokeWithArgArray(const ScopedObjectAccess& soa, ArtMethod* method,
+void InvokeWithArgArray(const ScopedObjectAccess& soa, mirror::ArtMethod* method,
ArgArray* arg_array, JValue* result, const char* shorty)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
uint32_t* args = arg_array->GetArray();
@@ -151,8 +132,8 @@
static JValue InvokeWithVarArgs(const ScopedObjectAccess& soa, jobject obj,
jmethodID mid, va_list args)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- ArtMethod* method = soa.DecodeMethod(mid);
- Object* receiver = method->IsStatic() ? NULL : soa.Decode<Object*>(obj);
+ mirror::ArtMethod* method = soa.DecodeMethod(mid);
+ mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
MethodHelper mh(method);
JValue result;
ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
@@ -161,7 +142,7 @@
return result;
}
-static ArtMethod* FindVirtualMethod(Object* receiver, ArtMethod* method)
+static mirror::ArtMethod* FindVirtualMethod(mirror::Object* receiver, mirror::ArtMethod* method)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return receiver->GetClass()->FindVirtualMethodForVirtualOrInterface(method);
}
@@ -169,8 +150,8 @@
static JValue InvokeVirtualOrInterfaceWithJValues(const ScopedObjectAccess& soa,
jobject obj, jmethodID mid, jvalue* args)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Object* receiver = soa.Decode<Object*>(obj);
- ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
+ mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
+ mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
MethodHelper mh(method);
JValue result;
ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
@@ -182,8 +163,8 @@
static JValue InvokeVirtualOrInterfaceWithVarArgs(const ScopedObjectAccess& soa,
jobject obj, jmethodID mid, va_list args)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Object* receiver = soa.Decode<Object*>(obj);
- ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
+ mirror::Object* receiver = soa.Decode<mirror::Object*>(obj);
+ mirror::ArtMethod* method = FindVirtualMethod(receiver, soa.DecodeMethod(mid));
MethodHelper mh(method);
JValue result;
ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
@@ -216,7 +197,7 @@
return result;
}
-static void ThrowNoSuchMethodError(ScopedObjectAccess& soa, Class* c,
+static void ThrowNoSuchMethodError(ScopedObjectAccess& soa, mirror::Class* c,
const char* name, const char* sig, const char* kind)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
@@ -240,68 +221,66 @@
static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class,
const char* name, const char* sig, bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(jni_class));
+ mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(jni_class));
if (c == nullptr) {
return nullptr;
}
-
- ArtMethod* method = NULL;
+ mirror::ArtMethod* method = nullptr;
if (is_static) {
method = c->FindDirectMethod(name, sig);
} else {
method = c->FindVirtualMethod(name, sig);
- if (method == NULL) {
+ if (method == nullptr) {
// No virtual method matching the signature. Search declared
// private methods and constructors.
method = c->FindDeclaredDirectMethod(name, sig);
}
}
-
- if (method == NULL || method->IsStatic() != is_static) {
+ if (method == nullptr || method->IsStatic() != is_static) {
ThrowNoSuchMethodError(soa, c, name, sig, is_static ? "static" : "non-static");
- return NULL;
+ return nullptr;
}
-
return soa.EncodeMethod(method);
}
-static ClassLoader* GetClassLoader(const ScopedObjectAccess& soa)
+static mirror::ClassLoader* GetClassLoader(const ScopedObjectAccess& soa)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- ArtMethod* method = soa.Self()->GetCurrentMethod(NULL);
+ mirror::ArtMethod* method = soa.Self()->GetCurrentMethod(nullptr);
// If we are running Runtime.nativeLoad, use the overriding ClassLoader it set.
if (method == soa.DecodeMethod(WellKnownClasses::java_lang_Runtime_nativeLoad)) {
return soa.Self()->GetClassLoaderOverride();
}
// If we have a method, use its ClassLoader for context.
- if (method != NULL) {
+ if (method != nullptr) {
return method->GetDeclaringClass()->GetClassLoader();
}
// We don't have a method, so try to use the system ClassLoader.
- ClassLoader* class_loader = soa.Decode<ClassLoader*>(Runtime::Current()->GetSystemClassLoader());
- if (class_loader != NULL) {
+ mirror::ClassLoader* class_loader =
+ soa.Decode<mirror::ClassLoader*>(Runtime::Current()->GetSystemClassLoader());
+ if (class_loader != nullptr) {
return class_loader;
}
// See if the override ClassLoader is set for gtests.
class_loader = soa.Self()->GetClassLoaderOverride();
- if (class_loader != NULL) {
+ if (class_loader != nullptr) {
// If so, CommonTest should have set UseCompileTimeClassPath.
CHECK(Runtime::Current()->UseCompileTimeClassPath());
return class_loader;
}
// Use the BOOTCLASSPATH.
- return NULL;
+ return nullptr;
}
static jfieldID FindFieldID(const ScopedObjectAccess& soa, jclass jni_class, const char* name,
const char* sig, bool is_static)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(jni_class));
- if (c == nullptr) {
+ SirtRef<mirror::Class> c(soa.Self(), EnsureInitialized(soa.Self(),
+ soa.Decode<mirror::Class*>(jni_class)));
+ if (c.get() == nullptr) {
return nullptr;
}
-
- ArtField* field = NULL;
- Class* field_type;
+ mirror::ArtField* field = nullptr;
+ mirror::Class* field_type;
ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
if (sig[1] != '\0') {
SirtRef<mirror::ClassLoader> class_loader(soa.Self(), c->GetClassLoader());
@@ -309,49 +288,49 @@
} else {
field_type = class_linker->FindPrimitiveClass(*sig);
}
- if (field_type == NULL) {
+ if (field_type == nullptr) {
// Failed to find type from the signature of the field.
DCHECK(soa.Self()->IsExceptionPending());
ThrowLocation throw_location;
- SirtRef<Throwable> cause(soa.Self(), soa.Self()->GetException(&throw_location));
+ SirtRef<mirror::Throwable> cause(soa.Self(), soa.Self()->GetException(&throw_location));
soa.Self()->ClearException();
soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
"no type \"%s\" found and so no field \"%s\" could be found in class "
"\"%s\" or its superclasses", sig, name,
- ClassHelper(c).GetDescriptor());
- soa.Self()->GetException(NULL)->SetCause(cause.get());
- return NULL;
+ ClassHelper(c.get()).GetDescriptor());
+ soa.Self()->GetException(nullptr)->SetCause(cause.get());
+ return nullptr;
}
if (is_static) {
field = c->FindStaticField(name, ClassHelper(field_type).GetDescriptor());
} else {
field = c->FindInstanceField(name, ClassHelper(field_type).GetDescriptor());
}
- if (field == NULL) {
+ if (field == nullptr) {
ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/NoSuchFieldError;",
"no \"%s\" field \"%s\" in class \"%s\" or its superclasses",
- sig, name, ClassHelper(c).GetDescriptor());
- return NULL;
+ sig, name, ClassHelper(c.get()).GetDescriptor());
+ return nullptr;
}
return soa.EncodeField(field);
}
-static void PinPrimitiveArray(const ScopedObjectAccess& soa, Array* array)
+static void PinPrimitiveArray(const ScopedObjectAccess& soa, mirror::Array* array)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
JavaVMExt* vm = soa.Vm();
MutexLock mu(soa.Self(), vm->pins_lock);
vm->pin_table.Add(array);
}
-static void UnpinPrimitiveArray(const ScopedObjectAccess& soa, Array* array)
+static void UnpinPrimitiveArray(const ScopedObjectAccess& soa, mirror::Array* array)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
JavaVMExt* vm = soa.Vm();
MutexLock mu(soa.Self(), vm->pins_lock);
vm->pin_table.Remove(array);
}
-static void ThrowAIOOBE(ScopedObjectAccess& soa, Array* array, jsize start,
+static void ThrowAIOOBE(ScopedObjectAccess& soa, mirror::Array* array, jsize start,
jsize length, const char* identifier)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
std::string type(PrettyTypeOf(array));
@@ -374,19 +353,19 @@
LOCKS_EXCLUDED(Locks::mutator_lock_) {
// Turn the const char* into a java.lang.String.
ScopedLocalRef<jstring> s(env, env->NewStringUTF(msg));
- if (msg != NULL && s.get() == NULL) {
+ if (msg != nullptr && s.get() == nullptr) {
return JNI_ERR;
}
// Choose an appropriate constructor and set up the arguments.
jvalue args[2];
const char* signature;
- if (msg == NULL && cause == NULL) {
+ if (msg == nullptr && cause == nullptr) {
signature = "()V";
- } else if (msg != NULL && cause == NULL) {
+ } else if (msg != nullptr && cause == nullptr) {
signature = "(Ljava/lang/String;)V";
args[0].l = s.get();
- } else if (msg == NULL && cause != NULL) {
+ } else if (msg == nullptr && cause != nullptr) {
signature = "(Ljava/lang/Throwable;)V";
args[0].l = cause;
} else {
@@ -395,31 +374,32 @@
args[1].l = cause;
}
jmethodID mid = env->GetMethodID(exception_class, "<init>", signature);
- if (mid == NULL) {
+ if (mid == nullptr) {
ScopedObjectAccess soa(env);
LOG(ERROR) << "No <init>" << signature << " in "
- << PrettyClass(soa.Decode<Class*>(exception_class));
+ << PrettyClass(soa.Decode<mirror::Class*>(exception_class));
return JNI_ERR;
}
- ScopedLocalRef<jthrowable> exception(env, reinterpret_cast<jthrowable>(env->NewObjectA(exception_class, mid, args)));
- if (exception.get() == NULL) {
+ ScopedLocalRef<jthrowable> exception(
+ env, reinterpret_cast<jthrowable>(env->NewObjectA(exception_class, mid, args)));
+ if (exception.get() == nullptr) {
return JNI_ERR;
}
ScopedObjectAccess soa(env);
ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
- soa.Self()->SetException(throw_location, soa.Decode<Throwable*>(exception.get()));
+ soa.Self()->SetException(throw_location, soa.Decode<mirror::Throwable*>(exception.get()));
return JNI_OK;
}
static jint JII_AttachCurrentThread(JavaVM* vm, JNIEnv** p_env, void* raw_args, bool as_daemon) {
- if (vm == NULL || p_env == NULL) {
+ if (vm == nullptr || p_env == nullptr) {
return JNI_ERR;
}
// Return immediately if we're already attached.
Thread* self = Thread::Current();
- if (self != NULL) {
+ if (self != nullptr) {
*p_env = self->GetJniEnv();
return JNI_OK;
}
@@ -433,9 +413,9 @@
}
JavaVMAttachArgs* args = static_cast<JavaVMAttachArgs*>(raw_args);
- const char* thread_name = NULL;
- jobject thread_group = NULL;
- if (args != NULL) {
+ const char* thread_name = nullptr;
+ jobject thread_group = nullptr;
+ if (args != nullptr) {
if (IsBadJniVersion(args->version)) {
LOG(ERROR) << "Bad JNI version passed to "
<< (as_daemon ? "AttachCurrentThreadAsDaemon" : "AttachCurrentThread") << ": "
@@ -447,7 +427,7 @@
}
if (!runtime->AttachCurrentThread(thread_name, as_daemon, thread_group, !runtime->IsCompiler())) {
- *p_env = NULL;
+ *p_env = nullptr;
return JNI_ERR;
} else {
*p_env = Thread::Current()->GetJniEnv();
@@ -457,7 +437,7 @@
class SharedLibrary {
public:
- SharedLibrary(const std::string& path, void* handle, Object* class_loader)
+ SharedLibrary(const std::string& path, void* handle, mirror::Object* class_loader)
: path_(path),
handle_(handle),
class_loader_(class_loader),
@@ -467,7 +447,7 @@
jni_on_load_result_(kPending) {
}
- Object* GetClassLoader() {
+ mirror::Object* GetClassLoader() {
return class_loader_;
}
@@ -543,7 +523,7 @@
void* handle_;
// The ClassLoader this library is associated with.
- Object* class_loader_;
+ mirror::Object* class_loader_;
// Guards remaining items.
Mutex jni_on_load_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
@@ -582,7 +562,7 @@
SharedLibrary* Get(const std::string& path) {
auto it = libraries_.find(path);
- return (it == libraries_.end()) ? NULL : it->second;
+ return (it == libraries_.end()) ? nullptr : it->second;
}
void Put(const std::string& path, SharedLibrary* library) {
@@ -590,11 +570,11 @@
}
// See section 11.3 "Linking Native Methods" of the JNI spec.
- void* FindNativeMethod(ArtMethod* m, std::string& detail)
+ void* FindNativeMethod(mirror::ArtMethod* m, std::string& detail)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
std::string jni_short_name(JniShortName(m));
std::string jni_long_name(JniLongName(m));
- const ClassLoader* declaring_class_loader = m->GetDeclaringClass()->GetClassLoader();
+ const mirror::ClassLoader* declaring_class_loader = m->GetDeclaringClass()->GetClassLoader();
for (const auto& lib : libraries_) {
SharedLibrary* library = lib.second;
if (library->GetClassLoader() != declaring_class_loader) {
@@ -603,10 +583,10 @@
}
// Try the short name then the long name...
void* fn = library->FindSymbol(jni_short_name);
- if (fn == NULL) {
+ if (fn == nullptr) {
fn = library->FindSymbol(jni_long_name);
}
- if (fn != NULL) {
+ if (fn != nullptr) {
VLOG(jni) << "[Found native code for " << PrettyMethod(m)
<< " in \"" << library->GetPath() << "\"]";
return fn;
@@ -616,7 +596,7 @@
detail += PrettyMethod(m);
detail += " (tried " + jni_short_name + " and " + jni_long_name + ")";
LOG(ERROR) << detail;
- return NULL;
+ return nullptr;
}
void VisitRoots(RootCallback* callback, void* arg) {
@@ -631,8 +611,8 @@
JValue InvokeWithJValues(const ScopedObjectAccess& soa, jobject obj, jmethodID mid,
jvalue* args) {
- ArtMethod* method = soa.DecodeMethod(mid);
- Object* receiver = method->IsStatic() ? NULL : soa.Decode<Object*>(obj);
+ mirror::ArtMethod* method = soa.DecodeMethod(mid);
+ mirror::Object* receiver = method->IsStatic() ? nullptr : soa.Decode<mirror::Object*>(obj);
MethodHelper mh(method);
JValue result;
ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
@@ -642,12 +622,12 @@
}
#define CHECK_NON_NULL_ARGUMENT(fn, value) \
- if (UNLIKELY(value == NULL)) { \
+ if (UNLIKELY(value == nullptr)) { \
JniAbortF(#fn, #value " == null"); \
}
#define CHECK_NON_NULL_MEMCPY_ARGUMENT(fn, length, value) \
- if (UNLIKELY(length != 0 && value == NULL)) { \
+ if (UNLIKELY(length != 0 && value == nullptr)) { \
JniAbortF(#fn, #value " == null"); \
}
@@ -659,7 +639,7 @@
static jclass DefineClass(JNIEnv*, const char*, jobject, const jbyte*, jsize) {
LOG(WARNING) << "JNI DefineClass is not supported";
- return NULL;
+ return nullptr;
}
static jclass FindClass(JNIEnv* env, const char* name) {
@@ -668,7 +648,7 @@
ClassLinker* class_linker = runtime->GetClassLinker();
std::string descriptor(NormalizeJniClassDescriptor(name));
ScopedObjectAccess soa(env);
- Class* c = NULL;
+ mirror::Class* c = nullptr;
if (runtime->IsStarted()) {
SirtRef<mirror::ClassLoader> class_loader(soa.Self(), GetClassLoader(soa));
c = class_linker->FindClass(descriptor.c_str(), class_loader);
@@ -681,10 +661,10 @@
static jmethodID FromReflectedMethod(JNIEnv* env, jobject java_method) {
CHECK_NON_NULL_ARGUMENT(FromReflectedMethod, java_method);
ScopedObjectAccess soa(env);
- jobject art_method = env->GetObjectField(java_method,
- WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod);
- ArtMethod* method = soa.Decode<ArtMethod*>(art_method);
- DCHECK(method != NULL);
+ jobject art_method = env->GetObjectField(
+ java_method, WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod);
+ mirror::ArtMethod* method = soa.Decode<mirror::ArtMethod*>(art_method);
+ DCHECK(method != nullptr);
return soa.EncodeMethod(method);
}
@@ -693,54 +673,51 @@
ScopedObjectAccess soa(env);
jobject art_field = env->GetObjectField(java_field,
WellKnownClasses::java_lang_reflect_Field_artField);
- ArtField* field = soa.Decode<ArtField*>(art_field);
- DCHECK(field != NULL);
+ mirror::ArtField* field = soa.Decode<mirror::ArtField*>(art_field);
+ DCHECK(field != nullptr);
return soa.EncodeField(field);
}
static jobject ToReflectedMethod(JNIEnv* env, jclass, jmethodID mid, jboolean) {
CHECK_NON_NULL_ARGUMENT(ToReflectedMethod, mid);
ScopedObjectAccess soa(env);
- ArtMethod* m = soa.DecodeMethod(mid);
+ mirror::ArtMethod* m = soa.DecodeMethod(mid);
+ CHECK(!kMovingMethods);
jobject art_method = soa.AddLocalReference<jobject>(m);
jobject reflect_method = env->AllocObject(WellKnownClasses::java_lang_reflect_Method);
if (env->ExceptionCheck()) {
- return NULL;
+ return nullptr;
}
- SetObjectField(env,
- reflect_method,
- WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod,
- art_method);
+ SetObjectField(env, reflect_method,
+ WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod, art_method);
return reflect_method;
}
static jobject ToReflectedField(JNIEnv* env, jclass, jfieldID fid, jboolean) {
CHECK_NON_NULL_ARGUMENT(ToReflectedField, fid);
ScopedObjectAccess soa(env);
- ArtField* f = soa.DecodeField(fid);
+ mirror::ArtField* f = soa.DecodeField(fid);
jobject art_field = soa.AddLocalReference<jobject>(f);
jobject reflect_field = env->AllocObject(WellKnownClasses::java_lang_reflect_Field);
if (env->ExceptionCheck()) {
- return NULL;
+ return nullptr;
}
- SetObjectField(env,
- reflect_field,
- WellKnownClasses::java_lang_reflect_Field_artField,
- art_field);
+ SetObjectField(env, reflect_field,
+ WellKnownClasses::java_lang_reflect_Field_artField, art_field);
return reflect_field;
}
static jclass GetObjectClass(JNIEnv* env, jobject java_object) {
CHECK_NON_NULL_ARGUMENT(GetObjectClass, java_object);
ScopedObjectAccess soa(env);
- Object* o = soa.Decode<Object*>(java_object);
+ mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
return soa.AddLocalReference<jclass>(o->GetClass());
}
static jclass GetSuperclass(JNIEnv* env, jclass java_class) {
CHECK_NON_NULL_ARGUMENT(GetSuperclass, java_class);
ScopedObjectAccess soa(env);
- Class* c = soa.Decode<Class*>(java_class);
+ mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
return soa.AddLocalReference<jclass>(c->GetSuperClass());
}
@@ -748,28 +725,28 @@
CHECK_NON_NULL_ARGUMENT(IsAssignableFrom, java_class1);
CHECK_NON_NULL_ARGUMENT(IsAssignableFrom, java_class2);
ScopedObjectAccess soa(env);
- Class* c1 = soa.Decode<Class*>(java_class1);
- Class* c2 = soa.Decode<Class*>(java_class2);
+ mirror::Class* c1 = soa.Decode<mirror::Class*>(java_class1);
+ mirror::Class* c2 = soa.Decode<mirror::Class*>(java_class2);
return c1->IsAssignableFrom(c2) ? JNI_TRUE : JNI_FALSE;
}
static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass java_class) {
CHECK_NON_NULL_ARGUMENT(IsInstanceOf, java_class);
- if (jobj == NULL) {
+ if (jobj == nullptr) {
// Note: JNI is different from regular Java instanceof in this respect
return JNI_TRUE;
} else {
ScopedObjectAccess soa(env);
- Object* obj = soa.Decode<Object*>(jobj);
- Class* c = soa.Decode<Class*>(java_class);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(jobj);
+ mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
return obj->InstanceOf(c) ? JNI_TRUE : JNI_FALSE;
}
}
static jint Throw(JNIEnv* env, jthrowable java_exception) {
ScopedObjectAccess soa(env);
- Throwable* exception = soa.Decode<Throwable*>(java_exception);
- if (exception == NULL) {
+ mirror::Throwable* exception = soa.Decode<mirror::Throwable*>(java_exception);
+ if (exception == nullptr) {
return JNI_ERR;
}
ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
@@ -779,7 +756,7 @@
static jint ThrowNew(JNIEnv* env, jclass c, const char* msg) {
CHECK_NON_NULL_ARGUMENT(ThrowNew, c);
- return ThrowNewException(env, c, msg, NULL);
+ return ThrowNewException(env, c, msg, nullptr);
}
static jboolean ExceptionCheck(JNIEnv* env) {
@@ -793,13 +770,13 @@
static void ExceptionDescribe(JNIEnv* env) {
ScopedObjectAccess soa(env);
- SirtRef<Object> old_throw_this_object(soa.Self(), NULL);
- SirtRef<ArtMethod> old_throw_method(soa.Self(), NULL);
- SirtRef<Throwable> old_exception(soa.Self(), NULL);
+ SirtRef<mirror::Object> old_throw_this_object(soa.Self(), nullptr);
+ SirtRef<mirror::ArtMethod> old_throw_method(soa.Self(), nullptr);
+ SirtRef<mirror::Throwable> old_exception(soa.Self(), nullptr);
uint32_t old_throw_dex_pc;
{
ThrowLocation old_throw_location;
- Throwable* old_exception_obj = soa.Self()->GetException(&old_throw_location);
+ mirror::Throwable* old_exception_obj = soa.Self()->GetException(&old_throw_location);
old_throw_this_object.reset(old_throw_location.GetThis());
old_throw_method.reset(old_throw_location.GetMethod());
old_exception.reset(old_exception_obj);
@@ -809,13 +786,13 @@
ScopedLocalRef<jthrowable> exception(env, soa.AddLocalReference<jthrowable>(old_exception.get()));
ScopedLocalRef<jclass> exception_class(env, env->GetObjectClass(exception.get()));
jmethodID mid = env->GetMethodID(exception_class.get(), "printStackTrace", "()V");
- if (mid == NULL) {
+ if (mid == nullptr) {
LOG(WARNING) << "JNI WARNING: no printStackTrace()V in "
<< PrettyTypeOf(old_exception.get());
} else {
env->CallVoidMethod(exception.get(), mid);
if (soa.Self()->IsExceptionPending()) {
- LOG(WARNING) << "JNI WARNING: " << PrettyTypeOf(soa.Self()->GetException(NULL))
+ LOG(WARNING) << "JNI WARNING: " << PrettyTypeOf(soa.Self()->GetException(nullptr))
<< " thrown while calling printStackTrace";
soa.Self()->ClearException();
}
@@ -828,7 +805,7 @@
static jthrowable ExceptionOccurred(JNIEnv* env) {
ScopedObjectAccess soa(env);
- Object* exception = soa.Self()->GetException(NULL);
+ mirror::Object* exception = soa.Self()->GetException(nullptr);
return soa.AddLocalReference<jthrowable>(exception);
}
@@ -846,7 +823,7 @@
static jobject PopLocalFrame(JNIEnv* env, jobject java_survivor) {
ScopedObjectAccess soa(env);
- Object* survivor = soa.Decode<Object*>(java_survivor);
+ mirror::Object* survivor = soa.Decode<mirror::Object*>(java_survivor);
soa.Env()->PopFrame();
return soa.AddLocalReference<jobject>(survivor);
}
@@ -857,7 +834,7 @@
static jobject NewGlobalRef(JNIEnv* env, jobject obj) {
ScopedObjectAccess soa(env);
- Object* decoded_obj = soa.Decode<Object*>(obj);
+ mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
// Check for null after decoding the object to handle cleared weak globals.
if (decoded_obj == nullptr) {
return nullptr;
@@ -870,7 +847,7 @@
}
static void DeleteGlobalRef(JNIEnv* env, jobject obj) {
- if (obj == NULL) {
+ if (obj == nullptr) {
return;
}
JavaVMExt* vm = reinterpret_cast<JNIEnvExt*>(env)->vm;
@@ -886,7 +863,7 @@
static jweak NewWeakGlobalRef(JNIEnv* env, jobject obj) {
ScopedObjectAccess soa(env);
- return AddWeakGlobalReference(soa, soa.Decode<Object*>(obj));
+ return AddWeakGlobalReference(soa, soa.Decode<mirror::Object*>(obj));
}
static void DeleteWeakGlobalRef(JNIEnv* env, jweak obj) {
@@ -898,7 +875,7 @@
static jobject NewLocalRef(JNIEnv* env, jobject obj) {
ScopedObjectAccess soa(env);
- mirror::Object* decoded_obj = soa.Decode<Object*>(obj);
+ mirror::Object* decoded_obj = soa.Decode<mirror::Object*>(obj);
// Check for null after decoding the object to handle cleared weak globals.
if (decoded_obj == nullptr) {
return nullptr;
@@ -907,7 +884,7 @@
}
static void DeleteLocalRef(JNIEnv* env, jobject obj) {
- if (obj == NULL) {
+ if (obj == nullptr) {
return;
}
IndirectReferenceTable& locals = reinterpret_cast<JNIEnvExt*>(env)->locals;
@@ -929,14 +906,14 @@
return JNI_TRUE;
} else {
ScopedObjectAccess soa(env);
- return (soa.Decode<Object*>(obj1) == soa.Decode<Object*>(obj2)) ? JNI_TRUE : JNI_FALSE;
+ return (soa.Decode<mirror::Object*>(obj1) == soa.Decode<mirror::Object*>(obj2)) ? JNI_TRUE : JNI_FALSE;
}
}
static jobject AllocObject(JNIEnv* env, jclass java_class) {
CHECK_NON_NULL_ARGUMENT(AllocObject, java_class);
ScopedObjectAccess soa(env);
- Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class));
+ mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
if (c == nullptr) {
return nullptr;
}
@@ -957,42 +934,40 @@
CHECK_NON_NULL_ARGUMENT(NewObjectV, java_class);
CHECK_NON_NULL_ARGUMENT(NewObjectV, mid);
ScopedObjectAccess soa(env);
- Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class));
+ mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
if (c == nullptr) {
return nullptr;
}
- Object* result = c->AllocObject(soa.Self());
+ mirror::Object* result = c->AllocObject(soa.Self());
if (result == nullptr) {
return nullptr;
}
jobject local_result = soa.AddLocalReference<jobject>(result);
CallNonvirtualVoidMethodV(env, local_result, java_class, mid, args);
- if (!soa.Self()->IsExceptionPending()) {
- return local_result;
- } else {
+ if (soa.Self()->IsExceptionPending()) {
return nullptr;
}
+ return local_result;
}
static jobject NewObjectA(JNIEnv* env, jclass java_class, jmethodID mid, jvalue* args) {
CHECK_NON_NULL_ARGUMENT(NewObjectA, java_class);
CHECK_NON_NULL_ARGUMENT(NewObjectA, mid);
ScopedObjectAccess soa(env);
- Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class));
+ mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
if (c == nullptr) {
return nullptr;
}
- Object* result = c->AllocObject(soa.Self());
- if (result == NULL) {
- return NULL;
+ mirror::Object* result = c->AllocObject(soa.Self());
+ if (result == nullptr) {
+ return nullptr;
}
jobject local_result = soa.AddLocalReference<jobjectArray>(result);
CallNonvirtualVoidMethodA(env, local_result, java_class, mid, args);
- if (!soa.Self()->IsExceptionPending()) {
- return local_result;
- } else {
- return NULL;
+ if (soa.Self()->IsExceptionPending()) {
+ return nullptr;
}
+ return local_result;
}
static jmethodID GetMethodID(JNIEnv* env, jclass java_class, const char* name, const char* sig) {
@@ -1557,15 +1532,15 @@
CHECK_NON_NULL_ARGUMENT(GetObjectField, obj);
CHECK_NON_NULL_ARGUMENT(GetObjectField, fid);
ScopedObjectAccess soa(env);
- Object* o = soa.Decode<Object*>(obj);
- ArtField* f = soa.DecodeField(fid);
+ mirror::Object* o = soa.Decode<mirror::Object*>(obj);
+ mirror::ArtField* f = soa.DecodeField(fid);
return soa.AddLocalReference<jobject>(f->GetObject(o));
}
static jobject GetStaticObjectField(JNIEnv* env, jclass, jfieldID fid) {
CHECK_NON_NULL_ARGUMENT(GetStaticObjectField, fid);
ScopedObjectAccess soa(env);
- ArtField* f = soa.DecodeField(fid);
+ mirror::ArtField* f = soa.DecodeField(fid);
return soa.AddLocalReference<jobject>(f->GetObject(f->GetDeclaringClass()));
}
@@ -1573,47 +1548,47 @@
CHECK_NON_NULL_ARGUMENT(SetObjectField, java_object);
CHECK_NON_NULL_ARGUMENT(SetObjectField, fid);
ScopedObjectAccess soa(env);
- Object* o = soa.Decode<Object*>(java_object);
- Object* v = soa.Decode<Object*>(java_value);
- ArtField* f = soa.DecodeField(fid);
- f->SetObject(o, v);
+ mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+ mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
+ mirror::ArtField* f = soa.DecodeField(fid);
+ f->SetObject<false>(o, v);
}
static void SetStaticObjectField(JNIEnv* env, jclass, jfieldID fid, jobject java_value) {
CHECK_NON_NULL_ARGUMENT(SetStaticObjectField, fid);
ScopedObjectAccess soa(env);
- Object* v = soa.Decode<Object*>(java_value);
- ArtField* f = soa.DecodeField(fid);
- f->SetObject(f->GetDeclaringClass(), v);
+ mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
+ mirror::ArtField* f = soa.DecodeField(fid);
+ f->SetObject<false>(f->GetDeclaringClass(), v);
}
#define GET_PRIMITIVE_FIELD(fn, instance) \
CHECK_NON_NULL_ARGUMENT(Get #fn Field, instance); \
CHECK_NON_NULL_ARGUMENT(Get #fn Field, fid); \
ScopedObjectAccess soa(env); \
- Object* o = soa.Decode<Object*>(instance); \
- ArtField* f = soa.DecodeField(fid); \
+ mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
+ mirror::ArtField* f = soa.DecodeField(fid); \
return f->Get ##fn (o)
#define GET_STATIC_PRIMITIVE_FIELD(fn) \
CHECK_NON_NULL_ARGUMENT(GetStatic #fn Field, fid); \
ScopedObjectAccess soa(env); \
- ArtField* f = soa.DecodeField(fid); \
+ mirror::ArtField* f = soa.DecodeField(fid); \
return f->Get ##fn (f->GetDeclaringClass())
#define SET_PRIMITIVE_FIELD(fn, instance, value) \
CHECK_NON_NULL_ARGUMENT(Set #fn Field, instance); \
CHECK_NON_NULL_ARGUMENT(Set #fn Field, fid); \
ScopedObjectAccess soa(env); \
- Object* o = soa.Decode<Object*>(instance); \
- ArtField* f = soa.DecodeField(fid); \
- f->Set ##fn(o, value)
+ mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
+ mirror::ArtField* f = soa.DecodeField(fid); \
+ f->Set ##fn <false>(o, value)
#define SET_STATIC_PRIMITIVE_FIELD(fn, value) \
CHECK_NON_NULL_ARGUMENT(SetStatic #fn Field, fid); \
ScopedObjectAccess soa(env); \
- ArtField* f = soa.DecodeField(fid); \
- f->Set ##fn(f->GetDeclaringClass(), value)
+ mirror::ArtField* f = soa.DecodeField(fid); \
+ f->Set ##fn <false>(f->GetDeclaringClass(), value)
static jboolean GetBooleanField(JNIEnv* env, jobject obj, jfieldID fid) {
GET_PRIMITIVE_FIELD(Boolean, obj);
@@ -1748,7 +1723,7 @@
va_start(ap, mid);
CHECK_NON_NULL_ARGUMENT(CallStaticObjectMethod, mid);
ScopedObjectAccess soa(env);
- JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+ JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
jobject local_result = soa.AddLocalReference<jobject>(result.GetL());
va_end(ap);
return local_result;
@@ -1757,14 +1732,14 @@
static jobject CallStaticObjectMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
CHECK_NON_NULL_ARGUMENT(CallStaticObjectMethodV, mid);
ScopedObjectAccess soa(env);
- JValue result(InvokeWithVarArgs(soa, NULL, mid, args));
+ JValue result(InvokeWithVarArgs(soa, nullptr, mid, args));
return soa.AddLocalReference<jobject>(result.GetL());
}
static jobject CallStaticObjectMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
CHECK_NON_NULL_ARGUMENT(CallStaticObjectMethodA, mid);
ScopedObjectAccess soa(env);
- JValue result(InvokeWithJValues(soa, NULL, mid, args));
+ JValue result(InvokeWithJValues(soa, nullptr, mid, args));
return soa.AddLocalReference<jobject>(result.GetL());
}
@@ -1773,7 +1748,7 @@
va_start(ap, mid);
CHECK_NON_NULL_ARGUMENT(CallStaticBooleanMethod, mid);
ScopedObjectAccess soa(env);
- JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+ JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
va_end(ap);
return result.GetZ();
}
@@ -1781,13 +1756,13 @@
static jboolean CallStaticBooleanMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
CHECK_NON_NULL_ARGUMENT(CallStaticBooleanMethodV, mid);
ScopedObjectAccess soa(env);
- return InvokeWithVarArgs(soa, NULL, mid, args).GetZ();
+ return InvokeWithVarArgs(soa, nullptr, mid, args).GetZ();
}
static jboolean CallStaticBooleanMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
CHECK_NON_NULL_ARGUMENT(CallStaticBooleanMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, NULL, mid, args).GetZ();
+ return InvokeWithJValues(soa, nullptr, mid, args).GetZ();
}
static jbyte CallStaticByteMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1795,7 +1770,7 @@
va_start(ap, mid);
CHECK_NON_NULL_ARGUMENT(CallStaticByteMethod, mid);
ScopedObjectAccess soa(env);
- JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+ JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
va_end(ap);
return result.GetB();
}
@@ -1803,13 +1778,13 @@
static jbyte CallStaticByteMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
CHECK_NON_NULL_ARGUMENT(CallStaticByteMethodV, mid);
ScopedObjectAccess soa(env);
- return InvokeWithVarArgs(soa, NULL, mid, args).GetB();
+ return InvokeWithVarArgs(soa, nullptr, mid, args).GetB();
}
static jbyte CallStaticByteMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
CHECK_NON_NULL_ARGUMENT(CallStaticByteMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, NULL, mid, args).GetB();
+ return InvokeWithJValues(soa, nullptr, mid, args).GetB();
}
static jchar CallStaticCharMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1817,7 +1792,7 @@
va_start(ap, mid);
CHECK_NON_NULL_ARGUMENT(CallStaticCharMethod, mid);
ScopedObjectAccess soa(env);
- JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+ JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
va_end(ap);
return result.GetC();
}
@@ -1825,13 +1800,13 @@
static jchar CallStaticCharMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
CHECK_NON_NULL_ARGUMENT(CallStaticCharMethodV, mid);
ScopedObjectAccess soa(env);
- return InvokeWithVarArgs(soa, NULL, mid, args).GetC();
+ return InvokeWithVarArgs(soa, nullptr, mid, args).GetC();
}
static jchar CallStaticCharMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
CHECK_NON_NULL_ARGUMENT(CallStaticCharMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, NULL, mid, args).GetC();
+ return InvokeWithJValues(soa, nullptr, mid, args).GetC();
}
static jshort CallStaticShortMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1839,7 +1814,7 @@
va_start(ap, mid);
CHECK_NON_NULL_ARGUMENT(CallStaticShortMethod, mid);
ScopedObjectAccess soa(env);
- JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+ JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
va_end(ap);
return result.GetS();
}
@@ -1847,13 +1822,13 @@
static jshort CallStaticShortMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
CHECK_NON_NULL_ARGUMENT(CallStaticShortMethodV, mid);
ScopedObjectAccess soa(env);
- return InvokeWithVarArgs(soa, NULL, mid, args).GetS();
+ return InvokeWithVarArgs(soa, nullptr, mid, args).GetS();
}
static jshort CallStaticShortMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
CHECK_NON_NULL_ARGUMENT(CallStaticShortMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, NULL, mid, args).GetS();
+ return InvokeWithJValues(soa, nullptr, mid, args).GetS();
}
static jint CallStaticIntMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1861,7 +1836,7 @@
va_start(ap, mid);
CHECK_NON_NULL_ARGUMENT(CallStaticIntMethod, mid);
ScopedObjectAccess soa(env);
- JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+ JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
va_end(ap);
return result.GetI();
}
@@ -1869,13 +1844,13 @@
static jint CallStaticIntMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
CHECK_NON_NULL_ARGUMENT(CallStaticIntMethodV, mid);
ScopedObjectAccess soa(env);
- return InvokeWithVarArgs(soa, NULL, mid, args).GetI();
+ return InvokeWithVarArgs(soa, nullptr, mid, args).GetI();
}
static jint CallStaticIntMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
CHECK_NON_NULL_ARGUMENT(CallStaticIntMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, NULL, mid, args).GetI();
+ return InvokeWithJValues(soa, nullptr, mid, args).GetI();
}
static jlong CallStaticLongMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1883,7 +1858,7 @@
va_start(ap, mid);
CHECK_NON_NULL_ARGUMENT(CallStaticLongMethod, mid);
ScopedObjectAccess soa(env);
- JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+ JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
va_end(ap);
return result.GetJ();
}
@@ -1891,13 +1866,13 @@
static jlong CallStaticLongMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
CHECK_NON_NULL_ARGUMENT(CallStaticLongMethodV, mid);
ScopedObjectAccess soa(env);
- return InvokeWithVarArgs(soa, NULL, mid, args).GetJ();
+ return InvokeWithVarArgs(soa, nullptr, mid, args).GetJ();
}
static jlong CallStaticLongMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
CHECK_NON_NULL_ARGUMENT(CallStaticLongMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, NULL, mid, args).GetJ();
+ return InvokeWithJValues(soa, nullptr, mid, args).GetJ();
}
static jfloat CallStaticFloatMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1905,7 +1880,7 @@
va_start(ap, mid);
CHECK_NON_NULL_ARGUMENT(CallStaticFloatMethod, mid);
ScopedObjectAccess soa(env);
- JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+ JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
va_end(ap);
return result.GetF();
}
@@ -1913,13 +1888,13 @@
static jfloat CallStaticFloatMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
CHECK_NON_NULL_ARGUMENT(CallStaticFloatMethodV, mid);
ScopedObjectAccess soa(env);
- return InvokeWithVarArgs(soa, NULL, mid, args).GetF();
+ return InvokeWithVarArgs(soa, nullptr, mid, args).GetF();
}
static jfloat CallStaticFloatMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
CHECK_NON_NULL_ARGUMENT(CallStaticFloatMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, NULL, mid, args).GetF();
+ return InvokeWithJValues(soa, nullptr, mid, args).GetF();
}
static jdouble CallStaticDoubleMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1927,7 +1902,7 @@
va_start(ap, mid);
CHECK_NON_NULL_ARGUMENT(CallStaticDoubleMethod, mid);
ScopedObjectAccess soa(env);
- JValue result(InvokeWithVarArgs(soa, NULL, mid, ap));
+ JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
va_end(ap);
return result.GetD();
}
@@ -1935,13 +1910,13 @@
static jdouble CallStaticDoubleMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
CHECK_NON_NULL_ARGUMENT(CallStaticDoubleMethodV, mid);
ScopedObjectAccess soa(env);
- return InvokeWithVarArgs(soa, NULL, mid, args).GetD();
+ return InvokeWithVarArgs(soa, nullptr, mid, args).GetD();
}
static jdouble CallStaticDoubleMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
CHECK_NON_NULL_ARGUMENT(CallStaticDoubleMethodA, mid);
ScopedObjectAccess soa(env);
- return InvokeWithJValues(soa, NULL, mid, args).GetD();
+ return InvokeWithJValues(soa, nullptr, mid, args).GetD();
}
static void CallStaticVoidMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
@@ -1949,20 +1924,20 @@
va_start(ap, mid);
CHECK_NON_NULL_ARGUMENT(CallStaticVoidMethod, mid);
ScopedObjectAccess soa(env);
- InvokeWithVarArgs(soa, NULL, mid, ap);
+ InvokeWithVarArgs(soa, nullptr, mid, ap);
va_end(ap);
}
static void CallStaticVoidMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
CHECK_NON_NULL_ARGUMENT(CallStaticVoidMethodV, mid);
ScopedObjectAccess soa(env);
- InvokeWithVarArgs(soa, NULL, mid, args);
+ InvokeWithVarArgs(soa, nullptr, mid, args);
}
static void CallStaticVoidMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
CHECK_NON_NULL_ARGUMENT(CallStaticVoidMethodA, mid);
ScopedObjectAccess soa(env);
- InvokeWithJValues(soa, NULL, mid, args);
+ InvokeWithJValues(soa, nullptr, mid, args);
}
static jstring NewString(JNIEnv* env, const jchar* chars, jsize char_count) {
@@ -1975,36 +1950,36 @@
return nullptr;
}
ScopedObjectAccess soa(env);
- String* result = String::AllocFromUtf16(soa.Self(), char_count, chars);
+ mirror::String* result = mirror::String::AllocFromUtf16(soa.Self(), char_count, chars);
return soa.AddLocalReference<jstring>(result);
}
static jstring NewStringUTF(JNIEnv* env, const char* utf) {
- if (utf == NULL) {
- return NULL;
+ if (utf == nullptr) {
+ return nullptr;
}
ScopedObjectAccess soa(env);
- String* result = String::AllocFromModifiedUtf8(soa.Self(), utf);
+ mirror::String* result = mirror::String::AllocFromModifiedUtf8(soa.Self(), utf);
return soa.AddLocalReference<jstring>(result);
}
static jsize GetStringLength(JNIEnv* env, jstring java_string) {
CHECK_NON_NULL_ARGUMENT(GetStringLength, java_string);
ScopedObjectAccess soa(env);
- return soa.Decode<String*>(java_string)->GetLength();
+ return soa.Decode<mirror::String*>(java_string)->GetLength();
}
static jsize GetStringUTFLength(JNIEnv* env, jstring java_string) {
CHECK_NON_NULL_ARGUMENT(GetStringLength, java_string);
ScopedObjectAccess soa(env);
- return soa.Decode<String*>(java_string)->GetUtfLength();
+ return soa.Decode<mirror::String*>(java_string)->GetUtfLength();
}
static void GetStringRegion(JNIEnv* env, jstring java_string, jsize start, jsize length,
jchar* buf) {
CHECK_NON_NULL_ARGUMENT(GetStringRegion, java_string);
ScopedObjectAccess soa(env);
- String* s = soa.Decode<String*>(java_string);
+ mirror::String* s = soa.Decode<mirror::String*>(java_string);
if (start < 0 || length < 0 || start + length > s->GetLength()) {
ThrowSIOOBE(soa, start, length, s->GetLength());
} else {
@@ -2018,7 +1993,7 @@
char* buf) {
CHECK_NON_NULL_ARGUMENT(GetStringUTFRegion, java_string);
ScopedObjectAccess soa(env);
- String* s = soa.Decode<String*>(java_string);
+ mirror::String* s = soa.Decode<mirror::String*>(java_string);
if (start < 0 || length < 0 || start + length > s->GetLength()) {
ThrowSIOOBE(soa, start, length, s->GetLength());
} else {
@@ -2029,10 +2004,10 @@
}
static const jchar* GetStringChars(JNIEnv* env, jstring java_string, jboolean* is_copy) {
- CHECK_NON_NULL_ARGUMENT(GetStringUTFRegion, java_string);
+ CHECK_NON_NULL_ARGUMENT(GetStringChars, java_string);
ScopedObjectAccess soa(env);
- String* s = soa.Decode<String*>(java_string);
- CharArray* chars = s->GetCharArray();
+ mirror::String* s = soa.Decode<mirror::String*>(java_string);
+ mirror::CharArray* chars = s->GetCharArray();
PinPrimitiveArray(soa, chars);
if (is_copy != nullptr) {
*is_copy = JNI_TRUE;
@@ -2048,10 +2023,10 @@
}
static void ReleaseStringChars(JNIEnv* env, jstring java_string, const jchar* chars) {
- CHECK_NON_NULL_ARGUMENT(GetStringUTFRegion, java_string);
+ CHECK_NON_NULL_ARGUMENT(ReleaseStringChars, java_string);
delete[] chars;
ScopedObjectAccess soa(env);
- UnpinPrimitiveArray(soa, soa.Decode<String*>(java_string)->GetCharArray());
+ UnpinPrimitiveArray(soa, soa.Decode<mirror::String*>(java_string)->GetCharArray());
}
static const jchar* GetStringCritical(JNIEnv* env, jstring java_string, jboolean* is_copy) {
@@ -2063,17 +2038,17 @@
}
static const char* GetStringUTFChars(JNIEnv* env, jstring java_string, jboolean* is_copy) {
- if (java_string == NULL) {
- return NULL;
+ if (java_string == nullptr) {
+ return nullptr;
}
- if (is_copy != NULL) {
+ if (is_copy != nullptr) {
*is_copy = JNI_TRUE;
}
ScopedObjectAccess soa(env);
- String* s = soa.Decode<String*>(java_string);
+ mirror::String* s = soa.Decode<mirror::String*>(java_string);
size_t byte_count = s->GetUtfLength();
char* bytes = new char[byte_count + 1];
- CHECK(bytes != NULL); // bionic aborts anyway.
+ CHECK(bytes != nullptr); // bionic aborts anyway.
const uint16_t* chars = s->GetCharArray()->GetData() + s->GetOffset();
ConvertUtf16ToModifiedUtf8(bytes, chars, s->GetLength());
bytes[byte_count] = '\0';
@@ -2087,18 +2062,19 @@
static jsize GetArrayLength(JNIEnv* env, jarray java_array) {
CHECK_NON_NULL_ARGUMENT(GetArrayLength, java_array);
ScopedObjectAccess soa(env);
- Object* obj = soa.Decode<Object*>(java_array);
+ mirror::Object* obj = soa.Decode<mirror::Object*>(java_array);
if (UNLIKELY(!obj->IsArrayInstance())) {
JniAbortF("GetArrayLength", "not an array: %s", PrettyTypeOf(obj).c_str());
}
- Array* array = obj->AsArray();
+ mirror::Array* array = obj->AsArray();
return array->GetLength();
}
static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray java_array, jsize index) {
CHECK_NON_NULL_ARGUMENT(GetObjectArrayElement, java_array);
ScopedObjectAccess soa(env);
- ObjectArray<Object>* array = soa.Decode<ObjectArray<Object>*>(java_array);
+ mirror::ObjectArray<mirror::Object>* array =
+ soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
return soa.AddLocalReference<jobject>(array->Get(index));
}
@@ -2106,44 +2082,45 @@
jobject java_value) {
CHECK_NON_NULL_ARGUMENT(SetObjectArrayElement, java_array);
ScopedObjectAccess soa(env);
- ObjectArray<Object>* array = soa.Decode<ObjectArray<Object>*>(java_array);
- Object* value = soa.Decode<Object*>(java_value);
- array->Set(index, value);
+ mirror::ObjectArray<mirror::Object>* array =
+ soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
+ mirror::Object* value = soa.Decode<mirror::Object*>(java_value);
+ array->Set<false>(index, value);
}
static jbooleanArray NewBooleanArray(JNIEnv* env, jsize length) {
ScopedObjectAccess soa(env);
- return NewPrimitiveArray<jbooleanArray, BooleanArray>(soa, length);
+ return NewPrimitiveArray<jbooleanArray, mirror::BooleanArray>(soa, length);
}
static jbyteArray NewByteArray(JNIEnv* env, jsize length) {
ScopedObjectAccess soa(env);
- return NewPrimitiveArray<jbyteArray, ByteArray>(soa, length);
+ return NewPrimitiveArray<jbyteArray, mirror::ByteArray>(soa, length);
}
static jcharArray NewCharArray(JNIEnv* env, jsize length) {
ScopedObjectAccess soa(env);
- return NewPrimitiveArray<jcharArray, CharArray>(soa, length);
+ return NewPrimitiveArray<jcharArray, mirror::CharArray>(soa, length);
}
static jdoubleArray NewDoubleArray(JNIEnv* env, jsize length) {
ScopedObjectAccess soa(env);
- return NewPrimitiveArray<jdoubleArray, DoubleArray>(soa, length);
+ return NewPrimitiveArray<jdoubleArray, mirror::DoubleArray>(soa, length);
}
static jfloatArray NewFloatArray(JNIEnv* env, jsize length) {
ScopedObjectAccess soa(env);
- return NewPrimitiveArray<jfloatArray, FloatArray>(soa, length);
+ return NewPrimitiveArray<jfloatArray, mirror::FloatArray>(soa, length);
}
static jintArray NewIntArray(JNIEnv* env, jsize length) {
ScopedObjectAccess soa(env);
- return NewPrimitiveArray<jintArray, IntArray>(soa, length);
+ return NewPrimitiveArray<jintArray, mirror::IntArray>(soa, length);
}
static jlongArray NewLongArray(JNIEnv* env, jsize length) {
ScopedObjectAccess soa(env);
- return NewPrimitiveArray<jlongArray, LongArray>(soa, length);
+ return NewPrimitiveArray<jlongArray, mirror::LongArray>(soa, length);
}
static jobjectArray NewObjectArray(JNIEnv* env, jsize length, jclass element_jclass,
@@ -2155,9 +2132,9 @@
// Compute the array class corresponding to the given element class.
ScopedObjectAccess soa(env);
- Class* array_class;
+ mirror::Class* array_class;
{
- Class* element_class = soa.Decode<Class*>(element_jclass);
+ mirror::Class* element_class = soa.Decode<mirror::Class*>(element_jclass);
if (UNLIKELY(element_class->IsPrimitive())) {
JniAbortF("NewObjectArray", "not an object type: %s",
PrettyDescriptor(element_class).c_str());
@@ -2176,9 +2153,10 @@
}
// Allocate and initialize if necessary.
- ObjectArray<Object>* result = ObjectArray<Object>::Alloc(soa.Self(), array_class, length);
+ mirror::ObjectArray<mirror::Object>* result =
+ mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), array_class, length);
if (result != nullptr && initial_element != nullptr) {
- Object* initial_object = soa.Decode<Object*>(initial_element);
+ mirror::Object* initial_object = soa.Decode<mirror::Object*>(initial_element);
if (initial_object != nullptr) {
mirror::Class* element_class = result->GetClass()->GetComponentType();
if (UNLIKELY(!element_class->IsAssignableFrom(initial_object->GetClass()))) {
@@ -2188,7 +2166,7 @@
} else {
for (jsize i = 0; i < length; ++i) {
- result->SetWithoutChecks(i, initial_object);
+ result->SetWithoutChecks<false>(i, initial_object);
}
}
}
@@ -2198,18 +2176,18 @@
static jshortArray NewShortArray(JNIEnv* env, jsize length) {
ScopedObjectAccess soa(env);
- return NewPrimitiveArray<jshortArray, ShortArray>(soa, length);
+ return NewPrimitiveArray<jshortArray, mirror::ShortArray>(soa, length);
}
static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray java_array, jboolean* is_copy) {
CHECK_NON_NULL_ARGUMENT(GetPrimitiveArrayCritical, java_array);
ScopedObjectAccess soa(env);
- Array* array = soa.Decode<Array*>(java_array);
+ mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
gc::Heap* heap = Runtime::Current()->GetHeap();
if (heap->IsMovableObject(array)) {
heap->IncrementDisableMovingGC(soa.Self());
// Re-decode in case the object moved since IncrementDisableGC waits for GC to complete.
- array = soa.Decode<Array*>(java_array);
+ array = soa.Decode<mirror::Array*>(java_array);
}
PinPrimitiveArray(soa, array);
if (is_copy != nullptr) {
@@ -2226,49 +2204,49 @@
static jboolean* GetBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* is_copy) {
CHECK_NON_NULL_ARGUMENT(GetBooleanArrayElements, array);
ScopedObjectAccess soa(env);
- return GetPrimitiveArray<jbooleanArray, jboolean*, BooleanArray>(soa, array, is_copy);
+ return GetPrimitiveArray<jbooleanArray, jboolean*, mirror::BooleanArray>(soa, array, is_copy);
}
static jbyte* GetByteArrayElements(JNIEnv* env, jbyteArray array, jboolean* is_copy) {
CHECK_NON_NULL_ARGUMENT(GetByteArrayElements, array);
ScopedObjectAccess soa(env);
- return GetPrimitiveArray<jbyteArray, jbyte*, ByteArray>(soa, array, is_copy);
+ return GetPrimitiveArray<jbyteArray, jbyte*, mirror::ByteArray>(soa, array, is_copy);
}
static jchar* GetCharArrayElements(JNIEnv* env, jcharArray array, jboolean* is_copy) {
CHECK_NON_NULL_ARGUMENT(GetCharArrayElements, array);
ScopedObjectAccess soa(env);
- return GetPrimitiveArray<jcharArray, jchar*, CharArray>(soa, array, is_copy);
+ return GetPrimitiveArray<jcharArray, jchar*, mirror::CharArray>(soa, array, is_copy);
}
static jdouble* GetDoubleArrayElements(JNIEnv* env, jdoubleArray array, jboolean* is_copy) {
CHECK_NON_NULL_ARGUMENT(GetDoubleArrayElements, array);
ScopedObjectAccess soa(env);
- return GetPrimitiveArray<jdoubleArray, jdouble*, DoubleArray>(soa, array, is_copy);
+ return GetPrimitiveArray<jdoubleArray, jdouble*, mirror::DoubleArray>(soa, array, is_copy);
}
static jfloat* GetFloatArrayElements(JNIEnv* env, jfloatArray array, jboolean* is_copy) {
CHECK_NON_NULL_ARGUMENT(GetFloatArrayElements, array);
ScopedObjectAccess soa(env);
- return GetPrimitiveArray<jfloatArray, jfloat*, FloatArray>(soa, array, is_copy);
+ return GetPrimitiveArray<jfloatArray, jfloat*, mirror::FloatArray>(soa, array, is_copy);
}
static jint* GetIntArrayElements(JNIEnv* env, jintArray array, jboolean* is_copy) {
CHECK_NON_NULL_ARGUMENT(GetIntArrayElements, array);
ScopedObjectAccess soa(env);
- return GetPrimitiveArray<jintArray, jint*, IntArray>(soa, array, is_copy);
+ return GetPrimitiveArray<jintArray, jint*, mirror::IntArray>(soa, array, is_copy);
}
static jlong* GetLongArrayElements(JNIEnv* env, jlongArray array, jboolean* is_copy) {
CHECK_NON_NULL_ARGUMENT(GetLongArrayElements, array);
ScopedObjectAccess soa(env);
- return GetPrimitiveArray<jlongArray, jlong*, LongArray>(soa, array, is_copy);
+ return GetPrimitiveArray<jlongArray, jlong*, mirror::LongArray>(soa, array, is_copy);
}
static jshort* GetShortArrayElements(JNIEnv* env, jshortArray array, jboolean* is_copy) {
CHECK_NON_NULL_ARGUMENT(GetShortArrayElements, array);
ScopedObjectAccess soa(env);
- return GetPrimitiveArray<jshortArray, jshort*, ShortArray>(soa, array, is_copy);
+ return GetPrimitiveArray<jshortArray, jshort*, mirror::ShortArray>(soa, array, is_copy);
}
static void ReleaseBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* elements,
@@ -2310,97 +2288,102 @@
static void GetBooleanArrayRegion(JNIEnv* env, jbooleanArray array, jsize start, jsize length,
jboolean* buf) {
ScopedObjectAccess soa(env);
- GetPrimitiveArrayRegion<jbooleanArray, jboolean, BooleanArray>(soa, array, start, length, buf);
+ GetPrimitiveArrayRegion<jbooleanArray, jboolean, mirror::BooleanArray>(soa, array, start,
+ length, buf);
}
static void GetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize length,
jbyte* buf) {
ScopedObjectAccess soa(env);
- GetPrimitiveArrayRegion<jbyteArray, jbyte, ByteArray>(soa, array, start, length, buf);
+ GetPrimitiveArrayRegion<jbyteArray, jbyte, mirror::ByteArray>(soa, array, start, length, buf);
}
static void GetCharArrayRegion(JNIEnv* env, jcharArray array, jsize start, jsize length,
jchar* buf) {
ScopedObjectAccess soa(env);
- GetPrimitiveArrayRegion<jcharArray, jchar, CharArray>(soa, array, start, length, buf);
+ GetPrimitiveArrayRegion<jcharArray, jchar, mirror::CharArray>(soa, array, start, length, buf);
}
static void GetDoubleArrayRegion(JNIEnv* env, jdoubleArray array, jsize start, jsize length,
jdouble* buf) {
ScopedObjectAccess soa(env);
- GetPrimitiveArrayRegion<jdoubleArray, jdouble, DoubleArray>(soa, array, start, length, buf);
+ GetPrimitiveArrayRegion<jdoubleArray, jdouble, mirror::DoubleArray>(soa, array, start, length,
+ buf);
}
static void GetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start, jsize length,
jfloat* buf) {
ScopedObjectAccess soa(env);
- GetPrimitiveArrayRegion<jfloatArray, jfloat, FloatArray>(soa, array, start, length, buf);
+ GetPrimitiveArrayRegion<jfloatArray, jfloat, mirror::FloatArray>(soa, array, start, length,
+ buf);
}
static void GetIntArrayRegion(JNIEnv* env, jintArray array, jsize start, jsize length,
jint* buf) {
ScopedObjectAccess soa(env);
- GetPrimitiveArrayRegion<jintArray, jint, IntArray>(soa, array, start, length, buf);
+ GetPrimitiveArrayRegion<jintArray, jint, mirror::IntArray>(soa, array, start, length, buf);
}
static void GetLongArrayRegion(JNIEnv* env, jlongArray array, jsize start, jsize length,
jlong* buf) {
ScopedObjectAccess soa(env);
- GetPrimitiveArrayRegion<jlongArray, jlong, LongArray>(soa, array, start, length, buf);
+ GetPrimitiveArrayRegion<jlongArray, jlong, mirror::LongArray>(soa, array, start, length, buf);
}
static void GetShortArrayRegion(JNIEnv* env, jshortArray array, jsize start, jsize length,
jshort* buf) {
ScopedObjectAccess soa(env);
- GetPrimitiveArrayRegion<jshortArray, jshort, ShortArray>(soa, array, start, length, buf);
+ GetPrimitiveArrayRegion<jshortArray, jshort, mirror::ShortArray>(soa, array, start, length,
+ buf);
}
static void SetBooleanArrayRegion(JNIEnv* env, jbooleanArray array, jsize start, jsize length,
const jboolean* buf) {
ScopedObjectAccess soa(env);
- SetPrimitiveArrayRegion<jbooleanArray, jboolean, BooleanArray>(soa, array, start, length, buf);
+ SetPrimitiveArrayRegion<jbooleanArray, jboolean, mirror::BooleanArray>(soa, array, start, length, buf);
}
static void SetByteArrayRegion(JNIEnv* env, jbyteArray array, jsize start, jsize length,
const jbyte* buf) {
ScopedObjectAccess soa(env);
- SetPrimitiveArrayRegion<jbyteArray, jbyte, ByteArray>(soa, array, start, length, buf);
+ SetPrimitiveArrayRegion<jbyteArray, jbyte, mirror::ByteArray>(soa, array, start, length, buf);
}
static void SetCharArrayRegion(JNIEnv* env, jcharArray array, jsize start, jsize length,
const jchar* buf) {
ScopedObjectAccess soa(env);
- SetPrimitiveArrayRegion<jcharArray, jchar, CharArray>(soa, array, start, length, buf);
+ SetPrimitiveArrayRegion<jcharArray, jchar, mirror::CharArray>(soa, array, start, length, buf);
}
static void SetDoubleArrayRegion(JNIEnv* env, jdoubleArray array, jsize start, jsize length,
const jdouble* buf) {
ScopedObjectAccess soa(env);
- SetPrimitiveArrayRegion<jdoubleArray, jdouble, DoubleArray>(soa, array, start, length, buf);
+ SetPrimitiveArrayRegion<jdoubleArray, jdouble, mirror::DoubleArray>(soa, array, start, length, buf);
}
static void SetFloatArrayRegion(JNIEnv* env, jfloatArray array, jsize start, jsize length,
const jfloat* buf) {
ScopedObjectAccess soa(env);
- SetPrimitiveArrayRegion<jfloatArray, jfloat, FloatArray>(soa, array, start, length, buf);
+ SetPrimitiveArrayRegion<jfloatArray, jfloat, mirror::FloatArray>(soa, array, start, length, buf);
}
static void SetIntArrayRegion(JNIEnv* env, jintArray array, jsize start, jsize length,
const jint* buf) {
ScopedObjectAccess soa(env);
- SetPrimitiveArrayRegion<jintArray, jint, IntArray>(soa, array, start, length, buf);
+ SetPrimitiveArrayRegion<jintArray, jint, mirror::IntArray>(soa, array, start, length, buf);
}
static void SetLongArrayRegion(JNIEnv* env, jlongArray array, jsize start, jsize length,
const jlong* buf) {
ScopedObjectAccess soa(env);
- SetPrimitiveArrayRegion<jlongArray, jlong, LongArray>(soa, array, start, length, buf);
+ SetPrimitiveArrayRegion<jlongArray, jlong, mirror::LongArray>(soa, array, start, length, buf);
}
static void SetShortArrayRegion(JNIEnv* env, jshortArray array, jsize start, jsize length,
const jshort* buf) {
ScopedObjectAccess soa(env);
- SetPrimitiveArrayRegion<jshortArray, jshort, ShortArray>(soa, array, start, length, buf);
+ SetPrimitiveArrayRegion<jshortArray, jshort, mirror::ShortArray>(soa, array, start, length,
+ buf);
}
static jint RegisterNatives(JNIEnv* env, jclass java_class, const JNINativeMethod* methods,
@@ -2416,7 +2399,7 @@
}
CHECK_NON_NULL_ARGUMENT(RegisterNatives, java_class);
ScopedObjectAccess soa(env);
- Class* c = soa.Decode<Class*>(java_class);
+ mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
if (UNLIKELY(method_count == 0)) {
LOG(WARNING) << "JNI RegisterNativeMethods: attempt to register 0 native methods for "
<< PrettyDescriptor(c);
@@ -2432,11 +2415,11 @@
++sig;
}
- ArtMethod* m = c->FindDirectMethod(name, sig);
- if (m == NULL) {
+ mirror::ArtMethod* m = c->FindDirectMethod(name, sig);
+ if (m == nullptr) {
m = c->FindVirtualMethod(name, sig);
}
- if (m == NULL) {
+ if (m == nullptr) {
c->DumpClass(LOG(ERROR), mirror::Class::kDumpClassFullDetail);
LOG(return_errors ? ERROR : FATAL) << "Failed to register native method "
<< PrettyDescriptor(c) << "." << name << sig << " in "
@@ -2461,18 +2444,18 @@
static jint UnregisterNatives(JNIEnv* env, jclass java_class) {
CHECK_NON_NULL_ARGUMENT(UnregisterNatives, java_class);
ScopedObjectAccess soa(env);
- Class* c = soa.Decode<Class*>(java_class);
+ mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
VLOG(jni) << "[Unregistering JNI native methods for " << PrettyClass(c) << "]";
for (size_t i = 0; i < c->NumDirectMethods(); ++i) {
- ArtMethod* m = c->GetDirectMethod(i);
+ mirror::ArtMethod* m = c->GetDirectMethod(i);
if (m->IsNative()) {
m->UnregisterNative(soa.Self());
}
}
for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
- ArtMethod* m = c->GetVirtualMethod(i);
+ mirror::ArtMethod* m = c->GetVirtualMethod(i);
if (m->IsNative()) {
m->UnregisterNative(soa.Self());
}
@@ -2485,8 +2468,8 @@
EXCLUSIVE_LOCK_FUNCTION(monitor_lock_) {
CHECK_NON_NULL_ARGUMENT(MonitorEnter, java_object);
ScopedObjectAccess soa(env);
- Object* o = soa.Decode<Object*>(java_object);
- o->MonitorEnter(soa.Self());
+ mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
+ o = o->MonitorEnter(soa.Self());
if (soa.Self()->IsExceptionPending()) {
return JNI_ERR;
}
@@ -2498,7 +2481,7 @@
UNLOCK_FUNCTION(monitor_lock_) {
CHECK_NON_NULL_ARGUMENT(MonitorExit, java_object);
ScopedObjectAccess soa(env);
- Object* o = soa.Decode<Object*>(java_object);
+ mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
o->MonitorExit(soa.Self());
if (soa.Self()->IsExceptionPending()) {
return JNI_ERR;
@@ -2510,20 +2493,20 @@
static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
CHECK_NON_NULL_ARGUMENT(GetJavaVM, vm);
Runtime* runtime = Runtime::Current();
- if (runtime != NULL) {
+ if (runtime != nullptr) {
*vm = runtime->GetJavaVM();
} else {
- *vm = NULL;
+ *vm = nullptr;
}
- return (*vm != NULL) ? JNI_OK : JNI_ERR;
+ return (*vm != nullptr) ? JNI_OK : JNI_ERR;
}
static jobject NewDirectByteBuffer(JNIEnv* env, void* address, jlong capacity) {
if (capacity < 0) {
JniAbortF("NewDirectByteBuffer", "negative buffer capacity: %" PRId64, capacity);
}
- if (address == NULL && capacity != 0) {
- JniAbortF("NewDirectByteBuffer", "non-zero capacity for NULL pointer: %" PRId64, capacity);
+ if (address == nullptr && capacity != 0) {
+ JniAbortF("NewDirectByteBuffer", "non-zero capacity for nullptr pointer: %" PRId64, capacity);
}
// At the moment, the Java side is limited to 32 bits.
@@ -2535,15 +2518,17 @@
jobject result = env->NewObject(WellKnownClasses::java_nio_DirectByteBuffer,
WellKnownClasses::java_nio_DirectByteBuffer_init,
address_arg, capacity_arg);
- return static_cast<JNIEnvExt*>(env)->self->IsExceptionPending() ? NULL : result;
+ return static_cast<JNIEnvExt*>(env)->self->IsExceptionPending() ? nullptr : result;
}
static void* GetDirectBufferAddress(JNIEnv* env, jobject java_buffer) {
- return reinterpret_cast<void*>(env->GetLongField(java_buffer, WellKnownClasses::java_nio_DirectByteBuffer_effectiveDirectAddress));
+ return reinterpret_cast<void*>(env->GetLongField(
+ java_buffer, WellKnownClasses::java_nio_DirectByteBuffer_effectiveDirectAddress));
}
static jlong GetDirectBufferCapacity(JNIEnv* env, jobject java_buffer) {
- return static_cast<jlong>(env->GetIntField(java_buffer, WellKnownClasses::java_nio_DirectByteBuffer_capacity));
+ return static_cast<jlong>(env->GetIntField(
+ java_buffer, WellKnownClasses::java_nio_DirectByteBuffer_capacity));
}
static jobjectRefType GetObjectRefType(JNIEnv* env, jobject java_object) {
@@ -2572,12 +2557,13 @@
return JNIInvalidRefType;
}
- // If we're handing out direct pointers, check whether it's a direct pointer
- // to a local reference.
+ // If we're handing out direct pointers, check whether it's a direct pointer to a local
+ // reference.
{
ScopedObjectAccess soa(env);
- if (soa.Decode<Object*>(java_object) == reinterpret_cast<Object*>(java_object)) {
- if (soa.Env()->locals.ContainsDirectPointer(reinterpret_cast<Object*>(java_object))) {
+ if (soa.Decode<mirror::Object*>(java_object) ==
+ reinterpret_cast<mirror::Object*>(java_object)) {
+ if (soa.Env()->locals.ContainsDirectPointer(reinterpret_cast<mirror::Object*>(java_object))) {
return JNILocalRefType;
}
}
@@ -2644,7 +2630,7 @@
template <typename ArrayT, typename ElementT>
static void ReleasePrimitiveArray(JNIEnv* env, ArrayT java_array, ElementT* elements, jint mode) {
ScopedObjectAccess soa(env);
- Array* array = soa.Decode<Array*>(java_array);
+ mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
size_t component_size = array->GetClass()->GetComponentSize();
void* array_data = array->GetRawData(component_size, 0);
gc::Heap* heap = Runtime::Current()->GetHeap();
@@ -2709,10 +2695,10 @@
};
const JNINativeInterface gJniNativeInterface = {
- NULL, // reserved0.
- NULL, // reserved1.
- NULL, // reserved2.
- NULL, // reserved3.
+ nullptr, // reserved0.
+ nullptr, // reserved1.
+ nullptr, // reserved2.
+ nullptr, // reserved3.
JNI::GetVersion,
JNI::DefineClass,
JNI::FindClass,
@@ -3032,7 +3018,7 @@
extern "C" jint JNI_GetCreatedJavaVMs(JavaVM** vms, jsize, jsize* vm_count) {
Runtime* runtime = Runtime::Current();
- if (runtime == NULL) {
+ if (runtime == nullptr) {
*vm_count = 0;
} else {
*vm_count = 1;
@@ -3049,7 +3035,7 @@
class JII {
public:
static jint DestroyJavaVM(JavaVM* vm) {
- if (vm == NULL) {
+ if (vm == nullptr) {
return JNI_ERR;
}
JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
@@ -3066,7 +3052,7 @@
}
static jint DetachCurrentThread(JavaVM* vm) {
- if (vm == NULL || Thread::Current() == NULL) {
+ if (vm == nullptr || Thread::Current() == nullptr) {
return JNI_ERR;
}
JavaVMExt* raw_vm = reinterpret_cast<JavaVMExt*>(vm);
@@ -3083,12 +3069,12 @@
LOG(ERROR) << "Bad JNI version passed to GetEnv: " << version;
return JNI_EVERSION;
}
- if (vm == NULL || env == NULL) {
+ if (vm == nullptr || env == nullptr) {
return JNI_ERR;
}
Thread* thread = Thread::Current();
- if (thread == NULL) {
- *env = NULL;
+ if (thread == nullptr) {
+ *env = nullptr;
return JNI_EDETACHED;
}
*env = thread->GetJniEnv();
@@ -3097,9 +3083,9 @@
};
const JNIInvokeInterface gJniInvokeInterface = {
- NULL, // reserved0
- NULL, // reserved1
- NULL, // reserved2
+ nullptr, // reserved0
+ nullptr, // reserved1
+ nullptr, // reserved2
JII::DestroyJavaVM,
JII::AttachCurrentThread,
JII::DetachCurrentThread,
@@ -3109,8 +3095,8 @@
JavaVMExt::JavaVMExt(Runtime* runtime, Runtime::ParsedOptions* options)
: runtime(runtime),
- check_jni_abort_hook(NULL),
- check_jni_abort_hook_data(NULL),
+ check_jni_abort_hook(nullptr),
+ check_jni_abort_hook_data(nullptr),
check_jni(false),
force_copy(false), // TODO: add a way to enable this
trace(options->jni_trace_),
@@ -3226,7 +3212,7 @@
}
bool JavaVMExt::LoadNativeLibrary(const std::string& path,
- const SirtRef<ClassLoader>& class_loader,
+ const SirtRef<mirror::ClassLoader>& class_loader,
std::string* detail) {
detail->clear();
@@ -3241,7 +3227,7 @@
MutexLock mu(self, libraries_lock);
library = libraries->Get(path);
}
- if (library != NULL) {
+ if (library != nullptr) {
if (library->GetClassLoader() != class_loader.get()) {
// The library will be associated with class_loader. The JNI
// spec says we can't load the same library into more than one
@@ -3276,12 +3262,12 @@
// This can execute slowly for a large library on a busy system, so we
// want to switch from kRunnable while it executes. This allows the GC to ignore us.
self->TransitionFromRunnableToSuspended(kWaitingForJniOnLoad);
- void* handle = dlopen(path.empty() ? NULL : path.c_str(), RTLD_LAZY);
+ void* handle = dlopen(path.empty() ? nullptr : path.c_str(), RTLD_LAZY);
self->TransitionFromSuspendedToRunnable();
VLOG(jni) << "[Call to dlopen(\"" << path << "\", RTLD_LAZY) returned " << handle << "]";
- if (handle == NULL) {
+ if (handle == nullptr) {
*detail = dlerror();
LOG(ERROR) << "dlopen(\"" << path << "\", RTLD_LAZY) failed: " << detail;
return false;
@@ -3293,7 +3279,7 @@
{
MutexLock mu(self, libraries_lock);
library = libraries->Get(path);
- if (library == NULL) { // We won race to get libraries_lock
+ if (library == nullptr) { // We won race to get libraries_lock
library = new SharedLibrary(path, handle, class_loader.get());
libraries->Put(path, library);
created_library = true;
@@ -3310,7 +3296,7 @@
bool was_successful = false;
void* sym = dlsym(handle, "JNI_OnLoad");
- if (sym == NULL) {
+ if (sym == nullptr) {
VLOG(jni) << "[No JNI_OnLoad found in \"" << path << "\"]";
was_successful = true;
} else {
@@ -3320,14 +3306,14 @@
// the comments in the JNI FindClass function.)
typedef int (*JNI_OnLoadFn)(JavaVM*, void*);
JNI_OnLoadFn jni_on_load = reinterpret_cast<JNI_OnLoadFn>(sym);
- SirtRef<ClassLoader> old_class_loader(self, self->GetClassLoaderOverride());
+ SirtRef<mirror::ClassLoader> old_class_loader(self, self->GetClassLoaderOverride());
self->SetClassLoaderOverride(class_loader.get());
int version = 0;
{
ScopedThreadStateChange tsc(self, kNative);
VLOG(jni) << "[Calling JNI_OnLoad in \"" << path << "\"]";
- version = (*jni_on_load)(this, NULL);
+ version = (*jni_on_load)(this, nullptr);
}
self->SetClassLoaderOverride(old_class_loader.get());
@@ -3354,11 +3340,9 @@
return was_successful;
}
-void* JavaVMExt::FindCodeForNativeMethod(ArtMethod* m) {
+void* JavaVMExt::FindCodeForNativeMethod(mirror::ArtMethod* m) {
CHECK(m->IsNative());
-
- Class* c = m->GetDeclaringClass();
-
+ mirror::Class* c = m->GetDeclaringClass();
// If this is a static method, it could be called before the class
// has been initialized.
if (m->IsStatic()) {
@@ -3369,7 +3353,6 @@
} else {
CHECK(c->IsInitializing()) << c->GetStatus() << " " << PrettyMethod(m);
}
-
std::string detail;
void* native_method;
Thread* self = Thread::Current();
@@ -3378,7 +3361,7 @@
native_method = libraries->FindNativeMethod(m, detail);
}
// Throwing can cause libraries_lock to be reacquired.
- if (native_method == NULL) {
+ if (native_method == nullptr) {
ThrowLocation throw_location = self->GetCurrentLocationForThrow();
self->ThrowNewException(throw_location, "Ljava/lang/UnsatisfiedLinkError;", detail.c_str());
}
@@ -3418,7 +3401,7 @@
void RegisterNativeMethods(JNIEnv* env, const char* jni_class_name, const JNINativeMethod* methods,
jint method_count) {
ScopedLocalRef<jclass> c(env, env->FindClass(jni_class_name));
- if (c.get() == NULL) {
+ if (c.get() == nullptr) {
LOG(FATAL) << "Couldn't find class: " << jni_class_name;
}
JNI::RegisterNativeMethods(env, c.get(), methods, method_count, false);
diff --git a/runtime/locks.cc b/runtime/locks.cc
index d08206a..246e339 100644
--- a/runtime/locks.cc
+++ b/runtime/locks.cc
@@ -33,6 +33,7 @@
Mutex* Locks::trace_lock_ = NULL;
Mutex* Locks::profiler_lock_ = NULL;
Mutex* Locks::unexpected_signal_lock_ = NULL;
+Mutex* Locks::intern_table_lock_ = NULL;
void Locks::Init() {
if (logging_lock_ != NULL) {
@@ -49,6 +50,7 @@
DCHECK(trace_lock_ != NULL);
DCHECK(profiler_lock_ != NULL);
DCHECK(unexpected_signal_lock_ != NULL);
+ DCHECK(intern_table_lock_ != NULL);
} else {
logging_lock_ = new Mutex("logging lock", kLoggingLock, true);
abort_lock_ = new Mutex("abort lock", kAbortLock, true);
@@ -76,6 +78,8 @@
profiler_lock_ = new Mutex("profiler lock", kProfilerLock);
DCHECK(unexpected_signal_lock_ == NULL);
unexpected_signal_lock_ = new Mutex("unexpected signal lock", kUnexpectedSignalLock, true);
+ DCHECK(intern_table_lock_ == NULL);
+ intern_table_lock_ = new Mutex("InternTable lock", kInternTableLock);
}
}
diff --git a/runtime/locks.h b/runtime/locks.h
index d4fbd91..2f9810d 100644
--- a/runtime/locks.h
+++ b/runtime/locks.h
@@ -44,6 +44,8 @@
kDexFileMethodInlinerLock,
kDexFileToMethodInlinerMapLock,
kMarkSweepMarkStackLock,
+ kTransactionLogLock,
+ kInternTableLock,
kDefaultMutexLevel,
kMarkSweepLargeObjectLock,
kPinTableLock,
@@ -163,6 +165,9 @@
// doesn't try to hold a higher level Mutex.
#define DEFAULT_MUTEX_ACQUIRED_AFTER ACQUIRED_AFTER(classlinker_classes_lock_)
+ // Guards intern table.
+ static Mutex* intern_table_lock_ ACQUIRED_AFTER(classlinker_classes_lock_);
+
// Have an exclusive aborting thread.
static Mutex* abort_lock_ ACQUIRED_AFTER(classlinker_classes_lock_);
diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc
index c23234e..2180857 100644
--- a/runtime/mirror/array.cc
+++ b/runtime/mirror/array.cc
@@ -60,7 +60,8 @@
CHECK(self->IsExceptionPending());
return nullptr;
}
- new_array->AsObjectArray<Array>()->Set(i, sub_array);
+ // Use non-transactional mode without check.
+ new_array->AsObjectArray<Array>()->Set<false, false>(i, sub_array);
}
}
return new_array.get();
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 2e123ef..7555975 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -20,6 +20,7 @@
#include "object.h"
#include "object_callbacks.h"
#include "gc/heap.h"
+#include "runtime.h"
#include "thread.h"
namespace art {
@@ -60,7 +61,9 @@
void SetLength(int32_t length) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
CHECK_GE(length, 0);
- SetField32(OFFSET_OF_OBJECT_MEMBER(Array, length_), length, false, false);
+ // We use non transactional version since we can't undo this write. We also disable checking
+ // since it would fail during a transaction.
+ SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(Array, length_), length, false, false);
}
static MemberOffset LengthOffset() {
@@ -144,14 +147,34 @@
}
void Set(int32_t i, T value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ if (Runtime::Current()->IsActiveTransaction()) {
+ Set<true>(i, value);
+ } else {
+ Set<false>(i, value);
+ }
+ }
+
+ // TODO fix thread safety analysis broken by the use of template. This should be
+ // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+ template<bool kTransactionActive, bool kCheckTransaction = true>
+ void Set(int32_t i, T value) NO_THREAD_SAFETY_ANALYSIS {
if (LIKELY(CheckIsValidIndex(i))) {
- SetWithoutChecks(i, value);
+ SetWithoutChecks<kTransactionActive, kCheckTransaction>(i, value);
} else {
DCHECK(Thread::Current()->IsExceptionPending());
}
}
- void SetWithoutChecks(int32_t i, T value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // TODO fix thread safety analysis broken by the use of template. This should be
+ // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+ template<bool kTransactionActive, bool kCheckTransaction = true>
+ void SetWithoutChecks(int32_t i, T value) NO_THREAD_SAFETY_ANALYSIS {
+ if (kCheckTransaction) {
+ DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+ }
+ if (kTransactionActive) {
+ Runtime::Current()->RecordWriteArray(this, i, GetWithoutChecks(i));
+ }
DCHECK(CheckIsValidIndex(i));
GetData()[i] = value;
}
diff --git a/runtime/mirror/art_field-inl.h b/runtime/mirror/art_field-inl.h
index 530226b..6253edd 100644
--- a/runtime/mirror/art_field-inl.h
+++ b/runtime/mirror/art_field-inl.h
@@ -37,7 +37,8 @@
}
inline void ArtField::SetDeclaringClass(Class *new_declaring_class) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtField, declaring_class_), new_declaring_class, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtField, declaring_class_),
+ new_declaring_class, false);
}
inline uint32_t ArtField::GetAccessFlags() {
@@ -61,10 +62,11 @@
return object->GetField32(GetOffset(), IsVolatile());
}
+template<bool kTransactionActive>
inline void ArtField::Set32(Object* object, uint32_t new_value) {
DCHECK(object != NULL) << PrettyField(this);
DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
- object->SetField32(GetOffset(), new_value, IsVolatile());
+ object->SetField32<kTransactionActive>(GetOffset(), new_value, IsVolatile());
}
inline uint64_t ArtField::Get64(Object* object) {
@@ -73,10 +75,11 @@
return object->GetField64(GetOffset(), IsVolatile());
}
+template<bool kTransactionActive>
inline void ArtField::Set64(Object* object, uint64_t new_value) {
DCHECK(object != NULL) << PrettyField(this);
DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
- object->SetField64(GetOffset(), new_value, IsVolatile());
+ object->SetField64<kTransactionActive>(GetOffset(), new_value, IsVolatile());
}
inline Object* ArtField::GetObj(Object* object) {
@@ -85,10 +88,11 @@
return object->GetFieldObject<Object>(GetOffset(), IsVolatile());
}
+template<bool kTransactionActive>
inline void ArtField::SetObj(Object* object, Object* new_value) {
DCHECK(object != NULL) << PrettyField(this);
DCHECK(!IsStatic() || (object == GetDeclaringClass()) || !Runtime::Current()->IsStarted());
- object->SetFieldObject(GetOffset(), new_value, IsVolatile());
+ object->SetFieldObject<kTransactionActive>(GetOffset(), new_value, IsVolatile());
}
inline bool ArtField::GetBoolean(Object* object) {
@@ -97,10 +101,11 @@
return Get32(object);
}
+template<bool kTransactionActive>
inline void ArtField::SetBoolean(Object* object, bool z) {
DCHECK_EQ(Primitive::kPrimBoolean, FieldHelper(this).GetTypeAsPrimitiveType())
<< PrettyField(this);
- Set32(object, z);
+ Set32<kTransactionActive>(object, z);
}
inline int8_t ArtField::GetByte(Object* object) {
@@ -109,10 +114,11 @@
return Get32(object);
}
+template<bool kTransactionActive>
inline void ArtField::SetByte(Object* object, int8_t b) {
DCHECK_EQ(Primitive::kPrimByte, FieldHelper(this).GetTypeAsPrimitiveType())
<< PrettyField(this);
- Set32(object, b);
+ Set32<kTransactionActive>(object, b);
}
inline uint16_t ArtField::GetChar(Object* object) {
@@ -121,10 +127,11 @@
return Get32(object);
}
+template<bool kTransactionActive>
inline void ArtField::SetChar(Object* object, uint16_t c) {
DCHECK_EQ(Primitive::kPrimChar, FieldHelper(this).GetTypeAsPrimitiveType())
<< PrettyField(this);
- Set32(object, c);
+ Set32<kTransactionActive>(object, c);
}
inline int16_t ArtField::GetShort(Object* object) {
@@ -133,42 +140,45 @@
return Get32(object);
}
+template<bool kTransactionActive>
inline void ArtField::SetShort(Object* object, int16_t s) {
DCHECK_EQ(Primitive::kPrimShort, FieldHelper(this).GetTypeAsPrimitiveType())
<< PrettyField(this);
- Set32(object, s);
+ Set32<kTransactionActive>(object, s);
}
inline int32_t ArtField::GetInt(Object* object) {
-#ifndef NDEBUG
- Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
- CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this);
-#endif
+ if (kIsDebugBuild) {
+ Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+ CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this);
+ }
return Get32(object);
}
+template<bool kTransactionActive>
inline void ArtField::SetInt(Object* object, int32_t i) {
-#ifndef NDEBUG
- Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
- CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this);
-#endif
- Set32(object, i);
+ if (kIsDebugBuild) {
+ Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+ CHECK(type == Primitive::kPrimInt || type == Primitive::kPrimFloat) << PrettyField(this);
+ }
+ Set32<kTransactionActive>(object, i);
}
inline int64_t ArtField::GetLong(Object* object) {
-#ifndef NDEBUG
- Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
- CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this);
-#endif
+ if (kIsDebugBuild) {
+ Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+ CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this);
+ }
return Get64(object);
}
+template<bool kTransactionActive>
inline void ArtField::SetLong(Object* object, int64_t j) {
-#ifndef NDEBUG
- Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
- CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this);
-#endif
- Set64(object, j);
+ if (kIsDebugBuild) {
+ Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+ CHECK(type == Primitive::kPrimLong || type == Primitive::kPrimDouble) << PrettyField(this);
+ }
+ Set64<kTransactionActive>(object, j);
}
inline float ArtField::GetFloat(Object* object) {
@@ -179,12 +189,13 @@
return bits.GetF();
}
+template<bool kTransactionActive>
inline void ArtField::SetFloat(Object* object, float f) {
DCHECK_EQ(Primitive::kPrimFloat, FieldHelper(this).GetTypeAsPrimitiveType())
<< PrettyField(this);
JValue bits;
bits.SetF(f);
- Set32(object, bits.GetI());
+ Set32<kTransactionActive>(object, bits.GetI());
}
inline double ArtField::GetDouble(Object* object) {
@@ -195,12 +206,13 @@
return bits.GetD();
}
+template<bool kTransactionActive>
inline void ArtField::SetDouble(Object* object, double d) {
DCHECK_EQ(Primitive::kPrimDouble, FieldHelper(this).GetTypeAsPrimitiveType())
<< PrettyField(this);
JValue bits;
bits.SetD(d);
- Set64(object, bits.GetJ());
+ Set64<kTransactionActive>(object, bits.GetJ());
}
inline Object* ArtField::GetObject(Object* object) {
@@ -209,10 +221,11 @@
return GetObj(object);
}
+template<bool kTransactionActive>
inline void ArtField::SetObject(Object* object, Object* l) {
DCHECK_EQ(Primitive::kPrimNot, FieldHelper(this).GetTypeAsPrimitiveType())
<< PrettyField(this);
- SetObj(object, l);
+ SetObj<kTransactionActive>(object, l);
}
} // namespace mirror
diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc
index 29aade9..dd628ea 100644
--- a/runtime/mirror/art_field.cc
+++ b/runtime/mirror/art_field.cc
@@ -42,14 +42,15 @@
void ArtField::SetOffset(MemberOffset num_bytes) {
DCHECK(GetDeclaringClass()->IsLoaded() || GetDeclaringClass()->IsErroneous());
-#if 0 // TODO enable later in boot and under !NDEBUG
- FieldHelper fh(this);
- Primitive::Type type = fh.GetTypeAsPrimitiveType();
- if (type == Primitive::kPrimDouble || type == Primitive::kPrimLong) {
- DCHECK_ALIGNED(num_bytes.Uint32Value(), 8);
+ if (kIsDebugBuild && Runtime::Current()->IsCompiler() &&
+ !Runtime::Current()->UseCompileTimeClassPath()) {
+ Primitive::Type type = FieldHelper(this).GetTypeAsPrimitiveType();
+ if (type == Primitive::kPrimDouble || type == Primitive::kPrimLong) {
+ DCHECK_ALIGNED(num_bytes.Uint32Value(), 8);
+ }
}
-#endif
- SetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, offset_), num_bytes.Uint32Value(), false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtField, offset_), num_bytes.Uint32Value(), false);
}
void ArtField::VisitRoots(RootCallback* callback, void* arg) {
diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h
index 716b736..46287c3e 100644
--- a/runtime/mirror/art_field.h
+++ b/runtime/mirror/art_field.h
@@ -38,7 +38,8 @@
uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, access_flags_), new_access_flags, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtField, access_flags_), new_access_flags, false);
}
bool IsPublic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -58,7 +59,8 @@
}
void SetDexFieldIndex(uint32_t new_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, field_dex_idx_), new_idx, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtField, field_dex_idx_), new_idx, false);
}
// Offset to field within an Object.
@@ -74,30 +76,42 @@
// field access, null object for static fields
bool GetBoolean(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void SetBoolean(Object* object, bool z) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
int8_t GetByte(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void SetByte(Object* object, int8_t b) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
uint16_t GetChar(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void SetChar(Object* object, uint16_t c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
int16_t GetShort(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void SetShort(Object* object, int16_t s) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
int32_t GetInt(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void SetInt(Object* object, int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
int64_t GetLong(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void SetLong(Object* object, int64_t j) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
float GetFloat(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void SetFloat(Object* object, float f) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
double GetDouble(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void SetDouble(Object* object, double d) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
Object* GetObject(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void SetObject(Object* object, Object* l) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Raw field accesses.
uint32_t Get32(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void Set32(Object* object, uint32_t new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
uint64_t Get64(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void Set64(Object* object, uint64_t new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
Object* GetObj(Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void SetObj(Object* object, Object* new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static Class* GetJavaLangReflectArtField() {
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index 8ef3be8..d347724 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -36,7 +36,8 @@
}
inline void ArtMethod::SetDeclaringClass(Class *new_declaring_class) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtMethod, declaring_class_), new_declaring_class, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, declaring_class_),
+ new_declaring_class, false);
}
inline uint32_t ArtMethod::GetAccessFlags() {
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 67e6c7d..b5c87ad 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -73,18 +73,18 @@
}
void ArtMethod::SetDexCacheStrings(ObjectArray<String>* new_dex_cache_strings) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_strings_),
- new_dex_cache_strings, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_strings_),
+ new_dex_cache_strings, false);
}
void ArtMethod::SetDexCacheResolvedMethods(ObjectArray<ArtMethod>* new_dex_cache_methods) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_methods_),
- new_dex_cache_methods, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_methods_),
+ new_dex_cache_methods, false);
}
void ArtMethod::SetDexCacheResolvedTypes(ObjectArray<Class>* new_dex_cache_classes) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_types_),
- new_dex_cache_classes, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_cache_resolved_types_),
+ new_dex_cache_classes, false);
}
size_t ArtMethod::NumArgRegisters(const StringPiece& shorty) {
@@ -337,8 +337,8 @@
#else
SetNativeMethod(reinterpret_cast<void*>(art_work_around_app_jni_bugs));
#endif
- SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_),
- reinterpret_cast<const uint8_t*>(native_method), false);
+ SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_),
+ reinterpret_cast<const uint8_t*>(native_method), false);
}
}
@@ -349,8 +349,8 @@
}
void ArtMethod::SetNativeMethod(const void* native_method) {
- SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_),
- native_method, false);
+ SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_jni_),
+ native_method, false);
}
} // namespace mirror
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index e678503..71cc7af 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -56,7 +56,8 @@
uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, access_flags_), new_access_flags, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, access_flags_), new_access_flags, false);
}
// Approximate what kind of method call would be used for this method.
@@ -156,7 +157,8 @@
}
void SetMethodIndex(uint16_t new_method_index) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_), new_method_index, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, method_index_), new_method_index, false);
}
static MemberOffset MethodIndexOffset() {
@@ -168,7 +170,8 @@
}
void SetCodeItemOffset(uint32_t new_code_off) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_code_item_offset_), new_code_off, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_code_item_offset_), new_code_off, false);
}
// Number of 32bit registers that would be required to hold all the arguments
@@ -177,7 +180,8 @@
uint32_t GetDexMethodIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void SetDexMethodIndex(uint32_t new_idx) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_method_index_), new_idx, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, dex_method_index_), new_idx, false);
}
ObjectArray<String>* GetDexCacheStrings() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -216,9 +220,8 @@
}
void SetEntryPointFromInterpreter(EntryPointFromInterpreter* entry_point_from_interpreter) {
- SetFieldPtr<EntryPointFromInterpreter*>(
- OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_interpreter_),
- entry_point_from_interpreter, false);
+ SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, entry_point_from_interpreter_),
+ entry_point_from_interpreter, false);
}
static MemberOffset EntryPointFromPortableCompiledCodeOffset() {
@@ -230,8 +233,8 @@
}
void SetEntryPointFromPortableCompiledCode(const void* entry_point_from_portable_compiled_code) {
- SetFieldPtr<const void*>(EntryPointFromPortableCompiledCodeOffset(),
- entry_point_from_portable_compiled_code, false);
+ SetFieldPtr<false>(EntryPointFromPortableCompiledCodeOffset(),
+ entry_point_from_portable_compiled_code, false);
}
static MemberOffset EntryPointFromQuickCompiledCodeOffset() {
@@ -243,8 +246,8 @@
}
void SetEntryPointFromQuickCompiledCode(const void* entry_point_from_quick_compiled_code) {
- SetFieldPtr<const void*>(EntryPointFromQuickCompiledCodeOffset(),
- entry_point_from_quick_compiled_code, false);
+ SetFieldPtr<false>(EntryPointFromQuickCompiledCodeOffset(),
+ entry_point_from_quick_compiled_code, false);
}
@@ -277,8 +280,8 @@
}
void SetMappingTable(const uint8_t* mapping_table) {
- SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_mapping_table_),
- mapping_table, false);
+ SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_mapping_table_),
+ mapping_table, false);
}
uint32_t GetOatMappingTableOffset();
@@ -292,8 +295,7 @@
}
void SetVmapTable(const uint8_t* vmap_table) {
- SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_vmap_table_), vmap_table,
- false);
+ SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_vmap_table_), vmap_table, false);
}
uint32_t GetOatVmapTableOffset();
@@ -304,7 +306,7 @@
return GetFieldPtr<uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_), false);
}
void SetNativeGcMap(const uint8_t* data) {
- SetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_), data, false);
+ SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_), data, false);
}
// When building the oat need a convenient place to stuff the offset of the native GC map.
@@ -319,8 +321,9 @@
}
void SetFrameSizeInBytes(size_t new_frame_size_in_bytes) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_frame_size_in_bytes_),
- new_frame_size_in_bytes, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_frame_size_in_bytes_),
+ new_frame_size_in_bytes, false);
}
size_t GetReturnPcOffsetInBytes() {
@@ -358,8 +361,9 @@
}
void SetCoreSpillMask(uint32_t core_spill_mask) {
- // Computed during compilation
- SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_core_spill_mask_), core_spill_mask, false);
+ // Computed during compilation.
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_core_spill_mask_), core_spill_mask, false);
}
uint32_t GetFpSpillMask() {
@@ -367,8 +371,9 @@
}
void SetFpSpillMask(uint32_t fp_spill_mask) {
- // Computed during compilation
- SetField32(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_fp_spill_mask_), fp_spill_mask, false);
+ // Computed during compilation.
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_fp_spill_mask_), fp_spill_mask, false);
}
// Is this a CalleSaveMethod or ResolutionMethod and therefore doesn't adhere to normal
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index a5f743b..4c2bdb0 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -64,8 +64,8 @@
DCHECK(NULL == GetFieldObject<ObjectArray<ArtMethod> >(
OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false));
DCHECK_NE(0, new_direct_methods->GetLength());
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_),
- new_direct_methods, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_),
+ new_direct_methods, false);
}
inline ArtMethod* Class::GetDirectMethod(int32_t i) {
@@ -77,7 +77,7 @@
ObjectArray<ArtMethod>* direct_methods =
GetFieldObject<ObjectArray<ArtMethod> >(
OFFSET_OF_OBJECT_MEMBER(Class, direct_methods_), false);
- direct_methods->Set(i, f);
+ direct_methods->Set<false>(i, f);
}
// Returns the number of static, private, and constructor methods.
@@ -93,10 +93,10 @@
inline void Class::SetVirtualMethods(ObjectArray<ArtMethod>* new_virtual_methods) {
// TODO: we reassign virtual methods to grow the table for miranda
- // methods.. they should really just be assigned once
+ // methods.. they should really just be assigned once.
DCHECK_NE(0, new_virtual_methods->GetLength());
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_),
- new_virtual_methods, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_),
+ new_virtual_methods, false);
}
inline uint32_t Class::NumVirtualMethods() {
@@ -118,7 +118,7 @@
ObjectArray<ArtMethod>* virtual_methods =
GetFieldObject<ObjectArray<ArtMethod> >(
OFFSET_OF_OBJECT_MEMBER(Class, virtual_methods_), false);
- virtual_methods->Set(i, f);
+ virtual_methods->Set<false>(i, f);
}
inline ObjectArray<ArtMethod>* Class::GetVTable() {
@@ -132,7 +132,7 @@
}
inline void Class::SetVTable(ObjectArray<ArtMethod>* new_vtable) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, vtable_), new_vtable, false);
}
inline ObjectArray<ArtMethod>* Class::GetImTable() {
@@ -140,7 +140,7 @@
}
inline void Class::SetImTable(ObjectArray<ArtMethod>* new_imtable) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), new_imtable, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, imtable_), new_imtable, false);
}
inline bool Class::Implements(Class* klass) {
@@ -347,7 +347,7 @@
}
inline void Class::SetIfTable(IfTable* new_iftable) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, iftable_), new_iftable, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, iftable_), new_iftable, false);
}
inline ObjectArray<ArtField>* Class::GetIFields() {
@@ -359,7 +359,7 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK(NULL == GetFieldObject<ObjectArray<ArtField> >(
OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false));
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), new_ifields, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, ifields_), new_ifields, false);
}
inline ObjectArray<ArtField>* Class::GetSFields() {
@@ -371,7 +371,7 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK(NULL == GetFieldObject<ObjectArray<ArtField> >(
OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false));
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), new_sfields, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, sfields_), new_sfields, false);
}
inline uint32_t Class::NumStaticFields() {
@@ -387,7 +387,7 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ObjectArray<ArtField>* sfields= GetFieldObject<ObjectArray<ArtField> >(
OFFSET_OF_OBJECT_MEMBER(Class, sfields_), false);
- sfields->Set(i, f);
+ sfields->Set<false>(i, f);
}
inline uint32_t Class::NumInstanceFields() {
@@ -403,12 +403,16 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
ObjectArray<ArtField>* ifields= GetFieldObject<ObjectArray<ArtField> >(
OFFSET_OF_OBJECT_MEMBER(Class, ifields_), false);
- ifields->Set(i, f);
+ ifields->Set<false>(i, f);
}
inline void Class::SetVerifyErrorClass(Class* klass) {
CHECK(klass != NULL) << PrettyClass(this);
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), klass, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), klass, false);
+ } else {
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, verify_error_class_), klass, false);
+ }
}
inline uint32_t Class::GetAccessFlags() {
@@ -425,7 +429,11 @@
return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(Class, name_), false);
}
inline void Class::SetName(String* name) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, name_), name, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Class, name_), name, false);
+ } else {
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, name_), name, false);
+ }
}
inline void Class::CheckObjectAlloc() {
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 99a35e3..6446d02 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -113,7 +113,11 @@
self->SetException(gc_safe_throw_location, old_exception.get());
}
CHECK(sizeof(Status) == sizeof(uint32_t)) << PrettyClass(this);
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status, false);
+ } else {
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, status_), new_status, false);
+ }
// Classes that are being resolved or initialized need to notify waiters that the class status
// changed. See ClassLinker::EnsureResolved and ClassLinker::WaitForInitializeClass.
if ((old_status >= kStatusResolved || new_status >= kStatusResolved) &&
@@ -123,7 +127,7 @@
}
void Class::SetDexCache(DexCache* new_dex_cache) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_), new_dex_cache, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_), new_dex_cache, false);
}
void Class::SetClassSize(uint32_t new_class_size) {
@@ -131,7 +135,8 @@
DumpClass(LOG(ERROR), kDumpClassFullDetail);
CHECK_GE(new_class_size, GetClassSize()) << " class=" << PrettyTypeOf(this);
}
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), new_class_size, false);
}
// Return the class' name. The exact format is bizarre, but it's the specified behavior for
@@ -254,8 +259,9 @@
}
CHECK_EQ((size_t)__builtin_popcount(new_reference_offsets), count);
}
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_),
- new_reference_offsets, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, reference_instance_offsets_),
+ new_reference_offsets, false);
}
void Class::SetReferenceStaticOffsets(uint32_t new_reference_offsets) {
@@ -265,8 +271,9 @@
CHECK_EQ((size_t)__builtin_popcount(new_reference_offsets),
NumReferenceStaticFieldsDuringLinking());
}
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, reference_static_offsets_),
- new_reference_offsets, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, reference_static_offsets_),
+ new_reference_offsets, false);
}
bool Class::IsInSamePackage(const StringPiece& descriptor1, const StringPiece& descriptor2) {
@@ -332,7 +339,11 @@
}
void Class::SetClassLoader(ClassLoader* new_class_loader) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false);
+ } else {
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false);
+ }
}
ArtMethod* Class::FindInterfaceMethod(const StringPiece& name, const Signature& signature) {
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 82c8264..cd8504b 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -174,7 +174,8 @@
uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void SetAccessFlags(uint32_t new_access_flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_), new_access_flags, false);
}
// Returns true if the class is an interface.
@@ -275,7 +276,7 @@
void SetPrimitiveType(Primitive::Type new_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK_EQ(sizeof(Primitive::Type), sizeof(int32_t));
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), new_type, false);
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, primitive_type_), new_type, false);
}
// Returns true if the class is a primitive type.
@@ -357,7 +358,11 @@
void SetComponentType(Class* new_component_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK(GetComponentType() == NULL);
DCHECK(new_component_type != NULL);
- SetFieldObject(ComponentTypeOffset(), new_component_type, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ SetFieldObject<true>(ComponentTypeOffset(), new_component_type, false);
+ } else {
+ SetFieldObject<false>(ComponentTypeOffset(), new_component_type, false);
+ }
}
size_t GetComponentSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -406,7 +411,8 @@
void SetObjectSize(uint32_t new_object_size) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK(!IsVariableSize());
- return SetField32(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), new_object_size, false);
+ // Not called within a transaction.
+ return SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, object_size_), new_object_size, false);
}
// Returns true if this class is in the same packages as that class.
@@ -499,7 +505,7 @@
false);
DCHECK(old_super_class == nullptr || old_super_class == new_super_class);
DCHECK(new_super_class != nullptr);
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Class, super_class_), new_super_class, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Class, super_class_), new_super_class, false);
}
bool HasSuperClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -672,7 +678,9 @@
}
void SetNumReferenceInstanceFields(uint32_t new_num) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), new_num, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_instance_fields_), new_num,
+ false);
}
uint32_t GetReferenceInstanceOffsets() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -700,7 +708,8 @@
}
void SetNumReferenceStaticFields(uint32_t new_num) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), new_num, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, num_reference_static_fields_), new_num, false);
}
// Gets the static fields of the class.
@@ -763,7 +772,13 @@
}
void SetClinitThreadId(pid_t new_clinit_thread_id) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), new_clinit_thread_id, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ SetField32<true>(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), new_clinit_thread_id,
+ false);
+ } else {
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, clinit_thread_id_), new_clinit_thread_id,
+ false);
+ }
}
Class* GetVerifyErrorClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -776,7 +791,8 @@
}
void SetDexClassDefIndex(uint16_t class_def_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), class_def_idx, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_class_def_idx_), class_def_idx, false);
}
uint16_t GetDexTypeIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -784,7 +800,8 @@
}
void SetDexTypeIndex(uint16_t type_idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), type_idx, false);
+ // Not called within a transaction.
+ SetField32<false>(OFFSET_OF_OBJECT_MEMBER(Class, dex_type_idx_), type_idx, false);
}
static Class* GetJavaLangClass() {
diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc
index fa0900c..0a77db3 100644
--- a/runtime/mirror/dex_cache.cc
+++ b/runtime/mirror/dex_cache.cc
@@ -44,12 +44,12 @@
CHECK(resolved_methods != nullptr);
CHECK(resolved_fields != nullptr);
- SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file, false);
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location, false);
- SetFieldObject(StringsOffset(), strings, false);
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_types_), resolved_types, false);
- SetFieldObject(ResolvedMethodsOffset(), resolved_methods, false);
- SetFieldObject(ResolvedFieldsOffset(), resolved_fields, false);
+ SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, location_), location, false);
+ SetFieldObject<false>(StringsOffset(), strings, false);
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, resolved_types_), resolved_types, false);
+ SetFieldObject<false>(ResolvedMethodsOffset(), resolved_methods, false);
+ SetFieldObject<false>(ResolvedFieldsOffset(), resolved_fields, false);
Runtime* runtime = Runtime::Current();
if (runtime->HasResolutionMethod()) {
@@ -57,7 +57,7 @@
ArtMethod* trampoline = runtime->GetResolutionMethod();
size_t length = resolved_methods->GetLength();
for (size_t i = 0; i < length; i++) {
- resolved_methods->SetWithoutChecks(i, trampoline);
+ resolved_methods->SetWithoutChecks<false>(i, trampoline);
}
}
}
@@ -69,7 +69,7 @@
size_t length = resolved_methods->GetLength();
for (size_t i = 0; i < length; i++) {
if (resolved_methods->GetWithoutChecks(i) == nullptr) {
- resolved_methods->SetWithoutChecks(i, trampoline);
+ resolved_methods->SetWithoutChecks<false>(i, trampoline);
}
}
}
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index 99529f0..843f860 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -90,6 +90,7 @@
void SetResolvedString(uint32_t string_idx, String* resolved)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // TODO default transaction support.
GetStrings()->Set(string_idx, resolved);
}
@@ -99,6 +100,7 @@
void SetResolvedType(uint32_t type_idx, Class* resolved)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+ // TODO default transaction support.
GetResolvedTypes()->Set(type_idx, resolved);
}
@@ -140,7 +142,7 @@
}
void SetDexFile(const DexFile* dex_file) {
- return SetFieldPtr(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file, false);
+ return SetFieldPtr<false>(OFFSET_OF_OBJECT_MEMBER(DexCache, dex_file_), dex_file, false);
}
private:
diff --git a/runtime/mirror/iftable-inl.h b/runtime/mirror/iftable-inl.h
index 9d5fa74..ec3e514 100644
--- a/runtime/mirror/iftable-inl.h
+++ b/runtime/mirror/iftable-inl.h
@@ -26,7 +26,7 @@
DCHECK(interface != NULL);
DCHECK(interface->IsInterface());
DCHECK(Get((i * kMax) + kInterface) == NULL);
- Set((i * kMax) + kInterface, interface);
+ Set<false>((i * kMax) + kInterface, interface);
}
} // namespace mirror
diff --git a/runtime/mirror/iftable.h b/runtime/mirror/iftable.h
index be83d03..bb4cd41 100644
--- a/runtime/mirror/iftable.h
+++ b/runtime/mirror/iftable.h
@@ -52,7 +52,7 @@
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK(new_ma != NULL);
DCHECK(Get((i * kMax) + kMethodArray) == NULL);
- Set((i * kMax) + kMethodArray, new_ma);
+ Set<false>((i * kMax) + kMethodArray, new_ma);
}
size_t Count() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index b994354..70291c1 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -40,7 +40,10 @@
// new_klass may be NULL prior to class linker initialization.
// We don't mark the card as this occurs as part of object allocation. Not all objects have
// backing cards, such as large objects.
- SetFieldObjectWithoutWriteBarrier(OFFSET_OF_OBJECT_MEMBER(Object, klass_), new_klass, false, false);
+ // We use non transactional version since we can't undo this write. We also disable checking as
+ // we may run in transaction mode here.
+ SetFieldObjectWithoutWriteBarrier<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, klass_),
+ new_klass, false, false);
}
inline LockWord Object::GetLockWord() {
@@ -48,20 +51,22 @@
}
inline void Object::SetLockWord(LockWord new_val) {
- SetField32(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue(), true);
+ // Force use of non-transactional mode and do not check.
+ SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), new_val.GetValue(), true);
}
inline bool Object::CasLockWord(LockWord old_val, LockWord new_val) {
- return CasField32(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(),
- new_val.GetValue());
+ // Force use of non-transactional mode and do not check.
+ return CasField32<false, false>(OFFSET_OF_OBJECT_MEMBER(Object, monitor_), old_val.GetValue(),
+ new_val.GetValue());
}
inline uint32_t Object::GetLockOwnerThreadId() {
return Monitor::GetLockOwnerThreadId(this);
}
-inline void Object::MonitorEnter(Thread* self) {
- Monitor::MonitorEnter(self, this);
+inline mirror::Object* Object::MonitorEnter(Thread* self) {
+ return Monitor::MonitorEnter(self, this);
}
inline bool Object::MonitorExit(Thread* self) {
@@ -199,6 +204,18 @@
return down_cast<LongArray*>(this);
}
+inline FloatArray* Object::AsFloatArray() {
+ DCHECK(GetClass()->IsArrayClass());
+ DCHECK(GetClass()->GetComponentType()->IsPrimitiveFloat());
+ return down_cast<FloatArray*>(this);
+}
+
+inline DoubleArray* Object::AsDoubleArray() {
+ DCHECK(GetClass()->IsArrayClass());
+ DCHECK(GetClass()->GetComponentType()->IsPrimitiveDouble());
+ return down_cast<DoubleArray*>(this);
+}
+
inline String* Object::AsString() {
DCHECK(GetClass()->IsStringClass());
return down_cast<String*>(this);
@@ -253,8 +270,16 @@
}
}
+template<bool kTransactionActive, bool kCheckTransaction>
inline void Object::SetField32(MemberOffset field_offset, int32_t new_value, bool is_volatile,
bool this_is_valid) {
+ if (kCheckTransaction) {
+ DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+ }
+ if (kTransactionActive) {
+ Runtime::Current()->RecordWriteField32(this, field_offset, GetField32(field_offset, is_volatile),
+ is_volatile);
+ }
if (this_is_valid) {
VerifyObject(this);
}
@@ -269,7 +294,14 @@
}
}
+template<bool kTransactionActive, bool kCheckTransaction>
inline bool Object::CasField32(MemberOffset field_offset, int32_t old_value, int32_t new_value) {
+ if (kCheckTransaction) {
+ DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+ }
+ if (kTransactionActive) {
+ Runtime::Current()->RecordWriteField32(this, field_offset, old_value, true);
+ }
VerifyObject(this);
byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
volatile int32_t* addr = reinterpret_cast<volatile int32_t*>(raw_addr);
@@ -289,8 +321,16 @@
}
}
+template<bool kTransactionActive, bool kCheckTransaction>
inline void Object::SetField64(MemberOffset field_offset, int64_t new_value, bool is_volatile,
bool this_is_valid) {
+ if (kCheckTransaction) {
+ DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+ }
+ if (kTransactionActive) {
+ Runtime::Current()->RecordWriteField64(this, field_offset, GetField64(field_offset, is_volatile),
+ is_volatile);
+ }
if (this_is_valid) {
VerifyObject(this);
}
@@ -309,7 +349,14 @@
}
}
+template<bool kTransactionActive, bool kCheckTransaction>
inline bool Object::CasField64(MemberOffset field_offset, int64_t old_value, int64_t new_value) {
+ if (kCheckTransaction) {
+ DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+ }
+ if (kTransactionActive) {
+ Runtime::Current()->RecordWriteField64(this, field_offset, old_value, true);
+ }
VerifyObject(this);
byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
volatile int64_t* addr = reinterpret_cast<volatile int64_t*>(raw_addr);
@@ -331,8 +378,17 @@
return result;
}
+template<bool kTransactionActive, bool kCheckTransaction>
inline void Object::SetFieldObjectWithoutWriteBarrier(MemberOffset field_offset, Object* new_value,
bool is_volatile, bool this_is_valid) {
+ if (kCheckTransaction) {
+ DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+ }
+ if (kTransactionActive) {
+ Runtime::Current()->RecordWriteFieldReference(this, field_offset,
+ GetFieldObject<Object>(field_offset, is_volatile),
+ true);
+ }
if (this_is_valid) {
VerifyObject(this);
}
@@ -349,16 +405,26 @@
}
}
+template<bool kTransactionActive, bool kCheckTransaction>
inline void Object::SetFieldObject(MemberOffset field_offset, Object* new_value, bool is_volatile,
bool this_is_valid) {
- SetFieldObjectWithoutWriteBarrier(field_offset, new_value, is_volatile, this_is_valid);
+ SetFieldObjectWithoutWriteBarrier<kTransactionActive, kCheckTransaction>(field_offset, new_value,
+ is_volatile,
+ this_is_valid);
if (new_value != nullptr) {
CheckFieldAssignment(field_offset, new_value);
Runtime::Current()->GetHeap()->WriteBarrierField(this, field_offset, new_value);
}
}
+template<bool kTransactionActive, bool kCheckTransaction>
inline bool Object::CasFieldObject(MemberOffset field_offset, Object* old_value, Object* new_value) {
+ if (kCheckTransaction) {
+ DCHECK_EQ(kTransactionActive, Runtime::Current()->IsActiveTransaction());
+ }
+ if (kTransactionActive) {
+ Runtime::Current()->RecordWriteFieldReference(this, field_offset, old_value, true);
+ }
VerifyObject(this);
byte* raw_addr = reinterpret_cast<byte*>(this) + field_offset.Int32Value();
volatile int32_t* addr = reinterpret_cast<volatile int32_t*>(raw_addr);
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index c42750f..eb118c7 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -23,6 +23,7 @@
#include "cutils/atomic-inline.h"
#include "object_reference.h"
#include "offsets.h"
+#include "runtime.h"
namespace art {
@@ -92,7 +93,7 @@
bool CasLockWord(LockWord old_val, LockWord new_val) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
uint32_t GetLockOwnerThreadId();
- void MonitorEnter(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ mirror::Object* MonitorEnter(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
EXCLUSIVE_LOCK_FUNCTION(monitor_lock_);
bool MonitorExit(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
@@ -130,6 +131,9 @@
IntArray* AsIntArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
LongArray* AsLongArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ FloatArray* AsFloatArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ DoubleArray* AsDoubleArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
String* AsString() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
Throwable* AsThrowable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -155,12 +159,15 @@
// Accessor for Java type fields.
template<class T> T* GetFieldObject(MemberOffset field_offset, bool is_volatile)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive, bool kCheckTransaction = true>
void SetFieldObjectWithoutWriteBarrier(MemberOffset field_offset, Object* new_value,
bool is_volatile, bool this_is_valid = true)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive, bool kCheckTransaction = true>
void SetFieldObject(MemberOffset field_offset, Object* new_value, bool is_volatile,
bool this_is_valid = true)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive, bool kCheckTransaction = true>
bool CasFieldObject(MemberOffset field_offset, Object* old_value, Object* new_value)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -172,27 +179,35 @@
int32_t GetField32(MemberOffset field_offset, bool is_volatile);
+ template<bool kTransactionActive, bool kCheckTransaction = true>
void SetField32(MemberOffset field_offset, int32_t new_value, bool is_volatile,
bool this_is_valid = true);
+ template<bool kTransactionActive, bool kCheckTransaction = true>
bool CasField32(MemberOffset field_offset, int32_t old_value, int32_t new_value)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
int64_t GetField64(MemberOffset field_offset, bool is_volatile);
+ template<bool kTransactionActive, bool kCheckTransaction = true>
void SetField64(MemberOffset field_offset, int64_t new_value, bool is_volatile,
bool this_is_valid = true);
+ template<bool kTransactionActive, bool kCheckTransaction = true>
bool CasField64(MemberOffset field_offset, int64_t old_value, int64_t new_value)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- template<typename T>
+ template<bool kTransactionActive, bool kCheckTransaction = true, typename T>
void SetFieldPtr(MemberOffset field_offset, T new_value, bool is_volatile,
bool this_is_valid = true) {
#ifndef __LP64__
- SetField32(field_offset, reinterpret_cast<int32_t>(new_value), is_volatile, this_is_valid);
+ SetField32<kTransactionActive, kCheckTransaction>(field_offset,
+ reinterpret_cast<int32_t>(new_value),
+ is_volatile, this_is_valid);
#else
- SetField64(field_offset, reinterpret_cast<int64_t>(new_value), is_volatile, this_is_valid);
+ SetField64<kTransactionActive, kCheckTransaction>(field_offset,
+ reinterpret_cast<int64_t>(new_value),
+ is_volatile, this_is_valid);
#endif
}
diff --git a/runtime/mirror/object_array-inl.h b/runtime/mirror/object_array-inl.h
index c342479..521b6ce 100644
--- a/runtime/mirror/object_array-inl.h
+++ b/runtime/mirror/object_array-inl.h
@@ -72,26 +72,39 @@
template<class T>
inline void ObjectArray<T>::Set(int32_t i, T* object) {
+ if (Runtime::Current()->IsActiveTransaction()) {
+ Set<true>(i, object);
+ } else {
+ Set<false>(i, object);
+ }
+}
+
+template<class T>
+template<bool kTransactionActive, bool kCheckTransaction>
+inline void ObjectArray<T>::Set(int32_t i, T* object) {
if (LIKELY(CheckIsValidIndex(i) && CheckAssignable(object))) {
- SetFieldObject(OffsetOfElement(i), object, false);
+ SetFieldObject<kTransactionActive, kCheckTransaction>(OffsetOfElement(i), object, false);
} else {
DCHECK(Thread::Current()->IsExceptionPending());
}
}
template<class T>
+template<bool kTransactionActive, bool kCheckTransaction>
inline void ObjectArray<T>::SetWithoutChecks(int32_t i, T* object) {
DCHECK(CheckIsValidIndex(i));
DCHECK(CheckAssignable(object));
- SetFieldObject(OffsetOfElement(i), object, false);
+ SetFieldObject<kTransactionActive, kCheckTransaction>(OffsetOfElement(i), object, false);
}
template<class T>
+template<bool kTransactionActive, bool kCheckTransaction>
inline void ObjectArray<T>::SetWithoutChecksAndWriteBarrier(int32_t i, T* object) {
DCHECK(CheckIsValidIndex(i));
// TODO: enable this check. It fails when writing the image in ImageWriter::FixupObjectArray.
// DCHECK(CheckAssignable(object));
- SetFieldObjectWithoutWriteBarrier(OffsetOfElement(i), object, false);
+ SetFieldObjectWithoutWriteBarrier<kTransactionActive, kCheckTransaction>(OffsetOfElement(i),
+ object, false);
}
template<class T>
@@ -164,15 +177,15 @@
o = src->GetWithoutChecks(src_pos + i);
if (o == nullptr) {
// Null is always assignable.
- SetWithoutChecks(dst_pos + i, nullptr);
+ SetWithoutChecks<false>(dst_pos + i, nullptr);
} else {
// TODO: use the underlying class reference to avoid uncompression when not necessary.
Class* o_class = o->GetClass();
if (LIKELY(lastAssignableElementClass == o_class)) {
- SetWithoutChecks(dst_pos + i, o);
+ SetWithoutChecks<false>(dst_pos + i, o);
} else if (LIKELY(dst_class->IsAssignableFrom(o_class))) {
lastAssignableElementClass = o_class;
- SetWithoutChecks(dst_pos + i, o);
+ SetWithoutChecks<false>(dst_pos + i, o);
} else {
// Can't put this element into the array, break to perform write-barrier and throw
// exception.
diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h
index 347494e..668b276 100644
--- a/runtime/mirror/object_array.h
+++ b/runtime/mirror/object_array.h
@@ -40,12 +40,20 @@
bool CheckAssignable(T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
void Set(int32_t i, T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // TODO fix thread safety analysis: should be SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+ template<bool kTransactionActive, bool kCheckTransaction = true>
+ void Set(int32_t i, T* object) NO_THREAD_SAFETY_ANALYSIS;
// Set element without bound and element type checks, to be used in limited
- // circumstances, such as during boot image writing
- void SetWithoutChecks(int32_t i, T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
- void SetWithoutChecksAndWriteBarrier(int32_t i, T* object)
- SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ // circumstances, such as during boot image writing.
+ // TODO fix thread safety analysis broken by the use of template. This should be
+ // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+ template<bool kTransactionActive, bool kCheckTransaction = true>
+ void SetWithoutChecks(int32_t i, T* object) NO_THREAD_SAFETY_ANALYSIS;
+ // TODO fix thread safety analysis broken by the use of template. This should be
+ // SHARED_LOCKS_REQUIRED(Locks::mutator_lock_).
+ template<bool kTransactionActive, bool kCheckTransaction = true>
+ void SetWithoutChecksAndWriteBarrier(int32_t i, T* object) NO_THREAD_SAFETY_ANALYSIS;
T* GetWithoutChecks(int32_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index db9723b..40c3748 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -116,10 +116,10 @@
EXPECT_EQ(2, oa->GetLength());
EXPECT_TRUE(oa->Get(0) == NULL);
EXPECT_TRUE(oa->Get(1) == NULL);
- oa->Set(0, oa.get());
+ oa->Set<false>(0, oa.get());
EXPECT_TRUE(oa->Get(0) == oa.get());
EXPECT_TRUE(oa->Get(1) == NULL);
- oa->Set(1, oa.get());
+ oa->Set<false>(1, oa.get());
EXPECT_TRUE(oa->Get(0) == oa.get());
EXPECT_TRUE(oa->Get(1) == oa.get());
@@ -235,12 +235,12 @@
SirtRef<Class> c(soa.Self(), class_linker_->FindSystemClass("I"));
SirtRef<IntArray> dims(soa.Self(), IntArray::Alloc(soa.Self(), 1));
- dims->Set(0, 1);
+ dims->Set<false>(0, 1);
Array* multi = Array::CreateMultiArray(soa.Self(), c, dims);
EXPECT_TRUE(multi->GetClass() == class_linker_->FindSystemClass("[I"));
EXPECT_EQ(1, multi->GetLength());
- dims->Set(0, -1);
+ dims->Set<false>(0, -1);
multi = Array::CreateMultiArray(soa.Self(), c, dims);
EXPECT_TRUE(soa.Self()->IsExceptionPending());
EXPECT_EQ(PrettyDescriptor(soa.Self()->GetException(NULL)->GetClass()),
@@ -250,8 +250,8 @@
dims.reset(IntArray::Alloc(soa.Self(), 2));
for (int i = 1; i < 20; ++i) {
for (int j = 0; j < 20; ++j) {
- dims->Set(0, i);
- dims->Set(1, j);
+ dims->Set<false>(0, i);
+ dims->Set<false>(1, j);
multi = Array::CreateMultiArray(soa.Self(), c, dims);
EXPECT_TRUE(multi->GetClass() == class_linker_->FindSystemClass("[[I"));
EXPECT_EQ(i, multi->GetLength());
@@ -301,10 +301,10 @@
EXPECT_TRUE(s0 != NULL);
SirtRef<CharArray> char_array(soa.Self(), CharArray::Alloc(soa.Self(), 0));
- field->SetObj(field->GetDeclaringClass(), char_array.get());
+ field->SetObj<false>(field->GetDeclaringClass(), char_array.get());
EXPECT_EQ(char_array.get(), field->GetObj(klass));
- field->SetObj(field->GetDeclaringClass(), NULL);
+ field->SetObj<false>(field->GetDeclaringClass(), NULL);
EXPECT_EQ(NULL, field->GetObj(klass));
// TODO: more exhaustive tests of all 6 cases of ArtField::*FromCode
@@ -387,8 +387,8 @@
EXPECT_EQ(string->GetLength(), 7);
EXPECT_EQ(string->GetUtfLength(), 7);
- string->SetOffset(2);
- string->SetCount(5);
+ string->SetOffset<false>(2);
+ string->SetCount<false>(5);
EXPECT_TRUE(string->Equals("droid"));
EXPECT_EQ(string->GetLength(), 5);
EXPECT_EQ(string->GetUtfLength(), 5);
diff --git a/runtime/mirror/stack_trace_element.cc b/runtime/mirror/stack_trace_element.cc
index 2e33198..6bc695d 100644
--- a/runtime/mirror/stack_trace_element.cc
+++ b/runtime/mirror/stack_trace_element.cc
@@ -46,18 +46,28 @@
StackTraceElement* trace =
down_cast<StackTraceElement*>(GetStackTraceElement()->AllocObject(self));
if (LIKELY(trace != NULL)) {
- trace->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, declaring_class_),
- declaring_class.get(), false);
- trace->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, method_name_),
- method_name.get(), false);
- trace->SetFieldObject(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, file_name_),
- file_name.get(), false);
- trace->SetField32(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, line_number_),
- line_number, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ trace->Init<true>(declaring_class, method_name, file_name, line_number);
+ } else {
+ trace->Init<false>(declaring_class, method_name, file_name, line_number);
+ }
}
return trace;
}
+template<bool kTransactionActive>
+void StackTraceElement::Init(SirtRef<String>& declaring_class, SirtRef<String>& method_name,
+ SirtRef<String>& file_name, int32_t line_number) {
+ SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, declaring_class_),
+ declaring_class.get(), false);
+ SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, method_name_),
+ method_name.get(), false);
+ SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, file_name_),
+ file_name.get(), false);
+ SetField32<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(StackTraceElement, line_number_),
+ line_number, false);
+}
+
void StackTraceElement::VisitRoots(RootCallback* callback, void* arg) {
if (java_lang_StackTraceElement_ != nullptr) {
java_lang_StackTraceElement_ = down_cast<Class*>(
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index 51817f6..779ec4b 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -67,6 +67,11 @@
HeapReference<String> method_name_;
int32_t line_number_;
+ template<bool kTransactionActive>
+ void Init(SirtRef<String>& declaring_class, SirtRef<String>& method_name,
+ SirtRef<String>& file_name, int32_t line_number)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
static Class* GetStackTraceElement() {
DCHECK(java_lang_StackTraceElement_ != NULL);
return java_lang_StackTraceElement_;
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index 6f4ead9..cd63c39 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -33,7 +33,7 @@
return GetFieldObject<CharArray>(ValueOffset(), false);
}
-void String::ComputeHashCode() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+void String::ComputeHashCode() {
SetHashCode(ComputeUtf16Hash(GetCharArray(), GetOffset(), GetLength()));
}
@@ -59,9 +59,10 @@
return -1;
}
-void String::SetArray(CharArray* new_array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+template<bool kTransactionActive>
+void String::SetArray(CharArray* new_array) {
DCHECK(new_array != NULL);
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(String, array_), new_array, false);
+ SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(String, array_), new_array, false);
}
// TODO: get global references for these
@@ -169,8 +170,13 @@
// Hold reference in case AllocObject causes GC.
String* string = down_cast<String*>(GetJavaLangString()->AllocObject(self));
if (LIKELY(string != nullptr)) {
- string->SetArray(array.get());
- string->SetCount(array->GetLength());
+ if (Runtime::Current()->IsActiveTransaction()) {
+ string->SetArray<true>(array.get());
+ string->SetCount<true>(array->GetLength());
+ } else {
+ string->SetArray<false>(array.get());
+ string->SetCount<false>(array->GetLength());
+ }
}
return string;
}
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 57ec314..1340e7d 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -112,19 +112,23 @@
private:
void SetHashCode(int32_t new_hash_code) {
+ // Hash code is invariant so use non-transactional mode. Also disable check as we may run inside
+ // a transaction.
DCHECK_EQ(0, GetField32(OFFSET_OF_OBJECT_MEMBER(String, hash_code_), false));
- SetField32(OFFSET_OF_OBJECT_MEMBER(String, hash_code_), new_hash_code, false);
+ SetField32<false, false>(OFFSET_OF_OBJECT_MEMBER(String, hash_code_), new_hash_code, false);
}
+ template<bool kTransactionActive>
void SetCount(int32_t new_count) {
DCHECK_LE(0, new_count);
- SetField32(OFFSET_OF_OBJECT_MEMBER(String, count_), new_count, false);
+ SetField32<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(String, count_), new_count, false);
}
+ template<bool kTransactionActive>
void SetOffset(int32_t new_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
DCHECK_LE(0, new_offset);
DCHECK_GE(GetLength(), new_offset);
- SetField32(OFFSET_OF_OBJECT_MEMBER(String, offset_), new_offset, false);
+ SetField32<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(String, offset_), new_offset, false);
}
static String* Alloc(Thread* self, int32_t utf16_length)
@@ -133,6 +137,7 @@
static String* Alloc(Thread* self, const SirtRef<CharArray>& array)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ template<bool kTransactionActive>
void SetArray(CharArray* new_array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
// Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index a57bd43..fef7d36 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -38,7 +38,11 @@
Throwable* current_cause = GetFieldObject<Throwable>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_),
false);
CHECK(current_cause == NULL || current_cause == this);
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), cause, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), cause, false);
+ } else {
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Throwable, cause_), cause, false);
+ }
}
bool Throwable::IsCheckedException() {
diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h
index de71957..c1438d7 100644
--- a/runtime/mirror/throwable.h
+++ b/runtime/mirror/throwable.h
@@ -31,7 +31,13 @@
class MANAGED Throwable : public Object {
public:
void SetDetailMessage(String* new_detail_message) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
- SetFieldObject(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), new_detail_message, false);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), new_detail_message,
+ false);
+ } else {
+ SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), new_detail_message,
+ false);
+ }
}
String* GetDetailMessage() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
return GetFieldObject<String>(OFFSET_OF_OBJECT_MEMBER(Throwable, detail_message_), false);
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 85f3a09..64794fe 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -650,7 +650,7 @@
}
}
-void Monitor::MonitorEnter(Thread* self, mirror::Object* obj) {
+mirror::Object* Monitor::MonitorEnter(Thread* self, mirror::Object* obj) {
DCHECK(self != NULL);
DCHECK(obj != NULL);
uint32_t thread_id = self->GetThreadId();
@@ -663,7 +663,7 @@
LockWord thin_locked(LockWord::FromThinLockId(thread_id, 0));
if (sirt_obj->CasLockWord(lock_word, thin_locked)) {
QuasiAtomic::MembarLoadLoad();
- return; // Success!
+ return sirt_obj.get(); // Success!
}
continue; // Go again.
}
@@ -675,7 +675,7 @@
if (LIKELY(new_count <= LockWord::kThinLockMaxCount)) {
LockWord thin_locked(LockWord::FromThinLockId(thread_id, new_count));
sirt_obj->SetLockWord(thin_locked);
- return; // Success!
+ return sirt_obj.get(); // Success!
} else {
// We'd overflow the recursion count, so inflate the monitor.
InflateThinLocked(self, sirt_obj, lock_word, 0);
@@ -696,7 +696,7 @@
case LockWord::kFatLocked: {
Monitor* mon = lock_word.FatLockMonitor();
mon->Lock(self);
- return; // Success!
+ return sirt_obj.get(); // Success!
}
case LockWord::kHashCode: {
// Inflate with the existing hashcode.
@@ -705,10 +705,11 @@
}
default: {
LOG(FATAL) << "Invalid monitor state " << lock_word.GetState();
- return;
+ return sirt_obj.get();
}
}
}
+ return sirt_obj.get();
}
bool Monitor::MonitorExit(Thread* self, mirror::Object* obj) {
diff --git a/runtime/monitor.h b/runtime/monitor.h
index ca95e0b..d0a3a2e 100644
--- a/runtime/monitor.h
+++ b/runtime/monitor.h
@@ -57,7 +57,7 @@
static uint32_t GetLockOwnerThreadId(mirror::Object* obj)
NO_THREAD_SAFETY_ANALYSIS; // TODO: Reading lock owner without holding lock is racy.
- static void MonitorEnter(Thread* thread, mirror::Object* obj)
+ static mirror::Object* MonitorEnter(Thread* thread, mirror::Object* obj)
EXCLUSIVE_LOCK_FUNCTION(monitor_lock_)
SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
static bool MonitorExit(Thread* thread, mirror::Object* obj)
diff --git a/runtime/native/dalvik_system_Zygote.cc b/runtime/native/dalvik_system_Zygote.cc
index 7e6432e..29c0bc0 100644
--- a/runtime/native/dalvik_system_Zygote.cc
+++ b/runtime/native/dalvik_system_Zygote.cc
@@ -566,7 +566,7 @@
return pid;
}
-static jint Zygote_nativeForkAndSpecialize_new(JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
+static jint Zygote_nativeForkAndSpecialize(JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
jint debug_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring se_name,
jintArray fdsToClose) {
@@ -574,13 +574,6 @@
se_info, se_name, false, fdsToClose);
}
-static jint Zygote_nativeForkAndSpecialize(JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
- jint debug_flags, jobjectArray rlimits,
- jint mount_external, jstring se_info, jstring se_name) {
- return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags, rlimits, 0, 0, mount_external,
- se_info, se_name, false, NULL);
-}
-
static jint Zygote_nativeForkSystemServer(JNIEnv* env, jclass, uid_t uid, gid_t gid, jintArray gids,
jint debug_flags, jobjectArray rlimits,
jlong permittedCapabilities,
@@ -605,8 +598,7 @@
}
static JNINativeMethod gMethods[] = {
- NATIVE_METHOD(Zygote, nativeForkAndSpecialize_new, "(II[II[[IILjava/lang/String;Ljava/lang/String;[I)I"),
- NATIVE_METHOD(Zygote, nativeForkAndSpecialize, "(II[II[[IILjava/lang/String;Ljava/lang/String;)I"),
+ NATIVE_METHOD(Zygote, nativeForkAndSpecialize, "(II[II[[IILjava/lang/String;Ljava/lang/String;[I)I"),
NATIVE_METHOD(Zygote, nativeForkSystemServer, "(II[II[[IJJ)I"),
};
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 269a4a3..40aebfa 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -183,32 +183,32 @@
o = sirt_obj.get();
switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
case Primitive::kPrimBoolean:
- f->SetBoolean(o, new_value.GetZ());
+ f->SetBoolean<false>(o, new_value.GetZ());
break;
case Primitive::kPrimByte:
- f->SetByte(o, new_value.GetB());
+ f->SetByte<false>(o, new_value.GetB());
break;
case Primitive::kPrimChar:
- f->SetChar(o, new_value.GetC());
+ f->SetChar<false>(o, new_value.GetC());
break;
case Primitive::kPrimDouble:
- f->SetDouble(o, new_value.GetD());
+ f->SetDouble<false>(o, new_value.GetD());
break;
case Primitive::kPrimFloat:
- f->SetFloat(o, new_value.GetF());
+ f->SetFloat<false>(o, new_value.GetF());
break;
case Primitive::kPrimInt:
- f->SetInt(o, new_value.GetI());
+ f->SetInt<false>(o, new_value.GetI());
break;
case Primitive::kPrimLong:
- f->SetLong(o, new_value.GetJ());
+ f->SetLong<false>(o, new_value.GetJ());
break;
case Primitive::kPrimShort:
- f->SetShort(o, new_value.GetS());
+ f->SetShort<false>(o, new_value.GetS());
break;
case Primitive::kPrimNot:
if (allow_references) {
- f->SetObject(o, new_value.GetL());
+ f->SetObject<false>(o, new_value.GetL());
break;
}
// Else fall through to report an error.
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index 6727862..ad0f317 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -27,7 +27,8 @@
jint expectedValue, jint newValue) {
ScopedFastNativeObjectAccess soa(env);
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- bool success = obj->CasField32(MemberOffset(offset), expectedValue, newValue);
+ // JNI must use non transactional mode.
+ bool success = obj->CasField32<false>(MemberOffset(offset), expectedValue, newValue);
return success ? JNI_TRUE : JNI_FALSE;
}
@@ -35,7 +36,8 @@
jlong expectedValue, jlong newValue) {
ScopedFastNativeObjectAccess soa(env);
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- bool success = obj->CasField64(MemberOffset(offset), expectedValue, newValue);
+ // JNI must use non transactional mode.
+ bool success = obj->CasField64<false>(MemberOffset(offset), expectedValue, newValue);
return success ? JNI_TRUE : JNI_FALSE;
}
@@ -45,7 +47,8 @@
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
mirror::Object* expectedValue = soa.Decode<mirror::Object*>(javaExpectedValue);
mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
- bool success = obj->CasFieldObject(MemberOffset(offset), expectedValue, newValue);
+ // JNI must use non transactional mode.
+ bool success = obj->CasFieldObject<false>(MemberOffset(offset), expectedValue, newValue);
return success ? JNI_TRUE : JNI_FALSE;
}
@@ -64,14 +67,16 @@
static void Unsafe_putInt(JNIEnv* env, jobject, jobject javaObj, jlong offset, jint newValue) {
ScopedFastNativeObjectAccess soa(env);
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- obj->SetField32(MemberOffset(offset), newValue, false);
+ // JNI must use non transactional mode.
+ obj->SetField32<false>(MemberOffset(offset), newValue, false);
}
static void Unsafe_putIntVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
jint newValue) {
ScopedFastNativeObjectAccess soa(env);
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- obj->SetField32(MemberOffset(offset), newValue, true);
+ // JNI must use non transactional mode.
+ obj->SetField32<false>(MemberOffset(offset), newValue, true);
}
static void Unsafe_putOrderedInt(JNIEnv* env, jobject, jobject javaObj, jlong offset,
@@ -79,7 +84,8 @@
ScopedFastNativeObjectAccess soa(env);
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
QuasiAtomic::MembarStoreStore();
- obj->SetField32(MemberOffset(offset), newValue, false);
+ // JNI must use non transactional mode.
+ obj->SetField32<false>(MemberOffset(offset), newValue, false);
}
static jlong Unsafe_getLong(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
@@ -97,14 +103,16 @@
static void Unsafe_putLong(JNIEnv* env, jobject, jobject javaObj, jlong offset, jlong newValue) {
ScopedFastNativeObjectAccess soa(env);
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- obj->SetField64(MemberOffset(offset), newValue, false);
+ // JNI must use non transactional mode.
+ obj->SetField64<false>(MemberOffset(offset), newValue, false);
}
static void Unsafe_putLongVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
jlong newValue) {
ScopedFastNativeObjectAccess soa(env);
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
- obj->SetField64(MemberOffset(offset), newValue, true);
+ // JNI must use non transactional mode.
+ obj->SetField64<false>(MemberOffset(offset), newValue, true);
}
static void Unsafe_putOrderedLong(JNIEnv* env, jobject, jobject javaObj, jlong offset,
@@ -112,7 +120,8 @@
ScopedFastNativeObjectAccess soa(env);
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
QuasiAtomic::MembarStoreStore();
- obj->SetField64(MemberOffset(offset), newValue, false);
+ // JNI must use non transactional mode.
+ obj->SetField64<false>(MemberOffset(offset), newValue, false);
}
static jobject Unsafe_getObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset) {
@@ -134,7 +143,8 @@
ScopedFastNativeObjectAccess soa(env);
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
- obj->SetFieldObject(MemberOffset(offset), newValue, false);
+ // JNI must use non transactional mode.
+ obj->SetFieldObject<false>(MemberOffset(offset), newValue, false);
}
static void Unsafe_putObjectVolatile(JNIEnv* env, jobject, jobject javaObj, jlong offset,
@@ -142,7 +152,8 @@
ScopedFastNativeObjectAccess soa(env);
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
- obj->SetFieldObject(MemberOffset(offset), newValue, true);
+ // JNI must use non transactional mode.
+ obj->SetFieldObject<false>(MemberOffset(offset), newValue, true);
}
static void Unsafe_putOrderedObject(JNIEnv* env, jobject, jobject javaObj, jlong offset,
@@ -151,7 +162,8 @@
mirror::Object* obj = soa.Decode<mirror::Object*>(javaObj);
mirror::Object* newValue = soa.Decode<mirror::Object*>(javaNewValue);
QuasiAtomic::MembarStoreStore();
- obj->SetFieldObject(MemberOffset(offset), newValue, false);
+ // JNI must use non transactional mode.
+ obj->SetFieldObject<false>(MemberOffset(offset), newValue, false);
}
static jint Unsafe_getArrayBaseOffsetForComponentType(JNIEnv* env, jclass, jobject component_class) {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 6ca45e8..e1b0ed4 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -60,6 +60,7 @@
#include "thread.h"
#include "thread_list.h"
#include "trace.h"
+#include "transaction.h"
#include "profiler.h"
#include "UniquePtr.h"
#include "verifier/method_verifier.h"
@@ -120,7 +121,8 @@
main_thread_group_(nullptr),
system_thread_group_(nullptr),
system_class_loader_(nullptr),
- dump_gc_performance_on_shutdown_(false) {
+ dump_gc_performance_on_shutdown_(false),
+ preinitialization_transaction(nullptr) {
for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
callee_save_methods_[i] = nullptr;
}
@@ -826,7 +828,8 @@
thread_class->FindDeclaredInstanceField("contextClassLoader", "Ljava/lang/ClassLoader;");
CHECK(contextClassLoader != NULL);
- contextClassLoader->SetObject(soa.Self()->GetPeer(), class_loader.get());
+ // We can't run in a transaction yet.
+ contextClassLoader->SetObject<false>(soa.Self()->GetPeer(), class_loader.get());
return env->NewGlobalRef(system_class_loader.get());
}
@@ -1305,6 +1308,10 @@
bool clean_dirty) {
intern_table_->VisitRoots(callback, arg, only_dirty, clean_dirty);
class_linker_->VisitRoots(callback, arg, only_dirty, clean_dirty);
+ // TODO: is it the right place ?
+ if (preinitialization_transaction != nullptr) {
+ preinitialization_transaction->VisitRoots(callback, arg);
+ }
}
void Runtime::VisitNonThreadRoots(RootCallback* callback, void* arg) {
@@ -1371,7 +1378,7 @@
SirtRef<mirror::ObjectArray<mirror::ArtMethod> > imtable(self, cl->AllocArtMethodArray(self, 64));
mirror::ArtMethod* imt_conflict_method = Runtime::Current()->GetImtConflictMethod();
for (size_t i = 0; i < static_cast<size_t>(imtable->GetLength()); i++) {
- imtable->Set(i, imt_conflict_method);
+ imtable->Set<false>(i, imt_conflict_method);
}
return imtable.get();
}
@@ -1547,4 +1554,74 @@
BackgroundMethodSamplingProfiler::Start(profile_period_s_, profile_duration_s_, appDir, profile_interval_us_,
profile_backoff_coefficient_, startImmediately);
}
+
+// Transaction support.
+// TODO move them to header file for inlining.
+bool Runtime::IsActiveTransaction() const {
+ return preinitialization_transaction != nullptr;
+}
+
+void Runtime::EnterTransactionMode(Transaction* transaction) {
+ DCHECK(IsCompiler());
+ DCHECK(transaction != nullptr);
+ DCHECK(!IsActiveTransaction());
+ preinitialization_transaction = transaction;
+}
+
+void Runtime::ExitTransactionMode() {
+ DCHECK(IsCompiler());
+ DCHECK(IsActiveTransaction());
+ preinitialization_transaction = nullptr;
+}
+
+void Runtime::RecordWriteField32(mirror::Object* obj, MemberOffset field_offset,
+ uint32_t value, bool is_volatile) const {
+ DCHECK(IsCompiler());
+ DCHECK(IsActiveTransaction());
+ preinitialization_transaction->RecordWriteField32(obj, field_offset, value, is_volatile);
+}
+
+void Runtime::RecordWriteField64(mirror::Object* obj, MemberOffset field_offset,
+ uint64_t value, bool is_volatile) const {
+ DCHECK(IsCompiler());
+ DCHECK(IsActiveTransaction());
+ preinitialization_transaction->RecordWriteField64(obj, field_offset, value, is_volatile);
+}
+
+void Runtime::RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
+ mirror::Object* value, bool is_volatile) const {
+ DCHECK(IsCompiler());
+ DCHECK(IsActiveTransaction());
+ preinitialization_transaction->RecordWriteFieldReference(obj, field_offset, value, is_volatile);
+}
+
+void Runtime::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) const {
+ DCHECK(IsCompiler());
+ DCHECK(IsActiveTransaction());
+ preinitialization_transaction->RecordWriteArray(array, index, value);
+}
+
+void Runtime::RecordStrongStringInsertion(mirror::String* s, uint32_t hash_code) const {
+ DCHECK(IsCompiler());
+ DCHECK(IsActiveTransaction());
+ preinitialization_transaction->RecordStrongStringInsertion(s, hash_code);
+}
+
+void Runtime::RecordWeakStringInsertion(mirror::String* s, uint32_t hash_code) const {
+ DCHECK(IsCompiler());
+ DCHECK(IsActiveTransaction());
+ preinitialization_transaction->RecordWeakStringInsertion(s, hash_code);
+}
+
+void Runtime::RecordStrongStringRemoval(mirror::String* s, uint32_t hash_code) const {
+ DCHECK(IsCompiler());
+ DCHECK(IsActiveTransaction());
+ preinitialization_transaction->RecordStrongStringRemoval(s, hash_code);
+}
+
+void Runtime::RecordWeakStringRemoval(mirror::String* s, uint32_t hash_code) const {
+ DCHECK(IsCompiler());
+ DCHECK(IsActiveTransaction());
+ preinitialization_transaction->RecordWeakStringRemoval(s, hash_code);
+}
} // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 07f3d7d..159de2e 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -46,6 +46,7 @@
namespace mirror {
class ArtMethod;
class ClassLoader;
+ class Array;
template<class T> class ObjectArray;
template<class T> class PrimitiveArray;
typedef PrimitiveArray<int8_t> ByteArray;
@@ -65,6 +66,7 @@
class SignalCatcher;
class ThreadList;
class Trace;
+class Transaction;
class Runtime {
public:
@@ -474,6 +476,27 @@
void StartProfiler(const char *appDir, bool startImmediately = false);
+ // Transaction support.
+ bool IsActiveTransaction() const;
+ void EnterTransactionMode(Transaction* transaction);
+ void ExitTransactionMode();
+ void RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
+ bool is_volatile) const;
+ void RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value,
+ bool is_volatile) const;
+ void RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
+ mirror::Object* value, bool is_volatile) const;
+ void RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) const
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void RecordStrongStringInsertion(mirror::String* s, uint32_t hash_code) const
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+ void RecordWeakStringInsertion(mirror::String* s, uint32_t hash_code) const
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+ void RecordStrongStringRemoval(mirror::String* s, uint32_t hash_code) const
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+ void RecordWeakStringRemoval(mirror::String* s, uint32_t hash_code) const
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+
private:
static void InitPlatformSignalHandlers();
@@ -612,6 +635,9 @@
// If true, then we dump the GC cumulative timings on shutdown.
bool dump_gc_performance_on_shutdown_;
+ // Transaction used for pre-initializing classes at compilation time.
+ Transaction* preinitialization_transaction;
+
DISALLOW_COPY_AND_ASSIGN(Runtime);
};
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 9420e7b..c0bf377 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -170,6 +170,42 @@
return ret;
}
+inline bool Thread::PushOnThreadLocalAllocationStack(mirror::Object* obj) {
+ DCHECK_LE(thread_local_alloc_stack_top_, thread_local_alloc_stack_end_);
+ if (thread_local_alloc_stack_top_ < thread_local_alloc_stack_end_) {
+ // There's room.
+ DCHECK_LE(reinterpret_cast<byte*>(thread_local_alloc_stack_top_) + sizeof(mirror::Object*),
+ reinterpret_cast<byte*>(thread_local_alloc_stack_end_));
+ DCHECK(*thread_local_alloc_stack_top_ == nullptr);
+ *thread_local_alloc_stack_top_ = obj;
+ ++thread_local_alloc_stack_top_;
+ return true;
+ }
+ return false;
+}
+
+inline void Thread::SetThreadLocalAllocationStack(mirror::Object** start, mirror::Object** end) {
+ DCHECK(Thread::Current() == this) << "Should be called by self";
+ DCHECK(start != nullptr);
+ DCHECK(end != nullptr);
+ DCHECK_ALIGNED(start, sizeof(mirror::Object*));
+ DCHECK_ALIGNED(end, sizeof(mirror::Object*));
+ DCHECK_LT(start, end);
+ thread_local_alloc_stack_end_ = end;
+ thread_local_alloc_stack_top_ = start;
+}
+
+inline void Thread::RevokeThreadLocalAllocationStack() {
+ if (kIsDebugBuild) {
+ // Note: self is not necessarily equal to this thread since thread may be suspended.
+ Thread* self = Thread::Current();
+ DCHECK(this == self || IsSuspended() || GetState() == kWaitingPerformingGc)
+ << GetState() << " thread " << this << " self " << self;
+ }
+ thread_local_alloc_stack_end_ = nullptr;
+ thread_local_alloc_stack_top_ = nullptr;
+}
+
} // namespace art
#endif // ART_RUNTIME_THREAD_INL_H_
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 9797a48..5728391 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -398,14 +398,11 @@
// non-null value. However, because we can run without code
// available (in the compiler, in tests), we manually assign the
// fields the constructor should have set.
- soa.DecodeField(WellKnownClasses::java_lang_Thread_daemon)->
- SetBoolean(opeer_, thread_is_daemon);
- soa.DecodeField(WellKnownClasses::java_lang_Thread_group)->
- SetObject(opeer_, soa.Decode<mirror::Object*>(thread_group));
- soa.DecodeField(WellKnownClasses::java_lang_Thread_name)->
- SetObject(opeer_, soa.Decode<mirror::Object*>(thread_name.get()));
- soa.DecodeField(WellKnownClasses::java_lang_Thread_priority)->
- SetInt(opeer_, thread_priority);
+ if (runtime->IsActiveTransaction()) {
+ InitPeer<true>(soa, thread_is_daemon, thread_group, thread_name.get(), thread_priority);
+ } else {
+ InitPeer<false>(soa, thread_is_daemon, thread_group, thread_name.get(), thread_priority);
+ }
peer_thread_name.reset(GetThreadName(soa));
}
// 'thread_name' may have been null, so don't trust 'peer_thread_name' to be non-null.
@@ -414,6 +411,19 @@
}
}
+template<bool kTransactionActive>
+void Thread::InitPeer(ScopedObjectAccess& soa, jboolean thread_is_daemon, jobject thread_group,
+ jobject thread_name, jint thread_priority) {
+ soa.DecodeField(WellKnownClasses::java_lang_Thread_daemon)->
+ SetBoolean<kTransactionActive>(opeer_, thread_is_daemon);
+ soa.DecodeField(WellKnownClasses::java_lang_Thread_group)->
+ SetObject<kTransactionActive>(opeer_, soa.Decode<mirror::Object*>(thread_group));
+ soa.DecodeField(WellKnownClasses::java_lang_Thread_name)->
+ SetObject<kTransactionActive>(opeer_, soa.Decode<mirror::Object*>(thread_name));
+ soa.DecodeField(WellKnownClasses::java_lang_Thread_priority)->
+ SetInt<kTransactionActive>(opeer_, thread_priority);
+}
+
void Thread::SetThreadName(const char* name) {
name_->assign(name);
::art::SetThreadName(name);
@@ -963,7 +973,9 @@
thread_local_start_(nullptr),
thread_local_pos_(nullptr),
thread_local_end_(nullptr),
- thread_local_objects_(0) {
+ thread_local_objects_(0),
+ thread_local_alloc_stack_top_(nullptr),
+ thread_local_alloc_stack_end_(nullptr) {
CHECK_EQ((sizeof(Thread) % 4), 0U) << sizeof(Thread);
state_and_flags_.as_struct.flags = 0;
state_and_flags_.as_struct.state = kNative;
@@ -1018,7 +1030,11 @@
RemoveFromThreadGroup(soa);
// this.nativePeer = 0;
- soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer)->SetLong(opeer_, 0);
+ if (Runtime::Current()->IsActiveTransaction()) {
+ soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer)->SetLong<true>(opeer_, 0);
+ } else {
+ soa.DecodeField(WellKnownClasses::java_lang_Thread_nativePeer)->SetLong<false>(opeer_, 0);
+ }
Dbg::PostThreadDeath(self);
// Thread.join() is implemented as an Object.wait() on the Thread.lock object. Signal anyone
@@ -1307,7 +1323,8 @@
}
// Save PC trace in last element of method trace, also places it into the
// object graph.
- method_trace->Set(depth, dex_pc_trace);
+ // We are called from native: use non-transactional mode.
+ method_trace->Set<false>(depth, dex_pc_trace);
// Set the Object*s and assert that no thread suspension is now possible.
const char* last_no_suspend_cause =
self_->StartAssertNoThreadSuspension("Building internal stack trace");
@@ -1335,8 +1352,14 @@
if (m->IsRuntimeMethod()) {
return true; // Ignore runtime frames (in particular callee save).
}
- method_trace_->Set(count_, m);
- dex_pc_trace_->Set(count_, m->IsProxyMethod() ? DexFile::kDexNoIndex : GetDexPc());
+ // TODO dedup this code.
+ if (Runtime::Current()->IsActiveTransaction()) {
+ method_trace_->Set<true>(count_, m);
+ dex_pc_trace_->Set<true>(count_, m->IsProxyMethod() ? DexFile::kDexNoIndex : GetDexPc());
+ } else {
+ method_trace_->Set<false>(count_, m);
+ dex_pc_trace_->Set<false>(count_, m->IsProxyMethod() ? DexFile::kDexNoIndex : GetDexPc());
+ }
++count_;
return true;
}
@@ -1459,7 +1482,8 @@
if (obj == nullptr) {
return nullptr;
}
- soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(result)->Set(i, obj);
+ // We are called from native: use non-transactional mode.
+ soa.Decode<mirror::ObjectArray<mirror::StackTraceElement>*>(result)->Set<false>(i, obj);
}
return result;
}
diff --git a/runtime/thread.h b/runtime/thread.h
index a3a77bb..48912d1 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -591,6 +591,11 @@
void CreatePeer(const char* name, bool as_daemon, jobject thread_group);
+ template<bool kTransactionActive>
+ void InitPeer(ScopedObjectAccess& soa, jboolean thread_is_daemon, jobject thread_group,
+ jobject thread_name, jint thread_priority)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
// Avoid use, callers should use SetState. Used only by SignalCatcher::HandleSigQuit, ~Thread and
// Dbg::Disconnected.
ThreadState SetStateUnsafe(ThreadState new_state) {
@@ -829,6 +834,19 @@
static const size_t kRosAllocNumOfSizeBrackets = 34;
void* rosalloc_runs_[kRosAllocNumOfSizeBrackets];
+ // Thread-local allocation stack data/routines.
+ mirror::Object** thread_local_alloc_stack_top_;
+ mirror::Object** thread_local_alloc_stack_end_;
+
+ // Push an object onto the allocation stack.
+ bool PushOnThreadLocalAllocationStack(mirror::Object* obj);
+
+ // Set the thread local allocation pointers to the given pointers.
+ void SetThreadLocalAllocationStack(mirror::Object** start, mirror::Object** end);
+
+ // Resets the thread local allocation pointers.
+ void RevokeThreadLocalAllocationStack();
+
private:
friend class Dbg; // For SetStateUnsafe.
friend class Monitor;
diff --git a/runtime/transaction.cc b/runtime/transaction.cc
new file mode 100644
index 0000000..6adcfec
--- /dev/null
+++ b/runtime/transaction.cc
@@ -0,0 +1,419 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "transaction.h"
+
+#include "base/stl_util.h"
+#include "base/logging.h"
+#include "gc/accounting/card_table-inl.h"
+#include "intern_table.h"
+#include "mirror/object-inl.h"
+#include "mirror/object_array-inl.h"
+
+#include <list>
+
+namespace art {
+
+// TODO: remove (only used for debugging purpose).
+static constexpr bool kEnableTransactionStats = false;
+
+Transaction::Transaction() : log_lock_("transaction log lock", kTransactionLogLock) {
+ CHECK(Runtime::Current()->IsCompiler());
+}
+
+Transaction::~Transaction() {
+ if (kEnableTransactionStats) {
+ MutexLock mu(Thread::Current(), log_lock_);
+ size_t objects_count = object_logs_.size();
+ size_t field_values_count = 0;
+ for (auto it : object_logs_) {
+ field_values_count += it.second.Size();
+ }
+ size_t array_count = array_logs_.size();
+ size_t array_values_count = 0;
+ for (auto it : array_logs_) {
+ array_values_count += it.second.Size();
+ }
+ size_t string_count = intern_string_logs_.size();
+ LOG(INFO) << "Transaction::~Transaction"
+ << ": objects_count=" << objects_count
+ << ", field_values_count=" << field_values_count
+ << ", array_count=" << array_count
+ << ", array_values_count=" << array_values_count
+ << ", string_count=" << string_count;
+ }
+}
+
+void Transaction::RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
+ bool is_volatile) {
+ DCHECK(obj != nullptr);
+ MutexLock mu(Thread::Current(), log_lock_);
+ ObjectLog& object_log = object_logs_[obj];
+ object_log.Log32BitsValue(field_offset, value, is_volatile);
+}
+
+void Transaction::RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value,
+ bool is_volatile) {
+ DCHECK(obj != nullptr);
+ MutexLock mu(Thread::Current(), log_lock_);
+ ObjectLog& object_log = object_logs_[obj];
+ object_log.Log64BitsValue(field_offset, value, is_volatile);
+}
+
+void Transaction::RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
+ mirror::Object* value, bool is_volatile) {
+ DCHECK(obj != nullptr);
+ MutexLock mu(Thread::Current(), log_lock_);
+ ObjectLog& object_log = object_logs_[obj];
+ object_log.LogReferenceValue(field_offset, value, is_volatile);
+}
+
+void Transaction::RecordWriteArray(mirror::Array* array, size_t index, uint64_t value) {
+ DCHECK(array != nullptr);
+ DCHECK(array->IsArrayInstance());
+ MutexLock mu(Thread::Current(), log_lock_);
+ ArrayLog& array_log = array_logs_[array];
+ array_log.LogValue(index, value);
+}
+
+void Transaction::RecordStrongStringInsertion(mirror::String* s, uint32_t hash_code) {
+ DCHECK(s != nullptr);
+ InternStringLog log(s, hash_code, InternStringLog::kStrongString, InternStringLog::kInsert);
+ LogInternedString(log);
+}
+
+void Transaction::RecordWeakStringInsertion(mirror::String* s, uint32_t hash_code) {
+ DCHECK(s != nullptr);
+ InternStringLog log(s, hash_code, InternStringLog::kWeakString, InternStringLog::kInsert);
+ LogInternedString(log);
+}
+
+void Transaction::RecordStrongStringRemoval(mirror::String* s, uint32_t hash_code) {
+ InternStringLog log(s, hash_code, InternStringLog::kStrongString, InternStringLog::kRemove);
+ LogInternedString(log);
+}
+
+void Transaction::RecordWeakStringRemoval(mirror::String* s, uint32_t hash_code) {
+ InternStringLog log(s, hash_code, InternStringLog::kWeakString, InternStringLog::kRemove);
+ LogInternedString(log);
+}
+
+void Transaction::LogInternedString(InternStringLog& log) {
+ Locks::intern_table_lock_->AssertExclusiveHeld(Thread::Current());
+ MutexLock mu(Thread::Current(), log_lock_);
+ intern_string_logs_.push_front(log);
+}
+
+void Transaction::Abort() {
+ CHECK(!Runtime::Current()->IsActiveTransaction());
+ Thread* self = Thread::Current();
+ self->AssertNoPendingException();
+ MutexLock mu1(self, *Locks::intern_table_lock_);
+ MutexLock mu2(self, log_lock_);
+ UndoObjectModifications();
+ UndoArrayModifications();
+ UndoInternStringTableModifications();
+}
+
+void Transaction::UndoObjectModifications() {
+ // TODO we may not need to restore objects allocated during this transaction. Or we could directly
+ // remove them from the heap.
+ for (auto it : object_logs_) {
+ it.second.Undo(it.first);
+ }
+ object_logs_.clear();
+}
+
+void Transaction::UndoArrayModifications() {
+ // TODO we may not need to restore array allocated during this transaction. Or we could directly
+ // remove them from the heap.
+ for (auto it : array_logs_) {
+ it.second.Undo(it.first);
+ }
+ array_logs_.clear();
+}
+
+void Transaction::UndoInternStringTableModifications() {
+ InternTable* const intern_table = Runtime::Current()->GetInternTable();
+ // We want to undo each operation from the most recent to the oldest. List has been filled so the
+ // most recent operation is at list begin so just have to iterate over it.
+ for (InternStringLog& string_log : intern_string_logs_) {
+ string_log.Undo(intern_table);
+ }
+ intern_string_logs_.clear();
+}
+
+void Transaction::VisitRoots(RootCallback* callback, void* arg) {
+ LOG(INFO) << "Transaction::VisitRoots";
+ MutexLock mu(Thread::Current(), log_lock_);
+ VisitObjectLogs(callback, arg);
+ VisitArrayLogs(callback, arg);
+ VisitStringLogs(callback, arg);
+}
+
+void Transaction::VisitObjectLogs(RootCallback* callback, void* arg) {
+ // List of moving roots.
+ typedef std::pair<mirror::Object*, mirror::Object*> ObjectPair;
+ std::list<ObjectPair> moving_roots;
+
+ // Visit roots.
+ for (auto it : object_logs_) {
+ it.second.VisitRoots(callback, arg);
+ mirror::Object* old_root = it.first;
+ mirror::Object* new_root = callback(old_root, arg, 0, kRootUnknown);
+ if (new_root != old_root) {
+ moving_roots.push_back(std::make_pair(old_root, new_root));
+ }
+ }
+
+ // Update object logs with moving roots.
+ for (const ObjectPair& pair : moving_roots) {
+ mirror::Object* old_root = pair.first;
+ mirror::Object* new_root = pair.second;
+ auto old_root_it = object_logs_.find(old_root);
+ CHECK(old_root_it != object_logs_.end());
+ CHECK(object_logs_.find(new_root) == object_logs_.end());
+ object_logs_.insert(std::make_pair(new_root, old_root_it->second));
+ object_logs_.erase(old_root_it);
+ }
+}
+
+void Transaction::VisitArrayLogs(RootCallback* callback, void* arg) {
+ // List of moving roots.
+ typedef std::pair<mirror::Array*, mirror::Array*> ArrayPair;
+ std::list<ArrayPair> moving_roots;
+
+ for (auto it : array_logs_) {
+ mirror::Array* old_root = it.first;
+ if (old_root->IsObjectArray()) {
+ it.second.VisitRoots(callback, arg);
+ }
+ mirror::Array* new_root = down_cast<mirror::Array*>(callback(old_root, arg, 0, kRootUnknown));
+ if (new_root != old_root) {
+ moving_roots.push_back(std::make_pair(old_root, new_root));
+ }
+ }
+
+ // Update array logs with moving roots.
+ for (const ArrayPair& pair : moving_roots) {
+ mirror::Array* old_root = pair.first;
+ mirror::Array* new_root = pair.second;
+ auto old_root_it = array_logs_.find(old_root);
+ CHECK(old_root_it != array_logs_.end());
+ CHECK(array_logs_.find(new_root) == array_logs_.end());
+ array_logs_.insert(std::make_pair(new_root, old_root_it->second));
+ array_logs_.erase(old_root_it);
+ }
+}
+
+void Transaction::VisitStringLogs(RootCallback* callback, void* arg) {
+ for (InternStringLog& log : intern_string_logs_) {
+ log.VisitRoots(callback, arg);
+ }
+}
+
+void Transaction::ObjectLog::Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile) {
+ auto it = field_values_.find(offset.Uint32Value());
+ if (it == field_values_.end()) {
+ ObjectLog::FieldValue field_value;
+ field_value.value = value;
+ field_value.is_volatile = is_volatile;
+ field_value.kind = ObjectLog::k32Bits;
+ field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
+ }
+}
+
+void Transaction::ObjectLog::Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile) {
+ auto it = field_values_.find(offset.Uint32Value());
+ if (it == field_values_.end()) {
+ ObjectLog::FieldValue field_value;
+ field_value.value = value;
+ field_value.is_volatile = is_volatile;
+ field_value.kind = ObjectLog::k64Bits;
+ field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
+ }
+}
+
+void Transaction::ObjectLog::LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile) {
+ auto it = field_values_.find(offset.Uint32Value());
+ if (it == field_values_.end()) {
+ ObjectLog::FieldValue field_value;
+ field_value.value = reinterpret_cast<uintptr_t>(obj);
+ field_value.is_volatile = is_volatile;
+ field_value.kind = ObjectLog::kReference;
+ field_values_.insert(std::make_pair(offset.Uint32Value(), field_value));
+ }
+}
+
+void Transaction::ObjectLog::Undo(mirror::Object* obj) {
+ for (auto& it : field_values_) {
+ // Garbage collector needs to access object's class and array's length. So we don't rollback
+ // these values.
+ MemberOffset field_offset(it.first);
+ if (field_offset.Uint32Value() == mirror::Class::ClassOffset().Uint32Value()) {
+ // Skip Object::class field.
+ continue;
+ }
+ if (obj->IsArrayInstance() &&
+ field_offset.Uint32Value() == mirror::Array::LengthOffset().Uint32Value()) {
+ // Skip Array::length field.
+ continue;
+ }
+ FieldValue& field_value = it.second;
+ UndoFieldWrite(obj, field_offset, field_value);
+ }
+}
+
+void Transaction::ObjectLog::UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
+ const FieldValue& field_value) {
+ // TODO We may want to abort a transaction while still being in transaction mode. In this case,
+ // we'd need to disable the check.
+ constexpr bool kCheckTransaction = true;
+ switch (field_value.kind) {
+ case k32Bits:
+ obj->SetField32<false, kCheckTransaction>(field_offset, static_cast<uint32_t>(field_value.value),
+ field_value.is_volatile);
+ break;
+ case k64Bits:
+ obj->SetField64<false, kCheckTransaction>(field_offset, field_value.value,
+ field_value.is_volatile);
+ break;
+ case kReference:
+ obj->SetFieldObject<false, kCheckTransaction>(field_offset,
+ reinterpret_cast<mirror::Object*>(field_value.value),
+ field_value.is_volatile);
+ break;
+ default:
+ LOG(FATAL) << "Unknown value kind " << field_value.kind;
+ break;
+ }
+}
+
+void Transaction::ObjectLog::VisitRoots(RootCallback* callback, void* arg) {
+ for (auto it : field_values_) {
+ FieldValue& field_value = it.second;
+ if (field_value.kind == ObjectLog::kReference) {
+ mirror::Object* obj = reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(field_value.value));
+ field_value.value = reinterpret_cast<uintptr_t>(callback(obj, arg, 0, kRootUnknown));
+ }
+ }
+}
+
+void Transaction::InternStringLog::Undo(InternTable* intern_table) {
+ DCHECK(intern_table != nullptr);
+ switch (string_op_) {
+ case InternStringLog::kInsert: {
+ switch (string_kind_) {
+ case InternStringLog::kStrongString:
+ intern_table->RemoveStrongFromTransaction(str_, hash_code_);
+ break;
+ case InternStringLog::kWeakString:
+ intern_table->RemoveWeakFromTransaction(str_, hash_code_);
+ break;
+ default:
+ LOG(FATAL) << "Unknown interned string kind";
+ break;
+ }
+ break;
+ }
+ case InternStringLog::kRemove: {
+ switch (string_kind_) {
+ case InternStringLog::kStrongString:
+ intern_table->InsertStrongFromTransaction(str_, hash_code_);
+ break;
+ case InternStringLog::kWeakString:
+ intern_table->InsertWeakFromTransaction(str_, hash_code_);
+ break;
+ default:
+ LOG(FATAL) << "Unknown interned string kind";
+ break;
+ }
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unknown interned string op";
+ break;
+ }
+}
+
+void Transaction::InternStringLog::VisitRoots(RootCallback* callback, void* arg) {
+ str_ = down_cast<mirror::String*>(callback(str_, arg, 0, kRootInternedString));
+}
+
+void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
+ auto it = array_values_.find(index);
+ if (it == array_values_.end()) {
+ array_values_.insert(std::make_pair(index, value));
+ }
+}
+
+void Transaction::ArrayLog::Undo(mirror::Array* array) {
+ DCHECK(array != nullptr);
+ DCHECK(array->IsArrayInstance());
+ Primitive::Type type = array->GetClass()->GetComponentType()->GetPrimitiveType();
+ for (auto it : array_values_) {
+ UndoArrayWrite(array, type, it.first, it.second);
+ }
+}
+
+void Transaction::ArrayLog::UndoArrayWrite(mirror::Array* array, Primitive::Type array_type,
+ size_t index, uint64_t value) {
+ // TODO We may want to abort a transaction while still being in transaction mode. In this case,
+ // we'd need to disable the check.
+ switch (array_type) {
+ case Primitive::kPrimBoolean:
+ array->AsBooleanArray()->SetWithoutChecks<false>(index, static_cast<uint8_t>(value));
+ break;
+ case Primitive::kPrimByte:
+ array->AsByteArray()->SetWithoutChecks<false>(index, static_cast<int8_t>(value));
+ break;
+ case Primitive::kPrimChar:
+ array->AsCharArray()->SetWithoutChecks<false>(index, static_cast<uint16_t>(value));
+ break;
+ case Primitive::kPrimShort:
+ array->AsShortArray()->SetWithoutChecks<false>(index, static_cast<int16_t>(value));
+ break;
+ case Primitive::kPrimInt:
+ array->AsIntArray()->SetWithoutChecks<false>(index, static_cast<int32_t>(value));
+ break;
+ case Primitive::kPrimFloat:
+ array->AsFloatArray()->SetWithoutChecks<false>(index, static_cast<float>(value));
+ break;
+ case Primitive::kPrimLong:
+ array->AsLongArray()->SetWithoutChecks<false>(index, static_cast<int64_t>(value));
+ break;
+ case Primitive::kPrimDouble:
+ array->AsDoubleArray()->SetWithoutChecks<false>(index, static_cast<double>(value));
+ break;
+ case Primitive::kPrimNot: {
+ mirror::ObjectArray<mirror::Object>* obj_array = array->AsObjectArray<mirror::Object>();
+ obj_array->SetWithoutChecks<false>(index, reinterpret_cast<mirror::Object*>(
+ static_cast<uintptr_t>(value)));
+ break;
+ }
+ default:
+ LOG(FATAL) << "Unsupported type " << array_type;
+ }
+}
+
+void Transaction::ArrayLog::VisitRoots(RootCallback* callback, void* arg) {
+ for (auto& it : array_values_) {
+ mirror::Object* obj = reinterpret_cast<mirror::Object*>(static_cast<uintptr_t>(it.second));
+ it.second = reinterpret_cast<uintptr_t>(callback(obj, arg, 0, kRootUnknown));
+ }
+}
+
+} // namespace art
diff --git a/runtime/transaction.h b/runtime/transaction.h
new file mode 100644
index 0000000..68f9540
--- /dev/null
+++ b/runtime/transaction.h
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2014 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_TRANSACTION_H_
+#define ART_RUNTIME_TRANSACTION_H_
+
+#include "base/macros.h"
+#include "base/mutex.h"
+#include "locks.h"
+#include "offsets.h"
+#include "primitive.h"
+#include "object_callbacks.h"
+#include "safe_map.h"
+
+#include <list>
+#include <map>
+
+namespace art {
+namespace mirror {
+class Array;
+class Object;
+class String;
+}
+class InternTable;
+
+class Transaction {
+ public:
+ Transaction();
+ ~Transaction();
+
+ // Record object field changes.
+ void RecordWriteField32(mirror::Object* obj, MemberOffset field_offset, uint32_t value,
+ bool is_volatile)
+ LOCKS_EXCLUDED(log_lock_);
+ void RecordWriteField64(mirror::Object* obj, MemberOffset field_offset, uint64_t value,
+ bool is_volatile)
+ LOCKS_EXCLUDED(log_lock_);
+ void RecordWriteFieldReference(mirror::Object* obj, MemberOffset field_offset,
+ mirror::Object* value, bool is_volatile)
+ LOCKS_EXCLUDED(log_lock_);
+
+ // Record array change.
+ void RecordWriteArray(mirror::Array* array, size_t index, uint64_t value)
+ LOCKS_EXCLUDED(log_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Record intern string table changes.
+ void RecordStrongStringInsertion(mirror::String* s, uint32_t hash_code)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_)
+ LOCKS_EXCLUDED(log_lock_);
+ void RecordWeakStringInsertion(mirror::String* s, uint32_t hash_code)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_)
+ LOCKS_EXCLUDED(log_lock_);
+ void RecordStrongStringRemoval(mirror::String* s, uint32_t hash_code)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_)
+ LOCKS_EXCLUDED(log_lock_);
+ void RecordWeakStringRemoval(mirror::String* s, uint32_t hash_code)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_)
+ LOCKS_EXCLUDED(log_lock_);
+
+ // Abort transaction by undoing all recorded changes.
+ void Abort()
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+ LOCKS_EXCLUDED(log_lock_);
+
+ void VisitRoots(RootCallback* callback, void* arg)
+ LOCKS_EXCLUDED(log_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+ class ObjectLog {
+ public:
+ void Log32BitsValue(MemberOffset offset, uint32_t value, bool is_volatile);
+ void Log64BitsValue(MemberOffset offset, uint64_t value, bool is_volatile);
+ void LogReferenceValue(MemberOffset offset, mirror::Object* obj, bool is_volatile);
+
+ void Undo(mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void VisitRoots(RootCallback* callback, void* arg);
+
+ size_t Size() const {
+ return field_values_.size();
+ }
+
+ private:
+ enum FieldValueKind {
+ k32Bits,
+ k64Bits,
+ kReference
+ };
+ struct FieldValue {
+ // TODO use JValue instead ?
+ uint64_t value;
+ FieldValueKind kind;
+ bool is_volatile;
+ };
+
+ void UndoFieldWrite(mirror::Object* obj, MemberOffset field_offset,
+ const FieldValue& field_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Maps field's offset to its value.
+ std::map<uint32_t, FieldValue> field_values_;
+ };
+
+ class ArrayLog {
+ public:
+ void LogValue(size_t index, uint64_t value);
+
+ void Undo(mirror::Array* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void VisitRoots(RootCallback* callback, void* arg);
+
+ size_t Size() const {
+ return array_values_.size();
+ }
+
+ private:
+ void UndoArrayWrite(mirror::Array* array, Primitive::Type array_type, size_t index,
+ uint64_t value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ // Maps index to value.
+ // TODO use JValue instead ?
+ std::map<size_t, uint64_t> array_values_;
+ };
+
+ class InternStringLog {
+ public:
+ enum StringKind {
+ kStrongString,
+ kWeakString
+ };
+ enum StringOp {
+ kInsert,
+ kRemove
+ };
+ InternStringLog(mirror::String* s, uint32_t hash_code, StringKind kind, StringOp op)
+ : str_(s), hash_code_(hash_code), string_kind_(kind), string_op_(op) {
+ }
+
+ void Undo(InternTable* intern_table) EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_);
+ void VisitRoots(RootCallback* callback, void* arg);
+
+ private:
+ mirror::String* str_;
+ uint32_t hash_code_;
+ StringKind string_kind_;
+ StringOp string_op_;
+ };
+
+ void LogInternedString(InternStringLog& log)
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_)
+ LOCKS_EXCLUDED(log_lock_);
+
+ void UndoObjectModifications()
+ EXCLUSIVE_LOCKS_REQUIRED(log_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void UndoArrayModifications()
+ EXCLUSIVE_LOCKS_REQUIRED(log_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void UndoInternStringTableModifications()
+ EXCLUSIVE_LOCKS_REQUIRED(Locks::intern_table_lock_)
+ EXCLUSIVE_LOCKS_REQUIRED(log_lock_);
+
+ void VisitObjectLogs(RootCallback* callback, void* arg)
+ EXCLUSIVE_LOCKS_REQUIRED(log_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void VisitArrayLogs(RootCallback* callback, void* arg)
+ EXCLUSIVE_LOCKS_REQUIRED(log_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+ void VisitStringLogs(RootCallback* callback, void* arg)
+ EXCLUSIVE_LOCKS_REQUIRED(log_lock_)
+ SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ Mutex log_lock_ ACQUIRED_AFTER(Locks::intern_table_lock_);
+ std::map<mirror::Object*, ObjectLog> object_logs_ GUARDED_BY(log_lock_);
+ std::map<mirror::Array*, ArrayLog> array_logs_ GUARDED_BY(log_lock_);
+ std::list<InternStringLog> intern_string_logs_ GUARDED_BY(log_lock_);
+
+ DISALLOW_COPY_AND_ASSIGN(Transaction);
+};
+
+} // namespace art
+
+#endif // ART_RUNTIME_TRANSACTION_H_
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
new file mode 100644
index 0000000..dcfa24b
--- /dev/null
+++ b/runtime/transaction_test.cc
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+#include "common_test.h"
+#include "invoke_arg_array_builder.h"
+#include "mirror/array-inl.h"
+#include "mirror/art_field-inl.h"
+#include "mirror/art_method-inl.h"
+#include "transaction.h"
+
+namespace art {
+
+class TransactionTest : public CommonTest {
+};
+
+TEST_F(TransactionTest, Object_class) {
+ ScopedObjectAccess soa(Thread::Current());
+ SirtRef<mirror::Class> sirt_klass(soa.Self(),
+ class_linker_->FindSystemClass("Ljava/lang/Object;"));
+ ASSERT_TRUE(sirt_klass.get() != nullptr);
+
+ Transaction transaction;
+ Runtime::Current()->EnterTransactionMode(&transaction);
+ SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
+ ASSERT_TRUE(sirt_obj.get() != nullptr);
+ ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+ Runtime::Current()->ExitTransactionMode();
+
+ // Aborting transaction must not clear the Object::class field.
+ transaction.Abort();
+ EXPECT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+}
+
+TEST_F(TransactionTest, Object_monitor) {
+ ScopedObjectAccess soa(Thread::Current());
+ SirtRef<mirror::Class> sirt_klass(soa.Self(),
+ class_linker_->FindSystemClass("Ljava/lang/Object;"));
+ ASSERT_TRUE(sirt_klass.get() != nullptr);
+ SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
+ ASSERT_TRUE(sirt_obj.get() != nullptr);
+ ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+
+ // Lock object's monitor outside the transaction.
+ sirt_obj->MonitorEnter(soa.Self());
+ uint32_t old_lock_word = sirt_obj->GetLockWord().GetValue();
+
+ Transaction transaction;
+ Runtime::Current()->EnterTransactionMode(&transaction);
+ // Unlock object's monitor inside the transaction.
+ sirt_obj->MonitorExit(soa.Self());
+ uint32_t new_lock_word = sirt_obj->GetLockWord().GetValue();
+ Runtime::Current()->ExitTransactionMode();
+
+ // Aborting transaction must not clear the Object::class field.
+ transaction.Abort();
+ uint32_t aborted_lock_word = sirt_obj->GetLockWord().GetValue();
+ EXPECT_NE(old_lock_word, new_lock_word);
+ EXPECT_EQ(aborted_lock_word, new_lock_word);
+}
+
+TEST_F(TransactionTest, Array_length) {
+ ScopedObjectAccess soa(Thread::Current());
+ SirtRef<mirror::Class> sirt_klass(soa.Self(),
+ class_linker_->FindSystemClass("[Ljava/lang/Object;"));
+ ASSERT_TRUE(sirt_klass.get() != nullptr);
+
+ constexpr int32_t kArraySize = 2;
+
+ Transaction transaction;
+ Runtime::Current()->EnterTransactionMode(&transaction);
+
+ // Allocate an array during transaction.
+ SirtRef<mirror::Array> sirt_obj(soa.Self(),
+ mirror::Array::Alloc<false>(soa.Self(), sirt_klass.get(), kArraySize));
+ ASSERT_TRUE(sirt_obj.get() != nullptr);
+ ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+ Runtime::Current()->ExitTransactionMode();
+
+ // Aborting transaction must not clear the Object::class field.
+ transaction.Abort();
+ EXPECT_EQ(sirt_obj->GetLength(), kArraySize);
+}
+
+TEST_F(TransactionTest, StaticFieldsTest) {
+ ScopedObjectAccess soa(Thread::Current());
+ SirtRef<mirror::ClassLoader> class_loader(
+ soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
+ ASSERT_TRUE(class_loader.get() != nullptr);
+
+ SirtRef<mirror::Class> sirt_klass(soa.Self(),
+ class_linker_->FindClass("LStaticFieldsTest;", class_loader));
+ ASSERT_TRUE(sirt_klass.get() != nullptr);
+ class_linker_->EnsureInitialized(sirt_klass, true, true);
+ ASSERT_TRUE(sirt_klass->IsInitialized());
+
+ // Lookup fields.
+ mirror::ArtField* booleanField = sirt_klass->FindDeclaredStaticField("booleanField", "Z");
+ ASSERT_TRUE(booleanField != nullptr);
+ ASSERT_EQ(FieldHelper(booleanField).GetTypeAsPrimitiveType(), Primitive::kPrimBoolean);
+ ASSERT_EQ(booleanField->GetBoolean(sirt_klass.get()), false);
+
+ mirror::ArtField* byteField = sirt_klass->FindDeclaredStaticField("byteField", "B");
+ ASSERT_TRUE(byteField != nullptr);
+ ASSERT_EQ(FieldHelper(byteField).GetTypeAsPrimitiveType(), Primitive::kPrimByte);
+ ASSERT_EQ(byteField->GetByte(sirt_klass.get()), 0);
+
+ mirror::ArtField* charField = sirt_klass->FindDeclaredStaticField("charField", "C");
+ ASSERT_TRUE(charField != nullptr);
+ ASSERT_EQ(FieldHelper(charField).GetTypeAsPrimitiveType(), Primitive::kPrimChar);
+ ASSERT_EQ(charField->GetChar(sirt_klass.get()), 0u);
+
+ mirror::ArtField* shortField = sirt_klass->FindDeclaredStaticField("shortField", "S");
+ ASSERT_TRUE(shortField != nullptr);
+ ASSERT_EQ(FieldHelper(shortField).GetTypeAsPrimitiveType(), Primitive::kPrimShort);
+ ASSERT_EQ(shortField->GetShort(sirt_klass.get()), 0);
+
+ mirror::ArtField* intField = sirt_klass->FindDeclaredStaticField("intField", "I");
+ ASSERT_TRUE(intField != nullptr);
+ ASSERT_EQ(FieldHelper(intField).GetTypeAsPrimitiveType(), Primitive::kPrimInt);
+ ASSERT_EQ(intField->GetInt(sirt_klass.get()), 0);
+
+ mirror::ArtField* longField = sirt_klass->FindDeclaredStaticField("longField", "J");
+ ASSERT_TRUE(longField != nullptr);
+ ASSERT_EQ(FieldHelper(longField).GetTypeAsPrimitiveType(), Primitive::kPrimLong);
+ ASSERT_EQ(longField->GetLong(sirt_klass.get()), static_cast<int64_t>(0));
+
+ mirror::ArtField* floatField = sirt_klass->FindDeclaredStaticField("floatField", "F");
+ ASSERT_TRUE(floatField != nullptr);
+ ASSERT_EQ(FieldHelper(floatField).GetTypeAsPrimitiveType(), Primitive::kPrimFloat);
+ ASSERT_EQ(floatField->GetFloat(sirt_klass.get()), static_cast<float>(0.0f));
+
+ mirror::ArtField* doubleField = sirt_klass->FindDeclaredStaticField("doubleField", "D");
+ ASSERT_TRUE(doubleField != nullptr);
+ ASSERT_EQ(FieldHelper(doubleField).GetTypeAsPrimitiveType(), Primitive::kPrimDouble);
+ ASSERT_EQ(doubleField->GetDouble(sirt_klass.get()), static_cast<double>(0.0));
+
+ mirror::ArtField* objectField = sirt_klass->FindDeclaredStaticField("objectField", "Ljava/lang/Object;");
+ ASSERT_TRUE(objectField != nullptr);
+ ASSERT_EQ(FieldHelper(objectField).GetTypeAsPrimitiveType(), Primitive::kPrimNot);
+ ASSERT_EQ(objectField->GetObject(sirt_klass.get()), nullptr);
+
+ // Create a java.lang.Object instance to set objectField.
+ SirtRef<mirror::Class> object_klass(soa.Self(), class_linker_->FindSystemClass("Ljava/lang/Object;"));
+ ASSERT_TRUE(object_klass.get() != nullptr);
+ SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
+ ASSERT_TRUE(sirt_obj.get() != nullptr);
+ ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+
+ // Modify fields inside transaction and abort it.
+ Transaction transaction;
+ Runtime::Current()->EnterTransactionMode(&transaction);
+ booleanField->SetBoolean<true>(sirt_klass.get(), true);
+ byteField->SetByte<true>(sirt_klass.get(), 1);
+ charField->SetChar<true>(sirt_klass.get(), 1u);
+ shortField->SetShort<true>(sirt_klass.get(), 1);
+ intField->SetInt<true>(sirt_klass.get(), 1);
+ longField->SetLong<true>(sirt_klass.get(), 1);
+ floatField->SetFloat<true>(sirt_klass.get(), 1.0);
+ doubleField->SetDouble<true>(sirt_klass.get(), 1.0);
+ objectField->SetObject<true>(sirt_klass.get(), sirt_obj.get());
+ Runtime::Current()->ExitTransactionMode();
+ transaction.Abort();
+
+ // Check values have properly been restored to their original (default) value.
+ EXPECT_EQ(booleanField->GetBoolean(sirt_klass.get()), false);
+ EXPECT_EQ(byteField->GetByte(sirt_klass.get()), 0);
+ EXPECT_EQ(charField->GetChar(sirt_klass.get()), 0u);
+ EXPECT_EQ(shortField->GetShort(sirt_klass.get()), 0);
+ EXPECT_EQ(intField->GetInt(sirt_klass.get()), 0);
+ EXPECT_EQ(longField->GetLong(sirt_klass.get()), static_cast<int64_t>(0));
+ EXPECT_EQ(floatField->GetFloat(sirt_klass.get()), static_cast<float>(0.0f));
+ EXPECT_EQ(doubleField->GetDouble(sirt_klass.get()), static_cast<double>(0.0));
+ EXPECT_EQ(objectField->GetObject(sirt_klass.get()), nullptr);
+}
+
+TEST_F(TransactionTest, InstanceFieldsTest) {
+ ScopedObjectAccess soa(Thread::Current());
+ SirtRef<mirror::ClassLoader> class_loader(
+ soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
+ ASSERT_TRUE(class_loader.get() != nullptr);
+
+ SirtRef<mirror::Class> sirt_klass(soa.Self(),
+ class_linker_->FindClass("LInstanceFieldsTest;", class_loader));
+ ASSERT_TRUE(sirt_klass.get() != nullptr);
+ class_linker_->EnsureInitialized(sirt_klass, true, true);
+ ASSERT_TRUE(sirt_klass->IsInitialized());
+
+ // Allocate an InstanceFieldTest object.
+ SirtRef<mirror::Object> sirt_instance(soa.Self(), sirt_klass->AllocObject(soa.Self()));
+ ASSERT_TRUE(sirt_instance.get() != nullptr);
+
+ // Lookup fields.
+ mirror::ArtField* booleanField = sirt_klass->FindDeclaredInstanceField("booleanField", "Z");
+ ASSERT_TRUE(booleanField != nullptr);
+ ASSERT_EQ(FieldHelper(booleanField).GetTypeAsPrimitiveType(), Primitive::kPrimBoolean);
+ ASSERT_EQ(booleanField->GetBoolean(sirt_instance.get()), false);
+
+ mirror::ArtField* byteField = sirt_klass->FindDeclaredInstanceField("byteField", "B");
+ ASSERT_TRUE(byteField != nullptr);
+ ASSERT_EQ(FieldHelper(byteField).GetTypeAsPrimitiveType(), Primitive::kPrimByte);
+ ASSERT_EQ(byteField->GetByte(sirt_instance.get()), 0);
+
+ mirror::ArtField* charField = sirt_klass->FindDeclaredInstanceField("charField", "C");
+ ASSERT_TRUE(charField != nullptr);
+ ASSERT_EQ(FieldHelper(charField).GetTypeAsPrimitiveType(), Primitive::kPrimChar);
+ ASSERT_EQ(charField->GetChar(sirt_instance.get()), 0u);
+
+ mirror::ArtField* shortField = sirt_klass->FindDeclaredInstanceField("shortField", "S");
+ ASSERT_TRUE(shortField != nullptr);
+ ASSERT_EQ(FieldHelper(shortField).GetTypeAsPrimitiveType(), Primitive::kPrimShort);
+ ASSERT_EQ(shortField->GetShort(sirt_instance.get()), 0);
+
+ mirror::ArtField* intField = sirt_klass->FindDeclaredInstanceField("intField", "I");
+ ASSERT_TRUE(intField != nullptr);
+ ASSERT_EQ(FieldHelper(intField).GetTypeAsPrimitiveType(), Primitive::kPrimInt);
+ ASSERT_EQ(intField->GetInt(sirt_instance.get()), 0);
+
+ mirror::ArtField* longField = sirt_klass->FindDeclaredInstanceField("longField", "J");
+ ASSERT_TRUE(longField != nullptr);
+ ASSERT_EQ(FieldHelper(longField).GetTypeAsPrimitiveType(), Primitive::kPrimLong);
+ ASSERT_EQ(longField->GetLong(sirt_instance.get()), static_cast<int64_t>(0));
+
+ mirror::ArtField* floatField = sirt_klass->FindDeclaredInstanceField("floatField", "F");
+ ASSERT_TRUE(floatField != nullptr);
+ ASSERT_EQ(FieldHelper(floatField).GetTypeAsPrimitiveType(), Primitive::kPrimFloat);
+ ASSERT_EQ(floatField->GetFloat(sirt_instance.get()), static_cast<float>(0.0f));
+
+ mirror::ArtField* doubleField = sirt_klass->FindDeclaredInstanceField("doubleField", "D");
+ ASSERT_TRUE(doubleField != nullptr);
+ ASSERT_EQ(FieldHelper(doubleField).GetTypeAsPrimitiveType(), Primitive::kPrimDouble);
+ ASSERT_EQ(doubleField->GetDouble(sirt_instance.get()), static_cast<double>(0.0));
+
+ mirror::ArtField* objectField = sirt_klass->FindDeclaredInstanceField("objectField", "Ljava/lang/Object;");
+ ASSERT_TRUE(objectField != nullptr);
+ ASSERT_EQ(FieldHelper(objectField).GetTypeAsPrimitiveType(), Primitive::kPrimNot);
+ ASSERT_EQ(objectField->GetObject(sirt_instance.get()), nullptr);
+
+ // Create a java.lang.Object instance to set objectField.
+ SirtRef<mirror::Class> object_klass(soa.Self(), class_linker_->FindSystemClass("Ljava/lang/Object;"));
+ ASSERT_TRUE(object_klass.get() != nullptr);
+ SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
+ ASSERT_TRUE(sirt_obj.get() != nullptr);
+ ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+
+ // Modify fields inside transaction and abort it.
+ Transaction transaction;
+ Runtime::Current()->EnterTransactionMode(&transaction);
+ booleanField->SetBoolean<true>(sirt_instance.get(), true);
+ byteField->SetByte<true>(sirt_instance.get(), 1);
+ charField->SetChar<true>(sirt_instance.get(), 1u);
+ shortField->SetShort<true>(sirt_instance.get(), 1);
+ intField->SetInt<true>(sirt_instance.get(), 1);
+ longField->SetLong<true>(sirt_instance.get(), 1);
+ floatField->SetFloat<true>(sirt_instance.get(), 1.0);
+ doubleField->SetDouble<true>(sirt_instance.get(), 1.0);
+ objectField->SetObject<true>(sirt_instance.get(), sirt_obj.get());
+ Runtime::Current()->ExitTransactionMode();
+ transaction.Abort();
+
+ // Check values have properly been restored to their original (default) value.
+ EXPECT_EQ(booleanField->GetBoolean(sirt_instance.get()), false);
+ EXPECT_EQ(byteField->GetByte(sirt_instance.get()), 0);
+ EXPECT_EQ(charField->GetChar(sirt_instance.get()), 0u);
+ EXPECT_EQ(shortField->GetShort(sirt_instance.get()), 0);
+ EXPECT_EQ(intField->GetInt(sirt_instance.get()), 0);
+ EXPECT_EQ(longField->GetLong(sirt_instance.get()), static_cast<int64_t>(0));
+ EXPECT_EQ(floatField->GetFloat(sirt_instance.get()), static_cast<float>(0.0f));
+ EXPECT_EQ(doubleField->GetDouble(sirt_instance.get()), static_cast<double>(0.0));
+ EXPECT_EQ(objectField->GetObject(sirt_instance.get()), nullptr);
+}
+
+
+TEST_F(TransactionTest, StaticArrayFieldsTest) {
+ ScopedObjectAccess soa(Thread::Current());
+ SirtRef<mirror::ClassLoader> class_loader(
+ soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
+ ASSERT_TRUE(class_loader.get() != nullptr);
+
+ SirtRef<mirror::Class> sirt_klass(soa.Self(),
+ class_linker_->FindClass("LStaticArrayFieldsTest;", class_loader));
+ ASSERT_TRUE(sirt_klass.get() != nullptr);
+ class_linker_->EnsureInitialized(sirt_klass, true, true);
+ ASSERT_TRUE(sirt_klass->IsInitialized());
+
+ // Lookup fields.
+ mirror::ArtField* booleanArrayField = sirt_klass->FindDeclaredStaticField("booleanArrayField", "[Z");
+ ASSERT_TRUE(booleanArrayField != nullptr);
+ mirror::BooleanArray* booleanArray = booleanArrayField->GetObject(sirt_klass.get())->AsBooleanArray();
+ ASSERT_TRUE(booleanArray != nullptr);
+ ASSERT_EQ(booleanArray->GetLength(), 1);
+ ASSERT_EQ(booleanArray->GetWithoutChecks(0), false);
+
+ mirror::ArtField* byteArrayField = sirt_klass->FindDeclaredStaticField("byteArrayField", "[B");
+ ASSERT_TRUE(byteArrayField != nullptr);
+ mirror::ByteArray* byteArray = byteArrayField->GetObject(sirt_klass.get())->AsByteArray();
+ ASSERT_TRUE(byteArray != nullptr);
+ ASSERT_EQ(byteArray->GetLength(), 1);
+ ASSERT_EQ(byteArray->GetWithoutChecks(0), 0);
+
+ mirror::ArtField* charArrayField = sirt_klass->FindDeclaredStaticField("charArrayField", "[C");
+ ASSERT_TRUE(charArrayField != nullptr);
+ mirror::CharArray* charArray = charArrayField->GetObject(sirt_klass.get())->AsCharArray();
+ ASSERT_TRUE(charArray != nullptr);
+ ASSERT_EQ(charArray->GetLength(), 1);
+ ASSERT_EQ(charArray->GetWithoutChecks(0), 0u);
+
+ mirror::ArtField* shortArrayField = sirt_klass->FindDeclaredStaticField("shortArrayField", "[S");
+ ASSERT_TRUE(shortArrayField != nullptr);
+ mirror::ShortArray* shortArray = shortArrayField->GetObject(sirt_klass.get())->AsShortArray();
+ ASSERT_TRUE(shortArray != nullptr);
+ ASSERT_EQ(shortArray->GetLength(), 1);
+ ASSERT_EQ(shortArray->GetWithoutChecks(0), 0);
+
+ mirror::ArtField* intArrayField = sirt_klass->FindDeclaredStaticField("intArrayField", "[I");
+ ASSERT_TRUE(intArrayField != nullptr);
+ mirror::IntArray* intArray = intArrayField->GetObject(sirt_klass.get())->AsIntArray();
+ ASSERT_TRUE(intArray != nullptr);
+ ASSERT_EQ(intArray->GetLength(), 1);
+ ASSERT_EQ(intArray->GetWithoutChecks(0), 0);
+
+ mirror::ArtField* longArrayField = sirt_klass->FindDeclaredStaticField("longArrayField", "[J");
+ ASSERT_TRUE(longArrayField != nullptr);
+ mirror::LongArray* longArray = longArrayField->GetObject(sirt_klass.get())->AsLongArray();
+ ASSERT_TRUE(longArray != nullptr);
+ ASSERT_EQ(longArray->GetLength(), 1);
+ ASSERT_EQ(longArray->GetWithoutChecks(0), static_cast<int64_t>(0));
+
+ mirror::ArtField* floatArrayField = sirt_klass->FindDeclaredStaticField("floatArrayField", "[F");
+ ASSERT_TRUE(floatArrayField != nullptr);
+ mirror::FloatArray* floatArray = floatArrayField->GetObject(sirt_klass.get())->AsFloatArray();
+ ASSERT_TRUE(floatArray != nullptr);
+ ASSERT_EQ(floatArray->GetLength(), 1);
+ ASSERT_EQ(floatArray->GetWithoutChecks(0), static_cast<float>(0.0f));
+
+ mirror::ArtField* doubleArrayField = sirt_klass->FindDeclaredStaticField("doubleArrayField", "[D");
+ ASSERT_TRUE(doubleArrayField != nullptr);
+ mirror::DoubleArray* doubleArray = doubleArrayField->GetObject(sirt_klass.get())->AsDoubleArray();
+ ASSERT_TRUE(doubleArray != nullptr);
+ ASSERT_EQ(doubleArray->GetLength(), 1);
+ ASSERT_EQ(doubleArray->GetWithoutChecks(0), static_cast<double>(0.0f));
+
+ mirror::ArtField* objectArrayField = sirt_klass->FindDeclaredStaticField("objectArrayField", "[Ljava/lang/Object;");
+ ASSERT_TRUE(objectArrayField != nullptr);
+ mirror::ObjectArray<mirror::Object>* objectArray = objectArrayField->GetObject(sirt_klass.get())->AsObjectArray<mirror::Object>();
+ ASSERT_TRUE(objectArray != nullptr);
+ ASSERT_EQ(objectArray->GetLength(), 1);
+ ASSERT_EQ(objectArray->GetWithoutChecks(0), nullptr);
+
+ // Create a java.lang.Object instance to set objectField.
+ SirtRef<mirror::Class> object_klass(soa.Self(), class_linker_->FindSystemClass("Ljava/lang/Object;"));
+ ASSERT_TRUE(object_klass.get() != nullptr);
+ SirtRef<mirror::Object> sirt_obj(soa.Self(), sirt_klass->AllocObject(soa.Self()));
+ ASSERT_TRUE(sirt_obj.get() != nullptr);
+ ASSERT_EQ(sirt_obj->GetClass(), sirt_klass.get());
+
+ // Modify fields inside transaction and abort it.
+ Transaction transaction;
+ Runtime::Current()->EnterTransactionMode(&transaction);
+ booleanArray->SetWithoutChecks<true>(0, true);
+ byteArray->SetWithoutChecks<true>(0, 1);
+ charArray->SetWithoutChecks<true>(0, 1u);
+ shortArray->SetWithoutChecks<true>(0, 1);
+ intArray->SetWithoutChecks<true>(0, 1);
+ longArray->SetWithoutChecks<true>(0, 1);
+ floatArray->SetWithoutChecks<true>(0, 1.0);
+ doubleArray->SetWithoutChecks<true>(0, 1.0);
+ objectArray->SetWithoutChecks<true>(0, sirt_obj.get());
+ Runtime::Current()->ExitTransactionMode();
+ transaction.Abort();
+
+ // Check values have properly been restored to their original (default) value.
+ EXPECT_EQ(booleanArray->GetWithoutChecks(0), false);
+ EXPECT_EQ(byteArray->GetWithoutChecks(0), 0);
+ EXPECT_EQ(charArray->GetWithoutChecks(0), 0u);
+ EXPECT_EQ(shortArray->GetWithoutChecks(0), 0);
+ EXPECT_EQ(intArray->GetWithoutChecks(0), 0);
+ EXPECT_EQ(longArray->GetWithoutChecks(0), static_cast<int64_t>(0));
+ EXPECT_EQ(floatArray->GetWithoutChecks(0), static_cast<float>(0.0f));
+ EXPECT_EQ(doubleArray->GetWithoutChecks(0), static_cast<double>(0.0f));
+ EXPECT_EQ(objectArray->GetWithoutChecks(0), nullptr);
+}
+
+TEST_F(TransactionTest, EmptyClass) {
+ ScopedObjectAccess soa(Thread::Current());
+ SirtRef<mirror::ClassLoader> class_loader(
+ soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
+ ASSERT_TRUE(class_loader.get() != nullptr);
+
+ SirtRef<mirror::Class> sirt_klass(soa.Self(),
+ class_linker_->FindClass("LTransaction$EmptyStatic;", class_loader));
+ ASSERT_TRUE(sirt_klass.get() != nullptr);
+ class_linker_->VerifyClass(sirt_klass);
+ ASSERT_TRUE(sirt_klass->IsVerified());
+
+ Transaction transaction;
+ Runtime::Current()->EnterTransactionMode(&transaction);
+ class_linker_->EnsureInitialized(sirt_klass, true, true);
+ Runtime::Current()->ExitTransactionMode();
+ ASSERT_FALSE(soa.Self()->IsExceptionPending());
+}
+
+TEST_F(TransactionTest, StaticFieldClass) {
+ ScopedObjectAccess soa(Thread::Current());
+ SirtRef<mirror::ClassLoader> class_loader(
+ soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction")));
+ ASSERT_TRUE(class_loader.get() != nullptr);
+
+ SirtRef<mirror::Class> sirt_klass(soa.Self(),
+ class_linker_->FindClass("LTransaction$StaticFieldClass;", class_loader));
+ ASSERT_TRUE(sirt_klass.get() != nullptr);
+ class_linker_->VerifyClass(sirt_klass);
+ ASSERT_TRUE(sirt_klass->IsVerified());
+
+ Transaction transaction;
+ Runtime::Current()->EnterTransactionMode(&transaction);
+ class_linker_->EnsureInitialized(sirt_klass, true, true);
+ Runtime::Current()->ExitTransactionMode();
+ ASSERT_FALSE(soa.Self()->IsExceptionPending());
+}
+
+TEST_F(TransactionTest, BlacklistedClass) {
+ ScopedObjectAccess soa(Thread::Current());
+ jobject jclass_loader = LoadDex("Transaction");
+ SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
+ soa.Decode<mirror::ClassLoader*>(jclass_loader));
+ ASSERT_TRUE(class_loader.get() != nullptr);
+
+ // Load and verify java.lang.ExceptionInInitializerError and java.lang.InternalError which will
+ // be thrown by class initialization due to native call.
+ SirtRef<mirror::Class> sirt_klass(soa.Self(),
+ class_linker_->FindSystemClass("Ljava/lang/ExceptionInInitializerError;"));
+ ASSERT_TRUE(sirt_klass.get() != nullptr);
+ class_linker_->VerifyClass(sirt_klass);
+ ASSERT_TRUE(sirt_klass->IsVerified());
+ sirt_klass.reset(class_linker_->FindSystemClass("Ljava/lang/InternalError;"));
+ ASSERT_TRUE(sirt_klass.get() != nullptr);
+ class_linker_->VerifyClass(sirt_klass);
+ ASSERT_TRUE(sirt_klass->IsVerified());
+
+ // Load and verify Transaction$NativeSupport used in class initialization.
+ sirt_klass.reset(class_linker_->FindClass("LTransaction$NativeSupport;", class_loader));
+ ASSERT_TRUE(sirt_klass.get() != nullptr);
+ class_linker_->VerifyClass(sirt_klass);
+ ASSERT_TRUE(sirt_klass->IsVerified());
+
+ sirt_klass.reset(class_linker_->FindClass("LTransaction$BlacklistedClass;", class_loader));
+ ASSERT_TRUE(sirt_klass.get() != nullptr);
+ class_linker_->VerifyClass(sirt_klass);
+ ASSERT_TRUE(sirt_klass->IsVerified());
+
+ Transaction transaction;
+ Runtime::Current()->EnterTransactionMode(&transaction);
+ class_linker_->EnsureInitialized(sirt_klass, true, true);
+ Runtime::Current()->ExitTransactionMode();
+ ASSERT_TRUE(soa.Self()->IsExceptionPending());
+}
+
+
+} // namespace art
diff --git a/test/Android.mk b/test/Android.mk
index 4d47651..dcf75d0 100644
--- a/test/Android.mk
+++ b/test/Android.mk
@@ -36,6 +36,7 @@
StaticLeafMethods \
Statics \
StaticsFromCode \
+ Transaction \
XandY
# subdirectories of which are used with test-art-target-oat
diff --git a/test/Transaction/InstanceFieldsTest.java b/test/Transaction/InstanceFieldsTest.java
new file mode 100644
index 0000000..38a44d2
--- /dev/null
+++ b/test/Transaction/InstanceFieldsTest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+public class InstanceFieldsTest {
+ public boolean booleanField;
+ public byte byteField;
+ public char charField;
+ public short shortField;
+ public int intField;
+ public long longField;
+ public float floatField;
+ public double doubleField;
+ public Object objectField;
+}
diff --git a/test/Transaction/StaticArrayFieldsTest.java b/test/Transaction/StaticArrayFieldsTest.java
new file mode 100644
index 0000000..6436839
--- /dev/null
+++ b/test/Transaction/StaticArrayFieldsTest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+public class StaticArrayFieldsTest {
+ public static boolean[] booleanArrayField = new boolean[1];
+ public static byte[] byteArrayField = new byte[1];
+ public static char [] charArrayField = new char[1];
+ public static short[] shortArrayField = new short[1];
+ public static int[] intArrayField = new int[1];
+ public static long[] longArrayField = new long[1];
+ public static float[] floatArrayField = new float[1];
+ public static double[] doubleArrayField = new double[1];
+ public static Object[] objectArrayField = new Object[1];
+}
diff --git a/test/Transaction/StaticFieldsTest.java b/test/Transaction/StaticFieldsTest.java
new file mode 100644
index 0000000..2316f3b
--- /dev/null
+++ b/test/Transaction/StaticFieldsTest.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+public class StaticFieldsTest {
+ public static boolean booleanField;
+ public static byte byteField;
+ public static char charField;
+ public static short shortField;
+ public static int intField;
+ public static long longField;
+ public static float floatField;
+ public static double doubleField;
+ public static Object objectField;
+}
diff --git a/test/Transaction/Transaction.java b/test/Transaction/Transaction.java
new file mode 100644
index 0000000..9ca7fbf
--- /dev/null
+++ b/test/Transaction/Transaction.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2014 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.
+ */
+
+public class Transaction {
+ static class EmptyStatic {
+ }
+
+ static class StaticFieldClass {
+ public static int intField;
+ static {
+ intField = 5;
+ }
+ }
+
+ static class BlacklistedClass {
+ static {
+ NativeSupport.native_call();
+ }
+ }
+
+ static class NativeSupport {
+ public static native void native_call();
+ }
+}