Implement MarkGCCard.

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