summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dex2oat/dex2oat_test.cc3
-rw-r--r--dexlayout/dex_ir.cc78
-rw-r--r--dexlayout/dex_ir.h72
-rw-r--r--dexlayout/dex_ir_builder.cc10
-rw-r--r--dexlayout/dex_writer.cc43
-rw-r--r--dexlayout/dex_writer.h2
-rw-r--r--runtime/common_runtime_test.h6
-rw-r--r--runtime/dex_file.h4
-rw-r--r--runtime/runtime_callbacks_test.cc3
9 files changed, 215 insertions, 6 deletions
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index d546072f58..6420aa8759 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -430,6 +430,9 @@ class Dex2oatSwapUseTest : public Dex2oatSwapTest {
};
TEST_F(Dex2oatSwapUseTest, CheckSwapUsage) {
+ // Native memory usage isn't correctly tracked under sanitization.
+ TEST_DISABLED_FOR_MEMORY_TOOL_ASAN();
+
// The `native_alloc_2_ >= native_alloc_1_` assertion below may not
// hold true on some x86 systems; disable this test while we
// investigate (b/29259363).
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index f1c6f67a7c..cf453b9a16 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -281,6 +281,16 @@ void Collections::ReadEncodedValue(
item->SetDouble(conv.d);
break;
}
+ case DexFile::kDexAnnotationMethodType: {
+ const uint32_t proto_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+ item->SetProtoId(GetProtoId(proto_index));
+ break;
+ }
+ case DexFile::kDexAnnotationMethodHandle: {
+ const uint32_t method_handle_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+ item->SetMethodHandle(GetMethodHandle(method_handle_index));
+ break;
+ }
case DexFile::kDexAnnotationString: {
const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
item->SetStringId(GetStringId(string_index));
@@ -766,6 +776,64 @@ ClassData* Collections::CreateClassData(
return class_data;
}
+void Collections::CreateCallSitesAndMethodHandles(const DexFile& dex_file) {
+ // Iterate through the map list and set the offset of the CallSiteIds and MethodHandleItems.
+ const DexFile::MapList* map =
+ reinterpret_cast<const DexFile::MapList*>(dex_file.Begin() + MapListOffset());
+ for (uint32_t i = 0; i < map->size_; ++i) {
+ const DexFile::MapItem* item = map->list_ + i;
+ switch (item->type_) {
+ case DexFile::kDexTypeCallSiteIdItem:
+ SetCallSiteIdsOffset(item->offset_);
+ break;
+ case DexFile::kDexTypeMethodHandleItem:
+ SetMethodHandleItemsOffset(item->offset_);
+ break;
+ default:
+ break;
+ }
+ }
+ // Populate MethodHandleItems first (CallSiteIds may depend on them).
+ for (uint32_t i = 0; i < dex_file.NumMethodHandles(); i++) {
+ CreateMethodHandleItem(dex_file, i);
+ }
+ // Populate CallSiteIds.
+ for (uint32_t i = 0; i < dex_file.NumCallSiteIds(); i++) {
+ CreateCallSiteId(dex_file, i);
+ }
+}
+
+void Collections::CreateCallSiteId(const DexFile& dex_file, uint32_t i) {
+ const DexFile::CallSiteIdItem& disk_call_site_id = dex_file.GetCallSiteId(i);
+ const uint8_t* disk_call_item_ptr = dex_file.Begin() + disk_call_site_id.data_off_;
+ EncodedArrayItem* call_site_item =
+ CreateEncodedArrayItem(disk_call_item_ptr, disk_call_site_id.data_off_);
+
+ CallSiteId* call_site_id = new CallSiteId(call_site_item);
+ call_site_ids_.AddIndexedItem(call_site_id, CallSiteIdsOffset() + i * CallSiteId::ItemSize(), i);
+}
+
+void Collections::CreateMethodHandleItem(const DexFile& dex_file, uint32_t i) {
+ const DexFile::MethodHandleItem& disk_method_handle = dex_file.GetMethodHandle(i);
+ uint16_t index = disk_method_handle.field_or_method_idx_;
+ DexFile::MethodHandleType type =
+ static_cast<DexFile::MethodHandleType>(disk_method_handle.method_handle_type_);
+ bool is_invoke = type == DexFile::MethodHandleType::kInvokeStatic ||
+ type == DexFile::MethodHandleType::kInvokeInstance ||
+ type == DexFile::MethodHandleType::kInvokeConstructor;
+ static_assert(DexFile::MethodHandleType::kLast == DexFile::MethodHandleType::kInvokeConstructor,
+ "Unexpected method handle types.");
+ IndexedItem* field_or_method_id;
+ if (is_invoke) {
+ field_or_method_id = GetMethodId(index);
+ } else {
+ field_or_method_id = GetFieldId(index);
+ }
+ MethodHandleItem* method_handle = new MethodHandleItem(type, field_or_method_id);
+ method_handle_items_.AddIndexedItem(
+ method_handle, MethodHandleItemsOffset() + i * MethodHandleItem::ItemSize(), i);
+}
+
static uint32_t HeaderOffset(const dex_ir::Collections& collections ATTRIBUTE_UNUSED) {
return 0;
}
@@ -823,6 +891,16 @@ static const FileSectionDescriptor kFileSectionDescriptors[] = {
&dex_ir::Collections::ClassDefsSize,
&dex_ir::Collections::ClassDefsOffset
}, {
+ "CallSiteId",
+ DexFile::kDexTypeCallSiteIdItem,
+ &dex_ir::Collections::CallSiteIdsSize,
+ &dex_ir::Collections::CallSiteIdsOffset
+ }, {
+ "MethodHandle",
+ DexFile::kDexTypeMethodHandleItem,
+ &dex_ir::Collections::MethodHandleItemsSize,
+ &dex_ir::Collections::MethodHandleItemsOffset
+ }, {
"StringData",
DexFile::kDexTypeStringDataItem,
&dex_ir::Collections::StringDatasSize,
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index cad039550a..5692eb2b39 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -35,6 +35,7 @@ class AnnotationItem;
class AnnotationsDirectoryItem;
class AnnotationSetItem;
class AnnotationSetRefList;
+class CallSiteId;
class ClassData;
class ClassDef;
class CodeItem;
@@ -47,6 +48,7 @@ class FieldItem;
class Header;
class MapList;
class MapItem;
+class MethodHandleItem;
class MethodId;
class MethodItem;
class ParameterAnnotation;
@@ -65,6 +67,8 @@ static constexpr size_t kProtoIdItemSize = 12;
static constexpr size_t kFieldIdItemSize = 8;
static constexpr size_t kMethodIdItemSize = 8;
static constexpr size_t kClassDefItemSize = 32;
+static constexpr size_t kCallSiteIdItemSize = 4;
+static constexpr size_t kMethodHandleItemSize = 8;
// Visitor support
class AbstractDispatcher {
@@ -79,6 +83,8 @@ class AbstractDispatcher {
virtual void Dispatch(const ProtoId* proto_id) = 0;
virtual void Dispatch(const FieldId* field_id) = 0;
virtual void Dispatch(const MethodId* method_id) = 0;
+ virtual void Dispatch(const CallSiteId* call_site_id) = 0;
+ virtual void Dispatch(const MethodHandleItem* method_handle_item) = 0;
virtual void Dispatch(ClassData* class_data) = 0;
virtual void Dispatch(ClassDef* class_def) = 0;
virtual void Dispatch(FieldItem* field_item) = 0;
@@ -165,6 +171,9 @@ class Collections {
std::vector<std::unique_ptr<FieldId>>& FieldIds() { return field_ids_.Collection(); }
std::vector<std::unique_ptr<MethodId>>& MethodIds() { return method_ids_.Collection(); }
std::vector<std::unique_ptr<ClassDef>>& ClassDefs() { return class_defs_.Collection(); }
+ std::vector<std::unique_ptr<CallSiteId>>& CallSiteIds() { return call_site_ids_.Collection(); }
+ std::vector<std::unique_ptr<MethodHandleItem>>& MethodHandleItems()
+ { return method_handle_items_.Collection(); }
std::map<uint32_t, std::unique_ptr<StringData>>& StringDatas()
{ return string_datas_.Collection(); }
std::map<uint32_t, std::unique_ptr<TypeList>>& TypeLists() { return type_lists_.Collection(); }
@@ -189,6 +198,10 @@ class Collections {
void CreateFieldId(const DexFile& dex_file, uint32_t i);
void CreateMethodId(const DexFile& dex_file, uint32_t i);
void CreateClassDef(const DexFile& dex_file, uint32_t i);
+ void CreateCallSiteId(const DexFile& dex_file, uint32_t i);
+ void CreateMethodHandleItem(const DexFile& dex_file, uint32_t i);
+
+ void CreateCallSitesAndMethodHandles(const DexFile& dex_file);
TypeList* CreateTypeList(const DexFile::TypeList* type_list, uint32_t offset);
EncodedArrayItem* CreateEncodedArrayItem(const uint8_t* static_data, uint32_t offset);
@@ -207,6 +220,8 @@ class Collections {
FieldId* GetFieldId(uint32_t index) { return FieldIds()[index].get(); }
MethodId* GetMethodId(uint32_t index) { return MethodIds()[index].get(); }
ClassDef* GetClassDef(uint32_t index) { return ClassDefs()[index].get(); }
+ CallSiteId* GetCallSiteId(uint32_t index) { return CallSiteIds()[index].get(); }
+ MethodHandleItem* GetMethodHandle(uint32_t index) { return MethodHandleItems()[index].get(); }
StringId* GetStringIdOrNullPtr(uint32_t index) {
return index == DexFile::kDexNoIndex ? nullptr : GetStringId(index);
@@ -221,6 +236,8 @@ class Collections {
uint32_t FieldIdsOffset() const { return field_ids_.GetOffset(); }
uint32_t MethodIdsOffset() const { return method_ids_.GetOffset(); }
uint32_t ClassDefsOffset() const { return class_defs_.GetOffset(); }
+ uint32_t CallSiteIdsOffset() const { return call_site_ids_.GetOffset(); }
+ uint32_t MethodHandleItemsOffset() const { return method_handle_items_.GetOffset(); }
uint32_t StringDatasOffset() const { return string_datas_.GetOffset(); }
uint32_t TypeListsOffset() const { return type_lists_.GetOffset(); }
uint32_t EncodedArrayItemsOffset() const { return encoded_array_items_.GetOffset(); }
@@ -240,6 +257,9 @@ class Collections {
void SetFieldIdsOffset(uint32_t new_offset) { field_ids_.SetOffset(new_offset); }
void SetMethodIdsOffset(uint32_t new_offset) { method_ids_.SetOffset(new_offset); }
void SetClassDefsOffset(uint32_t new_offset) { class_defs_.SetOffset(new_offset); }
+ void SetCallSiteIdsOffset(uint32_t new_offset) { call_site_ids_.SetOffset(new_offset); }
+ void SetMethodHandleItemsOffset(uint32_t new_offset)
+ { method_handle_items_.SetOffset(new_offset); }
void SetStringDatasOffset(uint32_t new_offset) { string_datas_.SetOffset(new_offset); }
void SetTypeListsOffset(uint32_t new_offset) { type_lists_.SetOffset(new_offset); }
void SetEncodedArrayItemsOffset(uint32_t new_offset)
@@ -262,6 +282,8 @@ class Collections {
uint32_t FieldIdsSize() const { return field_ids_.Size(); }
uint32_t MethodIdsSize() const { return method_ids_.Size(); }
uint32_t ClassDefsSize() const { return class_defs_.Size(); }
+ uint32_t CallSiteIdsSize() const { return call_site_ids_.Size(); }
+ uint32_t MethodHandleItemsSize() const { return method_handle_items_.Size(); }
uint32_t StringDatasSize() const { return string_datas_.Size(); }
uint32_t TypeListsSize() const { return type_lists_.Size(); }
uint32_t EncodedArrayItemsSize() const { return encoded_array_items_.Size(); }
@@ -288,6 +310,8 @@ class Collections {
CollectionVector<FieldId> field_ids_;
CollectionVector<MethodId> method_ids_;
CollectionVector<ClassDef> class_defs_;
+ CollectionVector<CallSiteId> call_site_ids_;
+ CollectionVector<MethodHandleItem> method_handle_items_;
CollectionMap<StringData> string_datas_;
CollectionMap<TypeList> type_lists_;
@@ -603,8 +627,10 @@ class EncodedValue {
void SetDouble(double d) { u_.double_val_ = d; }
void SetStringId(StringId* string_id) { u_.string_val_ = string_id; }
void SetTypeId(TypeId* type_id) { u_.type_val_ = type_id; }
+ void SetProtoId(ProtoId* proto_id) { u_.proto_val_ = proto_id; }
void SetFieldId(FieldId* field_id) { u_.field_val_ = field_id; }
void SetMethodId(MethodId* method_id) { u_.method_val_ = method_id; }
+ void SetMethodHandle(MethodHandleItem* method_handle) { u_.method_handle_val_ = method_handle; }
void SetEncodedArray(EncodedArrayItem* encoded_array) { encoded_array_.reset(encoded_array); }
void SetEncodedAnnotation(EncodedAnnotation* encoded_annotation)
{ encoded_annotation_.reset(encoded_annotation); }
@@ -619,8 +645,10 @@ class EncodedValue {
double GetDouble() const { return u_.double_val_; }
StringId* GetStringId() const { return u_.string_val_; }
TypeId* GetTypeId() const { return u_.type_val_; }
+ ProtoId* GetProtoId() const { return u_.proto_val_; }
FieldId* GetFieldId() const { return u_.field_val_; }
MethodId* GetMethodId() const { return u_.method_val_; }
+ MethodHandleItem* GetMethodHandle() const { return u_.method_handle_val_; }
EncodedArrayItem* GetEncodedArray() const { return encoded_array_.get(); }
EncodedAnnotation* GetEncodedAnnotation() const { return encoded_annotation_.get(); }
@@ -639,8 +667,10 @@ class EncodedValue {
double double_val_;
StringId* string_val_;
TypeId* type_val_;
+ ProtoId* proto_val_;
FieldId* field_val_;
MethodId* method_val_;
+ MethodHandleItem* method_handle_val_;
} u_;
std::unique_ptr<EncodedArrayItem> encoded_array_;
std::unique_ptr<EncodedAnnotation> encoded_annotation_;
@@ -1087,6 +1117,48 @@ class AnnotationsDirectoryItem : public Item {
DISALLOW_COPY_AND_ASSIGN(AnnotationsDirectoryItem);
};
+class CallSiteId : public IndexedItem {
+ public:
+ explicit CallSiteId(EncodedArrayItem* call_site_item) : call_site_item_(call_site_item) {
+ size_ = kCallSiteIdItemSize;
+ }
+ ~CallSiteId() OVERRIDE { }
+
+ static size_t ItemSize() { return kCallSiteIdItemSize; }
+
+ EncodedArrayItem* CallSiteItem() const { return call_site_item_; }
+
+ void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); }
+
+ private:
+ EncodedArrayItem* call_site_item_;
+
+ DISALLOW_COPY_AND_ASSIGN(CallSiteId);
+};
+
+class MethodHandleItem : public IndexedItem {
+ public:
+ MethodHandleItem(DexFile::MethodHandleType method_handle_type, IndexedItem* field_or_method_id)
+ : method_handle_type_(method_handle_type),
+ field_or_method_id_(field_or_method_id) {
+ size_ = kMethodHandleItemSize;
+ }
+ ~MethodHandleItem() OVERRIDE { }
+
+ static size_t ItemSize() { return kMethodHandleItemSize; }
+
+ DexFile::MethodHandleType GetMethodHandleType() const { return method_handle_type_; }
+ IndexedItem* GetFieldOrMethodId() const { return field_or_method_id_; }
+
+ void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); }
+
+ private:
+ DexFile::MethodHandleType method_handle_type_;
+ IndexedItem* field_or_method_id_;
+
+ DISALLOW_COPY_AND_ASSIGN(MethodHandleItem);
+};
+
// TODO(sehr): implement MapList.
class MapList : public Item {
public:
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
index d0c5bf964e..8eb726a64a 100644
--- a/dexlayout/dex_ir_builder.cc
+++ b/dexlayout/dex_ir_builder.cc
@@ -72,6 +72,8 @@ Header* DexIrBuilder(const DexFile& dex_file) {
}
// MapItem.
collections.SetMapListOffset(disk_header.map_off_);
+ // CallSiteIds and MethodHandleItems.
+ collections.CreateCallSitesAndMethodHandles(dex_file);
CheckAndSetRemainingOffsets(dex_file, &collections);
@@ -115,6 +117,14 @@ static void CheckAndSetRemainingOffsets(const DexFile& dex_file, Collections* co
CHECK_EQ(item->size_, collections->ClassDefsSize());
CHECK_EQ(item->offset_, collections->ClassDefsOffset());
break;
+ case DexFile::kDexTypeCallSiteIdItem:
+ CHECK_EQ(item->size_, collections->CallSiteIdsSize());
+ CHECK_EQ(item->offset_, collections->CallSiteIdsOffset());
+ break;
+ case DexFile::kDexTypeMethodHandleItem:
+ CHECK_EQ(item->size_, collections->MethodHandleItemsSize());
+ CHECK_EQ(item->offset_, collections->MethodHandleItemsOffset());
+ break;
case DexFile::kDexTypeMapList:
CHECK_EQ(item->size_, 1u);
CHECK_EQ(item->offset_, disk_header.map_off_);
diff --git a/dexlayout/dex_writer.cc b/dexlayout/dex_writer.cc
index 7ffa38bfd4..e1b828ca52 100644
--- a/dexlayout/dex_writer.cc
+++ b/dexlayout/dex_writer.cc
@@ -151,6 +151,12 @@ size_t DexWriter::WriteEncodedValue(dex_ir::EncodedValue* encoded_value, size_t
length = EncodeDoubleValue(encoded_value->GetDouble(), buffer);
start = 8 - length;
break;
+ case DexFile::kDexAnnotationMethodType:
+ length = EncodeUIntValue(encoded_value->GetProtoId()->GetIndex(), buffer);
+ break;
+ case DexFile::kDexAnnotationMethodHandle:
+ length = EncodeUIntValue(encoded_value->GetMethodHandle()->GetIndex(), buffer);
+ break;
case DexFile::kDexAnnotationString:
length = EncodeUIntValue(encoded_value->GetStringId()->GetIndex(), buffer);
break;
@@ -485,6 +491,27 @@ void DexWriter::WriteClasses() {
}
}
+void DexWriter::WriteCallSites() {
+ uint32_t call_site_off[1];
+ for (std::unique_ptr<dex_ir::CallSiteId>& call_site_id :
+ header_->GetCollections().CallSiteIds()) {
+ call_site_off[0] = call_site_id->CallSiteItem()->GetOffset();
+ Write(call_site_off, call_site_id->GetSize(), call_site_id->GetOffset());
+ }
+}
+
+void DexWriter::WriteMethodHandles() {
+ uint16_t method_handle_buff[4];
+ for (std::unique_ptr<dex_ir::MethodHandleItem>& method_handle :
+ header_->GetCollections().MethodHandleItems()) {
+ method_handle_buff[0] = static_cast<uint16_t>(method_handle->GetMethodHandleType());
+ method_handle_buff[1] = 0; // unused.
+ method_handle_buff[2] = method_handle->GetFieldOrMethodId()->GetIndex();
+ method_handle_buff[3] = 0; // unused.
+ Write(method_handle_buff, method_handle->GetSize(), method_handle->GetOffset());
+ }
+}
+
struct MapItemContainer {
MapItemContainer(uint32_t type, uint32_t size, uint32_t offset)
: type_(type), size_(size), offset_(offset) { }
@@ -528,6 +555,14 @@ void DexWriter::WriteMapItem() {
queue.push(MapItemContainer(DexFile::kDexTypeClassDefItem, collection.ClassDefsSize(),
collection.ClassDefsOffset()));
}
+ if (collection.CallSiteIdsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeCallSiteIdItem, collection.CallSiteIdsSize(),
+ collection.CallSiteIdsOffset()));
+ }
+ if (collection.MethodHandleItemsSize() != 0) {
+ queue.push(MapItemContainer(DexFile::kDexTypeMethodHandleItem,
+ collection.MethodHandleItemsSize(), collection.MethodHandleItemsOffset()));
+ }
// Data section.
queue.push(MapItemContainer(DexFile::kDexTypeMapList, 1, collection.MapListOffset()));
@@ -618,10 +653,8 @@ void DexWriter::WriteHeader() {
uint32_t class_defs_off = collections.ClassDefsOffset();
buffer[16] = class_defs_size;
buffer[17] = class_defs_off;
- uint32_t data_off = class_defs_off + class_defs_size * dex_ir::ClassDef::ItemSize();
- uint32_t data_size = file_size - data_off;
- buffer[18] = data_size;
- buffer[19] = data_off;
+ buffer[18] = header_->DataSize();
+ buffer[19] = header_->DataOffset();
Write(buffer, 20 * sizeof(uint32_t), offset);
}
@@ -640,6 +673,8 @@ void DexWriter::WriteMemMap() {
WriteDebugInfoItems();
WriteCodeItems();
WriteClasses();
+ WriteCallSites();
+ WriteMethodHandles();
WriteMapItem();
WriteHeader();
}
diff --git a/dexlayout/dex_writer.h b/dexlayout/dex_writer.h
index fb76e5ccfc..b396adf126 100644
--- a/dexlayout/dex_writer.h
+++ b/dexlayout/dex_writer.h
@@ -59,6 +59,8 @@ class DexWriter {
void WriteDebugInfoItems();
void WriteCodeItems();
void WriteClasses();
+ void WriteCallSites();
+ void WriteMethodHandles();
void WriteMapItem();
void WriteHeader();
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 56e8aa3685..a29cc6cd38 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -249,6 +249,12 @@ class CheckJniAbortCatcher {
return; \
}
+#define TEST_DISABLED_FOR_MEMORY_TOOL_ASAN() \
+ if (RUNNING_ON_MEMORY_TOOL > 0 && !kMemoryToolIsValgrind) { \
+ printf("WARNING: TEST DISABLED FOR MEMORY TOOL ASAN\n"); \
+ return; \
+ }
+
} // namespace art
namespace std {
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 1b18d21cb1..36c734197a 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -92,8 +92,8 @@ class DexFile {
uint32_t method_ids_off_; // file offset of MethodIds array
uint32_t class_defs_size_; // number of ClassDefs
uint32_t class_defs_off_; // file offset of ClassDef array
- uint32_t data_size_; // unused
- uint32_t data_off_; // unused
+ uint32_t data_size_; // size of data section
+ uint32_t data_off_; // file offset of data section
// Decode the dex magic version
uint32_t GetVersion() const;
diff --git a/runtime/runtime_callbacks_test.cc b/runtime/runtime_callbacks_test.cc
index abe99e0d50..640f9ce848 100644
--- a/runtime/runtime_callbacks_test.cc
+++ b/runtime/runtime_callbacks_test.cc
@@ -335,6 +335,9 @@ class RuntimeSigQuitCallbackRuntimeCallbacksTest : public RuntimeCallbacksTest {
};
TEST_F(RuntimeSigQuitCallbackRuntimeCallbacksTest, SigQuit) {
+ // SigQuit induces a dump. ASAN isn't happy with libunwind reading memory.
+ TEST_DISABLED_FOR_MEMORY_TOOL_ASAN();
+
// The runtime needs to be started for the signal handler.
Thread* self = Thread::Current();