Merge "Update frame size after the bitcode is translated into machine code." into ics-mr1-plus-art
diff --git a/src/compiler/codegen/x86/Assemble.cc b/src/compiler/codegen/x86/Assemble.cc
index bad7142..fc9878e 100644
--- a/src/compiler/codegen/x86/Assemble.cc
+++ b/src/compiler/codegen/x86/Assemble.cc
@@ -269,7 +269,7 @@
EXT_0F_ENCODING_MAP(Divsd, 0xF2, 0x5E),
EXT_0F_ENCODING_MAP(Divss, 0xF3, 0x5E),
- { kX86PsllqRI, kRegImm, IS_BINARY_OP, { 0, 0, 0x0F, 0x73, 0, 7, 0, 1 }, "PsllqRI", "!0r, !1d" },
+ { kX86PsllqRI, kRegImm, IS_BINARY_OP, { 0, 0, 0x0F, 0x73, 0, 6, 0, 1 }, "PsllqRI", "!0r, !1d" },
EXT_0F_ENCODING_MAP(Movdxr, 0x66, 0x6E),
EXT_0F_ENCODING_MAP(Movdrx, 0x66, 0x7E),
diff --git a/src/disassembler_x86.cc b/src/disassembler_x86.cc
index 496da2a..ed0cd25 100644
--- a/src/disassembler_x86.cc
+++ b/src/disassembler_x86.cc
@@ -52,10 +52,18 @@
}
}
+enum RegFile { GPR, MMX, SSE };
+
static void DumpReg(std::ostream& os, uint8_t rex, uint8_t reg,
- bool byte_operand, uint8_t size_override) {
+ bool byte_operand, uint8_t size_override, RegFile reg_file) {
size_t reg_num = reg; // TODO: combine with REX.R on 64bit
- DumpReg0(os, rex, reg_num, byte_operand, size_override);
+ if (reg_file == GPR) {
+ DumpReg0(os, rex, reg_num, byte_operand, size_override);
+ } else if (reg_file == SSE) {
+ os << "xmm" << reg_num;
+ } else {
+ os << "mm" << reg_num;
+ }
}
static void DumpBaseReg(std::ostream& os, uint8_t rex, uint8_t reg) {
@@ -138,6 +146,8 @@
bool byte_operand = false;
bool ax = false; // implicit use of ax
bool reg_in_opcode = false; // low 3-bits of opcode encode register parameter
+ RegFile src_reg_file = GPR;
+ RegFile dst_reg_file = GPR;
switch (*instr) {
#define DISASSEMBLER_ENTRY(opname, \
rm8_r8, rm32_r32, \
@@ -222,6 +232,7 @@
opcode << "movups";
}
has_modrm = true;
+ src_reg_file = dst_reg_file = SSE;
load = *instr == 0x10;
store = !load;
break;
@@ -231,6 +242,102 @@
case 0x3A: // 3 byte extended opcode
opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr);
break;
+ case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
+ case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: {
+ switch (*instr) {
+ case 0x50: opcode << "movmsk"; break;
+ case 0x51: opcode << "sqrt"; break;
+ case 0x52: opcode << "rsqrt"; break;
+ case 0x53: opcode << "rcp"; break;
+ case 0x54: opcode << "and"; break;
+ case 0x55: opcode << "andn"; break;
+ case 0x56: opcode << "or"; break;
+ case 0x57: opcode << "xor"; break;
+ case 0x58: opcode << "add"; break;
+ case 0x59: opcode << "mul"; break;
+ case 0x5C: opcode << "sub"; break;
+ case 0x5D: opcode << "min"; break;
+ case 0x5E: opcode << "div"; break;
+ case 0x5F: opcode << "max"; break;
+ default: LOG(FATAL) << "Unreachable";
+ }
+ if (prefix[2] == 0x66) {
+ opcode << "pd";
+ prefix[2] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else if (prefix[0] == 0xF2) {
+ opcode << "sd";
+ prefix[0] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else if (prefix[0] == 0xF3) {
+ opcode << "ss";
+ prefix[0] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else {
+ opcode << "ps";
+ }
+ load = true;
+ has_modrm = true;
+ src_reg_file = dst_reg_file = SSE;
+ break;
+ }
+ case 0x5A:
+ if (prefix[2] == 0x66) {
+ opcode << "cvtpd2ps";
+ prefix[2] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else if (prefix[0] == 0xF2) {
+ opcode << "cvtsd2ss";
+ prefix[0] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else if (prefix[0] == 0xF3) {
+ opcode << "cvtss2sd";
+ prefix[0] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else {
+ opcode << "cvtps2pd";
+ }
+ load = true;
+ has_modrm = true;
+ src_reg_file = dst_reg_file = SSE;
+ break;
+ case 0x5B:
+ if (prefix[2] == 0x66) {
+ opcode << "cvtps2dq";
+ prefix[2] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else if (prefix[0] == 0xF2) {
+ opcode << "bad opcode F2 0F 5B";
+ } else if (prefix[0] == 0xF3) {
+ opcode << "cvttps2dq";
+ prefix[0] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else {
+ opcode << "cvtdq2ps";
+ }
+ load = true;
+ has_modrm = true;
+ src_reg_file = dst_reg_file = SSE;
+ break;
+ case 0x6E:
+ if (prefix[2] == 0x66) {
+ dst_reg_file = SSE;
+ opcode << "movq";
+ prefix[2] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else {
+ dst_reg_file = MMX;
+ opcode << "movd";
+ }
+ load = true;
+ has_modrm = true;
+ break;
+ case 0x6F:
+ if (prefix[2] == 0x66) {
+ dst_reg_file = SSE;
+ opcode << "movdqa";
+ } else if (prefix[0] == 0xF3) {
+ dst_reg_file = SSE;
+ opcode << "movdqu";
+ prefix[0] = 0; // clear prefix now its served its purpose as part of the opcode
+ } else {
+ dst_reg_file = MMX;
+ opcode << "movq";
+ }
+ load = true;
+ has_modrm = true;
+ break;
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F:
opcode << "j" << condition_codes[*instr & 0xF];
@@ -312,7 +419,7 @@
std::ostringstream args;
if (reg_in_opcode) {
DCHECK(!has_modrm);
- DumpReg(args, rex, *instr & 0x7, false, prefix[2]);
+ DumpReg(args, rex, *instr & 0x7, false, prefix[2], GPR);
}
instr++;
uint32_t address_bits = 0;
@@ -355,18 +462,18 @@
}
address << "]";
} else {
- if (mod != 3) {
+ if (mod == 3) {
+ DumpReg(address, rex, rm, byte_operand, prefix[2], load ? src_reg_file : dst_reg_file);
+ } else {
address << "[";
- }
- DumpBaseReg(address, rex, rm);
- if (mod == 1) {
- address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr));
- instr++;
- } else if (mod == 2) {
- address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
- instr += 4;
- }
- if (mod != 3) {
+ DumpBaseReg(address, rex, rm);
+ if (mod == 1) {
+ address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr));
+ instr++;
+ } else if (mod == 2) {
+ address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
+ instr += 4;
+ }
address << "]";
}
}
@@ -376,7 +483,7 @@
}
if (load) {
if (!reg_is_opcode) {
- DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2]);
+ DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file);
args << ", ";
}
DumpSegmentOverride(args, prefix[1]);
@@ -387,12 +494,12 @@
args << address.str();
if (!reg_is_opcode) {
args << ", ";
- DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2]);
+ DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file);
}
}
}
if (ax) {
- DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2]);
+ DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2], GPR);
}
if (immediate_bytes > 0) {
if (has_modrm || reg_in_opcode || ax) {
diff --git a/src/heap.cc b/src/heap.cc
index eb62807..b4bc7ce 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -641,16 +641,10 @@
if (VLOG_IS_ON(gc) || gc_was_particularly_slow) {
// TODO: somehow make the specific GC implementation (here MarkSweep) responsible for logging.
size_t bytes_freed = initial_size - num_bytes_allocated_;
- if (bytes_freed > KB) { // ignore freed bytes in output if > 1KB
- bytes_freed = RoundDown(bytes_freed, KB);
- }
- size_t bytes_allocated = RoundUp(num_bytes_allocated_, KB);
// lose low nanoseconds in duration. TODO: make this part of PrettyDuration
duration_ns = (duration_ns / 1000) * 1000;
- size_t total = GetTotalMemory();
- size_t percentFree = 100 - static_cast<size_t>(100.0f * static_cast<float>(num_bytes_allocated_) / total);
- LOG(INFO) << "GC freed " << PrettySize(bytes_freed) << ", " << percentFree << "% free, "
- << PrettySize(bytes_allocated) << "/" << PrettySize(total) << ", "
+ LOG(INFO) << "GC freed " << PrettySize(bytes_freed) << ", " << GetPercentFree() << "% free, "
+ << PrettySize(num_bytes_allocated_) << "/" << PrettySize(GetTotalMemory()) << ", "
<< "paused " << PrettyDuration(duration_ns);
}
Dbg::GcDidFinish();
@@ -663,6 +657,17 @@
lock_->AssertHeld();
}
+void Heap::DumpForSigQuit(std::ostream& os) {
+ os << "Heap: " << GetPercentFree() << "% free, "
+ << PrettySize(num_bytes_allocated_) << "/" << PrettySize(GetTotalMemory())
+ << "; " << num_objects_allocated_ << " objects";
+}
+
+size_t Heap::GetPercentFree() {
+ size_t total = GetTotalMemory();
+ return 100 - static_cast<size_t>(100.0f * static_cast<float>(num_bytes_allocated_) / total);
+}
+
void Heap::SetIdealFootprint(size_t max_allowed_footprint) {
size_t alloc_space_capacity = alloc_space_->Capacity();
if (max_allowed_footprint > alloc_space_capacity) {
diff --git a/src/heap.h b/src/heap.h
index 7717871..3f0ffc0 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -17,6 +17,7 @@
#ifndef ART_SRC_HEAP_H_
#define ART_SRC_HEAP_H_
+#include <iosfwd>
#include <string>
#include <vector>
@@ -219,6 +220,8 @@
return alloc_space_;
}
+ void DumpForSigQuit(std::ostream& os);
+
private:
// Allocates uninitialized storage.
Object* AllocateLocked(size_t num_bytes);
@@ -239,6 +242,8 @@
// collection.
void GrowForUtilization();
+ size_t GetPercentFree();
+
void AddSpace(Space* space);
void VerifyObjectLocked(const Object *obj);
diff --git a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
index 3fe7640..6720e3e 100644
--- a/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
+++ b/src/oat/runtime/x86/oat_support_entrypoints_x86.cc
@@ -163,31 +163,31 @@
points->pCmpgFloat = CmpgFloat;
points->pCmplDouble = CmplDouble;
points->pCmplFloat = CmplFloat;
- points->pDadd = NULL;
- points->pDdiv = NULL;
- points->pDmul = NULL;
- points->pDsub = NULL;
- points->pF2d = NULL;
- points->pFmod = NULL;
- points->pI2d = NULL;
- points->pL2d = NULL;
- points->pD2f = NULL;
- points->pFadd = NULL;
- points->pFdiv = NULL;
- points->pFmodf = NULL;
- points->pFmul = NULL;
- points->pFsub = NULL;
- points->pI2f = NULL;
- points->pL2f = NULL;
- points->pD2iz = NULL;
- points->pF2iz = NULL;
+ //points->pDadd = NULL;
+ //points->pDdiv = NULL;
+ //points->pDmul = NULL;
+ //points->pDsub = NULL;
+ //points->pF2d = NULL;
+ //points->pFmod = NULL;
+ //points->pI2d = NULL;
+ //points->pL2d = NULL;
+ //points->pD2f = NULL;
+ //points->pFadd = NULL;
+ //points->pFdiv = NULL;
+ //points->pFmodf = NULL;
+ //points->pFmul = NULL;
+ //points->pFsub = NULL;
+ //points->pI2f = NULL;
+ //points->pL2f = NULL;
+ //points->pD2iz = NULL;
+ //points->pF2iz = NULL;
points->pIdiv = art_idiv_from_code;
points->pIdivmod = art_idivmod_from_code;
points->pD2l = D2L;
points->pF2l = F2L;
points->pLdiv = art_ldiv_from_code;
points->pLdivmod = art_ldivmod_from_code;
- points->pLmul = NULL;
+ //points->pLmul = NULL;
points->pShlLong = art_lshl_from_code;
points->pShrLong = art_lshr_from_code;
points->pUshrLong = art_lushr_from_code;
diff --git a/src/runtime.cc b/src/runtime.cc
index 77c887e..25789ab 100644
--- a/src/runtime.cc
+++ b/src/runtime.cc
@@ -37,6 +37,7 @@
#include "oat_file.h"
#include "ScopedLocalRef.h"
#include "signal_catcher.h"
+#include "signal_set.h"
#include "space.h"
#include "thread.h"
#include "thread_list.h"
@@ -658,6 +659,7 @@
options->image_);
BlockSignals();
+ InitPlatformSignalHandlers();
java_vm_ = new JavaVMExt(this, options.get());
@@ -745,13 +747,13 @@
#undef REGISTER
}
-void Runtime::Dump(std::ostream& os) {
- // TODO: dump other runtime statistics?
+void Runtime::DumpForSigQuit(std::ostream& os) {
GetClassLinker()->DumpForSigQuit(os);
GetInternTable()->DumpForSigQuit(os);
+ GetHeap()->DumpForSigQuit(os);
os << "\n";
- thread_list_->Dump(os);
+ thread_list_->DumpForSigQuit(os);
}
void Runtime::DumpLockHolders(std::ostream& os) {
@@ -822,22 +824,13 @@
}
void Runtime::BlockSignals() {
- sigset_t sigset;
- if (sigemptyset(&sigset) == -1) {
- PLOG(FATAL) << "sigemptyset failed";
- }
- if (sigaddset(&sigset, SIGPIPE) == -1) {
- PLOG(ERROR) << "sigaddset SIGPIPE failed";
- }
+ SignalSet signals;
+ signals.Add(SIGPIPE);
// SIGQUIT is used to dump the runtime's state (including stack traces).
- if (sigaddset(&sigset, SIGQUIT) == -1) {
- PLOG(ERROR) << "sigaddset SIGQUIT failed";
- }
+ signals.Add(SIGQUIT);
// SIGUSR1 is used to initiate a GC.
- if (sigaddset(&sigset, SIGUSR1) == -1) {
- PLOG(ERROR) << "sigaddset SIGUSR1 failed";
- }
- CHECK_EQ(sigprocmask(SIG_BLOCK, &sigset, NULL), 0);
+ signals.Add(SIGUSR1);
+ signals.Block();
}
void Runtime::AttachCurrentThread(const char* thread_name, bool as_daemon, Object* thread_group) {
diff --git a/src/runtime.h b/src/runtime.h
index 0dea763..dc61b15 100644
--- a/src/runtime.h
+++ b/src/runtime.h
@@ -130,7 +130,7 @@
// Detaches the current native thread from the runtime.
void DetachCurrentThread();
- void Dump(std::ostream& os);
+ void DumpForSigQuit(std::ostream& os);
void DumpLockHolders(std::ostream& os);
~Runtime();
@@ -247,6 +247,7 @@
private:
static void PlatformAbort(const char*, int);
+ static void InitPlatformSignalHandlers();
Runtime();
diff --git a/src/runtime_android.cc b/src/runtime_android.cc
index 4a736e6..b64f8a1 100644
--- a/src/runtime_android.cc
+++ b/src/runtime_android.cc
@@ -22,4 +22,8 @@
// On a device, debuggerd will give us a stack trace. Nothing to do here.
}
+void Runtime::InitPlatformSignalHandlers() {
+ // On a device, debuggerd will give us a stack trace. Nothing to do here.
+}
+
} // namespace art
diff --git a/src/runtime_linux.cc b/src/runtime_linux.cc
index a604819..4214003 100644
--- a/src/runtime_linux.cc
+++ b/src/runtime_linux.cc
@@ -18,13 +18,14 @@
#include <cxxabi.h>
#include <execinfo.h>
+#include <signal.h>
#include "logging.h"
#include "stringprintf.h"
namespace art {
-std::string Demangle(const std::string& mangled_name) {
+static std::string Demangle(const std::string& mangled_name) {
if (mangled_name.empty()) {
return "??";
}
@@ -41,9 +42,7 @@
return mangled_name + "()";
}
-void Runtime::PlatformAbort(const char* /*file*/, int /*line_number*/) {
- // On the host, we don't have debuggerd to dump a stack for us.
-
+static void Backtrace() {
// Get the raw stack frames.
size_t MAX_STACK_FRAMES = 64;
void* frames[MAX_STACK_FRAMES];
@@ -86,4 +85,144 @@
free(symbols);
}
+static const char* GetSignalCodeName(int signal_number, int signal_code) {
+ // Try the signal-specific codes...
+ switch (signal_number) {
+ case SIGILL:
+ switch (signal_code) {
+ case ILL_ILLOPC: return "ILL_ILLOPC";
+ case ILL_ILLOPN: return "ILL_ILLOPN";
+ case ILL_ILLADR: return "ILL_ILLADR";
+ case ILL_ILLTRP: return "ILL_ILLTRP";
+ case ILL_PRVOPC: return "ILL_PRVOPC";
+ case ILL_PRVREG: return "ILL_PRVREG";
+ case ILL_COPROC: return "ILL_COPROC";
+ case ILL_BADSTK: return "ILL_BADSTK";
+ }
+ break;
+ case SIGBUS:
+ switch (signal_code) {
+ case BUS_ADRALN: return "BUS_ADRALN";
+ case BUS_ADRERR: return "BUS_ADRERR";
+ case BUS_OBJERR: return "BUS_OBJERR";
+ }
+ break;
+ case SIGFPE:
+ switch (signal_code) {
+ case FPE_INTDIV: return "FPE_INTDIV";
+ case FPE_INTOVF: return "FPE_INTOVF";
+ case FPE_FLTDIV: return "FPE_FLTDIV";
+ case FPE_FLTOVF: return "FPE_FLTOVF";
+ case FPE_FLTUND: return "FPE_FLTUND";
+ case FPE_FLTRES: return "FPE_FLTRES";
+ case FPE_FLTINV: return "FPE_FLTINV";
+ case FPE_FLTSUB: return "FPE_FLTSUB";
+ }
+ break;
+ case SIGSEGV:
+ switch (signal_code) {
+ case SEGV_MAPERR: return "SEGV_MAPERR";
+ case SEGV_ACCERR: return "SEGV_ACCERR";
+ }
+ break;
+ case SIGTRAP:
+ switch (signal_code) {
+ case TRAP_BRKPT: return "TRAP_BRKPT";
+ case TRAP_TRACE: return "TRAP_TRACE";
+ }
+ break;
+ }
+ // Then the other codes...
+ switch (signal_code) {
+ case SI_USER: return "SI_USER";
+#if defined(SI_KERNEL)
+ case SI_KERNEL: return "SI_KERNEL";
+#endif
+ case SI_QUEUE: return "SI_QUEUE";
+ case SI_TIMER: return "SI_TIMER";
+ case SI_MESGQ: return "SI_MESGQ";
+ case SI_ASYNCIO: return "SI_ASYNCIO";
+#if defined(SI_SIGIO)
+ case SI_SIGIO: return "SI_SIGIO";
+#endif
+#if defined(SI_TKILL)
+ case SI_TKILL: return "SI_TKILL";
+#endif
+ }
+ // Then give up...
+ return "?";
+}
+
+static void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void*) {
+ const char* signal_name = "?";
+ bool has_address = false;
+ if (signal_number == SIGILL) {
+ signal_name = "SIGILL";
+ has_address = true;
+ } else if (signal_number == SIGTRAP) {
+ signal_name = "SIGTRAP";
+ } else if (signal_number == SIGABRT) {
+ signal_name = "SIGABRT";
+ } else if (signal_number == SIGBUS) {
+ signal_name = "SIGBUS";
+ has_address = true;
+ } else if (signal_number == SIGFPE) {
+ signal_name = "SIGFPE";
+ has_address = true;
+ } else if (signal_number == SIGSEGV) {
+ signal_name = "SIGSEGV";
+ has_address = true;
+#if defined(SIGSTKFLT)
+ } else if (signal_number == SIGSTKFLT) {
+ signal_name = "SIGSTKFLT";
+#endif
+ } else if (signal_number == SIGPIPE) {
+ signal_name = "SIGPIPE";
+ }
+
+ LOG(INTERNAL_FATAL) << "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"
+ << StringPrintf("Fatal signal %d (%s), code %d (%s)",
+ signal_number, signal_name,
+ info->si_code,
+ GetSignalCodeName(signal_number, info->si_code))
+ << (has_address ? StringPrintf(" fault addr %p", info->si_addr) : "");
+ Backtrace();
+
+ // TODO: make this part optional, like it is on the device?
+ // Wait for debugger to attach.
+ LOG(INTERNAL_FATAL) << "********************************************************\n"
+ << "* Process " << getpid() << " has been suspended while crashing. Attach gdb:\n"
+ << "* gdb -p " << getpid() << "\n"
+ << "********************************************************\n";
+ while (true) {
+ }
+}
+
+void Runtime::PlatformAbort(const char* /*file*/, int /*line_number*/) {
+ // On the host, we don't have debuggerd to dump a stack for us when we LOG(FATAL).
+ Backtrace();
+}
+
+void Runtime::InitPlatformSignalHandlers() {
+ // On the host, we don't have debuggerd to dump a stack for us when something unexpected happens.
+ struct sigaction action;
+ memset(&action, 0, sizeof(action));
+ sigemptyset(&action.sa_mask);
+ action.sa_sigaction = HandleUnexpectedSignal;
+ action.sa_flags = SA_RESTART | SA_SIGINFO;
+
+ int rc = 0;
+ rc += sigaction(SIGILL, &action, NULL);
+ rc += sigaction(SIGTRAP, &action, NULL);
+ rc += sigaction(SIGABRT, &action, NULL);
+ rc += sigaction(SIGBUS, &action, NULL);
+ rc += sigaction(SIGFPE, &action, NULL);
+ rc += sigaction(SIGSEGV, &action, NULL);
+#if defined(SIGSTKFLT)
+ rc += sigaction(SIGSTKFLT, &action, NULL);
+#endif
+ rc += sigaction(SIGPIPE, &action, NULL);
+ CHECK_EQ(rc, 0);
+}
+
} // namespace art
diff --git a/src/signal_catcher.cc b/src/signal_catcher.cc
index be21372..5a9bf4e 100644
--- a/src/signal_catcher.cc
+++ b/src/signal_catcher.cc
@@ -31,6 +31,7 @@
#include "os.h"
#include "runtime.h"
#include "scoped_heap_lock.h"
+#include "signal_set.h"
#include "thread.h"
#include "thread_list.h"
#include "utils.h"
@@ -114,7 +115,7 @@
os << "Cmd line: " << cmdline << "\n";
}
- runtime->Dump(os);
+ runtime->DumpForSigQuit(os);
if (false) {
std::string maps;
@@ -135,21 +136,14 @@
Runtime::Current()->GetHeap()->CollectGarbage(false);
}
-int SignalCatcher::WaitForSignal(sigset_t& mask) {
+int SignalCatcher::WaitForSignal(SignalSet& signals) {
ScopedThreadStateChange tsc(thread_, kVmWait);
// Signals for sigwait() must be blocked but not ignored. We
// block signals like SIGQUIT for all threads, so the condition
// is met. When the signal hits, we wake up, without any signal
// handlers being invoked.
-
- // Sleep in sigwait() until a signal arrives. gdb causes EINTR failures.
- int signal_number;
- int rc = TEMP_FAILURE_RETRY(sigwait(&mask, &signal_number));
- if (rc != 0) {
- PLOG(FATAL) << "sigwait failed";
- }
-
+ int signal_number = signals.Wait();
if (!ShouldHalt()) {
// Let the user know we got the signal, just in case the system's too screwed for us to
// actually do what they want us to do...
@@ -177,13 +171,12 @@
}
// Set up mask with signals we want to handle.
- sigset_t mask;
- sigemptyset(&mask);
- sigaddset(&mask, SIGQUIT);
- sigaddset(&mask, SIGUSR1);
+ SignalSet signals;
+ signals.Add(SIGQUIT);
+ signals.Add(SIGUSR1);
while (true) {
- int signal_number = signal_catcher->WaitForSignal(mask);
+ int signal_number = signal_catcher->WaitForSignal(signals);
if (signal_catcher->ShouldHalt()) {
runtime->DetachCurrentThread();
return NULL;
diff --git a/src/signal_catcher.h b/src/signal_catcher.h
index f237b12..131b07c 100644
--- a/src/signal_catcher.h
+++ b/src/signal_catcher.h
@@ -22,6 +22,7 @@
namespace art {
class Runtime;
+class SignalSet;
class Thread;
/*
@@ -43,7 +44,7 @@
void Output(const std::string& s);
void SetHaltFlag(bool new_value);
bool ShouldHalt();
- int WaitForSignal(sigset_t& mask);
+ int WaitForSignal(SignalSet& signals);
std::string stack_trace_file_;
mutable Mutex lock_;
diff --git a/src/signal_set.h b/src/signal_set.h
new file mode 100644
index 0000000..030a2d1
--- /dev/null
+++ b/src/signal_set.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2012 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_SRC_SIGNAL_SET_H_
+#define ART_SRC_SIGNAL_SET_H_
+
+#include <signal.h>
+
+#include "logging.h"
+
+namespace art {
+
+class SignalSet {
+ public:
+ SignalSet() {
+ if (sigemptyset(&set_) == -1) {
+ PLOG(FATAL) << "sigemptyset failed";
+ }
+ }
+
+ void Add(int signal) {
+ if (sigaddset(&set_, signal) == -1) {
+ PLOG(FATAL) << "sigaddset " << signal << " failed";
+ }
+ }
+
+ void Block() {
+ if (sigprocmask(SIG_BLOCK, &set_, NULL) == -1) {
+ PLOG(FATAL) << "sigprocmask failed";
+ }
+ }
+
+ int Wait() {
+ // Sleep in sigwait() until a signal arrives. gdb causes EINTR failures.
+ int signal_number;
+ int rc = TEMP_FAILURE_RETRY(sigwait(&set_, &signal_number));
+ if (rc != 0) {
+ PLOG(FATAL) << "sigwait failed";
+ }
+ return signal_number;
+ }
+
+ private:
+ sigset_t set_;
+};
+
+} // namespace art
+
+#endif // ART_SRC_SIGNAL_SET_H_
diff --git a/src/thread.cc b/src/thread.cc
index 930e0df..fbf2390 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -77,10 +77,20 @@
card_table_ = Runtime::Current()->GetHeap()->GetCardTable()->GetBiasedBegin();
}
+static void UnimplementedEntryPoint() {
+ UNIMPLEMENTED(FATAL);
+}
+
void Thread::InitFunctionPointers() {
#if defined(ART_USE_LLVM_COMPILER)
memset(&entrypoints_, 0, sizeof(entrypoints_));
#else
+ // Insert a placeholder so we can easily tell if we call an unimplemented entry point.
+ uintptr_t* begin = reinterpret_cast<uintptr_t*>(&entrypoints_);
+ uintptr_t* end = reinterpret_cast<uintptr_t*>(reinterpret_cast<uint8_t*>(begin) + sizeof(entrypoints_));
+ for (uintptr_t* it = begin; it != end; ++it) {
+ *it = reinterpret_cast<uintptr_t>(UnimplementedEntryPoint);
+ }
InitEntryPoints(&entrypoints_);
#endif
}
@@ -160,6 +170,11 @@
stack_size = Runtime::Current()->GetDefaultStackSize();
}
+ // Dalvik used the bionic pthread default stack size for native threads,
+ // so include that here to support apps that expect large native stacks.
+ stack_size += 1 * MB;
+
+
// It's not possible to request a stack smaller than the system-defined PTHREAD_STACK_MIN.
if (stack_size < PTHREAD_STACK_MIN) {
stack_size = PTHREAD_STACK_MIN;
diff --git a/src/thread.h b/src/thread.h
index 4f43473..c5695cf 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -92,7 +92,7 @@
static const size_t kStackOverflowReservedBytes = 8 * KB;
#endif
- static const size_t kDefaultStackSize = 128 * KB;
+ static const size_t kDefaultStackSize = 16 * KB;
class StackVisitor {
public:
diff --git a/src/thread_list.cc b/src/thread_list.cc
index 43a8561..80ab2cf 100644
--- a/src/thread_list.cc
+++ b/src/thread_list.cc
@@ -54,7 +54,7 @@
return thread_list_lock_.GetOwner();
}
-void ThreadList::Dump(std::ostream& os) {
+void ThreadList::DumpForSigQuit(std::ostream& os) {
ScopedThreadListLock thread_list_lock;
DumpLocked(os);
}
diff --git a/src/thread_list.h b/src/thread_list.h
index 0691808..f0b4f6b 100644
--- a/src/thread_list.h
+++ b/src/thread_list.h
@@ -31,7 +31,7 @@
explicit ThreadList();
~ThreadList();
- void Dump(std::ostream& os);
+ void DumpForSigQuit(std::ostream& os);
void DumpLocked(std::ostream& os); // For thread suspend timeout dumps.
pid_t GetLockOwner(); // For SignalCatcher.
diff --git a/src/utils.cc b/src/utils.cc
index 70d15bf..ea50073 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -345,16 +345,26 @@
return result;
}
-std::string PrettySize(size_t size_in_bytes) {
- if ((size_in_bytes / GB) * GB == size_in_bytes) {
- return StringPrintf("%zdGB", size_in_bytes / GB);
- } else if ((size_in_bytes / MB) * MB == size_in_bytes) {
- return StringPrintf("%zdMB", size_in_bytes / MB);
- } else if ((size_in_bytes / KB) * KB == size_in_bytes) {
- return StringPrintf("%zdKB", size_in_bytes / KB);
- } else {
- return StringPrintf("%zdB", size_in_bytes);
+std::string PrettySize(size_t byte_count) {
+ // The byte thresholds at which we display amounts. A byte count is displayed
+ // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1].
+ static const size_t kUnitThresholds[] = {
+ 0, // B up to...
+ 3*1024, // KB up to...
+ 2*1024*1024, // MB up to...
+ 1024*1024*1024 // GB from here.
+ };
+ static const size_t kBytesPerUnit[] = { 1, KB, MB, GB };
+ static const char* const kUnitStrings[] = { "B", "KB", "MB", "GB" };
+
+ int i = arraysize(kUnitThresholds);
+ while (--i > 0) {
+ if (byte_count >= kUnitThresholds[i]) {
+ break;
+ }
}
+
+ return StringPrintf("%zd%s", byte_count / kBytesPerUnit[i], kUnitStrings[i]);
}
std::string PrettyDuration(uint64_t nano_duration) {
diff --git a/src/utils.h b/src/utils.h
index f11a769..f94c05e 100644
--- a/src/utils.h
+++ b/src/utils.h
@@ -191,7 +191,7 @@
// Returns a human-readable form of the name of the given class with its class loader.
std::string PrettyClassAndClassLoader(const Class* c);
-// Returns a human-readable size string. e.g. "1MB"
+// Returns a human-readable size string such as "1MB".
std::string PrettySize(size_t size_in_bytes);
// Returns a human-readable time string which prints every nanosecond while trying to limit the
diff --git a/src/utils_test.cc b/src/utils_test.cc
index e0b2139..311bd16 100644
--- a/src/utils_test.cc
+++ b/src/utils_test.cc
@@ -135,15 +135,17 @@
if (sizeof(size_t) > sizeof(uint32_t)) {
EXPECT_EQ("100GB", PrettySize(100 * GB));
}
- EXPECT_EQ("1MB", PrettySize(1 * MB));
+ EXPECT_EQ("1024KB", PrettySize(1 * MB));
EXPECT_EQ("10MB", PrettySize(10 * MB));
EXPECT_EQ("100MB", PrettySize(100 * MB));
- EXPECT_EQ("1KB", PrettySize(1 * KB));
+ EXPECT_EQ("1024B", PrettySize(1 * KB));
EXPECT_EQ("10KB", PrettySize(10 * KB));
EXPECT_EQ("100KB", PrettySize(100 * KB));
+ EXPECT_EQ("0B", PrettySize(0));
EXPECT_EQ("1B", PrettySize(1));
EXPECT_EQ("10B", PrettySize(10));
EXPECT_EQ("100B", PrettySize(100));
+ EXPECT_EQ("512B", PrettySize(512));
}
TEST_F(UtilsTest, PrettyDuration) {