Add support for initializing static fields.
Change-Id: I1c5397e9ef03f4cef1646fa833e17d64fc586dce
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 4924810..8e43135 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -6,7 +6,9 @@
#include <vector>
#include <utility>
+#include "src/casts.h"
#include "src/dex_verifier.h"
+#include "src/heap.h"
#include "src/logging.h"
#include "src/monitor.h"
#include "src/object.h"
@@ -30,7 +32,7 @@
// No .dex file specified, search the class path.
dex_file = FindInClassPath(descriptor);
if (dex_file == NULL) {
- LG << "Class really not found";
+ LG << "Class " << descriptor << " really not found";
return NULL;
}
}
@@ -229,7 +231,7 @@
} else {
// JValue unused;
// TODO: dvmCallMethod(self, method, NULL, &unused);
- CHECK(!"unimplemented");
+ //CHECK(!"unimplemented");
}
{
@@ -357,10 +359,61 @@
}
void ClassLinker::InitializeStaticFields(Class* klass) {
- if (klass->NumStaticFields() == 0) {
+ size_t num_static_fields = klass->NumStaticFields();
+ if (num_static_fields == 0) {
return;
- } else {
- LOG(FATAL) << "Unimplemented";
+ }
+ DexFile* dex_file = klass->GetDexFile();
+ if (dex_file == NULL) {
+ return;
+ }
+ const char* descriptor = klass->GetDescriptor().data();
+ RawDexFile* raw = dex_file->GetRaw();
+ const RawDexFile::ClassDef* class_def = raw->FindClassDef(descriptor);
+ CHECK(class_def != NULL);
+ const byte* addr = raw->GetEncodedArray(*class_def);
+ size_t array_size = DecodeUnsignedLeb128(&addr);
+ for (size_t i = 0; i < array_size; ++i) {
+ StaticField* field = klass->GetStaticField(i);
+ JValue value;
+ RawDexFile::ValueType type = raw->ReadEncodedValue(&addr, &value);
+ switch (type) {
+ case RawDexFile::kByte:
+ field->SetByte(value.b);
+ break;
+ case RawDexFile::kShort:
+ field->SetShort(value.s);
+ break;
+ case RawDexFile::kChar:
+ field->SetChar(value.c);
+ break;
+ case RawDexFile::kInt:
+ field->SetInt(value.i);
+ break;
+ case RawDexFile::kLong:
+ field->SetLong(value.j);
+ break;
+ case RawDexFile::kFloat:
+ field->SetFloat(value.f);
+ break;
+ case RawDexFile::kDouble:
+ field->SetDouble(value.d);
+ break;
+ case RawDexFile::kString: {
+ uint32_t string_idx = value.i;
+ String* resolved = ResolveString(klass, string_idx);
+ field->SetObject(resolved);
+ break;
+ }
+ case RawDexFile::kBoolean:
+ field->SetBoolean(value.z);
+ break;
+ case RawDexFile::kNull:
+ field->SetObject(value.l);
+ break;
+ default:
+ LOG(FATAL) << "Unknown type " << type;
+ }
}
}
@@ -855,7 +908,7 @@
}
}
-Class* ClassLinker::ResolveClass(Class* referrer, uint32_t class_idx) {
+Class* ClassLinker::ResolveClass(const Class* referrer, uint32_t class_idx) {
DexFile* dex_file = referrer->GetDexFile();
Class* resolved = dex_file->GetResolvedClass(class_idx);
if (resolved != NULL) {
@@ -875,7 +928,7 @@
return NULL;
}
}
- dex_file->SetResolvedClass(class_idx, resolved);
+ dex_file->SetResolvedClass(resolved, class_idx);
} else {
CHECK(Thread::Self()->IsExceptionPending());
}
@@ -888,4 +941,14 @@
return NULL;
}
+String* ClassLinker::ResolveString(const Class* referring, uint32_t string_idx) {
+ const RawDexFile* raw = referring->GetDexFile()->GetRaw();
+ const RawDexFile::StringId& string_id = raw->GetStringId(string_idx);
+ const char* string_data = raw->GetStringData(string_id);
+ String* new_string = Heap::AllocStringFromModifiedUtf8(string_data);
+ // TODO: intern the new string
+ referring->GetDexFile()->SetResolvedString(new_string, string_idx);
+ return new_string;
+}
+
} // namespace art
diff --git a/src/class_linker.h b/src/class_linker.h
index 2021705..fec3cb1 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -29,7 +29,9 @@
Class* LookupClass(const char* descriptor, Object* class_loader);
- Class* ResolveClass(Class* klass, uint32_t idx);
+ Class* ResolveClass(const Class* referring, uint32_t class_idx);
+
+ String* ResolveString(const Class* referring, uint32_t string_idx);
DexFile* FindInClassPath(const char* descriptor);
diff --git a/src/dex_file.cc b/src/dex_file.cc
index 9526b5a..fcde266 100644
--- a/src/dex_file.cc
+++ b/src/dex_file.cc
@@ -110,7 +110,7 @@
for (size_t i = 0; i < klass->NumInstanceFields(); ++i) {
RawDexFile::Field raw_field;
raw_->dexReadClassDataField(&class_data, &raw_field, &last_idx);
- LoadField(klass, raw_field, &klass->ifields_[i]);
+ LoadField(klass, raw_field, klass->GetInstanceField(i));
}
}
@@ -177,7 +177,7 @@
// TODO: check for finalize method
- const RawDexFile::Code* code_item = raw_->GetCode(src);
+ const RawDexFile::CodeItem* code_item = raw_->GetCodeItem(src);
if (code_item != NULL) {
dst->num_registers_ = code_item->registers_size_;
dst->num_ins_ = code_item->ins_size_;
diff --git a/src/dex_file.h b/src/dex_file.h
index 07650c2..ae5101a 100644
--- a/src/dex_file.h
+++ b/src/dex_file.h
@@ -13,6 +13,7 @@
class Field;
class Method;
class String;
+union JValue;
class DexFile {
public:
@@ -51,11 +52,19 @@
return raw_.get();
}
+ String* GetResolvedString(uint32_t string_idx) const {
+ return strings_[string_idx];
+ }
+
+ void SetResolvedString(String* resolved, uint32_t string_idx) {
+ strings_[string_idx] = resolved;
+ }
+
Class* GetResolvedClass(uint32_t class_idx) const {
return classes_[class_idx];
}
- void SetResolvedClass(uint32_t class_idx, Class* resolved) {
+ void SetResolvedClass(Class* resolved, uint32_t class_idx) {
classes_[class_idx] = resolved;
}
diff --git a/src/heap.h b/src/heap.h
index 340e51c..c04a60f 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -12,10 +12,30 @@
class Heap {
public:
static Class* AllocClass(size_t size) {
- byte* raw = new byte[size];
- memset(raw, 0, size);
+ byte* raw = new byte[size]();
return reinterpret_cast<Class*>(raw);
}
+
+ static CharArray* AllocCharArray(size_t length) {
+ size_t size = sizeof(Array) + length * sizeof(uint16_t);
+ byte* raw = new byte[size]();
+ return reinterpret_cast<CharArray*>(raw);
+ }
+
+ static String* AllocString() {
+ size_t size = sizeof(String);
+ byte* raw = new byte[size]();
+ return reinterpret_cast<String*>(raw);
+ }
+
+ static String* AllocStringFromModifiedUtf8(const char* data) {
+ String* string = AllocString();
+ uint32_t count = strlen(data); // TODO
+ CharArray* array = AllocCharArray(count);
+ string->array_ = array;
+ string->count_ = count;
+ return string;
+ }
};
} // namespace art
diff --git a/src/object.h b/src/object.h
index 98e464a..8252de1 100644
--- a/src/object.h
+++ b/src/object.h
@@ -187,6 +187,10 @@
return signature_[0];
}
+ const char* GetSignature() const {
+ return signature_;
+ }
+
public: // TODO: private
// The class in which this field is declared.
Class* klass_;
@@ -224,6 +228,58 @@
// Static fields.
class StaticField : public Field {
+ public:
+ void SetBoolean(bool z) {
+ CHECK_EQ(GetType(), 'Z');
+ value_.z = z;
+ }
+
+ void SetByte(int8_t b) {
+ CHECK_EQ(GetType(), 'B');
+ value_.b = b;
+ }
+
+ void SetChar(uint16_t c) {
+ CHECK_EQ(GetType(), 'C');
+ value_.c = c;
+ }
+
+ void SetShort(uint16_t s) {
+ CHECK_EQ(GetType(), 'S');
+ value_.s = s;
+ }
+
+ void SetInt(int32_t i) {
+ CHECK_EQ(GetType(), 'I');
+ value_.i = i;
+ }
+
+ int64_t GetLong() {
+ CHECK_EQ(GetType(), 'J');
+ return value_.j;
+ }
+
+ void SetLong(int64_t j) {
+ CHECK_EQ(GetType(), 'J');
+ value_.j = j;
+ }
+
+ void SetFloat(float f) {
+ CHECK_EQ(GetType(), 'F');
+ value_.f = f;
+ }
+
+ void SetDouble(double d) {
+ CHECK_EQ(GetType(), 'D');
+ value_.d = d;
+ }
+
+ void SetObject(Object* l) {
+ CHECK_EQ(GetType(), 'L');
+ value_.l = l;
+ // TODO: write barrier
+ }
+
private:
JValue value_;
};
@@ -642,9 +698,22 @@
uint32_t fields_[1];
};
+class Array : public Object {
+ public:
+ void SetLength(uint32_t length) {
+ length_ = length;
+ }
+
+ private:
+ // The number of array elements.
+ uint32_t length_;
+};
+
+class CharArray : public Array {};
+
class String : public Object {
public:
- Array* array_;
+ CharArray* array_;
uint32_t hash_code_;
@@ -653,12 +722,6 @@
uint32_t count_;
};
-class Array : public Object {
- public:
- // The number of array elements.
- uint32_t length_;
-};
-
class InterfaceEntry {
public:
Class* GetClass() const {
diff --git a/src/raw_dex_file.cc b/src/raw_dex_file.cc
index 9994b9f..145509a 100644
--- a/src/raw_dex_file.cc
+++ b/src/raw_dex_file.cc
@@ -1,10 +1,6 @@
// Copyright 2011 Google Inc. All Rights Reserved.
-#include "src/base64.h"
-#include "src/globals.h"
-#include "src/logging.h"
#include "src/raw_dex_file.h"
-#include "src/scoped_ptr.h"
#include <errno.h>
#include <fcntl.h>
@@ -14,6 +10,13 @@
#include <sys/types.h>
#include <map>
+#include "src/base64.h"
+#include "src/globals.h"
+#include "src/logging.h"
+#include "src/object.h"
+#include "src/scoped_ptr.h"
+#include "src/utils.h"
+
namespace art {
const byte RawDexFile::kDexMagic[] = { 'd', 'e', 'x', '\n' };
@@ -162,4 +165,126 @@
}
}
+// Read a signed integer. "zwidth" is the zero-based byte count.
+static int32_t ReadSignedInt(const byte* ptr, int zwidth)
+{
+ int32_t val = 0;
+ for (int i = zwidth; i >= 0; --i) {
+ val = ((uint32_t)val >> 8) | (((int32_t)*ptr++) << 24);
+ }
+ val >>= (3 - zwidth) * 8;
+ return val;
+}
+
+// Read an unsigned integer. "zwidth" is the zero-based byte count,
+// "fill_on_right" indicates which side we want to zero-fill from.
+static uint32_t ReadUnsignedInt(const byte* ptr, int zwidth,
+ bool fill_on_right) {
+ uint32_t val = 0;
+ if (!fill_on_right) {
+ for (int i = zwidth; i >= 0; --i) {
+ val = (val >> 8) | (((uint32_t)*ptr++) << 24);
+ }
+ val >>= (3 - zwidth) * 8;
+ } else {
+ for (int i = zwidth; i >= 0; --i) {
+ val = (val >> 8) | (((uint32_t)*ptr++) << 24);
+ }
+ }
+ return val;
+}
+
+// Read a signed long. "zwidth" is the zero-based byte count.
+static int64_t ReadSignedLong(const byte* ptr, int zwidth) {
+ int64_t val = 0;
+ for (int i = zwidth; i >= 0; --i) {
+ val = ((uint64_t)val >> 8) | (((int64_t)*ptr++) << 56);
+ }
+ val >>= (7 - zwidth) * 8;
+ return val;
+}
+
+// Read an unsigned long. "zwidth" is the zero-based byte count,
+// "fill_on_right" indicates which side we want to zero-fill from.
+static uint64_t ReadUnsignedLong(const byte* ptr, int zwidth,
+ bool fill_on_right) {
+ uint64_t val = 0;
+ if (!fill_on_right) {
+ for (int i = zwidth; i >= 0; --i) {
+ val = (val >> 8) | (((uint64_t)*ptr++) << 56);
+ }
+ val >>= (7 - zwidth) * 8;
+ } else {
+ for (int i = zwidth; i >= 0; --i) {
+ val = (val >> 8) | (((uint64_t)*ptr++) << 56);
+ }
+ }
+ return val;
+}
+
+RawDexFile::ValueType RawDexFile::ReadEncodedValue(const byte** stream,
+ JValue* value) {
+ const byte* ptr = *stream;
+ byte value_type = *ptr++;
+ byte value_arg = value_type >> kEncodedValueArgShift;
+ size_t width = value_arg + 1; // assume and correct later
+ int type = value_type & kEncodedValueTypeMask;
+ switch (type) {
+ case RawDexFile::kByte: {
+ int32_t b = ReadSignedInt(ptr, value_arg);
+ CHECK(IsInt(8, b));
+ value->i = b;
+ break;
+ }
+ case RawDexFile::kShort: {
+ int32_t s = ReadSignedInt(ptr, value_arg);
+ CHECK(IsInt(16, s));
+ value->i = s;
+ break;
+ }
+ case RawDexFile::kChar: {
+ uint32_t c = ReadUnsignedInt(ptr, value_arg, false);
+ CHECK(IsUint(16, c));
+ value->i = c;
+ break;
+ }
+ case RawDexFile::kInt:
+ value->i = ReadSignedInt(ptr, value_arg);
+ break;
+ case RawDexFile::kLong:
+ value->j = ReadSignedLong(ptr, value_arg);
+ break;
+ case RawDexFile::kFloat:
+ value->i = ReadUnsignedInt(ptr, value_arg, true);
+ break;
+ case RawDexFile::kDouble:
+ value->j = ReadUnsignedLong(ptr, value_arg, true);
+ break;
+ case RawDexFile::kBoolean:
+ value->i = (value_arg != 0);
+ width = 0;
+ break;
+ case RawDexFile::kString:
+ case RawDexFile::kType:
+ case RawDexFile::kMethod:
+ case RawDexFile::kEnum:
+ value->i = ReadUnsignedInt(ptr, value_arg, false);
+ break;
+ case RawDexFile::kField:
+ case RawDexFile::kArray:
+ case RawDexFile::kAnnotation:
+ LOG(FATAL) << "Unimplemented";
+ break;
+ case RawDexFile::kNull:
+ value->i = 0;
+ width = 0;
+ break;
+ default:
+ LOG(FATAL) << "Unreached";
+ }
+ ptr += width;
+ *stream = ptr;
+ return static_cast<ValueType>(type);
+}
+
} // namespace art
diff --git a/src/raw_dex_file.h b/src/raw_dex_file.h
index 56b6ff6..afd65c2 100644
--- a/src/raw_dex_file.h
+++ b/src/raw_dex_file.h
@@ -13,15 +13,40 @@
namespace art {
+union JValue;
+
+// TODO: move all of the macro functionality into the DexFile class.
class RawDexFile {
public:
static const byte kDexMagic[];
static const byte kDexMagicVersion[];
static const size_t kSha1DigestSize = 20;
+ static const byte kEncodedValueTypeMask = 0x1f; // 0b11111
+ static const byte kEncodedValueArgShift = 5;
+
// The value of an invalid index.
static const uint32_t kDexNoIndex = 0xFFFFFFFF;
+ enum ValueType {
+ kByte = 0x00,
+ kShort = 0x02,
+ kChar = 0x03,
+ kInt = 0x04,
+ kLong = 0x06,
+ kFloat = 0x10,
+ kDouble = 0x11,
+ kString = 0x17,
+ kType = 0x18,
+ kField = 0x19,
+ kMethod = 0x1a,
+ kEnum = 0x1b,
+ kArray = 0x1c,
+ kAnnotation = 0x1d,
+ kNull = 0x1e,
+ kBoolean = 0x1f
+ };
+
// Raw header_item.
struct Header {
uint8_t magic_[8];
@@ -114,7 +139,7 @@
TypeItem list_[1]; // elements of the list
};
- class ParameterIterator {
+ class ParameterIterator { // TODO: stream
public:
ParameterIterator(const RawDexFile& raw, const ProtoId& proto_id)
: raw_(raw), size_(0), pos_(0) {
@@ -146,7 +171,7 @@
}
// Raw code_item.
- struct Code {
+ struct CodeItem {
uint16_t registers_size_;
uint16_t ins_size_;
uint16_t outs_size_;
@@ -310,12 +335,12 @@
}
}
- const Code* GetCode(const Method& method) const {
+ const CodeItem* GetCodeItem(const Method& method) const {
if (method.code_off_ == 0) {
return NULL; // native or abstract method
} else {
const byte* addr = base_ + method.code_off_;
- return reinterpret_cast<const Code*>(addr);
+ return reinterpret_cast<const CodeItem*>(addr);
}
}
@@ -334,11 +359,26 @@
}
}
+ const byte* GetEncodedArray(const ClassDef& class_def) const {
+ if (class_def.static_values_off_ == 0) {
+ return 0;
+ } else {
+ return base_ + class_def.static_values_off_;
+ }
+ }
+
+ int32_t GetStringLength(const StringId& string_id) const {
+ const byte* ptr = base_ + string_id.string_data_off_;
+ return DecodeUnsignedLeb128(&ptr);
+ }
+
+ ValueType ReadEncodedValue(const byte** encoded_value, JValue* value);
+
// From libdex...
// Returns a pointer to the UTF-8 string data referred to by the
// given string_id.
- const char* dexGetStringData(const StringId& string_id) const {
+ const char* GetStringData(const StringId& string_id) const {
const byte* ptr = base_ + string_id.string_data_off_;
// Skip the uleb128 length.
while (*(ptr++) > 0x7f) /* empty */ ;
@@ -348,7 +388,7 @@
// return the UTF-8 encoded string with the specified string_id index
const char* dexStringById(uint32_t idx) const {
const StringId& string_id = GetStringId(idx);
- return dexGetStringData(string_id);
+ return GetStringData(string_id);
}
// Get the descriptor string associated with a given type index.