add class_resolver

Implement the getfield and invokestatic opcodes.
This commit is contained in:
Zack Buhman 2024-12-23 23:25:45 -06:00
parent 39f53e8ee4
commit 932a7c82aa
16 changed files with 620 additions and 232 deletions

View File

@ -11,7 +11,9 @@ OBJ = \
c/malloc.o \
c/file.o \
c/execute.o \
c/memory_allocator.o
c/memory_allocator.o \
c/class_resolver.o \
c/hash_table.o
MAIN_OBJ = \
$(OBJ) \
@ -24,7 +26,7 @@ PRINT_CLASS_OBJ = \
CC ?= gcc
ARCH = -m32
CFLAGS ?= -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -std=c2x -DDEBUG -g
OPT ?= -Og
OPT ?= -O0
DEPFLAGS = -MMD -MP
%.o: %.c

BIN
c/a.out

Binary file not shown.

163
c/class_resolver.c Normal file
View File

@ -0,0 +1,163 @@
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include "class_file.h"
#include "file.h"
#include "hash_table.h"
#include "malloc.h"
#include "class_resolver.h"
#include "string.h"
#include "debug_class_file.h"
struct hash_table_entry * class_resolver_load_from_filenames(const char * filenames[], int length, int * hash_table_length)
{
int class_hash_table_length = length * 2;
uint32_t class_hash_table_size = (sizeof (struct hash_table_entry)) * class_hash_table_length;
struct hash_table_entry * class_hash_table = malloc_class_arena(class_hash_table_size);
uint32_t class_entry_size = (sizeof (struct class_entry)) * length;
struct class_entry * class_entry = malloc_class_arena(class_entry_size);
for (int i = 0; i < length; i++) {
uint32_t filename_length = string_length(filenames[i]);
const char * suffix = ".class";
uint32_t suffix_length = string_length(suffix);
const char * filename_suffix = &filenames[i][filename_length - suffix_length];
if (filename_length <= suffix_length || !string_equal(suffix, filename_suffix)) {
printf("invalid class filename: %s\n", filenames[i]);
continue;
}
uint32_t class_name_length = filename_length - suffix_length;
printf("load class: %s\n", filenames[i]);
uint8_t * buf = file_read(filenames[i]);
struct class_file * class_file = class_file_parse(buf);
free(buf);
assert(class_file->magic == 0xcafebabe);
class_entry[i].class_file = class_file;
hash_table_add(class_hash_table_length,
class_hash_table,
(const uint8_t *)filenames[i],
class_name_length,
&class_entry[i]);
// make hash table for interfaces
/*
if (class_file->interfaces_count != 0) {
uint32_t interfaces_hash_table_size = (sizeof (struct hash_table_entry)) * class_file->interfaces_count * 3 / 2;
struct hash_table_entry * interfaces_hash_table = malloc_class_arena(interfaces_hash_table_size);
for (int i = 0; i < class_file->interfaces_count; i++) {
}
}
*/
// make hash table for fields
if (class_file->fields_count != 0) {
int fields_hash_table_length = class_file->fields_count * 2;
uint32_t fields_hash_table_size = (sizeof (struct hash_table_entry)) * fields_hash_table_length;
struct hash_table_entry * fields_hash_table = malloc_class_arena(fields_hash_table_size);
uint32_t field_entry_size = (sizeof (struct field_entry)) * length;
struct field_entry * field_entry = malloc_class_arena(field_entry_size);
for (int i = 0; i < class_file->fields_count; i++) {
u2 name_index = class_file->fields[i].name_index;
struct constant * name_constant = &class_file->constant_pool[name_index - 1];
assert(name_constant->tag == CONSTANT_Utf8);
printf("hash table entry for field: ");
print_utf8_string(name_constant);
printf("\n");
field_entry[i].field_info = &class_file->fields[i];
field_entry[i].value = 0;
hash_table_add(fields_hash_table_length,
fields_hash_table,
name_constant->utf8.bytes,
name_constant->utf8.length,
(void *)&field_entry[i]);
}
class_entry[i].fields.length = fields_hash_table_length;
class_entry[i].fields.entry = fields_hash_table;
}
// make hash table for methods
if (class_file->methods_count != 0) {
int methods_hash_table_length = class_file->methods_count * 2;
uint32_t methods_hash_table_size = (sizeof (struct hash_table_entry)) * methods_hash_table_length;
struct hash_table_entry * methods_hash_table = malloc_class_arena(methods_hash_table_size);
for (int i = 0; i < class_file->methods_count; i++) {
u2 name_index = class_file->methods[i].name_index;
struct constant * name_constant = &class_file->constant_pool[name_index - 1];
assert(name_constant->tag == CONSTANT_Utf8);
printf("hash table entry for method: ");
print_utf8_string(name_constant);
printf("\n");
hash_table_add(methods_hash_table_length,
methods_hash_table,
name_constant->utf8.bytes,
name_constant->utf8.length,
(void *)&class_file->methods[i]);
}
class_entry[i].methods.length = methods_hash_table_length;
class_entry[i].methods.entry = methods_hash_table;
}
};
*hash_table_length = class_hash_table_length;
return class_hash_table;
}
struct class_entry * class_resolver_lookup_class(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
const uint8_t * class_name,
int class_name_length)
{
struct hash_table_entry * e = hash_table_find(class_hash_table_length,
class_hash_table,
class_name,
class_name_length);
assert(e != nullptr);
return (struct class_entry *)e->value;
}
struct field_entry * class_resolver_lookup_field(struct class_entry * class_entry,
const uint8_t * field_name,
int field_name_length)
{
int fields_hash_table_length = class_entry->fields.length;
struct hash_table_entry * fields_hash_table = class_entry->fields.entry;
struct hash_table_entry * e = hash_table_find(fields_hash_table_length,
fields_hash_table,
field_name,
field_name_length);
assert(e != nullptr);
return (struct field_entry *)e->value;
}
struct method_info * class_resolver_lookup_method(struct class_entry * class_entry,
const uint8_t * method_name,
int method_name_length)
{
int methods_hash_table_length = class_entry->methods.length;
struct hash_table_entry * methods_hash_table = class_entry->methods.entry;
struct hash_table_entry * e = hash_table_find(methods_hash_table_length,
methods_hash_table,
method_name,
method_name_length);
assert(e != nullptr);
return (struct method_info *)e->value;
}

