Add code size to oat files

Change-Id: Ic2519551864dd7090ba98f2fc92318f95f92947f
diff --git a/Android.mk b/Android.mk
index 904a5f1..6eb90bd 100644
--- a/Android.mk
+++ b/Android.mk
@@ -204,6 +204,7 @@
 	adb shell rm $(DEXPREOPT_BOOT_JAR_DIR)/*.oat
 	adb shell rm $(DEXPREOPT_BOOT_JAR_DIR)/*.art
 	adb shell rm system/app/*.oat
+	adb shell rm data/run-test/*.oat
 
 ########################################################################
 # cpplint target
diff --git a/src/exception_test.cc b/src/exception_test.cc
index eebba9d..120f16a 100644
--- a/src/exception_test.cc
+++ b/src/exception_test.cc
@@ -38,8 +38,13 @@
 
     dex_ = &Runtime::Current()->GetClassLinker()->FindDexFile(my_klass_->GetDexCache());
 
-    for (size_t i = 0 ; i < 12; i++) {
-      fake_code_.push_back(0x70000000 | i);
+    uint32_t code_size = 12;
+    fake_code_.push_back((code_size >> 24) & 0xFF);
+    fake_code_.push_back((code_size >> 16) & 0xFF);
+    fake_code_.push_back((code_size >>  8) & 0xFF);
+    fake_code_.push_back((code_size >>  0) & 0xFF);
+    for (size_t i = 0 ; i < code_size; i++) {
+      fake_code_.push_back(0x70 | i);
     }
 
     fake_mapping_data_.push_back(2);  // first element is count of remaining elements
@@ -49,13 +54,13 @@
     method_f_ = my_klass_->FindVirtualMethod("f", "()I");
     ASSERT_TRUE(method_f_ != NULL);
     method_f_->SetFrameSizeInBytes(kStackAlignment);
-    method_f_->SetCode(CompiledMethod::CodePointer(&fake_code_[0], kThumb2));
+    method_f_->SetCode(CompiledMethod::CodePointer(&fake_code_[sizeof(code_size)], kThumb2));
     method_f_->SetMappingTable(&fake_mapping_data_[0]);
 
     method_g_ = my_klass_->FindVirtualMethod("g", "(I)V");
     ASSERT_TRUE(method_g_ != NULL);
     method_g_->SetFrameSizeInBytes(kStackAlignment);
-    method_g_->SetCode(CompiledMethod::CodePointer(&fake_code_[0], kThumb2));
+    method_g_->SetCode(CompiledMethod::CodePointer(&fake_code_[sizeof(code_size)], kThumb2));
     method_g_->SetMappingTable(&fake_mapping_data_[0]);
   }
 
diff --git a/src/oat_file.cc b/src/oat_file.cc
index 22dc92c..f0c004d 100644
--- a/src/oat_file.cc
+++ b/src/oat_file.cc
@@ -82,7 +82,7 @@
     return false;
   }
   CHECK(requested_base == 0 || requested_base == map->Begin())
-          << GetLocation() << " " << reinterpret_cast<void*>(map->Begin());
+      << GetLocation() << " " << reinterpret_cast<void*>(map->Begin());
   DCHECK_EQ(0, memcmp(&oat_header, map->Begin(), sizeof(OatHeader))) << GetLocation();
 
   off_t code_offset = oat_header.GetExecutableOffset();
diff --git a/src/oat_file.h b/src/oat_file.h
index 831934a..9fcba2f 100644
--- a/src/oat_file.h
+++ b/src/oat_file.h
@@ -90,6 +90,15 @@
     const void* GetCode() const {
       return GetOatPointer<const void*>(code_offset_);
     }
+    uint32_t GetCodeSize() const {
+      uintptr_t code = reinterpret_cast<uint32_t>(GetCode());
+      if (code == 0) {
+        return 0;
+      }
+      // TODO: make this Thumb2 specific
+      code &= ~0x1;
+      return reinterpret_cast<uint32_t*>(code)[-1];
+    }
     const uint32_t* GetMappingTable() const {
       return GetOatPointer<const uint32_t*>(mapping_table_offset_);
     }
@@ -102,6 +111,13 @@
     const Method::InvokeStub* GetInvokeStub() const {
       return GetOatPointer<const Method::InvokeStub*>(invoke_stub_offset_);
     }
+    uint32_t GetInvokeStubSize() const {
+      uintptr_t code = reinterpret_cast<uint32_t>(GetInvokeStub());
+      if (code == 0) {
+        return 0;
+      }
+      return reinterpret_cast<uint32_t*>(code)[-1];
+    }
 
     ~OatMethod();
 
diff --git a/src/oat_writer.cc b/src/oat_writer.cc
index dcdff9a..1ac247e 100644
--- a/src/oat_writer.cc
+++ b/src/oat_writer.cc
@@ -220,9 +220,10 @@
     offset = compiled_method->AlignCode(offset);
     DCHECK_ALIGNED(offset, kArmAlignment);
     const std::vector<uint8_t>& code = compiled_method->GetCode();
-    size_t code_size = code.size() * sizeof(code[0]);
+    uint32_t code_size = code.size() * sizeof(code[0]);
+    CHECK_NE(code_size, 0U);
     uint32_t thumb_offset = compiled_method->CodeDelta();
-    code_offset = (code_size == 0) ? 0 : offset + thumb_offset;
+    code_offset = offset + sizeof(code_size) + thumb_offset;
 
     // Deduplicate code arrays
     std::map<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
@@ -230,10 +231,10 @@
       code_offset = code_iter->second;
     } else {
       code_offsets_.insert(std::pair<const std::vector<uint8_t>*, uint32_t>(&code, code_offset));
+      offset += sizeof(code_size);  // code size is prepended before code
       offset += code_size;
       oat_header_->UpdateChecksum(&code[0], code_size);
     }
-
     frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
     core_spill_mask = compiled_method->GetCoreSpillMask();
     fp_spill_mask = compiled_method->GetFpSpillMask();
@@ -297,8 +298,9 @@
     offset = CompiledMethod::AlignCode(offset, compiler_->GetInstructionSet());
     DCHECK_ALIGNED(offset, kArmAlignment);
     const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
-    size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
-    invoke_stub_offset = (invoke_stub_size == 0) ? 0 : offset;
+    uint32_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
+    CHECK_NE(invoke_stub_size, 0U);
+    invoke_stub_offset = offset + sizeof(invoke_stub_size);
 
     // Deduplicate invoke stubs
     std::map<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter = code_offsets_.find(&invoke_stub);
@@ -306,6 +308,7 @@
       invoke_stub_offset = stub_iter->second;
     } else {
       code_offsets_.insert(std::pair<const std::vector<uint8_t>*, uint32_t>(&invoke_stub, invoke_stub_offset));
+      offset += sizeof(invoke_stub_size);  // invoke stub size is prepended before code
       offset += invoke_stub_size;
       oat_header_->UpdateChecksum(&invoke_stub[0], invoke_stub_size);
     }
@@ -522,19 +525,22 @@
     }
     DCHECK_ALIGNED(code_offset, kArmAlignment);
     const std::vector<uint8_t>& code = compiled_method->GetCode();
-    size_t code_size = code.size() * sizeof(code[0]);
+    uint32_t code_size = code.size() * sizeof(code[0]);
+    CHECK_NE(code_size, 0U);
 
     // Deduplicate code arrays
-    size_t offset = code_offset + compiled_method->CodeDelta();
+    size_t offset = code_offset + sizeof(code_size) + compiled_method->CodeDelta();
     std::map<const std::vector<uint8_t>*, uint32_t>::iterator code_iter = code_offsets_.find(&code);
     if (code_iter != code_offsets_.end() && offset != method_offsets.code_offset_) {
-      DCHECK((code_size == 0 && method_offsets.code_offset_ == 0)
-             || code_iter->second == method_offsets.code_offset_)
-             << PrettyMethod(method_idx, dex_file);
+      DCHECK(code_iter->second == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
     } else {
-      DCHECK((code_size == 0 && method_offsets.code_offset_ == 0)
-             || offset == method_offsets.code_offset_)
-             << PrettyMethod(method_idx, dex_file);
+      DCHECK(offset == method_offsets.code_offset_) << PrettyMethod(method_idx, dex_file);
+      if (!file->WriteFully(&code_size, sizeof(code_size))) {
+        ReportWriteFailure("method code size", method_idx, dex_file, file);
+        return 0;
+      }
+      code_offset += sizeof(code_size);
+      DCHECK_CODE_OFFSET();
       if (!file->WriteFully(&code[0], code_size)) {
         ReportWriteFailure("method code", method_idx, dex_file, file);
         return 0;
@@ -633,20 +639,23 @@
     }
     DCHECK_ALIGNED(code_offset, kArmAlignment);
     const std::vector<uint8_t>& invoke_stub = compiled_invoke_stub->GetCode();
-    size_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
+    uint32_t invoke_stub_size = invoke_stub.size() * sizeof(invoke_stub[0]);
+    CHECK_NE(invoke_stub_size, 0U);
 
     // Deduplicate invoke stubs
+    size_t offset = code_offset + sizeof(invoke_stub_size);
     std::map<const std::vector<uint8_t>*, uint32_t>::iterator stub_iter =
         code_offsets_.find(&invoke_stub);
-    if (stub_iter != code_offsets_.end() &&
-        code_offset != method_offsets.invoke_stub_offset_) {
-      DCHECK((invoke_stub_size == 0 && method_offsets.invoke_stub_offset_ == 0)
-          || stub_iter->second == method_offsets.invoke_stub_offset_)
-          << PrettyMethod(method_idx, dex_file);
+    if (stub_iter != code_offsets_.end() && offset != method_offsets.invoke_stub_offset_) {
+      DCHECK(stub_iter->second == method_offsets.invoke_stub_offset_) << PrettyMethod(method_idx, dex_file);
     } else {
-      DCHECK((invoke_stub_size == 0 && method_offsets.invoke_stub_offset_ == 0)
-          || code_offset == method_offsets.invoke_stub_offset_)
-          << PrettyMethod(method_idx, dex_file);
+      DCHECK(offset == method_offsets.invoke_stub_offset_) << PrettyMethod(method_idx, dex_file);
+      if (!file->WriteFully(&invoke_stub_size, sizeof(invoke_stub_size))) {
+        ReportWriteFailure("invoke stub code size", method_idx, dex_file, file);
+        return 0;
+      }
+      code_offset += sizeof(invoke_stub_size);
+      DCHECK_CODE_OFFSET();
       if (!file->WriteFully(&invoke_stub[0], invoke_stub_size)) {
         ReportWriteFailure("invoke stub code", method_idx, dex_file, file);
         return 0;
diff --git a/src/oatdump.cc b/src/oatdump.cc
index 5574bb7..96af3b0 100644
--- a/src/oatdump.cc
+++ b/src/oatdump.cc
@@ -138,6 +138,10 @@
     return end_offset - begin_offset;
   }
 
+  InstructionSet GetInstructionSet() {
+    return oat_file_.GetOatHeader().GetInstructionSet();
+  }
+
   const void* GetOatCode(Method* m) {
     MethodHelper mh(m);
     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
@@ -299,9 +303,9 @@
     DumpGcMap(os, oat_method.GetGcMap());
     os << StringPrintf("\t\tinvoke_stub: %p (offset=0x%08x)\n",
                        oat_method.GetInvokeStub(), oat_method.GetInvokeStubOffset());
-    os << "\t\tCODE:\n";
+    os << "\t\tCODE: (size=" << oat_method.GetCodeSize() << ")\n";
     DumpCode(os, oat_method.GetCode(), oat_method.GetMappingTable(), dex_file, code_item);
-    os << "\t\tINVOKE STUB:\n";
+    os << "\t\tINVOKE STUB: (size=" << oat_method.GetInvokeStubSize() << ")\n";
     DumpCode(os, reinterpret_cast<const void*>(oat_method.GetInvokeStub()), NULL, dex_file, NULL);
   }
 
@@ -620,17 +624,36 @@
 
   bool InDumpSpace(const Object* object) {
     return image_space_.Contains(object);
- }
+  }
 
-  const void* GetOatCode(Method* m) {
+  const void* GetOatCodeBegin(Method* m) {
     Runtime* runtime = Runtime::Current();
     const void* code = m->GetCode();
     if (code == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData()) {
       code = oat_dumper_->GetOatCode(m);
     }
+    if (oat_dumper_->GetInstructionSet() == kThumb2) {
+      code = reinterpret_cast<void*>(reinterpret_cast<uint32_t>(code) & ~0x1);
+    }
     return code;
   }
 
+  uint32_t GetOatCodeSize(Method* m) {
+    const uint32_t* oat_code_begin = reinterpret_cast<const uint32_t*>(GetOatCodeBegin(m));
+    if (oat_code_begin == NULL) {
+      return 0;
+    }
+    return oat_code_begin[-1];
+  }
+
+  const void* GetOatCodeEnd(Method* m) {
+    const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetOatCodeBegin(m));
+    if (oat_code_begin == NULL) {
+      return NULL;
+    }
+    return oat_code_begin + GetOatCodeSize(m);
+  }
+
   static void Callback(Object* obj, void* arg) {
     DCHECK(obj != NULL);
     DCHECK(arg != NULL);
@@ -712,7 +735,7 @@
         if (first_occurrence) {
           state->stats_.managed_to_native_code_bytes += invoke_stub_size;
         }
-        const void* oat_code = state->GetOatCode(method);
+        const void* oat_code = state->GetOatCodeBegin(method);
         size_t code_size = state->ComputeOatSize(oat_code, &first_occurrence);
         if (first_occurrence) {
           state->stats_.native_to_managed_code_bytes += code_size;
@@ -756,16 +779,17 @@
         if (first_occurance) {
           state->stats_.native_to_managed_code_bytes += invoke_stub_size;
         }
-        const void* oat_code = state->GetOatCode(method);
-        size_t code_size = state->ComputeOatSize(oat_code, &first_occurance);
+        const void* oat_code_begin = state->GetOatCodeBegin(method);
+        const void* oat_code_end = state->GetOatCodeEnd(method);
+        // TODO: use oat_code_size and remove code_size based on offsets
+        // uint32_t oat_code_size = state->GetOatCodeSize(method);
+        size_t code_size = state->ComputeOatSize(oat_code_begin, &first_occurance);
         if (first_occurance) {
           state->stats_.managed_code_bytes += code_size;
         }
         state->stats_.managed_code_bytes_ignoring_deduplication += code_size;
 
-        if (oat_code != method->GetCode()) {
-          StringAppendF(&summary, "\t\tOAT CODE: %p\n", oat_code);
-        }
+        StringAppendF(&summary, "\t\tOAT CODE: %p-%p\n", oat_code_begin, oat_code_end);
         StringAppendF(&summary, "\t\tSIZE: Dex Instructions=%zd GC=%zd Mapping=%zd\n",
                       dex_instruction_bytes, gc_map_bytes, pc_mapping_table_bytes);
 
diff --git a/src/object.h b/src/object.h
index b3a4805..3a7efa2 100644
--- a/src/object.h
+++ b/src/object.h
@@ -633,6 +633,27 @@
     SetFieldPtr<const void*>(OFFSET_OF_OBJECT_MEMBER(Method, code_), code, false);
   }
 
+  uint32_t GetCodeSize() const {
+    DCHECK(!IsRuntimeMethod() && !IsProxyMethod()) << PrettyMethod(this);
+    uintptr_t code = reinterpret_cast<uintptr_t>(GetCode());
+    if (code == 0) {
+      return 0;
+    }
+    // TODO: make this Thumb2 specific
+    code &= ~0x1;
+    return reinterpret_cast<uint32_t*>(code)[-1];
+  }
+
+  bool IsWithinCode(uintptr_t pc) const {
+    uintptr_t code = reinterpret_cast<uintptr_t>(GetCode());
+    if (code == 0) {
+      return pc == 0;
+    }
+    return (code <= pc && pc < code + GetCodeSize());
+  }
+
+  void AssertPcIsWithinCode(uintptr_t pc) const;
+
   uint32_t GetOatCodeOffset() const {
     DCHECK(!Runtime::Current()->IsStarted());
     return reinterpret_cast<uint32_t>(GetCode());
@@ -781,7 +802,7 @@
   }
 
   // Native to managed invocation stub entry point
-  InvokeStub* GetInvokeStub() const {
+  const InvokeStub* GetInvokeStub() const {
     InvokeStub* result = GetFieldPtr<InvokeStub*>(
         OFFSET_OF_OBJECT_MEMBER(Method, invoke_stub_), false);
     // TODO: DCHECK(result != NULL);  should be ahead of time compiled
@@ -793,6 +814,14 @@
                                    invoke_stub, false);
   }
 
+  uint32_t GetInvokeStubSize() const {
+    const uint32_t* invoke_stub = reinterpret_cast<const uint32_t*>(GetInvokeStub());
+    if (invoke_stub == NULL) {
+      return 0;
+    }
+    return invoke_stub[-1];
+  }
+
   uint32_t GetOatInvokeStubOffset() const {
     DCHECK(!Runtime::Current()->IsStarted());
     return reinterpret_cast<uint32_t>(GetInvokeStub());
@@ -2303,6 +2332,23 @@
   return GetField32(OFFSET_OF_OBJECT_MEMBER(Method, method_dex_index_), false);
 }
 
+inline void Method::AssertPcIsWithinCode(uintptr_t pc) const {
+#ifndef NDEBUG
+  if (IsNative() || IsRuntimeMethod() || IsProxyMethod()) {
+    return;
+  }
+  Runtime* runtime = Runtime::Current();
+  if (GetCode() == runtime->GetResolutionStubArray(Runtime::kStaticMethod)->GetData()) {
+      return;
+  }
+  DCHECK(IsWithinCode(pc))
+      << PrettyMethod(this)
+      << " pc=" << std::hex << pc
+      << " code=" << GetCode()
+      << " size=" << GetCodeSize();
+#endif
+}
+
 inline String* Class::GetName() const {
   return GetFieldObject<String*>(OFFSET_OF_OBJECT_MEMBER(Class, name_), false);
 }
diff --git a/src/thread.cc b/src/thread.cc
index b511aa7..629cb0f 100644
--- a/src/thread.cc
+++ b/src/thread.cc
@@ -1205,7 +1205,7 @@
 
   while (frame.GetSP() != NULL) {
     for ( ; frame.GetMethod() != NULL; frame.Next()) {
-      // DCHECK(frame.GetMethod()->IsWithinCode(pc));  // TODO: restore IsWithinCode
+      frame.GetMethod()->AssertPcIsWithinCode(pc);
       bool should_continue = visitor->VisitFrame(frame, pc);
       if (!should_continue) {
         return;