From baa3db16b1321760fc1ac323c096dc1ed88dc209 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Tue, 24 Dec 2024 20:23:54 -0600 Subject: [PATCH] implement static method overloading --- .gitignore | 1 + c/a.out | Bin 19772 -> 0 bytes c/class_resolver.c | 33 ++++++---- c/class_resolver.h | 4 +- c/execute.c | 8 ++- c/frame.c | 8 ++- c/hash_table.c | 110 ++++++++++++++++++++++++++++++--- c/hash_table.h | 15 +++++ c/main.c | 6 +- c/malloc.c | 4 ++ c/test_hash_table.c | 9 ++- p/Instance.java | 24 +++++++ p/StaticMethodOverloading.java | 19 ++++++ 13 files changed, 215 insertions(+), 26 deletions(-) delete mode 100755 c/a.out create mode 100644 p/Instance.java create mode 100644 p/StaticMethodOverloading.java diff --git a/.gitignore b/.gitignore index 2556324..17c1e98 100644 --- a/.gitignore +++ b/.gitignore @@ -4,5 +4,6 @@ *.gch *.csv *.class +*.out main print_class \ No newline at end of file diff --git a/c/a.out b/c/a.out deleted file mode 100755 index 82903c4cc8e27f43af91ef18585110381b224d7c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19772 zcmeHPe{dVebzYE^McK3n*>t4Fv<*9wBik}W%B(C|PQzbEkqJpb{2~8Re1d=@0TBdX z;2={TbxH+tBLw0MlQx_wL?;2avRszuL}VIUm2>eQ)2seY>}J2ORE?l;#GT%_d|j6orCH{dOU$z(b9u zq)IqMiC8ag6XoJMRFO=g9}Ngas3Q~tLnuq!j52{_s5St~q=Usm5J)c2FX<3VG@?Vo zGOjn|4ip&nGN=O9_G5n_#8|6|-Ee5I&~ErmHVe@7BIFk#C(NQupmC86!g+Ke(Sb5S z%Gy8By;4S81sOrgU67xx6hcCWj3DJZAxCjRqW)>vZIE02uRtFJY7Y_{1OB}m1K#@s z{$Q-n84Wo%nX_Gl6bIRnqOk|Jz zEOMCRT1Ammn|7#C-Rlpkv8d)1s_KqLwTP~Ex%~l@5JnH=Zq)R;{Xx`t`rK-lKj;ql zpV34(;t%RwsD+BBNA>u6%!bsAqP|&dZ*HosQ#Uy)oeyO4Rhe8xCig%UTh52FTYUX<8M&@Q_7jp;mqs+UR_b_{zear#oFtg6w$9#~vpZPHJ5$2=JgUrt{ zKhJ!O`8e}S%qN&nGQY|^#C(eRH1ja?S?2T17nsMG$C)oOPcTn1Ut&%%Pcct3&oIw2 z&oPUgJfFv$mzYz`Q_R!MGt9HhbIhWR=byQlxrEuyT*kbHxt!U-JcWJX zI-De?iE)CMA;wNJM~oBC1b8_%xO%4Jlh%FDw>c@356-{n`0vIE(!LHsjP-=j zUt5owR07RrlI3ehx(2%jB~zaMQkSUF8#kcQz&Cf}Vr1a!^ndGl{kG)S%OS&9ZthHc z5T7dBNkg)~HR2r5?-nBiLw7?eQZE_p{|+AqK&#zqBR*Ah&-uj2nbaL;J}IzWe0x?e zOMZI;nf!%*J;LVNnf?U~CcidEHcfMbAD7<#2^mVY!|OvMQP_o@{=W&sDG~c(GVUM) z!}_ZDR7v_Z`qUtG`O|b7c2bpS@n)P9ZEO>MlD*51K$0w5J7SE(o>~i)WouwLsT3!a zxhq9+WzLpV=1PAe4iCrv4Y~W2;r#XECKIEh$~fIXCzbI5S31#o@yujV;*C=@kMWevHuf{h{WT!|F4%?>Z-SDC<1SPoa<0@zX3!FE zWYzC#bFr0I3@eT}8lUP%qpiw?gRhS&W5|lje}R8VWz1^tg?W3jK4Ys6@rFkUWiqKu zY*i*BHz7(!d{DNHQO%kpgz&7`H4s1bZaVEsy+3EnYWxo;MeL4&_!L$8PNL(1_?wg; zh+j1HehEElTwP3KF^m+oLHdCq{XSb!#^f-@N{`lHIV9#z(NL0|m$dtCp^4O&rCjiH zK%0K-i6_;s4Y=nv3?ax9m9_S7fTB@Wik=|pWwmU^c>VW*1D zvV^P1$gD}YiU*BDkPo=musD{z{18RY9OSxW=N!k!o@_z3#C9H`+VY0J+?bXtt1`p0 zAAIK&)}qKntc#324r4sN$BmU|86V79!j({FuT)~5lGR09m9p4vl;x(b)NUg-C5MOg zWvIWh+R#HBW(_Tb;Z4JxOy3{=H~Rk7R?Nr|S}e)INAchG^8`k7gt7=SN=7Z5cndpj zd+MA2MHBL8Xhf%qa+Hj7M%1YO4pq~6f~GW|@)5{KARmEz1o9EcM<5@8d<6dQM}WTX zwc)$JeeV74je9kBFuJiRs7FH4u;$T25hvBtC@gYUBoxNCs0Zq`s3+nN&ucBBvrE%M zN}opy>;6#CG-lDNMSo4fuFwKOT`a1HdhsP}#sN#K2F5=R#s zTTM6|(DbIDU-uhd0(1YCrb=HpqD7;b;bh0AMbmvDZ*I@oIx>EBK6kKNYmbG)p@=S> zvGkO!r|j2)tYy(bPyX&;OUSFS0gKFN(XQzWys_vs1-)9I=9OJ7P_@RC=90dzHvMj< z@3DiK39{I%3k9QkBu2}J?fSJ$uq}EyeVb-2!?gA-9aOx2m~C+f-QAh4t$Ooo7Za4T z@T_{$-eP01xcF#Gvl8?mx(nCAE`QX&*B|if2jtXQ?Ptg8Gv?SGarbI?ARssL*-q4J z7ALIzEItm@_OV+QJDG6gOr6zUw%<~5aeMVzmpc~FU0Nh+tOXAa$$-}F)_E;jyQan4 z=ni@Vi$tRxoOG3R~Z8kgfY^i)J;m`uW-I+O++l9?iSNF|<_MtPSXzeXQA! zhiGU!u=bWUcT4qWjuA7r-=8_Ku3?OpMVP&xURyu4n3?%=%{BB#(}<^nG}^@E(R3~2 zYtef5;*jw9!}9Qv8^kromUqi**5`Tu-TN~=yLvyyTCNNAhVjf&P`3u;>TT!aVO=R# zZ)erMmblAfCp!vP@5dOMB@jVP-)J1di|tq>>}+e!QE%`Ev{vlnE$(oRq&?*6(exe0 z1lrarg-UnC3~A& zeC0RldiW}V%DOtuxIN!_&T=7Z0j$X8kUMk!&$Ob!ZeDz_E!Yb>4uol!4QE|O_PTW+ zj&W|G%pHT#nUuhJf3KSl#(4=g${-#b?w-H3GGzYHM%wHjiTJUk zEaT$(+>Miu14wto^l(f!cbdgo@7TK!$465TO1#SF+t$Xqy71(%*J>lX@1`9}BqEO= z>1eY*sI|uEVx&#Wi8LI7D;S+&T%JIWcU^vJ1w3dt`xwT1tj`$-ouU_z#U~M=vWuMUg%m>SAFiNPu1z9;`9j3 zap#vD!B`*=)+1tF)UnQcy)YhHM_b#ih1xRg$p;2Xl-;0<8<%9)bw znKofNSZuqsq^RhKZF#XBb>+Z%^t*u+kQUb!!T}lS9{Xo}9}X5PiyKy!e5LdTy{J!o z`SaWE-L&>DvR4h9hmL#(h1zrgAE6H?Sk$a6ezu_Y#%24?!3$GgM|B!<8+;Y@B{tDy zUsezk^`(We@OAd(1+jzn>k49h_QHagUYN3-fkw?p&6_o&HRtNc2=z;GJdJq4q>-rK z3&2U#Jw`RM--1q~W0Fq+A3$!5CnIk*eI6;23Zgm;!G8f)Gxi8PI{}fgxZLC|ZkqAm9n04|on30w#btz_Ct< zEkFQx377=zc$(h@905)Nvp~fcp#vNPCV-;#xHkm)fD^zZaN|8f+zUJm>;iP)7;qN2 z1gyAMh;_h&KnL&?FbKR3j03a4?f1bSU=MH@I02joCIB05f^P%10gnPt1J40Nz&P+R zPUvdq6s6E{mPr?Y@!xxB^0zZZjx8s0r;qrE{ zOr%d;$vD`IJ7_6IydZxZMS0xWurqj2rguM>X_eTI4DAt=Y~piS??s?};YUCZ`ltK( zo8Zr1fn{i_vFn-#bsr(_z2^79dW$6DW%3D#UkWzUC?8x|$zqg<)lLMJT zDx2=Y-VI_S%7-!Eay)dtkcr~C$j5o~8DLc4l@Aeo9*7q}xZ0GCj>pu7&epn)rX8)S z>Z}l5!ToBb=+O?S+EX!i03Y`S0wE7R3-r*Z=W4IkE7bbOT5DRG>Rn= zc>7RmeMv_~onFDAs??YH9t{+-U#g*cqal2xN{^r{crS=XW9LOma$%|~aRm=>g$Pz%e*J~|e_&QqQy&tO5TCaZATRx1np<-Qh>pnEGyt5=T+6ruT z(F48sa2TvdO!mo~pT6%33uiEdM{&A?F=v>c*yF02+NS&Q#j`MEVZn*pge2OWZg1e~N^J<7kubsO2EYe|9wc{(3aB0WMYa05Vkv}X{G zBTwfmm^O51o7n{v0;D&Ae}uP@mx**KJqghDBk9q#BLUl5reCTj^Z<0dNqM^FB+%Yx z?H5Jy46p(qJ-UV^&^4@e9L12uS+5pM*SrJ=@}x(n9U3d?9Rs-)hJk(YYbcR`U3C8_sQZ<2sW*!9N&wSkzS{~v z0hKaRr99yspcEiIy0;l$Lhsj*(_D}qUBA#fv1YjrWZ0tkeGedajDB$)Gln1AR-i1C z>^Fr9sb@@BHO`|(kW5X7N#b9@WS8vGd3*yFjw3S*lsD7IAhIX>B0Y^|L?n~2bR(XF r-WV$A_@{W0e>BImmZ?vfyb7-AEe**QC7MdB-l^^8HI*U6KdJXWT+<9H diff --git a/c/class_resolver.c b/c/class_resolver.c index e118e04..d8fa8d4 100644 --- a/c/class_resolver.c +++ b/c/class_resolver.c @@ -62,7 +62,7 @@ struct hash_table_entry * class_resolver_load_from_filenames(const char * filena 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; + uint32_t field_entry_size = (sizeof (struct field_entry)) * class_file->fields_count; 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; @@ -95,15 +95,20 @@ struct hash_table_entry * class_resolver_load_from_filenames(const char * filena 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); + u2 descriptor_index = class_file->methods[i].descriptor_index; + struct constant * descriptor_constant = &class_file->constant_pool[descriptor_index - 1]; + assert(descriptor_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]); + hash_table_add2(methods_hash_table_length, + methods_hash_table, + name_constant->utf8.bytes, + name_constant->utf8.length, + descriptor_constant->utf8.bytes, + descriptor_constant->utf8.length, + (void *)&class_file->methods[i]); } class_entry[i].methods.length = methods_hash_table_length; @@ -157,19 +162,25 @@ struct field_entry * class_resolver_lookup_field(struct class_entry * class_entr struct method_info * class_resolver_lookup_method(struct class_entry * class_entry, const uint8_t * method_name, - int method_name_length) + int method_name_length, + const uint8_t * method_descriptor, + int method_descriptor_length) { printf("class_resolver_lookup_method: "); for (int i = 0; i < method_name_length; i++) { fputc(method_name[i], stdout); } + fputc(' ', stdout); + for (int i = 0; i < method_descriptor_length; i++) { fputc(method_descriptor[i], stdout); } fputc('\n', stdout); 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); + struct hash_table_entry * e = hash_table_find2(methods_hash_table_length, + methods_hash_table, + method_name, + method_name_length, + method_descriptor, + method_descriptor_length); assert(e != nullptr); return (struct method_info *)e->value; diff --git a/c/class_resolver.h b/c/class_resolver.h index dbe91f3..1815c9d 100644 --- a/c/class_resolver.h +++ b/c/class_resolver.h @@ -43,7 +43,9 @@ struct class_entry * class_resolver_lookup_class(int class_hash_table_length, 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); + int method_name_length, + const uint8_t * method_descriptor, + int method_descriptor_length); struct field_entry * class_resolver_lookup_field(struct class_entry * class_entry, const uint8_t * field_name, int field_name_length); diff --git a/c/execute.c b/c/execute.c index 84e8761..708e2d2 100644 --- a/c/execute.c +++ b/c/execute.c @@ -920,6 +920,10 @@ void op_invokestatic(struct vm * vm, uint32_t index) #ifdef DEBUG assert(method_name_constant->tag == CONSTANT_Utf8); #endif + struct constant * method_descriptor_constant = &vm->current_thread.current_class->constant_pool[nameandtype_constant->nameandtype.descriptor_index - 1]; + #ifdef DEBUG + assert(method_descriptor_constant->tag == CONSTANT_Utf8); + #endif struct class_entry * class_entry = class_resolver_lookup_class(vm->class_hash_table.length, vm->class_hash_table.entry, @@ -929,7 +933,9 @@ void op_invokestatic(struct vm * vm, uint32_t index) struct method_info * method_info = class_resolver_lookup_method(class_entry, method_name_constant->utf8.bytes, - method_name_constant->utf8.length); + method_name_constant->utf8.length, + method_descriptor_constant->utf8.bytes, + method_descriptor_constant->utf8.length); assert(method_info != nullptr); /* On successful resolution of the method, the class or interface that diff --git a/c/frame.c b/c/frame.c index 5e1916a..235494d 100644 --- a/c/frame.c +++ b/c/frame.c @@ -121,11 +121,15 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry) /* Next, if C declares a class or interface initialization method, execute that method. */ const uint8_t * method_name = (const uint8_t *)""; - int method_length = 8; + int method_name_length = 8; + const uint8_t * method_descriptor = (const uint8_t *)"()V"; + int method_descriptor_length = 3; struct method_info * method_info = class_resolver_lookup_method(class_entry, method_name, - method_length); + method_name_length, + method_descriptor, + method_descriptor_length); if (method_info != nullptr) { assert((method_info->access_flags & METHOD_ACC_STATIC) != 0); printf("\n"); diff --git a/c/hash_table.c b/c/hash_table.c index 9c871df..1456ba3 100644 --- a/c/hash_table.c +++ b/c/hash_table.c @@ -1,12 +1,11 @@ #include "malloc.h" #include "hash_table.h" -static uint32_t fnv_1(const uint8_t * buf, int length) -{ - const uint32_t fnv_offset_basis = 0x811c9dc5; - const uint32_t fnv_prime = 0x01000193; +static const uint32_t fnv_offset_basis = 0x811c9dc5; - uint32_t hash = fnv_offset_basis; +static uint32_t fnv_1(uint32_t hash, const uint8_t * buf, int length) +{ + const uint32_t fnv_prime = 0x01000193; for (int i = 0; i < length; i++) { hash = hash * fnv_prime; @@ -25,13 +24,24 @@ void hash_table_init(int hash_table_length, } } + +#include + +void print_key(const uint8_t * key, int key_length) +{ + printf("key: "); + for (int i = 0; i < key_length; i++) + fputc(key[i], stdout); + fputc('\n', stdout); +} + void hash_table_add(int hash_table_length, struct hash_table_entry * entry, const uint8_t * key, int key_length, void * value) { - uint32_t hash = fnv_1(key, key_length) & (hash_table_length - 1); + uint32_t hash = fnv_1(fnv_offset_basis, key, key_length) & (hash_table_length - 1); struct hash_table_entry * e = &entry[hash]; while (e->next != nullptr) { @@ -44,7 +54,12 @@ void hash_table_add(int hash_table_length, e = e->next; } - e->key = key; + uint8_t * key_copy = malloc_class_arena(key_length); + for (int i = 0; i < key_length; i++) key_copy[i] = key[i]; + printf("key copy: %p ", key_copy); + print_key(key_copy, key_length); + + e->key = key_copy; e->key_length = key_length; e->value = value; } @@ -63,11 +78,88 @@ struct hash_table_entry * hash_table_find(int hash_table_length, const uint8_t * key, int key_length) { - uint32_t hash = fnv_1(key, key_length) & (hash_table_length - 1); + uint32_t hash = fnv_1(fnv_offset_basis, key, key_length) & (hash_table_length - 1); struct hash_table_entry * e = &entry[hash]; while (e != nullptr && e->key != nullptr) { - if (e->key_length == key_length && key_equal(e->key, key, key_length)) { + printf("key find: %p ", e->key); + print_key(e->key, e->key_length); + if (e->key_length == key_length && key_equal(key, e->key, e->key_length)) { + return e; + } + e = e->next; + } + return nullptr; +} + +static inline bool key_equal2(const uint8_t * a1, int a1_length, + const uint8_t * a2, int a2_length, + const uint8_t * b) +{ + for (int i = 0; i < a1_length; i++) { + if (a1[i] != b[i]) + return false; + } + for (int i = 0; i < a2_length; i++) { + if (a2[i] != b[a1_length + i]) + return false; + } + 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) +{ + uint32_t hash = fnv_offset_basis; + hash = fnv_1(hash, key1, key1_length); + hash = fnv_1(hash, key2, key2_length); + hash &= (hash_table_length - 1); + struct hash_table_entry * e = &entry[hash]; + + while (e->next != nullptr) { + e = e->next; + } + + if (e->key != nullptr) { + // allocate e from overflow + e->next = malloc_class_arena((sizeof (struct hash_table_entry))); + e = e->next; + } + + uint8_t * key_copy = malloc_class_arena(key1_length + key2_length); + for (int i = 0; i < key1_length; i++) key_copy[i] = key1[i]; + for (int i = 0; i < key2_length; i++) key_copy[key1_length + i] = key2[i]; + e->key = key_copy; + e->key_length = key1_length + key2_length; + e->value = value; +} + +struct hash_table_entry * hash_table_find2(int hash_table_length, + struct hash_table_entry * entry, + const uint8_t * key1, + int key1_length, + const uint8_t * key2, + int key2_length) +{ + uint32_t hash = fnv_offset_basis; + hash = fnv_1(hash, key1, key1_length); + hash = fnv_1(hash, key2, key2_length); + hash &= (hash_table_length - 1); + + struct hash_table_entry * e = &entry[hash]; + + while (e != nullptr && e->key != nullptr) { + bool equal = + e->key_length == (key1_length + key2_length) && + key_equal2(key1, key1_length, + key2, key2_length, + e->key); + if (equal) { return e; } e = e->next; diff --git a/c/hash_table.h b/c/hash_table.h index e316a4e..8cd76d6 100644 --- a/c/hash_table.h +++ b/c/hash_table.h @@ -22,3 +22,18 @@ 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_find2(int hash_table_length, + struct hash_table_entry * entry, + const uint8_t * key1, + int key1_length, + const uint8_t * key2, + int key2_length); diff --git a/c/main.c b/c/main.c index 4d7e780..4447875 100644 --- a/c/main.c +++ b/c/main.c @@ -21,9 +21,13 @@ int main(int argc, const char * argv[]) const char * method_name = "main"; int method_name_length = string_length(method_name); + const char * method_descriptor = "()V"; + int method_descriptor_length = string_length(method_descriptor); struct method_info * method_info = class_resolver_lookup_method(class_entry, (const uint8_t *)method_name, - method_name_length); + method_name_length, + (const uint8_t *)method_descriptor, + method_descriptor_length); struct vm vm; vm.class_hash_table.entry = class_hash_table; diff --git a/c/malloc.c b/c/malloc.c index cafd2c5..1f6b035 100644 --- a/c/malloc.c +++ b/c/malloc.c @@ -1,5 +1,7 @@ #include "malloc.h" +#include + struct arena { uint8_t * mem; uint32_t size; @@ -16,7 +18,9 @@ struct arena class_arena = { void * malloc_class_arena(uint32_t size) { + assert((class_arena.ix & (~3)) == class_arena.ix); void * ptr = &class_arena.mem[class_arena.ix]; + size = (size + 3) & (~3); class_arena.ix += size; return ptr; } diff --git a/c/test_hash_table.c b/c/test_hash_table.c index e22bba9..df7a42f 100644 --- a/c/test_hash_table.c +++ b/c/test_hash_table.c @@ -145,6 +145,12 @@ static uint32_t _strlen(const char * s) return si - s; } +void print_key(const uint8_t * key, int key_length) +{ + for (int i = 0; i < key_length; i++) + fputc(key[i], stdout); +} + int main() { int hash_table_length = 128 * 2; @@ -170,6 +176,7 @@ int main() printf("collision %s\n", e->key); } assert(e != nullptr); - printf("%s %d\n", e->key, (int)e->value); + print_key(e->key, e->key_length); + printf(" %d\n", (int)e->value); } } diff --git a/p/Instance.java b/p/Instance.java new file mode 100644 index 0000000..935f903 --- /dev/null +++ b/p/Instance.java @@ -0,0 +1,24 @@ +package p; + +class Instance { + int a; + int b; + + public Instance(int a) { + this.a = a; + this.b = 13; + } + + int mul() { + return a * b; + } + + static int test() { + Instance i = new Instance(12); + return i.mul(); + } + + public static void main() { + test(); + } +} diff --git a/p/StaticMethodOverloading.java b/p/StaticMethodOverloading.java new file mode 100644 index 0000000..d1c4451 --- /dev/null +++ b/p/StaticMethodOverloading.java @@ -0,0 +1,19 @@ +package p; + +class StaticMethodOverloading { + static int test() { + return test(4); + } + + static int test(int a) { + return test(a, 3); + } + + static int test(int a, int b) { + return a * b + 1; + } + + public static void main() { + test(); + } +}