42
c/class_resolver.h Normal file
View File

@ -0,0 +1,42 @@
#pragma once
#include <stdint.h>
#include "class_file.h"
#include "hash_table.h"
struct field_entry {
struct field_info * field_info;
uint32_t value;
};
struct class_entry {
struct class_file * class_file;
struct {
int length;
struct hash_table_entry * entry;
} interfaces;
struct {
int length;
struct hash_table_entry * entry;
} fields;
struct {
int length;
struct hash_table_entry * entry;
} methods;
};
struct hash_table_entry * class_resolver_load_from_filenames(const char * filenames[], int length, int * hash_table_length);
struct class_entry * class_resolver_lookup_class(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
const uint8_t * class_name,
int class_name_length);
struct method_info * class_resolver_lookup_method(struct class_entry * class_entry,
const uint8_t * method_name,
int method_name_length);
struct field_entry * class_resolver_lookup_field(struct class_entry * class_entry,
const uint8_t * field_name,
int field_name_length);

View File

@ -8,6 +8,13 @@
#include "decode.h"
#include "debug_class_file.h"
void print_utf8_string(struct constant * constant)
{
for (int i = 0; i < constant->utf8.length; i++) {
fputc(constant->utf8.bytes[i], stdout);
}
}
void print_constant(struct constant * constant)
{
switch (constant->tag) {
@ -60,10 +67,8 @@ void print_constant(struct constant * constant)
case CONSTANT_Utf8:
printf("CONSTANT_Utf8 length=%d bytes=",
constant->utf8.length);
for (int i = 0; i < constant->utf8.length; i++) {
fputc(constant->utf8.bytes[i], stdout);
}
fputc('\n', stdout);
print_utf8_string(constant);
printf("\n");
break;
case CONSTANT_MethodHandle:
printf("CONSTANT_MethodHandle reference_kind=%d reference_index=%d\n",

View File

@ -2,6 +2,7 @@
#include "class_file.h"
void print_utf8_string(struct constant * constant);
void print_constant(struct constant * constant);
void print_attribute(const char * indent, struct attribute_info * attribute, struct constant * constant_pool);
void print_class_file(struct class_file * class_file);

View File

@ -3,6 +3,7 @@
#include "execute.h"
#include "memory_allocator.h"
#include "bswap.h"
#include "class_resolver.h"
void op_aaload(struct vm * vm)
{
@ -449,7 +450,40 @@ void op_getfield(struct vm * vm, uint32_t index)
void op_getstatic(struct vm * vm, uint32_t index)
{
assert(!"op_getstatic");
struct constant * fieldref_constant = &vm->current_thread.current_class->constant_pool[index - 1];
#ifdef DEBUG
assert(fieldref_constant->tag == CONSTANT_Fieldref);
#endif
struct constant * class_constant = &vm->current_thread.current_class->constant_pool[fieldref_constant->fieldref.class_index - 1];
#ifdef DEBUG
assert(class_constant->tag == CONSTANT_Class);
#endif
struct constant * nameandtype_constant = &vm->current_thread.current_class->constant_pool[fieldref_constant->fieldref.name_and_type_index - 1];
#ifdef DEBUG
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
#endif
struct constant * class_name_constant = &vm->current_thread.current_class->constant_pool[class_constant->class.name_index - 1];
#ifdef DEBUG
assert(class_name_constant->tag == CONSTANT_Utf8);
#endif
struct constant * field_name_constant = &vm->current_thread.current_class->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
#ifdef DEBUG
assert(field_name_constant->tag == CONSTANT_Utf8);
#endif
struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
vm->class_hash_table.entry,
class_name_constant->utf8.bytes,
class_name_constant->utf8.length);
assert(class_entry != nullptr);
struct field_entry * field_entry = class_resolver_lookup_field(class_entry,
field_name_constant->utf8.bytes,
field_name_constant->utf8.length);
assert(field_entry != nullptr);
uint32_t value = field_entry->value;
operand_stack_push_u32(vm->current_frame, value);
}
void op_goto(struct vm * vm, int32_t branch)
@ -789,7 +823,39 @@ void op_invokespecial(struct vm * vm, uint32_t index)
void op_invokestatic(struct vm * vm, uint32_t index)
{
assert(!"op_invokestatic");
struct constant * methodref_constant = &vm->current_thread.current_class->constant_pool[index - 1];
#ifdef DEBUG
assert(methodref_constant->tag == CONSTANT_Methodref);
#endif
struct constant * class_constant = &vm->current_thread.current_class->constant_pool[methodref_constant->methodref.class_index - 1];
#ifdef DEBUG
assert(class_constant->tag == CONSTANT_Class);
#endif
struct constant * nameandtype_constant = &vm->current_thread.current_class->constant_pool[methodref_constant->methodref.name_and_type_index - 1];
#ifdef DEBUG
assert(nameandtype_constant->tag == CONSTANT_NameAndType);
#endif
struct constant * class_name_constant = &vm->current_thread.current_class->constant_pool[class_constant->class.name_index - 1];
#ifdef DEBUG
assert(class_name_constant->tag == CONSTANT_Utf8);
#endif
struct constant * method_name_constant = &vm->current_thread.current_class->constant_pool[nameandtype_constant->nameandtype.name_index - 1];
#ifdef DEBUG
assert(method_name_constant->tag == CONSTANT_Utf8);
#endif
struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length,
vm->class_hash_table.entry,
class_name_constant->utf8.bytes,
class_name_constant->utf8.length);
assert(class_entry != nullptr);
struct method_info * method_info = class_resolver_lookup_method(class_entry,
method_name_constant->utf8.bytes,
method_name_constant->utf8.length);
assert(method_info != nullptr);
vm_static_method_call(vm, class_entry->class_file, method_info);
}
void op_invokevirtual(struct vm * vm, uint32_t index)
@ -815,6 +881,13 @@ void op_irem(struct vm * vm)
void op_ireturn(struct vm * vm)
{
/* Prior to pushing value onto the operand stack of the frame of the invoker,
it may have to be converted. If the return type of the invoked method was
byte, char, or short, then value is converted from int to the return type
as if by execution of i2b, i2c, or i2s, respectively. If the return type
of the invoked method was boolean, then value is narrowed from int to
boolean by taking the bitwise AND of value and 1. */
uint32_t value = operand_stack_pop_u32(vm->current_frame);
printf("return %d\n", value);
}

101
c/frame.c
View File

@ -3,12 +3,13 @@
#include <stdio.h>
#include "class_file.h"
#include "file.h"
#include "memory.h"
#include "debug_class_file.h"
#include "bytes.h"
#include "decode.h"
#include "frame.h"
#include "class_resolver.h"
#include "string.h"
struct frame * stack_push_frame(struct stack * stack, int num_frames)
{
@ -66,28 +67,70 @@ int find_code_name_index(struct class_file * class_file)
return 0;
}
void vm_execute(struct vm * vm)
static int descriptor_nargs(struct constant * descriptor_constant)
{
printf("execute:\n");
struct constant * class = &vm->current_thread.current_class->constant_pool[vm->current_thread.current_class->this_class - 1];
print_constant(class);
print_constant(&vm->current_thread.current_class->constant_pool[class->class.name_index - 1]);
print_constant(&vm->current_thread.current_class->constant_pool[vm->current_thread.current_method->name_index - 1]);
assert(descriptor_constant->tag == CONSTANT_Utf8);
assert(descriptor_constant->utf8.length >= 2);
assert(descriptor_constant->utf8.bytes[0] == '(');
int code_name_index = find_code_name_index(vm->current_thread.current_class);
int i = 1;
int nargs = 0;
while (i < descriptor_constant->utf8.length) {
if (descriptor_constant->utf8.bytes[i] == ')')
break;
nargs += 1;
i += 1;
}
assert(i + 2 == descriptor_constant->utf8.length);
return nargs;
}
void vm_static_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info)
{
/* If the method is not native, the nargs argument values are popped from the
operand stack. A new frame is created on the Java Virtual Machine stack for
the method being invoked. The nargs argument values are consecutively made
the values of local variables of the new frame, with arg1 in local variable
0 (or, if arg1 is of type long or double, in local variables 0 and 1) and
so on. The new frame is then made current, and the Java Virtual Machine pc
is set to the opcode of the first instruction of the method to be
invoked. Execution continues with the first instruction of the method.
*/
int code_name_index = find_code_name_index(class_file);
assert(code_name_index > 0);
printf("code_name_index %d\n", code_name_index);
struct Code_attribute * code = get_code_attribute(code_name_index,
vm->current_thread.current_method->attributes_count,
vm->current_thread.current_method->attributes);
method_info->attributes_count,
method_info->attributes);
assert(code != nullptr);
struct frame * old_frame = vm->current_frame;
vm->current_frame = stack_push_frame(&vm->frame_stack, 1);
vm->current_frame->code = code;
vm->current_frame->local_variable = stack_push_data(&vm->data_stack, code->max_locals);
vm->current_frame->operand_stack = stack_push_data(&vm->data_stack, code->max_stack);
vm->current_frame->operand_stack_ix = 0;
struct constant * descriptor_constant = &class_file->constant_pool[method_info->descriptor_index - 1];
int nargs = descriptor_nargs(descriptor_constant);
printf("nargs %d\n", nargs);
for (int i = 0; i < nargs; i++) {
uint32_t value = operand_stack_pop_u32(old_frame);
vm->current_frame->local_variable[nargs - i - 1] = value;
}
vm->current_thread.pc = 0;
vm->current_thread.current_class = class_file;
vm->current_thread.current_method = method_info;
}
void vm_execute(struct vm * vm)
{
printf("execute:\n");
while (true) {
printf("[ ");
for (int i = 5; i > 0; i--) {
@ -102,34 +145,47 @@ void vm_execute(struct vm * vm)
printf("%10d ", value);
}
printf("]\n");
decode_print_instruction(code->code, vm->current_thread.pc);
decode_print_instruction(vm->current_frame->code->code, vm->current_thread.pc);
uint32_t old_pc = vm->current_thread.pc;
uint32_t next_pc = decode_execute_instruction(vm, code->code, vm->current_thread.pc);
uint32_t next_pc = decode_execute_instruction(vm, vm->current_frame->code->code, vm->current_thread.pc);
if (vm->current_thread.pc == old_pc) {
// if the instruction did not branch, increment pc
vm->current_thread.pc = next_pc;
}
if (vm->current_thread.pc >= code->code_length) {
if (vm->current_thread.pc >= vm->current_frame->code->code_length) {
printf("terminate\n");
break;
}
}
}
int main(int argc, char * argv[])
int main(int argc, const char * argv[])
{
assert(argc >= 2);
uint8_t * buf = file_read(argv[1]);
struct class_file * class_file = class_file_parse(buf);
assert(argc >= 3);
assert(class_file->magic == 0xcafebabe);
assert(class_file->methods_count >= 1);
const char * main_class = argv[1];
const char ** class_filenames = &argv[2];
int num_class_filenames = argc - 2;
int class_hash_table_length;
struct hash_table_entry * class_hash_table = class_resolver_load_from_filenames(class_filenames, num_class_filenames, &class_hash_table_length);
struct class_entry * class_entry = class_resolver_lookup_class(class_hash_table_length,
class_hash_table,
(const uint8_t *)main_class,
string_length(main_class));
const char * method_name = "test";
int method_name_length = string_length(method_name);
struct method_info * method_info = class_resolver_lookup_method(class_entry,
(const uint8_t *)method_name,
method_name_length);
struct vm vm;
vm.current_thread.pc = 0;
vm.current_thread.current_class = class_file;
vm.current_thread.current_method = &class_file->methods[1];
vm.class_hash_table.entry = class_hash_table;
vm.class_hash_table.length = class_hash_table_length;
vm.frame_stack.ix = 0;
vm.frame_stack.capacity = 1024;
@ -141,5 +197,6 @@ int main(int argc, char * argv[])
uint32_t data[vm.data_stack.capacity];
vm.data_stack.data = data;
vm_static_method_call(&vm, class_entry->class_file, method_info);
vm_execute(&vm);
}

View File

@ -5,12 +5,10 @@
#include "class_file.h"
struct frame {
struct Code_attribute * code;
uint32_t * local_variable;
uint32_t * operand_stack;
uint16_t operand_stack_ix;
#ifdef DEBUG
uint32_t operand_stack_capacity;
#endif
};
struct thread {
@ -33,6 +31,10 @@ struct vm {
struct stack data_stack;
struct thread current_thread;
struct frame * current_frame;
struct {
int length;
struct hash_table_entry * entry;
} class_hash_table;
};
static inline void operand_stack_push_u32(struct frame * frame, uint32_t value)
@ -55,3 +57,5 @@ static inline void operand_stack_dup_u32(struct frame * frame)
frame->operand_stack[frame->operand_stack_ix] = value;
frame->operand_stack_ix++;
}
void vm_static_method_call(struct vm * vm, struct class_file * class_file, struct method_info * method_info);

View File

@ -1,4 +1,5 @@
#include <stdint.h>
#include "malloc.h"
#include "hash_table.h"
static uint32_t fnv_1(const uint8_t * buf, int length)
{
@ -15,31 +16,17 @@ static uint32_t fnv_1(const uint8_t * buf, int length)
return hash;
}
struct hash_table_entry {
const uint8_t * key;
int key_length;
void * value;
struct hash_table_entry * next;
};
void hash_table_init(int hash_table_length,
struct hash_table_entry * entry,
struct hash_table_entry * overflow)
struct hash_table_entry * entry)
{
for (int i = 0; i < hash_table_length; i++) {
entry[i].key = nullptr;
entry[i].next = nullptr;
overflow[i].key = nullptr;
overflow[i].next = nullptr;
}
}
static int max = 0;
void hash_table_add(int hash_table_length,
struct hash_table_entry * entry,
struct hash_table_entry * overflow,
int * overflow_length,
const uint8_t * key,
int key_length,
void * value)
@ -51,12 +38,9 @@ void hash_table_add(int hash_table_length,
e = e->next;
}
int i = 0;
if (e->key != nullptr) {
if ((++i) > max) max = i;
// allocate e from overflow
e->next = &overflow[(*overflow_length)++];
e->next = malloc_class_arena((sizeof (struct hash_table_entry)));
e = e->next;
}
@ -74,195 +58,19 @@ static inline bool key_equal(const uint8_t * a, const uint8_t * b, int length)
return true;
}
#include <stdio.h>
struct hash_table_entry * hash_table_find(int hash_table_length,
struct hash_table_entry * entry,
struct hash_table_entry * overflow,
const uint8_t * key,
int key_length)
{
uint32_t hash = fnv_1(key, key_length) & (hash_table_length - 1);
struct hash_table_entry * e = &entry[hash];
while (e->key != nullptr) {
while (e != nullptr && e->key != nullptr) {
if (e->key_length == key_length && key_equal(e->key, key, key_length)) {
return e;
}
printf("collision %s %s\n", (char *)e->key, (char *)key);
e = e->next;
}
return nullptr;
}
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <assert.h>
static const char * names[] = {
"java/beans/Introspector.java",
"java/beans/PropertyDescriptor.java",
"java/beans/PropertyVetoException.java",
"java/beans/BeanInfo.java",
"java/beans/Customizer.java",
"java/beans/FeatureDescriptor.java",
"java/beans/BeanDescriptor.java",
"java/beans/Beans.java",
"java/beans/AppletInitializer.java",
"java/beans/Expression.java",
"java/beans/MethodDescriptor.java",
"java/beans/PropertyChangeSupport.java",
"java/beans/PropertyChangeEvent.java",
"java/beans/DesignMode.java",
"java/beans/EventSetDescriptor.java",
"java/beans/IndexedPropertyDescriptor.java",
"java/beans/VetoableChangeListener.java",
"java/beans/ConstructorProperties.java",
"java/beans/IndexedPropertyChangeEvent.java",
"java/beans/PropertyEditorManager.java",
"java/beans/IntrospectionException.java",
"java/beans/PropertyChangeListener.java",
"java/beans/XMLEncoder.java",
"java/beans/Visibility.java",
"java/beans/VetoableChangeSupport.java",
"java/beans/ParameterDescriptor.java",
"java/beans/XMLDecoder.java",
"java/beans/PropertyChangeListenerProxy.java",
"java/beans/ExceptionListener.java",
"java/beans/VetoableChangeListenerProxy.java",
"java/beans/DefaultPersistenceDelegate.java",
"java/beans/EventHandler.java",
"java/beans/Statement.java",
"java/beans/PropertyEditor.java",
"java/beans/PropertyEditorSupport.java",
"java/beans/SimpleBeanInfo.java",
"java/beans/PersistenceDelegate.java",
"java/beans/Encoder.java",
"java/beans/beancontext/BeanContextChildSupport.java",
"java/beans/beancontext/BeanContextServicesSupport.java",
"java/beans/beancontext/BeanContextServiceRevokedEvent.java",
"java/beans/beancontext/BeanContextSupport.java",
"java/beans/beancontext/BeanContextServiceAvailableEvent.java",
"java/beans/beancontext/BeanContextServiceProvider.java",
"java/beans/beancontext/BeanContextProxy.java",
"java/beans/beancontext/BeanContextServiceProviderBeanInfo.java",
"java/beans/beancontext/BeanContextContainerProxy.java",
"java/beans/beancontext/BeanContextMembershipListener.java",
"java/beans/beancontext/BeanContextServices.java",
"java/beans/beancontext/BeanContextServiceRevokedListener.java",
"java/beans/beancontext/BeanContext.java",
"java/beans/beancontext/BeanContextChildComponentProxy.java",
"java/beans/beancontext/BeanContextMembershipEvent.java",
"java/beans/beancontext/BeanContextEvent.java",
"java/beans/beancontext/BeanContextServicesListener.java",
"java/beans/beancontext/BeanContextChild.java",
"java/net/ContentHandler.java",
"java/net/URL.java",
"java/net/FileNameMap.java",
"java/net/SocketOptions.java",
"java/net/DatagramSocketImplFactory.java",
"java/net/UnknownServiceException.java",
"java/net/SocketPermission.java",
"java/net/NoRouteToHostException.java",
"java/net/NetPermission.java",
"java/net/URI.java",
"java/net/DatagramSocket.java",
"java/net/DatagramPacket.java",
"java/net/BindException.java",
"java/net/SocketTimeoutException.java",
"java/net/ProxySelector.java",
"java/net/MalformedURLException.java",
"java/net/URLStreamHandlerFactory.java",
"java/net/InetAddress.java",
"java/net/PortUnreachableException.java",
"java/net/DatagramSocketImpl.java",
"java/net/UnknownHostException.java",
"java/net/ProtocolException.java",
"java/net/Proxy.java",
"java/net/PasswordAuthentication.java",
"java/net/SocketAddress.java",
"java/net/MulticastSocket.java",
"java/net/ServerSocket.java",
"java/net/JarURLConnection.java",
"java/net/Authenticator.java",
"java/net/URLStreamHandler.java",
"java/net/ConnectException.java",
"java/net/NetworkInterface.java",
"java/net/URLConnection.java",
"java/net/URLEncoder.java",
"java/net/InetSocketAddress.java",
"java/net/URISyntaxException.java",
"java/net/ResolverCache.java",
"java/net/Socket.java",
"java/net/Inet4Address.java",
"java/net/SocketException.java",
"java/net/SocketImplFactory.java",
"java/net/ContentHandlerFactory.java",
"java/net/HttpURLConnection.java",
"java/net/URLDecoder.java",
"java/net/SocketImpl.java",
"java/net/URLClassLoader.java",
"java/net/Inet6Address.java",
"java/net/MimeTypeMapper.java",
"java/math/MathContext.java",
"java/math/BigInteger.java",
"java/math/BigDecimal.java",
"java/math/RoundingMode.java",
"java/io/FileWriter.java",
"java/io/FilePermission.java",
"java/io/OutputStreamWriter.java",
"java/io/ObjectInput.java",
"java/io/BufferedOutputStream.java",
"java/io/IOError.java",
"java/io/LineNumberReader.java",
"java/io/StringReader.java",
"java/io/BufferedInputStream.java",
"java/io/CharArrayWriter.java",
"java/io/InputStreamReader.java",
"java/io/Console.java",
"java/io/FileOutputStream.java",
"java/io/StringBufferInputStream.java",
"java/io/DataOutput.java",
"java/io/UTFDataFormatException.java",
"java/io/ObjectStreamConstants.java",
"java/io/ObjectStreamException.java",
"java/io/BufferedReader.java",
"java/io/FilenameFilter.java",
};
const int names_length = (sizeof (names)) / (sizeof (names[0]));
int main()
{
int hash_table_length = 512;
struct hash_table_entry entry[hash_table_length];
struct hash_table_entry overflow[hash_table_length];
int overflow_length = 0;
hash_table_init(hash_table_length,
entry,
overflow);
for (int i = 0; i < names_length; i++) {
hash_table_add(hash_table_length,
entry,
overflow,
&overflow_length,
(const uint8_t *)names[i],
strlen(names[i]),
(void *)(ptrdiff_t)(i * 2));
}
printf("overflow_length %d %d\n", overflow_length, max);
for (int j = 0; j < names_length; j++) {
struct hash_table_entry * e = hash_table_find(hash_table_length,
entry,
overflow,
(const uint8_t *)names[j],
strlen(names[j]));
assert(e != nullptr);
printf("%s %d\n", e->key, (int)e->value);
}
}

24
c/hash_table.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <stdint.h>
struct hash_table_entry {
const uint8_t * key;
int key_length;
void * value;
struct hash_table_entry * next;
};
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_find(int hash_table_length,
struct hash_table_entry * entry,
const uint8_t * key,
int key_length);

View File

@ -1,5 +1,3 @@
#include <stdint.h>
#include "malloc.h"
struct arena {

View File

@ -1,3 +1,5 @@
#pragma once
#include <stdint.h>
void * malloc_class_arena(uint32_t size);

21
c/string.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
static inline int string_length(const char * s)
{
const char * si = s;
while (*si != 0) {
si++;
}
return si - s;
}
static inline bool string_equal(const char * a, const char * b)
{
int i = 0;
while (a[i] != 0) {
if (a[i] != b[i])
return false;
i += 1;
}
return b[i] == 0;
}

175
c/test_hash_table.c Normal file
View File

@ -0,0 +1,175 @@
#include <stdio.h>
#include <stddef.h>
#include <assert.h>
#include "hash_table.h"
static const char * names[] = {
"java/beans/Introspector.java",
"java/beans/PropertyDescriptor.java",
"java/beans/PropertyVetoException.java",
"java/beans/BeanInfo.java",
"java/beans/Customizer.java",
"java/beans/FeatureDescriptor.java",
"java/beans/BeanDescriptor.java",
"java/beans/Beans.java",
"java/beans/AppletInitializer.java",
"java/beans/Expression.java",
"java/beans/MethodDescriptor.java",
"java/beans/PropertyChangeSupport.java",
"java/beans/PropertyChangeEvent.java",
"java/beans/DesignMode.java",
"java/beans/EventSetDescriptor.java",
"java/beans/IndexedPropertyDescriptor.java",
"java/beans/VetoableChangeListener.java",
"java/beans/ConstructorProperties.java",
"java/beans/IndexedPropertyChangeEvent.java",
"java/beans/PropertyEditorManager.java",
"java/beans/IntrospectionException.java",
"java/beans/PropertyChangeListener.java",
"java/beans/XMLEncoder.java",
"java/beans/Visibility.java",
"java/beans/VetoableChangeSupport.java",
"java/beans/ParameterDescriptor.java",
"java/beans/XMLDecoder.java",
"java/beans/PropertyChangeListenerProxy.java",
"java/beans/ExceptionListener.java",
"java/beans/VetoableChangeListenerProxy.java",
"java/beans/DefaultPersistenceDelegate.java",
"java/beans/EventHandler.java",
"java/beans/Statement.java",
"java/beans/PropertyEditor.java",
"java/beans/PropertyEditorSupport.java",
"java/beans/SimpleBeanInfo.java",
"java/beans/PersistenceDelegate.java",
"java/beans/Encoder.java",
"java/beans/beancontext/BeanContextChildSupport.java",
"java/beans/beancontext/BeanContextServicesSupport.java",
"java/beans/beancontext/BeanContextServiceRevokedEvent.java",
"java/beans/beancontext/BeanContextSupport.java",
"java/beans/beancontext/BeanContextServiceAvailableEvent.java",
"java/beans/beancontext/BeanContextServiceProvider.java",
"java/beans/beancontext/BeanContextProxy.java",
"java/beans/beancontext/BeanContextServiceProviderBeanInfo.java",
"java/beans/beancontext/BeanContextContainerProxy.java",
"java/beans/beancontext/BeanContextMembershipListener.java",
"java/beans/beancontext/BeanContextServices.java",
"java/beans/beancontext/BeanContextServiceRevokedListener.java",
"java/beans/beancontext/BeanContext.java",
"java/beans/beancontext/BeanContextChildComponentProxy.java",
"java/beans/beancontext/BeanContextMembershipEvent.java",
"java/beans/beancontext/BeanContextEvent.java",
"java/beans/beancontext/BeanContextServicesListener.java",
"java/beans/beancontext/BeanContextChild.java",
"java/net/ContentHandler.java",
"java/net/URL.java",
"java/net/FileNameMap.java",
"java/net/SocketOptions.java",
"java/net/DatagramSocketImplFactory.java",
"java/net/UnknownServiceException.java",
"java/net/SocketPermission.java",
"java/net/NoRouteToHostException.java",
"java/net/NetPermission.java",
"java/net/URI.java",
"java/net/DatagramSocket.java",
"java/net/DatagramPacket.java",
"java/net/BindException.java",
"java/net/SocketTimeoutException.java",
"java/net/ProxySelector.java",
"java/net/MalformedURLException.java",
"java/net/URLStreamHandlerFactory.java",
"java/net/InetAddress.java",
"java/net/PortUnreachableException.java",
"java/net/DatagramSocketImpl.java",
"java/net/UnknownHostException.java",
"java/net/ProtocolException.java",
"java/net/Proxy.java",
"java/net/PasswordAuthentication.java",
"java/net/SocketAddress.java",
"java/net/MulticastSocket.java",
"java/net/ServerSocket.java",
"java/net/JarURLConnection.java",
"java/net/Authenticator.java",
"java/net/URLStreamHandler.java",
"java/net/ConnectException.java",
"java/net/NetworkInterface.java",
"java/net/URLConnection.java",
"java/net/URLEncoder.java",
"java/net/InetSocketAddress.java",
"java/net/URISyntaxException.java",
"java/net/ResolverCache.java",
"java/net/Socket.java",
"java/net/Inet4Address.java",
"java/net/SocketException.java",
"java/net/SocketImplFactory.java",
"java/net/ContentHandlerFactory.java",
"java/net/HttpURLConnection.java",
"java/net/URLDecoder.java",
"java/net/SocketImpl.java",
"java/net/URLClassLoader.java",
"java/net/Inet6Address.java",
"java/net/MimeTypeMapper.java",
"java/math/MathContext.java",
"java/math/BigInteger.java",
"java/math/BigDecimal.java",
"java/math/RoundingMode.java",
"java/io/FileWriter.java",
"java/io/FilePermission.java",
"java/io/OutputStreamWriter.java",
"java/io/ObjectInput.java",
"java/io/BufferedOutputStream.java",
"java/io/IOError.java",
"java/io/LineNumberReader.java",
"java/io/StringReader.java",
"java/io/BufferedInputStream.java",
"java/io/CharArrayWriter.java",
"java/io/InputStreamReader.java",
"java/io/Console.java",
"java/io/FileOutputStream.java",
"java/io/StringBufferInputStream.java",
"java/io/DataOutput.java",
"java/io/UTFDataFormatException.java",
"java/io/ObjectStreamConstants.java",
"java/io/ObjectStreamException.java",
"java/io/BufferedReader.java",
"java/io/FilenameFilter.java",
};
const int names_length = (sizeof (names)) / (sizeof (names[0]));
static uint32_t _strlen(const char * s)
{
const char * si = s;
while (*si != 0) {
si++;
}
return si - s;
}
int main()
{
int hash_table_length = 128 * 2;
struct hash_table_entry entry[hash_table_length];
hash_table_init(hash_table_length,
entry);
for (int i = 0; i < names_length; i++) {
hash_table_add(hash_table_length,
entry,
(const uint8_t *)names[i],
_strlen(names[i]),
(void *)(ptrdiff_t)(i * 2));
}
for (int j = 0; j < names_length; j++) {
struct hash_table_entry * e = hash_table_find(hash_table_length,
entry,
(const uint8_t *)names[j],
_strlen(names[j]));
if (e < entry || e >= entry + hash_table_length) {
printf("collision %s\n", e->key);
}
assert(e != nullptr);
printf("%s %d\n", e->key, (int)e->value);
}
}

13
p/DataTest.java Normal file
View File

@ -0,0 +1,13 @@
package p;
import p.Data;
class DataTest {
static int test() {
return test2(6, 3) * 5;
}
static int test2(int a, int b) {
return a - b;
}
}