Implement MarkGCCard.

Change-Id: Ic004750a303897d33a5459a41ac60ac552926e07
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