refactor multiarray/anewarray/newarray/instanceof/checkedcast

This commit is contained in:
Zack Buhman 2025-01-06 21:41:31 -06:00
parent 1dcda3d2ad
commit 895646c25a
16 changed files with 617 additions and 497 deletions

View File

@ -7,7 +7,7 @@ CC ?= gcc
ARCH = -m32
CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protector -std=c2x -g
CFLAGS += -DDEBUG
#CFLAGS += -DDEBUG_PRINT
CFLAGS += -DDEBUG_PRINT
LDFLAGS = -lm
OPT ?= -O0
DEPFLAGS = -MMD -MP

View File

@ -309,7 +309,6 @@ struct class_entry * class_resolver_lookup_class_from_class_index(int class_hash
struct parse_type_ret parse_type_ret = parse_type(class_name_constant->utf8.bytes,
class_name_constant->utf8.length);
struct class_entry * _class_entry = class_resolver_lookup_class(class_hash_table_length,
class_hash_table,
parse_type_ret.bytes,
@ -586,10 +585,10 @@ struct method_entry class_resolver_lookup_method_from_method_name_method_descrip
}
}
int32_t * class_resolver_lookup_string(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
struct class_entry * class_entry,
const int string_index)
struct objectref * class_resolver_lookup_string(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
struct class_entry * class_entry,
const int string_index)
{
debugf("class_resolver_lookup_string: %d\n", string_index);
if (class_entry->attribute_entry[string_index - 1].string_objectref != nullptr) {
@ -605,22 +604,98 @@ int32_t * class_resolver_lookup_string(int class_hash_table_length,
(const uint8_t *)"java/lang/String",
16);
int32_t size = utf8_constant->utf8.length + 4;
int32_t * arrayref = memory_allocate(size);
int32_t size = utf8_constant->utf8.length + (sizeof (struct arrayref));
struct arrayref * arrayref = memory_allocate(size);
assert(arrayref != nullptr);
arrayref[0] = utf8_constant->utf8.length;
uint8_t * bytearray = (uint8_t *)&arrayref[1];
for (int i = 0; i < utf8_constant->utf8.length; i++)
bytearray[i] = utf8_constant->utf8.bytes[i];
arrayref->class_entry = nullptr; // byte[]
arrayref->length = utf8_constant->utf8.length;
for (int i = 0; i < utf8_constant->utf8.length; i++) {
arrayref->u8[i] = utf8_constant->utf8.bytes[i];
}
assert(string_class_entry != nullptr);
int32_t * objectref = memory_allocate(4 + 4);
struct objectref * objectref = memory_allocate((sizeof (struct objectref)) + (sizeof (void *)));
assert(objectref != nullptr);
objectref[0] = (int32_t)string_class_entry;
objectref[1] = (int32_t)arrayref;
objectref->class_entry = string_class_entry;
objectref->aref[0] = arrayref;
// cache the result
class_entry->attribute_entry[string_index - 1].string_objectref = objectref;
return objectref;
}
bool class_resolver_instanceof(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
struct class_entry * origin_class_entry,
const int class_index,
struct objectref * objectref)
{
struct class_entry * index_class_entry =
class_resolver_lookup_class_from_class_index(class_hash_table_length,
class_hash_table,
origin_class_entry,
class_index);
assert(index_class_entry != nullptr);
assert(objectref != nullptr);
struct class_entry * class_entry = objectref->class_entry;
while (true) {
debugf("class_entry: %p\n", class_entry);
assert(class_entry != nullptr);
if (class_entry == index_class_entry) {
return true;
}
if (class_entry->class_file->super_class == 0) {
return false;
}
struct constant * class_constant = &class_entry->class_file->constant_pool[class_entry->class_file->super_class - 1];
assert(class_constant->tag == CONSTANT_Class);
struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
assert(class_name_constant->tag == CONSTANT_Utf8);
debug_print__constant__utf8_string(class_name_constant);
debugf("\n");
// superclass lookup
class_entry = class_resolver_lookup_class_from_class_index(class_hash_table_length,
class_hash_table,
class_entry,
class_entry->class_file->super_class);
}
}
struct hash_table_entry * class_resolver_init_string_hash_table(int length)
{
assert((length & (length - 1)) == 0); // length must be a power of two
int hash_table_length = length;
uint32_t hash_table_size = (sizeof (struct hash_table_entry)) * hash_table_length;
struct hash_table_entry * hash_table = malloc_class_arena(hash_table_size);
hash_table_init(hash_table_length, hash_table);
return hash_table;
}
void * class_resolver_memoize_string_type(int string_hash_table_length,
struct hash_table_entry * string_hash_table,
const uint8_t * type,
int length)
{
struct hash_table_entry * e = hash_table_find(string_hash_table_length,
string_hash_table,
type,
length);
if (e != nullptr) {
assert(e->value == (void *)0x12345678);
return e;
} else {
struct hash_table_entry * e = hash_table_add(string_hash_table_length,
string_hash_table,
type,
length,
(void *)0x12345678);
assert(e != nullptr);
return e;
}
}

View File

@ -4,6 +4,7 @@
#include "class_file.h"
#include "hash_table.h"
#include "native_types.h"
enum initialization_state {
CLASS_UNINITIALIZED,
@ -21,7 +22,7 @@ union attribute_entry {
struct class_entry * class_entry;
struct method_entry * method_entry;
struct field_entry * field_entry;
int32_t * string_objectref;
struct objectref * string_objectref;
};
struct field_entry {
@ -84,7 +85,20 @@ struct field_entry * class_resolver_lookup_field_from_fieldref_index(int fields_
struct class_entry * class_entry,
int fieldref_index);
int32_t * class_resolver_lookup_string(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
struct class_entry * class_entry,
const int string_index);
struct objectref * class_resolver_lookup_string(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
struct class_entry * class_entry,
const int string_index);
bool class_resolver_instanceof(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
struct class_entry * origin_class_entry,
const int class_index,
struct objectref * objectref);
struct hash_table_entry * class_resolver_init_string_hash_table(int length);
void * class_resolver_memoize_string_type(int string_hash_table_length,
struct hash_table_entry * string_hash_table,
const uint8_t * type,
int length);

File diff suppressed because it is too large Load Diff

View File

@ -6,13 +6,13 @@
#include "printf.h"
#include "field_size.h"
#include "debug.h"
#include "parse_type.h"
#include "native_types.h"
#include "parse_type.h"
void op_aaload(struct vm * vm)
{
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct object_arrayref * arrayref = (struct object_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
uint32_t value = arrayref->u32[index];
operand_stack_push_u32(vm->current_frame, value);
@ -22,7 +22,7 @@ void op_aastore(struct vm * vm)
{
uint32_t value = operand_stack_pop_u32(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct object_arrayref * arrayref = (struct object_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
arrayref->u32[index] = value;
}
@ -64,20 +64,27 @@ void op_aload_3(struct vm * vm)
void op_anewarray(struct vm * vm, uint32_t index)
{
struct class_entry * class_entry =
class_resolver_lookup_class_from_class_index(vm->class_hash_table.length,
vm->class_hash_table.entry,
vm->current_frame->class_entry,
index);
int32_t count = operand_stack_pop_u32(vm->current_frame);
int32_t element_size = (sizeof (void *));
int32_t size = element_size * count + (sizeof (struct object_arrayref));
struct object_arrayref * arrayref = memory_allocate(size);
int32_t size = element_size * count + (sizeof (struct arrayref));
struct arrayref * arrayref = memory_allocate(size);
assert(arrayref != nullptr);
arrayref->length = count;
arrayref->class_entry = class_entry;
/* All components of the new array are initialized to null, the default value
for reference types */
for (int i = 0; i < count; i++) {
arrayref->a[i] = nullptr;
arrayref->oref[i] = nullptr;
}
operand_stack_push_u32(vm->current_frame, (uint32_t)arrayref);
operand_stack_push_ref(vm->current_frame, arrayref);
}
void op_areturn(struct vm * vm)
@ -88,8 +95,8 @@ void op_areturn(struct vm * vm)
void op_arraylength(struct vm * vm)
{
int32_t * arrayref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
int32_t length = arrayref[0];
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
int32_t length = arrayref->length;
operand_stack_push_u32(vm->current_frame, length);
}
@ -125,14 +132,14 @@ void op_astore_3(struct vm * vm)
void op_athrow(struct vm * vm)
{
int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
struct objectref * objectref = operand_stack_pop_ref(vm->current_frame);
vm_exception(vm, objectref);
}
void op_baload(struct vm * vm)
{
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
int8_t value = arrayref->u8[index];
operand_stack_push_u32(vm->current_frame, value);
@ -142,7 +149,7 @@ void op_bastore(struct vm * vm)
{
uint8_t value = operand_stack_pop_u32(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
arrayref->u8[index] = value;
}
@ -160,7 +167,7 @@ void op_breakpoint(struct vm * vm)
void op_caload(struct vm * vm)
{
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
uint16_t value = arrayref->u16[index];
operand_stack_push_u32(vm->current_frame, value);
@ -170,66 +177,25 @@ void op_castore(struct vm * vm)
{
uint16_t value = operand_stack_pop_u32(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
arrayref->u16[index] = value;
}
void op_checkcast(struct vm * vm, uint32_t index)
{
int32_t * objectref = (int32_t *)operand_stack_peek_u32(vm->current_frame, 1);
if (objectref == nullptr) {
return;
}
struct class_entry * index_class_entry =
class_resolver_lookup_class_from_class_index(vm->class_hash_table.length,
vm->class_hash_table.entry,
vm->current_frame->class_entry,
index);
struct constant * class_constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1];
assert(class_constant->tag == CONSTANT_Class);
struct constant * class_name_constant = &vm->current_frame->class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
assert(class_name_constant->tag == CONSTANT_Utf8);
int depth = parse_type_array_depth(class_name_constant->utf8.bytes, class_name_constant->utf8.length);
while (depth-- > 0) {
if (objectref == nullptr || objectref[0] == 0)
assert(!"checkcast on null or zero-length array not implemented");
objectref = (int32_t *)objectref[1];
}
if (objectref == nullptr) {
assert(!"checkcast on array with null elements not implemented");
}
struct class_entry * class_entry = (struct class_entry *)objectref[0];
debug_print__class_file__class_name(index_class_entry->class_file);
debug_print__class_file__class_name(class_entry->class_file);
while (true) {
assert(class_entry != nullptr);
if (class_entry == index_class_entry) {
return;
struct objectref * objectref = operand_stack_peek_ref(vm->current_frame, 1);
if (objectref != nullptr) {
bool isinstance =
class_resolver_instanceof(vm->class_hash_table.length,
vm->class_hash_table.entry,
vm->current_frame->class_entry,
index,
objectref);
if (!isinstance) {
assert(!"ClassCastException");
}
if (class_entry->class_file->super_class == 0) {
break;
}
struct constant * class_constant = &class_entry->class_file->constant_pool[class_entry->class_file->super_class - 1];
assert(class_constant->tag == CONSTANT_Class);
struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
assert(class_name_constant->tag == CONSTANT_Utf8);
debug_print__constant__utf8_string(class_name_constant);
debugf("\n");
// superclass lookup
class_entry = class_resolver_lookup_class_from_class_index(vm->class_hash_table.length,
vm->class_hash_table.entry,
class_entry,
class_entry->class_file->super_class);
}
assert(!"ClassCastException");
}
void op_d2f(struct vm * vm)
@ -264,7 +230,7 @@ void op_dadd(struct vm * vm)
void op_daload(struct vm * vm)
{
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
uint64_t value = arrayref->u64[index];
operand_stack_push_u64(vm->current_frame, value);
@ -274,7 +240,7 @@ void op_dastore(struct vm * vm)
{
int64_t value = operand_stack_pop_u64(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
arrayref->u64[index] = value;
}
@ -546,7 +512,7 @@ void op_fadd(struct vm * vm)
void op_faload(struct vm * vm)
{
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
uint32_t value = arrayref->u32[index];
operand_stack_push_u32(vm->current_frame, value);
@ -556,7 +522,7 @@ void op_fastore(struct vm * vm)
{
uint32_t value = operand_stack_pop_u32(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
arrayref->u32[index] = value;
}
@ -732,9 +698,8 @@ void op_getfield(struct vm * vm, uint32_t index)
debugf("getfield instance_index %d\n", field_entry->instance_index);
int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
struct objectref * objectref = operand_stack_pop_ref(vm->current_frame);
assert(objectref != nullptr);
int32_t * objectfields = &objectref[1];
switch (field_descriptor_constant->utf8.bytes[0]) {
case 'B': [[fallthrough]];
@ -746,17 +711,17 @@ void op_getfield(struct vm * vm, uint32_t index)
case 'Z': [[fallthrough]];
case '[':
{
uint32_t value = objectfields[field_entry->instance_index];
operand_stack_push_u32(vm->current_frame, value);
void * value = objectref->oref[field_entry->instance_index];
operand_stack_push_ref(vm->current_frame, value);
}
break;
case 'D': [[fallthrough]];
case 'J':
{
uint32_t low = objectfields[field_entry->instance_index];
uint32_t high = objectfields[field_entry->instance_index + 1];
operand_stack_push_u32(vm->current_frame, low);
operand_stack_push_u32(vm->current_frame, high);
void * low = objectref->oref[field_entry->instance_index];
void * high = objectref->oref[field_entry->instance_index + 1];
operand_stack_push_ref(vm->current_frame, low);
operand_stack_push_ref(vm->current_frame, high);
}
break;
default:
@ -872,7 +837,7 @@ void op_iadd(struct vm * vm)
void op_iaload(struct vm * vm)
{
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
int32_t value = arrayref->u32[index];
operand_stack_push_u32(vm->current_frame, value);
@ -890,7 +855,7 @@ void op_iastore(struct vm * vm)
{
uint32_t value = operand_stack_pop_u32(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
arrayref->u32[index] = value;
}
@ -1060,7 +1025,7 @@ void op_ifne(struct vm * vm, int32_t branch)
void op_ifnonnull(struct vm * vm, int32_t branch)
{
void * value = (void *)operand_stack_pop_u32(vm->current_frame);
void * value = operand_stack_pop_ref(vm->current_frame);
if (value != nullptr) {
vm->current_frame->next_pc = vm->current_frame->pc + branch;
}
@ -1068,7 +1033,7 @@ void op_ifnonnull(struct vm * vm, int32_t branch)
void op_ifnull(struct vm * vm, int32_t branch)
{
void * value = (void *)operand_stack_pop_u32(vm->current_frame);
void * value = operand_stack_pop_ref(vm->current_frame);
if (value == nullptr) {
vm->current_frame->next_pc = vm->current_frame->pc + branch;
}
@ -1138,61 +1103,18 @@ void op_ineg(struct vm * vm)
void op_instanceof(struct vm * vm, uint32_t index)
{
struct class_entry * index_class_entry =
class_resolver_lookup_class_from_class_index(vm->class_hash_table.length,
vm->class_hash_table.entry,
vm->current_frame->class_entry,
index);
assert(index_class_entry != nullptr);
int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
struct objectref * objectref = operand_stack_pop_ref(vm->current_frame);
if (objectref == nullptr) {
operand_stack_push_u32(vm->current_frame, (uint32_t)false);
return;
operand_stack_push_u32(vm->current_frame, false);
} else {
bool isinstance =
class_resolver_instanceof(vm->class_hash_table.length,
vm->class_hash_table.entry,
vm->current_frame->class_entry,
index,
objectref);
operand_stack_push_u32(vm->current_frame, isinstance);
}
struct constant * class_constant = &vm->current_frame->class_entry->class_file->constant_pool[index - 1];
assert(class_constant->tag == CONSTANT_Class);
struct constant * class_name_constant = &vm->current_frame->class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
assert(class_name_constant->tag == CONSTANT_Utf8);
int depth = parse_type_array_depth(class_name_constant->utf8.bytes, class_name_constant->utf8.length);
printf("depth: %d\n", depth);
while (depth-- > 0) {
if (objectref == nullptr || objectref[0] == 0)
assert(!"instanceof on null or zero-length array not implemented");
objectref = (int32_t *)objectref[1];
}
if (objectref == nullptr) {
assert(!"instanceof on array with null elements not implemented");
}
bool value = false;
struct class_entry * class_entry = (struct class_entry *)objectref[0];
while (true) {
assert(class_entry != nullptr);
if (class_entry == index_class_entry) {
value = true;
break;
}
if (class_entry->class_file->super_class == 0) {
break;
}
struct constant * class_constant = &class_entry->class_file->constant_pool[class_entry->class_file->super_class - 1];
assert(class_constant->tag == CONSTANT_Class);
struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
assert(class_name_constant->tag == CONSTANT_Utf8);
debug_print__constant__utf8_string(class_name_constant);
debugf("\n");
// superclass lookup
class_entry = class_resolver_lookup_class_from_class_index(vm->class_hash_table.length,
vm->class_hash_table.entry,
class_entry,
class_entry->class_file->super_class);
}
operand_stack_push_u32(vm->current_frame, (uint32_t)value);
}
void op_invokedynamic(struct vm * vm, uint32_t index)
@ -1202,9 +1124,9 @@ void op_invokedynamic(struct vm * vm, uint32_t index)
void op_invokeinterface(struct vm * vm, uint32_t index, uint32_t count)
{
int32_t * objectref = (int32_t *)operand_stack_peek_u32(vm->current_frame, count);
struct objectref * objectref = operand_stack_peek_ref(vm->current_frame, count);
assert(objectref != nullptr);
struct class_entry * class_entry = (struct class_entry *)objectref[0];
struct class_entry * class_entry = objectref->class_entry;
struct method_entry method_entry =
class_resolver_lookup_method_from_interfacemethodref_index(vm->class_hash_table.length,
@ -1242,8 +1164,6 @@ void op_invokestatic(struct vm * vm, uint32_t index)
vm_static_method_call(vm, method_entry->class_entry, method_entry);
}
#include "debug.h"
void op_invokevirtual(struct vm * vm, uint32_t index)
{
struct class_entry * origin_class_entry = vm->current_frame->class_entry;
@ -1261,9 +1181,9 @@ void op_invokevirtual(struct vm * vm, uint32_t index)
int nargs = descriptor_nargs(method_descriptor_constant, &return_type);
(void)return_type;
int32_t * objectref = (int32_t *)operand_stack_peek_u32(vm->current_frame, nargs + 1);
struct objectref * objectref = operand_stack_peek_ref(vm->current_frame, nargs + 1);
assert(objectref != nullptr);
struct class_entry * class_entry = (struct class_entry *)objectref[0];
struct class_entry * class_entry = objectref->class_entry;
debugf("class_entry: %p\n", class_entry);
struct method_entry method_entry =
@ -1449,7 +1369,7 @@ void op_ladd(struct vm * vm)
void op_laload(struct vm * vm)
{
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
int64_t value = arrayref->u64[index];
operand_stack_push_u64(vm->current_frame, value);
@ -1467,7 +1387,7 @@ void op_lastore(struct vm * vm)
{
uint64_t value = operand_stack_pop_u64(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
arrayref->u64[index] = value;
}
@ -1506,11 +1426,11 @@ void op_ldc(struct vm * vm, uint32_t index)
int32_t value = constant->integer.bytes;
operand_stack_push_u32(vm->current_frame, value);
} else if (constant->tag == CONSTANT_String) {
int32_t * objectref = class_resolver_lookup_string(vm->class_hash_table.length,
vm->class_hash_table.entry,
vm->current_frame->class_entry,
constant->string.string_index);
operand_stack_push_u32(vm->current_frame, (uint32_t)objectref);
struct objectref * objectref = class_resolver_lookup_string(vm->class_hash_table.length,
vm->class_hash_table.entry,
vm->current_frame->class_entry,
constant->string.string_index);
operand_stack_push_ref(vm->current_frame, objectref);
} else {
assert(false);
}
@ -1533,11 +1453,11 @@ void op_ldc_w(struct vm * vm, uint32_t index)
int32_t value = constant->integer.bytes;
operand_stack_push_u32(vm->current_frame, value);
} else if (constant->tag == CONSTANT_String) {
int32_t * objectref = class_resolver_lookup_string(vm->class_hash_table.length,
vm->class_hash_table.entry,
vm->current_frame->class_entry,
constant->string.string_index);
operand_stack_push_u32(vm->current_frame, (uint32_t)objectref);
struct objectref * objectref = class_resolver_lookup_string(vm->class_hash_table.length,
vm->class_hash_table.entry,
vm->current_frame->class_entry,
constant->string.string_index);
operand_stack_push_ref(vm->current_frame, objectref);
} else {
assert(false);
}
@ -1735,22 +1655,40 @@ void op_monitorexit(struct vm * vm)
assert(!"op_monitorexit");
}
static int32_t * _multiarray(int32_t * dims, int num_dimensions, int level, uint8_t * type)
static struct arrayref * _multiarray(struct vm * vm, int32_t * dims, int num_dimensions, int level, uint8_t * type, uint8_t * type_end)
{
int32_t count = dims[level];
int32_t element_size = field_size_array(*type);
int32_t size = element_size * count + 4;
int32_t * arrayref = memory_allocate(size);
int32_t size = element_size * count + (sizeof (struct arrayref));
struct arrayref * arrayref = memory_allocate(size);
assert(arrayref != nullptr);
arrayref[0] = count;
arrayref->length = count;
{ // generate/recall unique pointer for type string
uint8_t * array_type = type - 1;
assert(*array_type == '[');
int type_length = type_end - array_type;
assert(type_length > 0);
void * type = class_resolver_memoize_string_type(vm->string_hash_table.length,
vm->string_hash_table.entry,
array_type,
type_length);
debugf("memoized string type: %d %p: ", count, type);
print_string((const char *)array_type, type_length);
debugc('\n');
assert(type != nullptr);
arrayref->class_entry = type;
}
int32_t u32_count = (size - 4 + 3) / 4;
int32_t array_element_size = count * element_size; // bytes
int32_t u32_count = (array_element_size + 3) / 4; // u32 units
debugf("u32_count: %d\n", u32_count);
for (int i = 0; i < u32_count; i++) {
if (level == num_dimensions - 1) {
arrayref[i + 1] = 0;
assert(*type != '[');
arrayref->u32[1] = 0;
} else {
assert(*type == '[');
arrayref[1 + i] = (int32_t)_multiarray(dims, num_dimensions, level + 1, type + 1);
arrayref->aref[i] = _multiarray(vm, dims, num_dimensions, level + 1, type + 1, type_end);
}
}
return arrayref;
@ -1763,9 +1701,14 @@ void op_multianewarray(struct vm * vm, uint32_t index, uint32_t dimensions)
struct constant * type_constant = &vm->current_frame->class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
assert(type_constant->tag == CONSTANT_Utf8);
debugs("type_constant: ");
debug_print__constant__utf8_string(type_constant);
debugc('\n');
// The run-time constant pool entry at the index must be a symbolic reference
// to a class, array, or interface type
uint8_t * type = type_constant->utf8.bytes;
uint8_t * type_end = type + type_constant->utf8.length;
assert(*type == '[');
assert(dimensions > 0);
@ -1773,8 +1716,8 @@ void op_multianewarray(struct vm * vm, uint32_t index, uint32_t dimensions)
for (int i = 0; i < dimensions; i++) {
dims[dimensions - i - 1] = operand_stack_pop_u32(vm->current_frame);
}
int32_t * arrayref = _multiarray(dims, dimensions, 0, type + 1);
operand_stack_push_u32(vm->current_frame, (uint32_t)arrayref);
struct arrayref * arrayref = _multiarray(vm, dims, dimensions, 0, type + 1, type_end);
operand_stack_push_ref(vm->current_frame, arrayref);
}
void op_new(struct vm * vm, uint32_t index)
@ -1800,15 +1743,14 @@ void op_new(struct vm * vm, uint32_t index)
reference to the instance, is pushed onto the operand stack. */
int fields_count = class_entry->instance_fields_count;
int32_t * objectref = memory_allocate(fields_count * 4 + 4);
struct objectref * objectref = memory_allocate(fields_count * 4 + 4);
assert(objectref != nullptr);
objectref[0] = (int32_t)class_entry;
int32_t * objectfields = &objectref[1];
objectref->class_entry = class_entry;
for (int i = 0; i < fields_count; i++) {
objectfields[i] = 0;
objectref->oref[i] = nullptr;
}
operand_stack_push_u32(vm->current_frame, (uint32_t)objectref);
operand_stack_push_ref(vm->current_frame, objectref);
}
@ -1816,10 +1758,11 @@ void op_newarray(struct vm * vm, uint32_t atype)
{
int32_t count = operand_stack_pop_u32(vm->current_frame);
int32_t element_size = array_element_size(atype);
int32_t size = element_size * count + (sizeof (struct primitive_arrayref));
struct primitive_arrayref * arrayref = memory_allocate(size);
int32_t size = element_size * count + (sizeof (struct arrayref));
struct arrayref * arrayref = memory_allocate(size);
assert(arrayref != nullptr);
arrayref->length = count;
arrayref->class_entry = nullptr;
/* Each of the elements of the new array is initialized to the default initial
value (§2.3, §2.4) for the element type of the array type. */
@ -1832,7 +1775,7 @@ void op_newarray(struct vm * vm, uint32_t atype)
arrayref->u32[i] = 0;
}
operand_stack_push_u32(vm->current_frame, (uint32_t)arrayref);
operand_stack_push_ref(vm->current_frame, arrayref);
}
void op_nop(struct vm * vm)
@ -1882,10 +1825,9 @@ void op_putfield(struct vm * vm, uint32_t index)
case '[':
{
uint32_t value = operand_stack_pop_u32(vm->current_frame);
int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
struct objectref * objectref = operand_stack_pop_ref(vm->current_frame);
assert(objectref != nullptr);
int32_t * objectfields = &objectref[1];
objectfields[field_entry->instance_index] = value;
objectref->u32[field_entry->instance_index] = value;
}
break;
case 'D': [[fallthrough]];
@ -1893,11 +1835,10 @@ void op_putfield(struct vm * vm, uint32_t index)
{
uint32_t high = operand_stack_pop_u32(vm->current_frame);
uint32_t low = operand_stack_pop_u32(vm->current_frame);
int32_t * objectref = (int32_t *)operand_stack_pop_u32(vm->current_frame);
struct objectref * objectref = operand_stack_pop_ref(vm->current_frame);
assert(objectref != nullptr);
int32_t * objectfields = &objectref[1];
objectfields[field_entry->instance_index + 1] = high;
objectfields[field_entry->instance_index] = low;
objectref->u32[field_entry->instance_index + 1] = high;
objectref->u32[field_entry->instance_index] = low;
}
break;
default:
@ -1971,7 +1912,7 @@ void op_return(struct vm * vm)
void op_saload(struct vm * vm)
{
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
int16_t value = arrayref->u16[index];
operand_stack_push_u32(vm->current_frame, value);
@ -1981,7 +1922,7 @@ void op_sastore(struct vm * vm)
{
uint16_t value = operand_stack_pop_u32(vm->current_frame);
int32_t index = operand_stack_pop_u32(vm->current_frame);
struct primitive_arrayref * arrayref = (struct primitive_arrayref *)operand_stack_pop_u32(vm->current_frame);
struct arrayref * arrayref = operand_stack_pop_ref(vm->current_frame);
assert(arrayref->length > 0 && index >= 0 && index < arrayref->length);
arrayref->u16[index] = value;
}

View File

@ -13,6 +13,7 @@
#include "debug.h"
#include "find_attribute.h"
#include "backtrace.h"
#include "native_types.h"
int descriptor_nargs(struct constant * descriptor_constant, uint8_t * return_type)
{
@ -490,15 +491,15 @@ void vm_method_return(struct vm * vm)
}
}
void vm_exception(struct vm * vm, int32_t * objectref)
void vm_exception(struct vm * vm, struct objectref * objectref)
{
// If objectref is null, athrow throws a NullPointerException instead of objectref.
assert(objectref != nullptr);
struct class_entry * exception_class_entry = (struct class_entry *)objectref[0];
if (objectref[1] == 0) {
struct backtrace * backtrace = backtrace_allocate(vm);
objectref[1] = (int32_t)backtrace;
struct class_entry * exception_class_entry = objectref->class_entry;
if (objectref->oref[0] == nullptr) {
// FIXME: make backtrace a real objectref
objectref->oref[0] = (struct objectref *)backtrace_allocate(vm);
}
while (vm->frame_stack.ix > 0) {
@ -533,23 +534,21 @@ void vm_exception(struct vm * vm, int32_t * objectref)
print__class_file__class_name(exception_class_entry->class_file);
printc('\n');
{
int32_t * string_objectref = (int32_t *)objectref[2];
struct objectref * string_objectref = objectref->oref[1]; // message
if (string_objectref != nullptr) {
prints(" message: ");
struct class_entry * string_class_entry = (struct class_entry *)string_objectref[0];
struct class_entry * string_class_entry = string_objectref->class_entry;
prints("(class: ");
print__class_file__class_name(string_class_entry->class_file);
printc(')');
prints("\n ");
int32_t * arrayref = (int32_t *)string_objectref[1];
int32_t length = arrayref[0];
uint8_t * bytes = (uint8_t *)&arrayref[1];
print__string(bytes, length);
struct arrayref * arrayref = string_objectref->aref[0];
print__string(arrayref->u8, arrayref->length);
printc('\n');
}
}
assert(objectref[1] != 0);
backtrace_print((struct backtrace *)objectref[1]);
assert(objectref->oref[0] != 0);
backtrace_print((struct backtrace *)objectref->oref[0]);
}
static void print_vm_stack(struct vm * vm)
@ -574,7 +573,9 @@ void vm_execute(struct vm * vm)
while (true) {
assert(vm->current_frame->pc < vm->current_frame->code_attribute->code_length);
print_vm_stack(vm);
#ifdef DEBUG_PRINT
decode_print_instruction(vm->current_frame->code_attribute->code, vm->current_frame->pc);
#endif
decode_execute_instruction(vm, vm->current_frame->code_attribute->code, vm->current_frame->pc);
if (vm->frame_stack.ix == 0) {
debugf("terminate\n");
@ -608,8 +609,11 @@ struct vm * vm_start(int class_hash_table_length,
assert(method_entry.method_info != nullptr);
static struct vm vm;
vm.class_hash_table.entry = class_hash_table;
vm.class_hash_table.length = class_hash_table_length;
vm.class_hash_table.entry = class_hash_table;
vm.string_hash_table.length = 128;
vm.string_hash_table.entry = class_resolver_init_string_hash_table(vm.string_hash_table.length);
vm.frame_stack.ix = 0;
vm.frame_stack.capacity = 1024;

View File

@ -3,6 +3,7 @@
#include "assert.h"
#include "class_file.h"
#include "class_resolver.h"
#include "native_types.h"
struct frame {
struct class_entry * class_entry;
@ -34,6 +35,10 @@ struct vm {
int length;
struct hash_table_entry * entry;
} class_hash_table;
struct {
int length;
struct hash_table_entry * entry;
} string_hash_table;
};
static inline struct frame * stack_push_frame(struct stack * stack, int num_frames)
{
@ -96,6 +101,28 @@ static inline void operand_stack_dup_u32(struct frame * frame)
frame->operand_stack_ix++;
}
static inline void operand_stack_push_ref(struct frame * frame, void * value)
{
frame->operand_stack[frame->operand_stack_ix] = (uint32_t)value;
frame->operand_stack_ix++;
}
static inline void * operand_stack_pop_ref(struct frame * frame)
{
frame->operand_stack_ix--;
assert(frame->operand_stack_ix >= 0);
uint32_t value = frame->operand_stack[frame->operand_stack_ix];
frame->operand_stack[frame->operand_stack_ix] = -1;
return (void *)value;
}
static inline void * operand_stack_peek_ref(struct frame * frame, int index)
{
assert((frame->operand_stack_ix - index) >= 0);
uint32_t value = frame->operand_stack[frame->operand_stack_ix - index];
return (void *)value;
}
static inline void operand_stack_push_f32(struct frame * frame, float f)
{
uint32_t value = *((uint32_t *)&f);
@ -165,4 +192,4 @@ struct vm * vm_start(int class_hash_table_length,
const uint8_t * main_class_name,
int main_class_name_length);
int descriptor_nargs(struct constant * descriptor_constant, uint8_t * return_type);
void vm_exception(struct vm * vm, int32_t * objectref);
void vm_exception(struct vm * vm, struct objectref * objectref);

View File

@ -46,11 +46,11 @@ void print_key(const uint8_t * key, int key_length)
debugc('\n');
}
void hash_table_add(int hash_table_length,
struct hash_table_entry * entry,
const uint8_t * key,
int key_length,
void * value)
struct hash_table_entry * hash_table_add(int hash_table_length,
struct hash_table_entry * entry,
const uint8_t * key,
int key_length,
void * value)
{
assert(hash_table_length != 0);
assert((hash_table_length & (hash_table_length - 1)) == 0);
@ -74,6 +74,8 @@ void hash_table_add(int hash_table_length,
e->key = key_copy;
e->key_length = key_length;
e->value = value;
return e;
}
struct hash_table_entry * hash_table_find(int hash_table_length,
@ -114,13 +116,13 @@ static inline bool key_equal2(const uint8_t * a1, int a1_length,
return true;
}
void hash_table_add2(int hash_table_length,
struct hash_table_entry * entry,
const uint8_t * key1,
int key1_length,
const uint8_t * key2,
int key2_length,
void * value)
struct hash_table_entry * hash_table_add2(int hash_table_length,
struct hash_table_entry * entry,
const uint8_t * key1,
int key1_length,
const uint8_t * key2,
int key2_length,
void * value)
{
assert(hash_table_length != 0);
assert((hash_table_length & (hash_table_length - 1)) == 0);
@ -148,6 +150,8 @@ void hash_table_add2(int hash_table_length,
e->key = key_copy;
e->key_length = key1_length + key2_length;
e->value = value;
return e;
}
struct hash_table_entry * hash_table_find2(int hash_table_length,

View File

@ -14,24 +14,24 @@ int32_t hash_table_next_power_of_two(int32_t n);
void hash_table_init(int hash_table_length,
struct hash_table_entry * entry);
void hash_table_add(int hash_table_length,
struct hash_table_entry * entry,
const uint8_t * key,
int key_length,
void * value);
struct hash_table_entry * hash_table_add(int hash_table_length,
struct hash_table_entry * entry,
const uint8_t * key,
int key_length,
void * value);
struct hash_table_entry * hash_table_find(int hash_table_length,
struct hash_table_entry * entry,
const uint8_t * key,
int key_length);
void hash_table_add2(int hash_table_length,
struct hash_table_entry * entry,
const uint8_t * key1,
int key1_length,
const uint8_t * key2,
int key2_length,
void * value);
struct hash_table_entry * hash_table_add2(int hash_table_length,
struct hash_table_entry * entry,
const uint8_t * key1,
int key1_length,
const uint8_t * key2,
int key2_length,
void * value);
struct hash_table_entry * hash_table_find2(int hash_table_length,
struct hash_table_entry * entry,

View File

@ -6,24 +6,17 @@
#include "class_resolver.h"
#include "frame.h"
void native_java_io_printstream_write(uint32_t * arrayref)
{
int32_t length = arrayref[0];
char * buf = (char *)&arrayref[1];
print_string(buf, length);
}
void native_java_io_printstream_write_1(uint32_t * args)
{
uint32_t * arrayref = (uint32_t *)args[0];
native_java_io_printstream_write(arrayref);
struct arrayref * arrayref = (struct arrayref *)args[0];
print_string((const char *)arrayref->u8, arrayref->length);
}
void native_java_io_printstream_write_2(uint32_t * args)
{
//uint32_t this = args[0];
uint32_t * arrayref = (uint32_t *)args[1];
native_java_io_printstream_write(arrayref);
struct arrayref * arrayref = (struct arrayref *)args[1];
print_string((const char *)arrayref->u8, arrayref->length);
}
void native_java_misc_memory_putU4_2(uint32_t * args)
@ -73,16 +66,16 @@ extern uint32_t store_queue[0x4000000] __asm("store_queue");
void native_java_misc_memory_putSQ1_2(uint32_t * args)
{
#if defined(__dreamcast__)
uint32_t * objectref = (uint32_t *)args[0];
struct objectref * objectref = (struct objectref *)args[0];
uint32_t address = (uint32_t)args[1];
store_queue[0] = objectref[1];
store_queue[1] = objectref[2];
store_queue[2] = objectref[3];
store_queue[3] = objectref[4];
store_queue[4] = objectref[5];
store_queue[5] = objectref[6];
store_queue[6] = objectref[7];
store_queue[7] = objectref[8];
store_queue[0] = objectref->u32[0];
store_queue[1] = objectref->u32[1];
store_queue[2] = objectref->u32[2];
store_queue[3] = objectref->u32[3];
store_queue[4] = objectref->u32[4];
store_queue[5] = objectref->u32[5];
store_queue[6] = objectref->u32[6];
store_queue[7] = objectref->u32[7];
*((uint32_t*)0xff000038) = ((address >> 26) & 0b111) << 2;
@ -122,16 +115,13 @@ uint32_t native_java_lang_math_abs_1(uint32_t * args)
uint32_t java_misc_resource_getresource_1(uint32_t * args)
{
uint32_t * objectref = (uint32_t *)args[0];
int32_t * arrayref = (int32_t *)objectref[1];
int32_t name_length = (int32_t)arrayref[0];
uint8_t * name = (uint8_t *)&arrayref[1];
struct objectref * objectref = (struct objectref *)args[0];
struct arrayref * arrayref = objectref->aref[0];
#if defined(__dreamcast__)
uint32_t resource = find_resource(name, name_length);
uint32_t resource = find_resource(arrayref->u8, arrayref->length);
return resource;
#else
(void)name;
(void)name_length;
(void)arrayref;
return 0;
#endif
}
@ -152,9 +142,8 @@ extern struct vm vm;
void native_jvm_internal_loader_load(uint32_t * args)
{
uint32_t * arrayref = (uint32_t *)args[0];
//int32_t buffers_length = (int32_t)arrayref[0];
const uint8_t ** buffers = (const uint8_t **)&arrayref[1];
struct arrayref * arrayref = (struct arrayref *)args[0];
const uint8_t ** buffers = (const uint8_t **)&arrayref->u32[0];
int32_t num_buffers = (int32_t)args[1];
printf("num_buffers: %d\n", num_buffers);
printf("loader_buffer[0]: %p ; buffers[0]: %p\n", &loader_buffer[0], (uint32_t)buffers[0]);

View File

@ -1,19 +1,32 @@
#pragma once
#include <stdint.h>
#include <assert.h>
#include "class_resolver.h"
struct object_arrayref;
struct objectref {
int32_t _res;
struct class_entry * class_entry;
union {
void * field[0];
struct objectref * oref[0];
struct arrayref * aref[0];
uint32_t u32[0];
};
};
static_assert((sizeof (struct objectref)) == 4);
static_assert((sizeof (struct objectref)) == 8);
struct primitive_arrayref {
int32_t length;
struct arrayref {
int32_t length; // length position must match primitive_arrayref
struct class_entry * class_entry;
union {
// object array:
struct objectref * oref[0];
struct arrayref * aref[0];
// primitive array:
uint8_t u8[0];
uint16_t u16[0];
uint32_t u32[0];
@ -21,18 +34,7 @@ struct primitive_arrayref {
};
};
static_assert((sizeof (struct primitive_arrayref)) == 4);
struct object_arrayref {
struct class_entry * class_entry;
int32_t length;
union {
struct objectref * a[0];
uint32_t u32[0];
};
};
static_assert((sizeof (struct object_arrayref)) == 8);
static_assert((sizeof (struct arrayref)) == 8);
enum ARRAY_TYPE {
T_BOOLEAN = 4, // 1 byte

View File

@ -1,5 +1,6 @@
#include "assert.h"
#include "parse_type.h"
#include "printf.h"
struct parse_type_ret parse_type(uint8_t * bytes, uint32_t length)
{

View File

@ -115,16 +115,16 @@ def generate_print_fixed_width_instruction(instruction):
if argument_values:
argument_values = ", " + argument_values
mnemonic = instruction.mnemonic.ljust(13)
yield f'debugf("%4d: {mnemonic} {argument_format}\\n", pc{argument_values});'
yield f'printf("%4d: {mnemonic} {argument_format}\\n", pc{argument_values});'
yield f"return pc + {1 + instruction.arguments_size};"
def generate_print_variable_width_instruction(instruction):
n = '' if instruction.mnemonic == "wide" else '\\n'
mnemonic = instruction.mnemonic.ljust(13)
yield f"{instruction.mnemonic.upper()}_ARGS;"
yield f'debugf("%4d: {mnemonic} {{{n}", pc);'
yield f'printf("%4d: {mnemonic} {{{n}", pc);'
yield f"{instruction.mnemonic.upper()}_PRINT_ARGS();"
yield f'debugf("}}{n}\\n");'
yield f'printf("}}{n}\\n");'
yield f"return {instruction.mnemonic.upper()}_NEXT_PC;"
def generate_print_decoder():

20
test/TestMultiArray.java Normal file
View File

@ -0,0 +1,20 @@
package test;
class TestMultiArray {
static boolean testInstanceof() {
Object[][] a = new Object[2][3];
return a instanceof Object[][];
}
static boolean testInstanceof2() {
TestMultiArray[][] a = new TestMultiArray[2][3];
return a instanceof Object[][];
}
public static void main(String[] args) {
System.out.print("testInstanceof: ");
System.out.println(testInstanceof());
System.out.print("testInstanceof2: ");
System.out.println(testInstanceof2());
}
}

42
test/TestObjectArray.java Normal file
View File

@ -0,0 +1,42 @@
package test;
class TestObjectArray {
static boolean testInstanceEqual() {
TestObjectArray t1 = new TestObjectArray();
TestObjectArray t2 = new TestObjectArray();
TestObjectArray t3 = new TestObjectArray();
TestObjectArray[] a = {t1, t2, t3};
return
a[0] == t1 &&
a[1] == t2 &&
a[2] == t3 &&
a[0] != t2 &&
a[1] != t3 &&
a[2] != t1;
}
static boolean testEmptyInstanceof() {
TestObjectArray[] a = new TestObjectArray[1];
return a instanceof TestObjectArray[];
}
static boolean testNullInstanceof() {
TestObjectArray[] a = null;
return !(a instanceof TestObjectArray[]);
}
public static void main() {
System.out.print("testInstanceEqual: ");
System.out.println(testInstanceEqual());
System.out.print("testEmptyInstanceof: ");
System.out.println(testEmptyInstanceof());
System.out.print("testNullInstanceof: ");
System.out.println(testNullInstanceof());
}
}

View File

@ -1,4 +1,4 @@
package p;
package test;
class TestPrimitiveArray {
static boolean testBool() {
@ -24,12 +24,13 @@ class TestPrimitiveArray {
}
static boolean testChar() {
char[] a = {'a', 'b', 'c', 'd'};
char[] a = {'a', 'b', 'c', 'd', 200};
return
a[0] == 'a' &&
a[1] == 'b' &&
a[2] == 'c' &&
a[3] == 'd';
a[3] == 'd' &&
a[4] > 0;
}
static boolean testShort() {