Merge "Renamed ReferenceMapVisitor to prevent confusion with art version." into ics-mr1-plus-art
diff --git a/src/compiler_llvm/art_module.ll b/src/compiler_llvm/art_module.ll
index 110b393..6f7fdfb 100644
--- a/src/compiler_llvm/art_module.ll
+++ b/src/compiler_llvm/art_module.ll
@@ -165,6 +165,8 @@
 ; Temporary runtime support, will be removed in the future
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
+declare void @art_mark_gc_card_from_code(%JavaObject*, %JavaObject*)
+
 declare %JavaObject* @art_ensure_resolved_from_code(%JavaObject*,
                                                     %JavaObject*,
                                                     i32,
diff --git a/src/compiler_llvm/generated/art_module.cc b/src/compiler_llvm/generated/art_module.cc
index db1a3de..1b9bcf5 100644
--- a/src/compiler_llvm/generated/art_module.cc
+++ b/src/compiler_llvm/generated/art_module.cc
@@ -933,6 +933,17 @@
 AttrListPtr func_F2I_PAL;
 func_F2I->setAttributes(func_F2I_PAL);
 
+Function* func_art_mark_gc_card_from_code = mod->getFunction("art_mark_gc_card_from_code");
+if (!func_art_mark_gc_card_from_code) {
+func_art_mark_gc_card_from_code = Function::Create(
+ /*Type=*/FuncTy_28,
+ /*Linkage=*/GlobalValue::ExternalLinkage,
+ /*Name=*/"art_mark_gc_card_from_code", mod); // (external, no body)
+func_art_mark_gc_card_from_code->setCallingConv(CallingConv::C);
+}
+AttrListPtr func_art_mark_gc_card_from_code_PAL;
+func_art_mark_gc_card_from_code->setAttributes(func_art_mark_gc_card_from_code_PAL);
+
 Function* func_art_ensure_resolved_from_code = mod->getFunction("art_ensure_resolved_from_code");
 if (!func_art_ensure_resolved_from_code) {
 func_art_ensure_resolved_from_code = Function::Create(
diff --git a/src/compiler_llvm/method_compiler.cc b/src/compiler_llvm/method_compiler.cc
index 153d99a..fa8a827 100644
--- a/src/compiler_llvm/method_compiler.cc
+++ b/src/compiler_llvm/method_compiler.cc
@@ -2252,6 +2252,12 @@
   }
 }
 
+void MethodCompiler::EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr) {
+  // Using runtime support, let the target can override by InlineAssembly.
+  llvm::Function* runtime_func = irb_.GetRuntime(MarkGCCard);
+
+  irb_.CreateCall2(runtime_func, value, target_addr);
+}
 
 void
 MethodCompiler::EmitGuard_ArrayIndexOutOfBoundsException(uint32_t dex_pc,
@@ -2354,12 +2360,14 @@
 
   llvm::Value* new_value = EmitLoadDalvikReg(dec_insn.vA, elem_jty, kArray);
 
-  if (elem_jty == kObject) { // If put an object, check the type.
+  if (elem_jty == kObject) { // If put an object, check the type, and mark GC card table.
     llvm::Function* runtime_func = irb_.GetRuntime(CheckPutArrayElement);
 
     irb_.CreateCall2(runtime_func, new_value, array_addr);
 
     EmitGuard_ExceptionLandingPad(dex_pc);
+
+    EmitMarkGCCard(new_value, array_addr);
   }
 
   irb_.CreateStore(new_value, array_elem_addr);
@@ -2488,6 +2496,10 @@
     // TODO: Check is_volatile.  We need to generate atomic store instruction
     // when is_volatile is true.
     irb_.CreateStore(new_value, field_addr);
+
+    if (field_jty == kObject) { // If put an object, mark the GC card table.
+      EmitMarkGCCard(new_value, object_addr);
+    }
   }
 
   irb_.CreateBr(GetNextBasicBlock(dex_pc));
@@ -2704,6 +2716,10 @@
     // TODO: Check is_volatile.  We need to generate atomic store instruction
     // when is_volatile is true.
     irb_.CreateStore(new_value, static_field_addr);
+
+    if (field_jty == kObject) { // If put an object, mark the GC card table.
+      EmitMarkGCCard(new_value, static_storage_addr);
+    }
   }
 
   irb_.CreateBr(GetNextBasicBlock(dex_pc));
