Implement JNI NewBooleanArray et cetera.
(Primitive types only. NewObjectArray to come...)
Change-Id: I2f54031d96062d666089c91ba40e16028ae21bd4
diff --git a/src/class_linker.cc b/src/class_linker.cc
index 50b1a07..3437a5a 100644
--- a/src/class_linker.cc
+++ b/src/class_linker.cc
@@ -27,7 +27,7 @@
}
void ClassLinker::Init(const std::vector<DexFile*>& boot_class_path) {
- init_done_ = false;
+ CHECK(!init_done_);
// java_lang_Class comes first, its needed for AllocClass
Class* java_lang_Class = down_cast<Class*>(Heap::AllocObject(NULL, sizeof(Class)));
@@ -61,14 +61,17 @@
Class* char_array_class = AllocClass(java_lang_Class);
CHECK(char_array_class != NULL);
char_array_class->descriptor_ = "[C";
+ CharArray::SetArrayClass(char_array_class);
// int[] and long[] are used for static field storage
Class* int_array_class = AllocClass(java_lang_Class);
CHECK(int_array_class != NULL);
int_array_class->descriptor_ = "[I";
+ IntArray::SetArrayClass(int_array_class);
Class* long_array_class = AllocClass(java_lang_Class);
CHECK(long_array_class != NULL);
long_array_class->descriptor_ = "[J";
+ LongArray::SetArrayClass(long_array_class);
// Field and Method are necessary so that FindClass can link members
Class* java_lang_reflect_Field = AllocClass(java_lang_Class);
@@ -95,7 +98,7 @@
class_roots_->Set(kJavaLangReflectMethod, java_lang_reflect_Method);
// now that these are registered, we can use AllocClass() and AllocObjectArray
- String::InitClasses(java_lang_String, char_array_class);
+ String::InitClasses(java_lang_String);
// Now AllocString* can be used
// setup boot_class_path_ now that we can use AllocObjectArray to
@@ -172,6 +175,7 @@
CHECK_EQ(java_io_Serializable, object_array_class->GetInterface(1));
// Setup the primitive type classes.
+ class_roots_->Set(kPrimitiveBoolean, CreatePrimitiveClass("Z"));
class_roots_->Set(kPrimitiveByte, CreatePrimitiveClass("B"));
class_roots_->Set(kPrimitiveChar, CreatePrimitiveClass("C"));
class_roots_->Set(kPrimitiveDouble, CreatePrimitiveClass("D"));
@@ -179,7 +183,6 @@
class_roots_->Set(kPrimitiveInt, CreatePrimitiveClass("I"));
class_roots_->Set(kPrimitiveLong, CreatePrimitiveClass("J"));
class_roots_->Set(kPrimitiveShort, CreatePrimitiveClass("S"));
- class_roots_->Set(kPrimitiveBoolean, CreatePrimitiveClass("Z"));
class_roots_->Set(kPrimitiveVoid, CreatePrimitiveClass("V"));
// now we can use FindSystemClass for anything, including for "[C"
@@ -191,6 +194,19 @@
Class* found_long_array_class = FindSystemClass("[J");
CHECK_EQ(long_array_class, found_long_array_class);
+ // Initialize all the other primitive array types for PrimitiveArray::Alloc.
+ // These are easy because everything we need has already been set up.
+ class_roots_->Set(kBooleanArrayClass, FindSystemClass("[Z"));
+ class_roots_->Set(kByteArrayClass, FindSystemClass("[B"));
+ class_roots_->Set(kDoubleArrayClass, FindSystemClass("[D"));
+ class_roots_->Set(kFloatArrayClass, FindSystemClass("[F"));
+ class_roots_->Set(kShortArrayClass, FindSystemClass("[S"));
+ BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass));
+ ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass));
+ DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass));
+ FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass));
+ ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass));
+
// ensure all class_roots_ were initialized
for (size_t i = 0; i < kClassRootsMax; i++) {
CHECK(GetClassRoot(static_cast<ClassRoot>(i)));
@@ -1378,12 +1394,10 @@
klass->static_references_ = ObjectArray<Object>::Alloc(array_class, next_reference_slot);
}
if (next_32bit_primitive_slot > 0) {
- Class* array_class = GetClassRoot(kIntArrayClass);
- klass->static_32bit_primitives_ = IntArray::Alloc(array_class, next_32bit_primitive_slot);
+ klass->static_32bit_primitives_ = IntArray::Alloc(next_32bit_primitive_slot);
}
if (next_64bit_primitive_slot > 0) {
- Class* array_class = GetClassRoot(kLongArrayClass);
- klass->static_64bit_primitives_ = LongArray::Alloc(array_class, next_64bit_primitive_slot);
+ klass->static_64bit_primitives_ = LongArray::Alloc(next_64bit_primitive_slot);
}
return true;
diff --git a/src/class_linker.h b/src/class_linker.h
index fa50537..b2b4c95 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -31,6 +31,8 @@
Class* FindClass(const StringPiece& descriptor,
ClassLoader* class_loader);
+ Class* FindPrimitiveClass(char type);
+
Class* FindSystemClass(const StringPiece& descriptor) {
return FindClass(descriptor, NULL);
}
@@ -42,8 +44,9 @@
void VisitRoots(Heap::RootVistor* root_visitor, void* arg);
private:
- ClassLinker() {
- classes_lock_ = Mutex::Create("ClassLinker::Lock");
+ ClassLinker()
+ : classes_lock_(Mutex::Create("ClassLinker::Lock")),
+ init_done_(false) {
}
void Init(const std::vector<DexFile*>& boot_class_path_);
@@ -69,8 +72,6 @@
Class* CreateArrayClass(const StringPiece& descriptor,
ClassLoader* class_loader);
- Class* FindPrimitiveClass(char type);
-
const DexFile& FindDexFile(const DexCache* dex_cache) const;
DexCache* FindDexCache(const DexFile* dex_file) const;
@@ -165,23 +166,28 @@
kJavaLangObject,
kObjectArrayClass,
kJavaLangString,
- kCharArrayClass,
- kIntArrayClass,
- kLongArrayClass,
kJavaLangReflectField,
kJavaLangReflectMethod,
kJavaLangClassLoader,
kDalvikSystemBaseDexClassLoader,
kDalvikSystemPathClassLoader,
kPrimitiveBoolean,
- kPrimitiveChar,
- kPrimitiveFloat,
- kPrimitiveDouble,
kPrimitiveByte,
- kPrimitiveShort,
+ kPrimitiveChar,
+ kPrimitiveDouble,
+ kPrimitiveFloat,
kPrimitiveInt,
kPrimitiveLong,
+ kPrimitiveShort,
kPrimitiveVoid,
+ kBooleanArrayClass,
+ kByteArrayClass,
+ kCharArrayClass,
+ kDoubleArrayClass,
+ kFloatArrayClass,
+ kIntArrayClass,
+ kLongArrayClass,
+ kShortArrayClass,
kClassRootsMax,
};
ObjectArray<Class>* class_roots_;
diff --git a/src/class_linker_test.cc b/src/class_linker_test.cc
index 25b03b2..683310d 100644
--- a/src/class_linker_test.cc
+++ b/src/class_linker_test.cc
@@ -372,8 +372,8 @@
}
TEST_F(ClassLinkerTest, ValidatePrimitiveArrayElementsOffset) {
- Class* array_class = class_linker_->FindSystemClass("[J");
- LongArray* array = LongArray::Alloc(array_class, 0);
+ LongArray* array = LongArray::Alloc(0);
+ EXPECT_EQ(class_linker_->FindSystemClass("[J"), array->GetClass());
uint32_t array_offset = reinterpret_cast<uint32_t>(array);
uint32_t data_offset = reinterpret_cast<uint32_t>(array->GetData());
EXPECT_EQ(16U, data_offset - array_offset);
diff --git a/src/image_writer.cc b/src/image_writer.cc
index 0014724..6ac5803 100644
--- a/src/image_writer.cc
+++ b/src/image_writer.cc
@@ -22,7 +22,7 @@
}
CalculateNewObjectOffsets();
CopyAndFixupObjects();
-
+
scoped_ptr<File> file(OS::OpenBinaryFile(filename, true));
if (file == NULL) {
return false;
@@ -72,7 +72,7 @@
DCHECK(obj != NULL);
DCHECK(arg != NULL);
ImageWriter* image_writer = reinterpret_cast<ImageWriter*>(arg);
-
+
size_t offset = image_writer->GetImageOffset(obj);
byte* dst = image_writer->mem_map_->GetAddress() + offset;
byte* src = reinterpret_cast<byte*>(obj);
@@ -96,7 +96,7 @@
}
void ImageWriter::FixupObjectArray(ObjectArray<Object>* orig, ObjectArray<Object>* copy) {
- for (size_t i = 0; i < orig->GetLength(); ++i) {
+ for (int32_t i = 0; i < orig->GetLength(); ++i) {
const Object* element = orig->Get(i);
copy->Set(i, GetImageAddress(element));
}
diff --git a/src/jni_internal.cc b/src/jni_internal.cc
index 23c8273..0e9cb84 100644
--- a/src/jni_internal.cc
+++ b/src/jni_internal.cc
@@ -79,7 +79,7 @@
return true;
}
-static byte* CreateArgArray(Method* method, va_list ap) {
+byte* CreateArgArray(Method* method, va_list ap) {
size_t num_bytes = method->NumArgArrayBytes();
scoped_array<byte> arg_array(new byte[num_bytes]);
const StringPiece& shorty = method->GetShorty();
@@ -117,7 +117,7 @@
return arg_array.release();
}
-static byte* CreateArgArray(Method* method, jvalue* args) {
+byte* CreateArgArray(Method* method, jvalue* args) {
size_t num_bytes = method->NumArgArrayBytes();
scoped_array<byte> arg_array(new byte[num_bytes]);
const StringPiece& shorty = method->GetShorty();
@@ -1301,52 +1301,52 @@
UNIMPLEMENTED(FATAL);
}
+template<typename JniT, typename ArtT>
+JniT NewPrimitiveArray(ScopedJniThreadState& ts, jsize length) {
+ CHECK_GE(length, 0); // TODO: ReportJniError
+ ArtT* result = ArtT::Alloc(length);
+ // TODO: local reference
+ return reinterpret_cast<JniT>(result);
+}
+
jbooleanArray NewBooleanArray(JNIEnv* env, jsize len) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return NewPrimitiveArray<jbooleanArray, BooleanArray>(ts, len);
}
jbyteArray NewByteArray(JNIEnv* env, jsize len) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return NewPrimitiveArray<jbyteArray, ByteArray>(ts, len);
}
jcharArray NewCharArray(JNIEnv* env, jsize len) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jshortArray NewShortArray(JNIEnv* env, jsize len) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jintArray NewIntArray(JNIEnv* env, jsize len) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jlongArray NewLongArray(JNIEnv* env, jsize len) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
-}
-
-jfloatArray NewFloatArray(JNIEnv* env, jsize len) {
- ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return NewPrimitiveArray<jcharArray, CharArray>(ts, len);
}
jdoubleArray NewDoubleArray(JNIEnv* env, jsize len) {
ScopedJniThreadState ts(env);
- UNIMPLEMENTED(FATAL);
- return NULL;
+ return NewPrimitiveArray<jdoubleArray, DoubleArray>(ts, len);
+}
+
+jfloatArray NewFloatArray(JNIEnv* env, jsize len) {
+ ScopedJniThreadState ts(env);
+ return NewPrimitiveArray<jfloatArray, FloatArray>(ts, len);
+}
+
+jintArray NewIntArray(JNIEnv* env, jsize len) {
+ ScopedJniThreadState ts(env);
+ return NewPrimitiveArray<jintArray, IntArray>(ts, len);
+}
+
+jlongArray NewLongArray(JNIEnv* env, jsize len) {
+ ScopedJniThreadState ts(env);
+ return NewPrimitiveArray<jlongArray, LongArray>(ts, len);
+}
+
+jshortArray NewShortArray(JNIEnv* env, jsize len) {
+ ScopedJniThreadState ts(env);
+ return NewPrimitiveArray<jshortArray, ShortArray>(ts, len);
}
jboolean* GetBooleanArrayElements(JNIEnv* env,
diff --git a/src/jni_internal_test.cc b/src/jni_internal_test.cc
index 457bae8..ce640e2 100644
--- a/src/jni_internal_test.cc
+++ b/src/jni_internal_test.cc
@@ -57,6 +57,28 @@
EXPECT_CLASS_NOT_FOUND("K");
}
+TEST_F(JniInternalTest, NewPrimitiveArray) {
+ // TODO: death tests for negative array sizes.
+
+ CHECK(env_->NewBooleanArray(0) != NULL);
+ CHECK(env_->NewByteArray(0) != NULL);
+ CHECK(env_->NewCharArray(0) != NULL);
+ CHECK(env_->NewDoubleArray(0) != NULL);
+ CHECK(env_->NewFloatArray(0) != NULL);
+ CHECK(env_->NewIntArray(0) != NULL);
+ CHECK(env_->NewLongArray(0) != NULL);
+ CHECK(env_->NewShortArray(0) != NULL);
+
+ CHECK(env_->NewBooleanArray(1) != NULL);
+ CHECK(env_->NewByteArray(1) != NULL);
+ CHECK(env_->NewCharArray(1) != NULL);
+ CHECK(env_->NewDoubleArray(1) != NULL);
+ CHECK(env_->NewFloatArray(1) != NULL);
+ CHECK(env_->NewIntArray(1) != NULL);
+ CHECK(env_->NewLongArray(1) != NULL);
+ CHECK(env_->NewShortArray(1) != NULL);
+}
+
bool EnsureInvokeStub(Method* method);
byte* AllocateCode(void* code, size_t length) {
diff --git a/src/mark_sweep.cc b/src/mark_sweep.cc
index 5d7c139..06a1c92 100644
--- a/src/mark_sweep.cc
+++ b/src/mark_sweep.cc
@@ -204,7 +204,7 @@
MarkObject(obj->GetClass());
if (obj->IsObjectArray()) {
const ObjectArray<Object>* array = obj->AsObjectArray<Object>();
- for (size_t i = 0; i < array->GetLength(); ++i) {
+ for (int32_t i = 0; i < array->GetLength(); ++i) {
const Object* element = array->Get(i);
MarkObject(element);
}
diff --git a/src/object.cc b/src/object.cc
index 34b0bb9..21f3537 100644
--- a/src/object.cc
+++ b/src/object.cc
@@ -5,6 +5,7 @@
#include <string.h>
#include <algorithm>
+#include "class_linker.h"
#include "globals.h"
#include "heap.h"
#include "logging.h"
@@ -441,13 +442,29 @@
return NULL;
}
+template<typename T>
+PrimitiveArray<T>* PrimitiveArray<T>::Alloc(size_t length) {
+ Array* raw_array = Array::Alloc(array_class_, length, sizeof(T));
+ return down_cast<PrimitiveArray<T>*>(raw_array);
+}
+
+template <typename T> Class* PrimitiveArray<T>::array_class_ = NULL;
+
+// Explicitly instantiate all the primitive array types.
+template class PrimitiveArray<uint8_t>; // BooleanArray
+template class PrimitiveArray<int8_t>; // ByteArray
+template class PrimitiveArray<uint16_t>; // CharArray
+template class PrimitiveArray<double>; // DoubleArray
+template class PrimitiveArray<float>; // FloatArray
+template class PrimitiveArray<int32_t>; // IntArray
+template class PrimitiveArray<int64_t>; // LongArray
+template class PrimitiveArray<int16_t>; // ShortArray
+
// TODO: get global references for these
Class* String::java_lang_String_ = NULL;
-Class* String::char_array_ = NULL;
-void String::InitClasses(Class* java_lang_String, Class* char_array) {
+void String::InitClasses(Class* java_lang_String) {
java_lang_String_ = java_lang_String;
- char_array_ = char_array;
}
static const char* kClassStatusNames[] = {
diff --git a/src/object.h b/src/object.h
index cb7f379..5110992 100644
--- a/src/object.h
+++ b/src/object.h
@@ -27,9 +27,14 @@
class String;
template<class T> class ObjectArray;
template<class T> class PrimitiveArray;
+typedef PrimitiveArray<uint8_t> BooleanArray;
+typedef PrimitiveArray<int8_t> ByteArray;
typedef PrimitiveArray<uint16_t> CharArray;
-typedef PrimitiveArray<uint32_t> IntArray;
-typedef PrimitiveArray<uint64_t> LongArray;
+typedef PrimitiveArray<double> DoubleArray;
+typedef PrimitiveArray<float> FloatArray;
+typedef PrimitiveArray<int32_t> IntArray;
+typedef PrimitiveArray<int64_t> LongArray;
+typedef PrimitiveArray<int16_t> ShortArray;
union JValue {
uint8_t z;
@@ -611,7 +616,7 @@
size_t Size() const;
- uint32_t GetLength() const {
+ int32_t GetLength() const {
return length_;
}
@@ -644,12 +649,12 @@
return reinterpret_cast<T**>(&elements_);
}
- T* Get(uint32_t i) const {
+ T* Get(int32_t i) const {
CHECK_LT(i, GetLength());
return GetData()[i];
}
- void Set(uint32_t i, T* object) {
+ void Set(int32_t i, T* object) {
CHECK_LT(i, GetLength());
GetData()[i] = object; // TODO: write barrier
}
@@ -662,7 +667,7 @@
}
}
- ObjectArray<T>* CopyOf(size_t new_length) {
+ ObjectArray<T>* CopyOf(int32_t new_length) {
ObjectArray<T>* new_array = Alloc(klass_, new_length);
Copy(this, 0, new_array, 0, std::min(GetLength(), new_length));
return new_array;
@@ -795,24 +800,28 @@
return component_type_;
}
- size_t GetComponentSize() const {
- switch (component_type_->descriptor_[0]) {
- case 'B': return 1; // byte
- case 'C': return 2; // char
- case 'D': return 8; // double
- case 'F': return 4; // float
- case 'I': return 4; // int
- case 'J': return 8; // long
- case 'S': return 2; // short
- case 'Z': return 1; // boolean
- case 'L': return sizeof(Object*);
- case '[': return sizeof(Array*);
- default:
- LOG(ERROR) << "Unknown component type " << component_type_->descriptor_;
- return 0;
+ static size_t GetTypeSize(const StringPiece& descriptor) {
+ switch (descriptor[0]) {
+ case 'B': return 1; // byte
+ case 'C': return 2; // char
+ case 'D': return 8; // double
+ case 'F': return 4; // float
+ case 'I': return 4; // int
+ case 'J': return 8; // long
+ case 'S': return 2; // short
+ case 'Z': return 1; // boolean
+ case 'L': return sizeof(Object*);
+ case '[': return sizeof(Array*);
+ default:
+ LOG(ERROR) << "Unknown type " << descriptor;
+ return 0;
}
}
+ size_t GetComponentSize() const {
+ return GetTypeSize(component_type_->descriptor_);
+ }
+
const StringPiece& GetDescriptor() const {
DCHECK_NE(0, descriptor_.size());
return descriptor_;
@@ -902,7 +911,7 @@
return (direct_methods_ != NULL) ? direct_methods_->GetLength() : 0;
}
- Method* GetDirectMethod(uint32_t i) const {
+ Method* GetDirectMethod(int32_t i) const {
DCHECK_NE(NumDirectMethods(), 0U);
return direct_methods_->Get(i);
}
@@ -1186,11 +1195,7 @@
template<class T>
class PrimitiveArray : public Array {
public:
- static PrimitiveArray<T>* Alloc(Class* element_class, size_t length) {
- return down_cast<PrimitiveArray<T>*>(Array::Alloc(element_class,
- length,
- sizeof(T)));
- }
+ static PrimitiveArray<T>* Alloc(size_t length);
const T* GetData() const {
return reinterpret_cast<const T*>(&elements_);
@@ -1200,20 +1205,27 @@
return reinterpret_cast<T*>(&elements_);
}
- T Get(T i) const {
+ T Get(int32_t i) const {
CHECK_LT(i, GetLength());
return GetData()[i];
}
- void Set(uint32_t i, T value) {
+ void Set(int32_t i, T value) {
CHECK_LT(i, GetLength());
GetData()[i] = value;
}
+ static void SetArrayClass(Class* array_class) {
+ CHECK(array_class != NULL);
+ array_class_ = array_class;
+ }
+
private:
// Location of first element.
T elements_[0];
+ static Class* array_class_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(PrimitiveArray);
};
@@ -1245,7 +1257,6 @@
uint16_t* utf16_data_in,
int32_t hash_code) {
String* string = Alloc(GetJavaLangString(),
- GetCharArrayClass(),
utf16_length);
// TODO use 16-bit wide memset variant
for (int i = 0; i < utf16_length; i++ ) {
@@ -1256,10 +1267,9 @@
}
static String* AllocFromModifiedUtf8(Class* java_lang_String,
- Class* char_array,
int32_t utf16_length,
const char* utf8_data_in) {
- String* string = Alloc(java_lang_String, char_array, utf16_length);
+ String* string = Alloc(java_lang_String, utf16_length);
uint16_t* utf16_data_out = string->array_->GetData();
ConvertModifiedUtf8ToUtf16(utf16_data_out, utf8_data_in);
string->ComputeHashCode();
@@ -1270,24 +1280,22 @@
// using non-ASCII characters as this function assumes one char per byte.
static String* AllocFromAscii(const char* ascii_data_in) {
return AllocFromModifiedUtf8(GetJavaLangString(),
- GetCharArrayClass(),
strlen(ascii_data_in),
ascii_data_in);
}
static String* AllocFromModifiedUtf8(int32_t utf16_length,
const char* utf8_data_in) {
- return AllocFromModifiedUtf8(GetJavaLangString(), GetCharArrayClass(),
+ return AllocFromModifiedUtf8(GetJavaLangString(),
utf16_length, utf8_data_in);
}
- static void InitClasses(Class* java_lang_String, Class* char_array);
+ static void InitClasses(Class* java_lang_String);
static String* Alloc(Class* java_lang_String,
- Class* char_array,
int32_t utf16_length) {
String* string = down_cast<String*>(java_lang_String->NewInstance());
- CharArray* array = CharArray::Alloc(char_array, utf16_length);
+ CharArray* array = CharArray::Alloc(utf16_length);
string->array_ = array;
string->count_ = utf16_length;
return string;
@@ -1428,13 +1436,8 @@
DCHECK(java_lang_String_ != NULL);
return java_lang_String_;
}
- static Class* GetCharArrayClass() {
- DCHECK(char_array_ != NULL);
- return char_array_;
- }
static Class* java_lang_String_;
- static Class* char_array_;
DISALLOW_IMPLICIT_CONSTRUCTORS(String);
};
diff --git a/src/object_test.cc b/src/object_test.cc
index 52fb288..28aecb0 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -55,7 +55,7 @@
TEST_F(ObjectTest, AllocObjectArray) {
ObjectArray<Object>* oa = class_linker_->AllocObjectArray<Object>(2);
- EXPECT_EQ(2U, oa->GetLength());
+ EXPECT_EQ(2, oa->GetLength());
EXPECT_TRUE(oa->Get(0) == NULL);
EXPECT_TRUE(oa->Get(1) == NULL);
oa->Set(0, oa);