summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/Android.bp3
l---------compiler/generate-operator-out.py1
-rw-r--r--runtime/Android.bp3
-rw-r--r--runtime/arch/arm/quick_entrypoints_arm.S14
-rw-r--r--runtime/arch/arm64/quick_entrypoints_arm64.S15
-rw-r--r--runtime/arch/x86/quick_entrypoints_x86.S15
-rw-r--r--runtime/arch/x86_64/quick_entrypoints_x86_64.S7
-rw-r--r--runtime/base/unix_file/fd_file.cc53
-rw-r--r--runtime/base/unix_file/fd_file.h9
-rw-r--r--runtime/base/unix_file/fd_file_test.cc20
-rw-r--r--runtime/gc/collector/concurrent_copying-inl.h2
l---------runtime/generate-operator-out.py1
-rw-r--r--runtime/generated/asm_support_gen.h2
-rw-r--r--runtime/lock_word.h3
-rw-r--r--test/115-native-bridge/nativebridge.cc2
-rw-r--r--tools/cpp-define-generator/constant_lockword.def1
16 files changed, 131 insertions, 20 deletions
diff --git a/compiler/Android.bp b/compiler/Android.bp
index b2ed074fa7..f1bf27ece7 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -204,7 +204,8 @@ art_cc_defaults {
gensrcs {
name: "art_compiler_operator_srcs",
- cmd: "art/tools/generate-operator-out.py art/compiler $in > $out",
+ cmd: "$(location generate-operator-out.py) art/compiler $(in) > $(out)",
+ tool_files: ["generate-operator-out.py"],
srcs: [
"compiled_method.h",
"dex/dex_to_dex_compiler.h",
diff --git a/compiler/generate-operator-out.py b/compiler/generate-operator-out.py
new file mode 120000
index 0000000000..cc291d20c1
--- /dev/null
+++ b/compiler/generate-operator-out.py
@@ -0,0 +1 @@
+../tools/generate-operator-out.py \ No newline at end of file
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 9157907cee..57413dcaab 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -405,7 +405,8 @@ cc_defaults {
gensrcs {
name: "art_operator_srcs",
- cmd: "art/tools/generate-operator-out.py art/runtime $in > $out",
+ cmd: "$(location generate-operator-out.py) art/runtime $(in) > $(out)",
+ tool_files: ["generate-operator-out.py"],
srcs: [
"arch/instruction_set.h",
"base/allocator.h",
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index bf70c554b1..0135260de8 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1999,11 +1999,17 @@ ENTRY \name
// Check lock word for mark bit, if marked return. Use IP for scratch since it is blocked.
ldr ip, [\reg, MIRROR_OBJECT_LOCK_WORD_OFFSET]
tst ip, #LOCK_WORD_MARK_BIT_MASK_SHIFTED
- beq .Lslow_rb_\name
+ beq .Lnot_marked_rb_\name
// Already marked, return right away.
.Lret_rb_\name:
bx lr
+.Lnot_marked_rb_\name:
+ // Test that both the forwarding state bits are 1.
+ mvn ip, ip
+ tst ip, #(LOCK_WORD_STATE_FORWARDING_ADDRESS << LOCK_WORD_STATE_SHIFT)
+ beq .Lret_forwarding_address\name
+
.Lslow_rb_\name:
// Save IP: the kSaveEverything entrypoint art_quick_resolve_string makes a tail call here.
push {r0-r4, r9, ip, lr} @ save return address, core caller-save registers and ip
@@ -2064,6 +2070,12 @@ ENTRY \name
.cfi_restore ip
.cfi_restore lr
bx lr
+.Lret_forwarding_address\name:
+ // Shift left by the forwarding address shift. This clears out the state bits since they are
+ // in the top 2 bits of the lock word.
+ mvn ip, ip
+ lsl \reg, ip, #LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT
+ bx lr
END \name
.endm
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 483cee3100..d806715ec9 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -2539,10 +2539,17 @@ ENTRY \name
*/
// Use wIP0 as temp and check the mark bit of the reference. wIP0 is not used by the compiler.
ldr wIP0, [\xreg, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
- tbz wIP0, #LOCK_WORD_MARK_BIT_SHIFT, .Lslow_rb_\name
+ tbz wIP0, #LOCK_WORD_MARK_BIT_SHIFT, .Lnot_marked_rb_\name
.Lret_rb_\name:
ret
+.Lnot_marked_rb_\name:
+ // Check if the top two bits are one, if this is the case it is a forwarding address.
+ mvn wIP0, wIP0
+ cmp wzr, wIP0, lsr #30
+ beq .Lret_forwarding_address\name
.Lslow_rb_\name:
+ // We must not clobber IP0 since art_quick_resolve_string makes a tail call here and relies on
+ // IP0 being restored.
// Save all potentially live caller-save core registers.
SAVE_TWO_REGS_INCREASE_FRAME x0, x1, 368
SAVE_TWO_REGS x2, x3, 16
@@ -2608,6 +2615,12 @@ ENTRY \name
RESTORE_REG xLR, 360
DECREASE_FRAME 368
ret
+.Lret_forwarding_address\name:
+ mvn wIP0, wIP0
+ // Shift left by the forwarding address shift. This clears out the state bits since they are
+ // in the top 2 bits of the lock word.
+ lsl \wreg, wIP0, #LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT
+ ret
END \name
.endm
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index f4f9a68e30..98739d3cc8 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -2155,8 +2155,15 @@ MACRO2(READ_BARRIER_MARK_REG, name, reg)
jz .Lslow_rb_\name
ret
.Lslow_rb_\name:
- // Save all potentially live caller-save core registers.
PUSH eax
+ mov MIRROR_OBJECT_LOCK_WORD_OFFSET(REG_VAR(reg)), %eax
+ add LITERAL(LOCK_WORD_STATE_FORWARDING_ADDRESS_OVERFLOW), %eax
+ // Jump if overflow, the only case where it overflows should be the forwarding address one.
+ // Taken ~25% of the time.
+ jnae .Lret_forwarding_address\name
+
+ // Save all potentially live caller-save core registers.
+ mov 0(%esp), %eax
PUSH ecx
PUSH edx
PUSH ebx
@@ -2204,6 +2211,12 @@ MACRO2(READ_BARRIER_MARK_REG, name, reg)
POP_REG_NE eax, RAW_VAR(reg)
.Lret_rb_\name:
ret
+.Lret_forwarding_address\name:
+ // The overflow cleared the top bits.
+ sall LITERAL(LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT), %eax
+ mov %eax, REG_VAR(reg)
+ POP_REG_NE eax, RAW_VAR(reg)
+ ret
END_FUNCTION VAR(name)
END_MACRO
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index fc549ecb04..185e55e114 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -2279,9 +2279,10 @@ MACRO2(READ_BARRIER_MARK_REG, name, reg)
PUSH rax
movl MIRROR_OBJECT_LOCK_WORD_OFFSET(REG_VAR(reg)), %eax
addl LITERAL(LOCK_WORD_STATE_FORWARDING_ADDRESS_OVERFLOW), %eax
- // Jump if overflow, the only case where it overflows should be the forwarding address one.
+ // Jump if the addl caused eax to unsigned overflow. The only case where it overflows is the
+ // forwarding address one.
// Taken ~25% of the time.
- jnae .Lret_overflow\name
+ jnae .Lret_forwarding_address\name
// Save all potentially live caller-save core registers.
movq 0(%rsp), %rax
@@ -2349,7 +2350,7 @@ MACRO2(READ_BARRIER_MARK_REG, name, reg)
POP_REG_NE rax, RAW_VAR(reg)
.Lret_rb_\name:
ret
-.Lret_overflow\name:
+.Lret_forwarding_address\name:
// The overflow cleared the top bits.
sall LITERAL(LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT), %eax
movq %rax, REG_VAR(reg)
diff --git a/runtime/base/unix_file/fd_file.cc b/runtime/base/unix_file/fd_file.cc
index 4498198b34..ff2dd1b399 100644
--- a/runtime/base/unix_file/fd_file.cc
+++ b/runtime/base/unix_file/fd_file.cc
@@ -339,22 +339,59 @@ bool FdFile::Copy(FdFile* input_file, int64_t offset, int64_t size) {
return true;
}
-void FdFile::Erase() {
+bool FdFile::Unlink() {
+ if (file_path_.empty()) {
+ return false;
+ }
+
+ // Try to figure out whether this file is still referring to the one on disk.
+ bool is_current = false;
+ {
+ struct stat this_stat, current_stat;
+ int cur_fd = TEMP_FAILURE_RETRY(open(file_path_.c_str(), O_RDONLY));
+ if (cur_fd > 0) {
+ // File still exists.
+ if (fstat(fd_, &this_stat) == 0 && fstat(cur_fd, &current_stat) == 0) {
+ is_current = (this_stat.st_dev == current_stat.st_dev) &&
+ (this_stat.st_ino == current_stat.st_ino);
+ }
+ close(cur_fd);
+ }
+ }
+
+ if (is_current) {
+ unlink(file_path_.c_str());
+ }
+
+ return is_current;
+}
+
+bool FdFile::Erase(bool unlink) {
DCHECK(!read_only_mode_);
- TEMP_FAILURE_RETRY(SetLength(0));
- TEMP_FAILURE_RETRY(Flush());
- TEMP_FAILURE_RETRY(Close());
+
+ bool ret_result = true;
+ if (unlink) {
+ ret_result = Unlink();
+ }
+
+ int result;
+ result = SetLength(0);
+ result = Flush();
+ result = Close();
+ // Ignore the errors.
+
+ return ret_result;
}
int FdFile::FlushCloseOrErase() {
DCHECK(!read_only_mode_);
- int flush_result = TEMP_FAILURE_RETRY(Flush());
+ int flush_result = Flush();
if (flush_result != 0) {
LOG(ERROR) << "CloseOrErase failed while flushing a file.";
Erase();
return flush_result;
}
- int close_result = TEMP_FAILURE_RETRY(Close());
+ int close_result = Close();
if (close_result != 0) {
LOG(ERROR) << "CloseOrErase failed while closing a file.";
Erase();
@@ -365,11 +402,11 @@ int FdFile::FlushCloseOrErase() {
int FdFile::FlushClose() {
DCHECK(!read_only_mode_);
- int flush_result = TEMP_FAILURE_RETRY(Flush());
+ int flush_result = Flush();
if (flush_result != 0) {
LOG(ERROR) << "FlushClose failed while flushing a file.";
}
- int close_result = TEMP_FAILURE_RETRY(Close());
+ int close_result = Close();
if (close_result != 0) {
LOG(ERROR) << "FlushClose failed while closing a file.";
}
diff --git a/runtime/base/unix_file/fd_file.h b/runtime/base/unix_file/fd_file.h
index d896ee9ecb..eb85c4f097 100644
--- a/runtime/base/unix_file/fd_file.h
+++ b/runtime/base/unix_file/fd_file.h
@@ -97,7 +97,14 @@ class FdFile : public RandomAccessFile {
int Flush() OVERRIDE WARN_UNUSED;
// Short for SetLength(0); Flush(); Close();
- void Erase();
+ // If the file was opened with a path name and unlink = true, also calls Unlink() on the path.
+ // Note that it is the the caller's responsibility to avoid races.
+ bool Erase(bool unlink = false);
+
+ // Call unlink() if the file was opened with a path, and if open() with the name shows that
+ // the file descriptor of this file is still up-to-date. This is still racy, though, and it
+ // is up to the caller to ensure correctness in a multi-process setup.
+ bool Unlink();
// Try to Flush(), then try to Close(); If either fails, call Erase().
int FlushCloseOrErase() WARN_UNUSED;
diff --git a/runtime/base/unix_file/fd_file_test.cc b/runtime/base/unix_file/fd_file_test.cc
index 99ef6f73ba..7657a38cec 100644
--- a/runtime/base/unix_file/fd_file_test.cc
+++ b/runtime/base/unix_file/fd_file_test.cc
@@ -186,4 +186,24 @@ TEST_F(FdFileTest, MoveConstructor) {
ASSERT_EQ(file2.Close(), 0);
}
+TEST_F(FdFileTest, EraseWithPathUnlinks) {
+ // New scratch file, zero-length.
+ art::ScratchFile tmp;
+ std::string filename = tmp.GetFilename();
+ tmp.Close(); // This is required because of the unlink race between the scratch file and the
+ // FdFile, which leads to close-guard breakage.
+ FdFile file(filename, O_RDWR, false);
+ ASSERT_TRUE(file.IsOpened());
+ EXPECT_GE(file.Fd(), 0);
+ uint8_t buffer[16] = { 0 };
+ EXPECT_TRUE(file.WriteFully(&buffer, sizeof(buffer)));
+ EXPECT_EQ(file.Flush(), 0);
+
+ EXPECT_TRUE(file.Erase(true));
+
+ EXPECT_FALSE(file.IsOpened());
+
+ EXPECT_FALSE(art::OS::FileExists(filename.c_str())) << filename;
+}
+
} // namespace unix_file
diff --git a/runtime/gc/collector/concurrent_copying-inl.h b/runtime/gc/collector/concurrent_copying-inl.h
index 6b6a12defb..7c649525e4 100644
--- a/runtime/gc/collector/concurrent_copying-inl.h
+++ b/runtime/gc/collector/concurrent_copying-inl.h
@@ -149,8 +149,6 @@ inline mirror::Object* ConcurrentCopying::Mark(mirror::Object* from_ref) {
inline mirror::Object* ConcurrentCopying::MarkFromReadBarrier(mirror::Object* from_ref) {
mirror::Object* ret;
- // TODO: Delete GetMarkBit check when all of the callers properly check the bit. Remaining caller
- // is array allocations.
if (from_ref == nullptr) {
return from_ref;
}
diff --git a/runtime/generate-operator-out.py b/runtime/generate-operator-out.py
new file mode 120000
index 0000000000..cc291d20c1
--- /dev/null
+++ b/runtime/generate-operator-out.py
@@ -0,0 +1 @@
+../tools/generate-operator-out.py \ No newline at end of file
diff --git a/runtime/generated/asm_support_gen.h b/runtime/generated/asm_support_gen.h
index f938c9f08a..2c95fe942e 100644
--- a/runtime/generated/asm_support_gen.h
+++ b/runtime/generated/asm_support_gen.h
@@ -98,6 +98,8 @@ DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_READ_BARRIER_STATE_MASK), (stati
DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_READ_BARRIER_STATE_MASK_TOGGLED), (static_cast<uint32_t>(art::LockWord::kReadBarrierStateMaskShiftedToggled)))
#define LOCK_WORD_THIN_LOCK_COUNT_ONE 65536
DEFINE_CHECK_EQ(static_cast<int32_t>(LOCK_WORD_THIN_LOCK_COUNT_ONE), (static_cast<int32_t>(art::LockWord::kThinLockCountOne)))
+#define LOCK_WORD_STATE_FORWARDING_ADDRESS 0x3
+DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_STATE_FORWARDING_ADDRESS), (static_cast<uint32_t>(art::LockWord::kStateForwardingAddress)))
#define LOCK_WORD_STATE_FORWARDING_ADDRESS_OVERFLOW 0x40000000
DEFINE_CHECK_EQ(static_cast<uint32_t>(LOCK_WORD_STATE_FORWARDING_ADDRESS_OVERFLOW), (static_cast<uint32_t>(art::LockWord::kStateForwardingAddressOverflow)))
#define LOCK_WORD_STATE_FORWARDING_ADDRESS_SHIFT 0x3
diff --git a/runtime/lock_word.h b/runtime/lock_word.h
index dea301c451..2f2565b9d0 100644
--- a/runtime/lock_word.h
+++ b/runtime/lock_word.h
@@ -265,6 +265,9 @@ class LockWord {
static_cast<uint64_t>(kStateForwardingAddressOverflow);
constexpr bool is_larger = overflow > static_cast<uint64_t>(0xFFFFFFFF);
static_assert(is_larger, "should have overflowed");
+ static_assert(
+ (~kStateForwardingAddress & kStateMask) == 0,
+ "READ_BARRIER_MARK_REG relies on the forwarding address state being only one bits");
CheckReadBarrierState();
}
diff --git a/test/115-native-bridge/nativebridge.cc b/test/115-native-bridge/nativebridge.cc
index 56d737f4ee..41329af138 100644
--- a/test/115-native-bridge/nativebridge.cc
+++ b/test/115-native-bridge/nativebridge.cc
@@ -466,7 +466,7 @@ extern "C" int native_bridge_unloadLibrary(void* handle ATTRIBUTE_UNUSED) {
return 0;
}
-extern "C" char* native_bridge_getError() {
+extern "C" const char* native_bridge_getError() {
printf("dlerror() in native bridge.\n");
return nullptr;
}
diff --git a/tools/cpp-define-generator/constant_lockword.def b/tools/cpp-define-generator/constant_lockword.def
index f9b6b19655..08d588505d 100644
--- a/tools/cpp-define-generator/constant_lockword.def
+++ b/tools/cpp-define-generator/constant_lockword.def
@@ -30,6 +30,7 @@ DEFINE_LOCK_WORD_EXPR(READ_BARRIER_STATE_MASK, uint32_t, kReadBarrierStateMas
DEFINE_LOCK_WORD_EXPR(READ_BARRIER_STATE_MASK_TOGGLED, uint32_t, kReadBarrierStateMaskShiftedToggled)
DEFINE_LOCK_WORD_EXPR(THIN_LOCK_COUNT_ONE, int32_t, kThinLockCountOne)
+DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS, uint32_t, kStateForwardingAddress)
DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS_OVERFLOW, uint32_t, kStateForwardingAddressOverflow)
DEFINE_LOCK_WORD_EXPR(STATE_FORWARDING_ADDRESS_SHIFT, uint32_t, kForwardingAddressShift)