diff --git a/src/compiler_llvm/method_compiler.h b/src/compiler_llvm/method_compiler.h
index 0bfdf5d..7a5d66f 100644
--- a/src/compiler_llvm/method_compiler.h
+++ b/src/compiler_llvm/method_compiler.h
@@ -260,6 +260,8 @@
 
 #undef GEN_INSN_ARGS
 
+  // GC card table helper function
+  void EmitMarkGCCard(llvm::Value* value, llvm::Value* target_addr);
 
   // Shadow frame helper function
   void EmitPopShadowFrame();
diff --git a/src/compiler_llvm/runtime_support_builder.cc b/src/compiler_llvm/runtime_support_builder.cc
index 4183df6..a8a3ed7 100644
--- a/src/compiler_llvm/runtime_support_builder.cc
+++ b/src/compiler_llvm/runtime_support_builder.cc
@@ -16,6 +16,7 @@
 
 #include "runtime_support_builder.h"
 
+#include "card_table.h"
 #include "ir_builder.h"
 #include "shadow_frame.h"
 #include "thread.h"
@@ -38,6 +39,7 @@
                                              IRBuilder& irb)
     : context_(context), module_(module), irb_(irb)
 {
+  memset(target_runtime_support_func_, 0, sizeof(target_runtime_support_func_));
 #define GET_RUNTIME_SUPPORT_FUNC_DECL(ID, NAME) \
   do { \
     llvm::Function* fn = module_.getFunction(#NAME); \
@@ -162,6 +164,38 @@
 
     OverrideRuntimeSupportFunction(TestSuspend, func);
   }
+
+  if (!target_runtime_support_func_[MarkGCCard]) {
+    Function* func = GetRuntimeSupportFunction(MarkGCCard);
+    MakeFunctionInline(func);
+    BasicBlock* basic_block = BasicBlock::Create(context_, "entry", func);
+    irb_.SetInsertPoint(basic_block);
+    Function::arg_iterator arg_iter = func->arg_begin();
+    Value* value = arg_iter++;
+    Value* target_addr = arg_iter++;
+
+    llvm::Value* is_value_null = irb_.CreateICmpEQ(value, irb_.getJNull());
+
+    llvm::BasicBlock* block_value_is_null = BasicBlock::Create(context_, "value_is_null", func);
+    llvm::BasicBlock* block_mark_gc_card = BasicBlock::Create(context_, "mark_gc_card", func);
+
+    irb_.CreateCondBr(is_value_null, block_value_is_null, block_mark_gc_card);
+
+    irb_.SetInsertPoint(block_value_is_null);
+    irb_.CreateRetVoid();
+
+    irb_.SetInsertPoint(block_mark_gc_card);
+    Function* get_thread = GetRuntimeSupportFunction(GetCurrentThread);
+    Value* thread = irb_.CreateCall(get_thread);
+    Value* card_table = irb_.LoadFromObjectOffset(thread,
+                                                  Thread::CardTableOffset().Int32Value(),
+                                                  irb_.getInt8Ty()->getPointerTo());
+    Value* target_addr_int = irb_.CreatePtrToInt(target_addr, irb_.getPtrEquivIntTy());
+    Value* card_no = irb_.CreateLShr(target_addr_int, irb_.getPtrEquivInt(GC_CARD_SHIFT));
+    Value* card_table_entry = irb_.CreateGEP(card_table, card_no);
+    irb_.CreateStore(irb_.getInt8(GC_CARD_DIRTY), card_table_entry);
+    irb_.CreateRetVoid();
+  }
 }
 
 } // namespace compiler_llvm
diff --git a/src/compiler_llvm/runtime_support_func_list.h b/src/compiler_llvm/runtime_support_func_list.h
index 498502a..2f3a6fa 100644
--- a/src/compiler_llvm/runtime_support_func_list.h
+++ b/src/compiler_llvm/runtime_support_func_list.h
@@ -61,6 +61,7 @@
   V(InitializeStaticStorage, art_initialize_static_storage_from_code) \
   V(IsExceptionPending, art_is_exception_pending_from_code) \
   V(FindCatchBlock, art_find_catch_block_from_code) \
+  V(MarkGCCard, art_mark_gc_card_from_code) \
   V(EnsureResolved, art_ensure_resolved_from_code) \
   V(FixStub, art_fix_stub_from_code) \
   V(ProxyInvokeHandler, art_proxy_invoke_handler_from_code) \
diff --git a/src/compiler_llvm/runtime_support_llvm.cc b/src/compiler_llvm/runtime_support_llvm.cc
index c526847..0fd3611 100644
--- a/src/compiler_llvm/runtime_support_llvm.cc
+++ b/src/compiler_llvm/runtime_support_llvm.cc
@@ -39,6 +39,9 @@
 // Thread
 //----------------------------------------------------------------------------
 
+// This is used by other runtime support functions, NOT FROM CODE. The REAL GetCurrentThread is
+// implemented by IRBuilder. (So, ARM can't return R9 in this function.)
+// TODO: Maybe remove these which are implemented by IRBuilder after refactor runtime support.
 Thread* art_get_current_thread_from_code() {
 #if defined(__i386__)
   Thread* ptr;
@@ -53,6 +56,7 @@
 }
 
 void art_set_current_thread_from_code(void* thread_object_addr) {
+  LOG(FATAL) << "Implemented by IRBuilder.";
 }
 
 void art_lock_object_from_code(Object* obj) {
@@ -77,23 +81,24 @@
 }
 
 void art_push_shadow_frame_from_code(void* new_shadow_frame) {
-  Thread* thread = art_get_current_thread_from_code();
-  thread->PushShadowFrame(static_cast<ShadowFrame*>(new_shadow_frame));
+  LOG(FATAL) << "Implemented by IRBuilder.";
 }
 
 void art_pop_shadow_frame_from_code() {
-  Thread* thread = art_get_current_thread_from_code();
-  thread->PopShadowFrame();
+  LOG(FATAL) << "Implemented by IRBuilder.";
 }
 
-
+void art_mark_gc_card_from_code(void *, void*) {
+  LOG(FATAL) << "Implemented by IRBuilder.";
+}
 
 //----------------------------------------------------------------------------
 // Exception
 //----------------------------------------------------------------------------
 
 bool art_is_exception_pending_from_code() {
-  return art_get_current_thread_from_code()->IsExceptionPending();
+  LOG(FATAL) << "Implemented by IRBuilder.";
+  return false;
 }
 
 void art_throw_div_zero_from_code() {
diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc
index 1553dd8..381c7f0 100644
--- a/src/mark_sweep.cc
+++ b/src/mark_sweep.cc
@@ -139,7 +139,6 @@
   void* arg = reinterpret_cast<void*>(this);
   const std::vector<Space*>& spaces = heap_->GetSpaces();
   for (size_t i = 0; i < spaces.size(); ++i) {
-#if !defined(ART_USE_LLVM_COMPILER)
 #ifndef NDEBUG
     uintptr_t begin = reinterpret_cast<uintptr_t>(spaces[i]->Begin());
     uintptr_t end = reinterpret_cast<uintptr_t>(spaces[i]->End());
@@ -155,12 +154,6 @@
       mark_bitmap_->ScanWalk(begin, end, &MarkSweep::ScanBitmapCallback, arg);
     }
 #endif
-#else
-    // TODO: Implement card marking.
-    uintptr_t begin = reinterpret_cast<uintptr_t>(spaces[i]->Begin());
-    uintptr_t end = reinterpret_cast<uintptr_t>(spaces[i]->End());
-    mark_bitmap_->ScanWalk(begin, end, &MarkSweep::ScanBitmapCallback, arg);
-#endif
   }
   finger_ = reinterpret_cast<Object*>(~0);
   // TODO: tune the frequency of emptying the mark stack
diff --git a/src/runtime_linux.cc b/src/runtime_linux.cc
index 4214003..c96b1e5 100644
--- a/src/runtime_linux.cc
+++ b/src/runtime_linux.cc
@@ -209,7 +209,7 @@
   memset(&action, 0, sizeof(action));
   sigemptyset(&action.sa_mask);
   action.sa_sigaction = HandleUnexpectedSignal;
-  action.sa_flags = SA_RESTART | SA_SIGINFO;
+  action.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
 
   int rc = 0;
   rc += sigaction(SIGILL, &action, NULL);
diff --git a/src/thread.cc b/src/thread.cc
index ca8922b..3892c23 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -18,6 +18,7 @@
 
 #include <dynamic_annotations.h>
 #include <pthread.h>
+#include <signal.h>
 #include <sys/mman.h>
 #include <sys/resource.h>
 #include <sys/time.h>
@@ -75,17 +76,21 @@
   card_table_ = Runtime::Current()->GetHeap()->GetCardTable()->GetBiasedBegin();
 }
 
+#if !defined(__APPLE__)
 static void UnimplementedEntryPoint() {
   UNIMPLEMENTED(FATAL);
 }
+#endif
 
 void Thread::InitFunctionPointers() {
+#if !defined(__APPLE__) // The Mac GCC is too old to accept this code.
   // 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);
   }
+#endif
   InitEntryPoints(&entrypoints_);
 }
 
@@ -185,6 +190,43 @@
   return stack_size;
 }
 
+static void SigAltStack(stack_t* new_stack, stack_t* old_stack) {
+  if (sigaltstack(new_stack, old_stack) == -1) {
+    PLOG(FATAL) << "sigaltstack failed";
+  }
+}
+
+static void SetUpAlternateSignalStack() {
+  // Create and set an alternate signal stack.
+  stack_t ss;
+  ss.ss_sp = new uint8_t[SIGSTKSZ];
+  ss.ss_size = SIGSTKSZ;
+  ss.ss_flags = 0;
+  CHECK(ss.ss_sp != NULL);
+  SigAltStack(&ss, NULL);
+
+  // Double-check that it worked.
+  ss.ss_sp = NULL;
+  SigAltStack(NULL, &ss);
+  VLOG(threads) << "Alternate signal stack is " << PrettySize(ss.ss_size) << " at " << ss.ss_sp;
+}
+
+static void TearDownAlternateSignalStack() {
+  // Get the pointer so we can free the memory.
+  stack_t ss;
+  SigAltStack(NULL, &ss);
+  uint8_t* allocated_signal_stack = reinterpret_cast<uint8_t*>(ss.ss_sp);
+
+  // Tell the kernel to stop using it.
+  ss.ss_sp = NULL;
+  ss.ss_flags = SS_DISABLE;
+  ss.ss_size = 0;
+  SigAltStack(&ss, NULL);
+
+  // Free it.
+  delete[] allocated_signal_stack;
+}
+
 void Thread::Create(Object* peer, size_t stack_size) {
   CHECK(peer != NULL);
 
@@ -219,6 +261,7 @@
   // thread hasn't been through here already...
   CHECK(Thread::Current() == NULL);
 
+  SetUpAlternateSignalStack();
   InitCpu();
   InitFunctionPointers();
   InitCardTable();
@@ -878,6 +921,8 @@
   delete debug_invoke_req_;
   delete trace_stack_;
   delete name_;
+
+  TearDownAlternateSignalStack();
 }
 
 void Thread::HandleUncaughtExceptions() {