Full Code of ozy/ToyJVM for AI

master 65be158f9ddd cached
44 files
105.8 KB
29.3k tokens
95 symbols
1 requests
Download .txt
Repository: ozy/ToyJVM
Branch: master
Commit: 65be158f9ddd
Files: 44
Total size: 105.8 KB

Directory structure:
gitextract_j969pa58/

├── .gitignore
├── LICENSE
├── README.md
├── include/
│   ├── attribute.h
│   ├── classFile.h
│   ├── constantPool.h
│   ├── debug.h
│   ├── endianness.h
│   ├── field.h
│   ├── frame.h
│   ├── heap.h
│   ├── javaClass.h
│   ├── machine.h
│   ├── method.h
│   ├── opcode.h
│   ├── printStream.h
│   ├── stack.h
│   └── stringBuilder.h
├── makefile
├── readme.md
├── src/
│   ├── attribute.c
│   ├── classFile.c
│   ├── constantPool.c
│   ├── field.c
│   ├── frame.c
│   ├── heap.c
│   ├── javaClass.c
│   ├── machine.c
│   ├── main.c
│   ├── opcode.c
│   ├── printStream.c
│   ├── stack.c
│   └── stringBuilder.c
├── test/
│   ├── Factorial.class.txt
│   ├── Factorial.java
│   ├── HelloWorld.class.txt
│   ├── HelloWorld.java
│   ├── InstanceTest.class.txt
│   ├── InstanceTest.java
│   ├── StringExample.class.txt
│   ├── StringExample.java
│   ├── returnTest.class.txt
│   └── returnTest.java
└── test.sh

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================
# Ignore the build and lib dirs
build
dep/*

# Ignore any executables
bin/*

# Ignore Mac specific files
.DS_Store 

# Ignore valgrind dumps
vgcore.*

# Ignore OpenJDK classes
java/*

# Ignore Class Files
test/*.class

# Ignore test outputs
test/*.out

.vscode/*

================================================
FILE: LICENSE
================================================
                    GNU GENERAL PUBLIC LICENSE
                       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

                            Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

                    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

                            NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

                     END OF TERMS AND CONDITIONS

            How to Apply These Terms to Your New Programs

  If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.

  To do so, attach the following notices to the program.  It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

    <one line to give the program's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License along
    with this program; if not, write to the Free Software Foundation, Inc.,
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:

    Gnomovision version 69, Copyright (C) year name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License.  Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
  `Gnomovision' (which makes passes at compilers) written by James Hacker.

  <signature of Ty Coon>, 1 April 1989
  Ty Coon, President of Vice

This General Public License does not permit incorporating your program into
proprietary programs.  If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library.  If this is what you want to do, use the GNU Lesser General
Public License instead of this License.


================================================
FILE: README.md
================================================
# ToyJVM

Experimental Java Bytecode Interpreter written in C to understand Java concepts better.

## Getting Started

These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.

## Prerequisites


```Javac``` is required to compile Java codes into Java bytecodes.

## Running the tests

You can run the tests with the ```test.sh``` script. As the project grows up, new tests will be added.

## Running the software

You need to give the class name without extension to the executable. For example ```./bin/main test/HelloWorld``` will run the test/HelloWorld.class file.


================================================
FILE: include/attribute.h
================================================
#ifndef ATTRIBUTE_H_
#define ATTRIBUTE_H_
#include <inttypes.h>
#include <stdio.h>

typedef struct attribute_info {
    uint16_t attribute_name_index;
    uint32_t attribute_length;
    uint8_t* info;
}attribute_info;

typedef struct exception_table{ // aligned.
    uint16_t start_pc;
    uint16_t end_pc;
    uint16_t handler_pc;
    uint16_t catch_type;
} exception_table;

//If the method is either native or abstract, its method_info structure must not have a 
//Code attribute in its attributes table. Otherwise, its method_info structure must have
//exactly one Code attribute in its attributes table
typedef struct Code_attribute {
    uint16_t attribute_name_index;
    uint32_t attribute_length;
    uint16_t max_stack;
    uint16_t max_locals;
    uint32_t code_length;
    uint8_t* code;
    uint16_t exception_table_lenght;
    exception_table* exceptionTable;
    uint16_t attributes_count;
    attribute_info* attributes;
}Code_attribute;

attribute_info getAttribute_Info(FILE* fd);
Code_attribute getCode_AttributeFromAttribute_info(attribute_info fd);

void destroyAttribute_Info(attribute_info* attribute);
#endif

================================================
FILE: include/classFile.h
================================================
#ifndef CLASSFILE_H_
#define CLASSFILE_H_
#include <inttypes.h>
#include "machine.h"
#include "constantPool.h"
#include "field.h"
#include "method.h"

typedef struct field_info field_info;

typedef struct ClassFile{
    uint32_t       magic;
    uint16_t       minor_version;
    uint16_t       major_version;
    uint16_t       constant_pool_count;
    cp_info*       constant_pool; //[constant_pool_count-1]
    uint16_t       access_flags;
    uint16_t       this_class;
    uint16_t       super_class;
    uint16_t       interfaces_count;
    uint16_t*      interfaces;
    uint16_t       fields_count;
    field_info*    fields;
    uint16_t       methods_count;
    method_info*   methods;
    uint16_t       attributes_count;
    attribute_info* attributes;
    uint8_t initalized;
}ClassFile;

ClassFile classFromFile(const char* filename);

ClassFile* getClassFromUtf8(CONSTANT_Utf8_info className_utf8, Machine* machine);
ClassFile* getClassFromName(const char* className, Machine* machine);

int getNumArgs(ClassFile* cf, CONSTANT_Ref_info methodOrInterfaceRef);

int isUtf8Equal(CONSTANT_Utf8_info s1, CONSTANT_Utf8_info s2);
int isUtf8EqualsToString(CONSTANT_Utf8_info s1, const char* s2);

void initClass(ClassFile* cf, Frame* frame);
void destroyClass(ClassFile* cf);

method_info* getMethodByName(ClassFile* cf, const char* name, const char* desc);
method_info* canClassHandleMethod(ClassFile* cf, CONSTANT_Utf8_info name_utf8, CONSTANT_Utf8_info descriptor_utf8);
int checkFormat(ClassFile* cf);
/*
Returns 1 if the class file passes the test. Anything else if not.

1-The first four bytes must contain the right magic number.+
2-All recognized attributes must be of the proper length.?
3-The class file must not be truncated or have extra bytes at the end.-
4-The constant pool must satisfy the constraints documented throughout §4.4.?
For example, each CONSTANT_Class_info structure in the constant pool 
must contain in its name_index item a valid constant pool index for a CONSTANT_Utf8_info structure.
6-All field references and method references in the constant pool must 
have valid names, valid classes, and valid descriptors (§4.3).
7-Format checking does not ensure that the given field or method actually 
exists in the given class, nor that the descriptors given refer to real classes. 
Format checking ensures only that these items are well formed. More detailed 
checking is performed when the bytecodes themselves are verified, and during resolution.
*/
#endif

================================================
FILE: include/constantPool.h
================================================
#ifndef CONSTANTPOOL_H_
#define CONSTANTPOOL_H_
#include <inttypes.h>
#include <stdio.h>

typedef enum cp_tags{
    CONSTANT_Class=7,

    CONSTANT_Fieldref=9,

    CONSTANT_Methodref=10,

    CONSTANT_InterfaceMethodref=11,
    CONSTANT_String=8,

    CONSTANT_Integer=3,
    CONSTANT_Float=4,
    CONSTANT_Long=5,
    CONSTANT_Double=6,
    CONSTANT_NameAndType=12,
    
    CONSTANT_Utf8=1,

    CONSTANT_MethodHandle=15,
    CONSTANT_MethodType=16,
    CONSTANT_InvokeDynamic=18
}cp_tags;


//////////////////////////////
// CONSTANT INFO STRUCTURES //
//////////////////////////////

// the data written directly into the structures.
// padding across the platforms should be
// checked.
typedef struct CONSTANT_Class_info {
    uint16_t name_index;
}CONSTANT_Class_info;

typedef struct CONSTANT_Ref_info{
    // also applies for The CONSTANT_Fieldref_info, CONSTANT_Methodref_info, and CONSTANT_InterfaceMethodref_info Structures
    uint16_t class_index;
    uint16_t name_and_type_index;
}CONSTANT_Ref_info;


typedef struct CONSTANT_String_info {
    uint16_t string_index;
}CONSTANT_String_info;

typedef struct CONSTANT_4BYTES_info {
    uint32_t bytes;
}CONSTANT_4BYTES_info;

typedef struct CONSTANT_8BYTES_info {
    uint64_t bytes;
}CONSTANT_8BYTES_info;

typedef struct CONSTANT_NameAndType_info {
    uint16_t name_index;
    uint16_t descriptor_index;
}CONSTANT_NameAndType_info;

typedef struct CONSTANT_Utf8_info {  // not aligned
    uint16_t length;
    // 6 bytes padding
    uint8_t* bytes;
}CONSTANT_Utf8_info;

typedef struct CONSTANT_MethodHandle_info { // not aligned
    uint8_t reference_kind; // ref to method handle.
    // 1 byte compiler padding
    uint16_t reference_index; 
}CONSTANT_MethodHandle_info;

typedef struct CONSTANT_MethodType_info {
    uint16_t descriptor_index;
    //The constant_pool entry at that index must be a CONSTANT_Utf8_info structure (§4.4.7) 
    //representing a method descriptor (§4.3.3). 
}CONSTANT_MethodType_info;

typedef struct CONSTANT_InvokeDynamic_info {
    uint16_t bootstrap_method_attr_index;
    uint16_t name_and_type_index;
}CONSTANT_InvokeDynamic_info;

typedef enum array_type{
    T_BOOLEAN =4,
    T_CHAR    =5,
    T_FLOAT   =6,
    T_DOUBLE  =7,
    T_BYTE 	  =8,
    T_SHORT   =9,
    T_INT 	  =10,
    T_LONG 	  =11
}array_type;

typedef struct CONSTANT_Array_info{  // custom
    int32_t size; // array size is signed 32 bit int.
    array_type atype;
    uint8_t* ref;
}CONSTANT_Array_info;

union CONSTANT_INFO {
    CONSTANT_Class_info class_info;
    CONSTANT_Ref_info   ref_info;
    CONSTANT_String_info    string_info;
    CONSTANT_4BYTES_info   _4BYTES_info;
    CONSTANT_8BYTES_info  _8BYTES_info;
    CONSTANT_NameAndType_info   nameAndType_info;
    CONSTANT_Utf8_info  utf8_info;
    CONSTANT_MethodHandle_info  methodHandle_info;
    CONSTANT_MethodType_info  methodType_info;
    CONSTANT_InvokeDynamic_info invodeDynamic_info;
}; // unified for runtime constant pool

typedef struct cp_info {
    uint8_t tag;
    union CONSTANT_INFO info;
}cp_info;


cp_info cp_infoFromFile(FILE* fd);
void destroyCp_Info(cp_info* info);


#endif

================================================
FILE: include/debug.h
================================================
#ifdef DEBUG
# define DEBUG_PRINT(x) printf x
#else
# define DEBUG_PRINT(x) do {} while(0)
#endif

================================================
FILE: include/endianness.h
================================================
#ifndef ENDIAN_H_
#define ENDIAN_H_

// endian.h was not cross platform and was under a different
// name in different OS'es. Assuming most of the desktop cpu's 
// are little endian, I forged these functions into internal swap
// functions in gcc and clang. The visual studio users may use
// the _byteswap_ushort, _byteswap_ulong, _byteswap_uint64 functions
// respectively. 
#define be16toh(x) __builtin_bswap16(x)
#define be32toh(x) __builtin_bswap32(x)
#define be64toh(x) __builtin_bswap64(x)

#endif

================================================
FILE: include/field.h
================================================
#ifndef FIELD_H_
#define FIELD_H_
#include <inttypes.h>
#include "attribute.h"
#include <stdio.h>
#include "classFile.h"
#include "constantPool.h"

typedef struct JavaClass JavaClass;
typedef enum field_access_flags{
    F_ACC_PUBLIC 	    = 0x0001, // Declared public; may be accessed from outside its package.
    F_ACC_PRIVATE 	    = 0x0002, // Declared private; usable only within the defining class.
    F_ACC_PROTECTED 	= 0x0004, // Declared protected; may be accessed within subclasses.
    F_ACC_STATIC 	    = 0x0008, // Declared static.
    F_ACC_FINAL 	    = 0x0010, // Declared final; never directly assigned to after object construction (JLS §17.5).
    F_ACC_VOLATILE 	    = 0x0040, // Declared volatile; cannot be cached.
    F_ACC_TRANSIENT 	= 0x0080, // Declared transient; not written or read by a persistent object manager.
    F_ACC_SYNTHETIC 	= 0x1000, // Declared synthetic; not present in the source code.
    F_ACC_ENUM 	        = 0x4000  // Declared as an element of an enum. 
}access_flags;

typedef struct field_info {
    uint16_t access_flags;
    uint16_t name_index;
    uint16_t descriptor_index;
    uint16_t attributes_count;
    attribute_info* attributes;
    uint64_t value;
}field_info;

field_info getField_Info(FILE* fd);

field_info* getStaticField(ClassFile* cf, CONSTANT_Utf8_info fieldName, CONSTANT_Utf8_info fieldDesc);
field_info* getField(JavaClass* jc, CONSTANT_Utf8_info fieldName, CONSTANT_Utf8_info fieldDesc);
void putField(JavaClass* instance, CONSTANT_Utf8_info fieldName, CONSTANT_Utf8_info fieldDesc, uint64_t val);

void destroyField_Info(field_info* field);
#endif

================================================
FILE: include/frame.h
================================================
#ifndef FRAME_H_
#define FRAME_H_
#include <inttypes.h>
//#include "stack.h"
#include "attribute.h"
#include "constantPool.h"

typedef struct ClassFile ClassFile;
typedef struct Machine Machine;
typedef uint64_t LocalVariable;
// A single local variable can hold a value of type boolean, byte, char, short, int, float, reference, or returnAddress. 
// A pair of local variables can hold a value of type long or double. 
// But we wont implement this, instead a local variable in our jvm can hold up to 64 bits.
typedef uint64_t Operand;
// Each entry on the operand stack can hold a value of any Java Virtual Machine type, including a value of type long or type double. 

typedef struct Frame{
    LocalVariable* localVariables;
    struct Stack* operandStack;
    struct Machine* machine;
    struct ClassFile* classRef;
    uint32_t pc; // program counter
    Code_attribute* code;
    //A run-time constant pool is a per-class or per-interface run-time representation of the constant_pool table in a class file (§4.4).
    //It contains several kinds of constants, ranging from numeric literals known at compile-time to method and field references that must be resolved at run-time.
} Frame;

Frame createNewFrame (Code_attribute code, ClassFile* cf, Machine* machine);
void destroyFrame (Frame* frame);
#endif

================================================
FILE: include/heap.h
================================================
#ifndef HEAP_H_
#define HEAP_H_
#include <inttypes.h>
#include <stdlib.h>

typedef struct HeapObject{
    void* addr;
    size_t size;
    uint8_t isUsed;
}HeapObject;

typedef struct Heap{
    uint64_t size;
    uint64_t top;
    HeapObject* heap;
}Heap;

Heap initHeap(size_t size);
void* hGet(uint64_t addr, Heap* heap);
uint64_t hAlloc(size_t size, Heap* heap);
uint64_t hExtend(uint64_t addr, size_t size, Heap* heap);
void* hFree(uint64_t addr, Heap* heap);

void destroyHeap(Heap* heap);
#endif

================================================
FILE: include/javaClass.h
================================================
#ifndef JAVACLASS_H_
#define JAVACLASS_H_
#include "classFile.h"

typedef struct JavaClass{
    ClassFile* classFile;
    field_info* fields;
}JavaClass;

void initInstanceFields(JavaClass* instance);

#endif

================================================
FILE: include/machine.h
================================================
#ifndef MACHINE_H_
#define MACHINE_H_
#include "opcode.h"
#include "stack.h"
#include "heap.h"

typedef struct Machine{
    struct ClassFile* classFiles;
    uint64_t numClasses;
    Stack* JVMSTACK;
    Heap* heap;
}Machine;

void* executeCode(Machine* machine, OPCODE** opcodes);
void destroyMachine(Machine* machine);

#endif

================================================
FILE: include/method.h
================================================
#ifndef METHOD_H_
#define METHOD_H_
#include "attribute.h"
#include "field.h"

typedef struct field_info method_info; // same as field info

typedef enum method_access_flags{
    M_ACC_PUBLIC 	      = 0x0001, // Declared public; may be accessed from outside its package.
    M_ACC_PRIVATE 	      = 0x0002, // Declared private; accessible only within the defining class.
    M_ACC_PROTECTED 	  = 0x0004, // Declared protected; may be accessed within subclasses.
    M_ACC_STATIC  	      = 0x0008, // Declared static.
    M_ACC_FINAL   	      = 0x0010, // Declared final; must not be overridden (§5.4.5).
    M_ACC_SYNCHRONIZED    = 0x0020, // Declared synchronized; invocation is wrapped by a monitor use.
    M_ACC_BRIDGE  	      = 0x0040, // A bridge method, generated by the compiler.
    M_ACC_VARARGS 	      = 0x0080, // Declared with variable number of arguments.
    M_ACC_NATIVE  	      = 0x0100, // Declared native; implemented in a language other than Java.
    M_ACC_ABSTRACT 	      = 0x0400, // Declared abstract; no implementation is provided.
    M_ACC_STRICT  	      = 0x0800, // Declared strictfp; floating-point mode is FP-strict.
    M_ACC_SYNTHETIC 	  = 0x1000 	// Declared synthetic; not present in the source code. 
}method_access_flags;

#define getMethod_Info(fd) getField_Info(fd) // same too, no need to reimplement
#define destroyMethod_Info(info) destroyField_Info(info)

#endif


================================================
FILE: include/opcode.h
================================================
#ifndef OPCODE_H_
#define OPCODE_H_
#include <inttypes.h>
#include "frame.h"

typedef void* OPCODE(struct Frame*);

OPCODE** initOpcodes();


typedef enum OPCODENAMES{
    ICONST_M1     = 0x02,
    ICONST_0      = 0x03,
    ICONST_1      = 0x04,
    ICONST_2      = 0x05,
    ICONST_3      = 0x06,
    ICONST_4      = 0x07,
    ICONST_5      = 0x08,
    LCONST_0      = 0x09,
    LCONST_1      = 0x0A,
    DCONST_0      = 0x0E,
    DCONST_1      = 0x0F,
    BIPUSH        = 0x10,
    SIPUSH        = 0x11,
    LDC           = 0x12,
    LDC2_W        = 0x14,
    ILOAD         = 0x15,
    LLOAD         = 0x16,
    DLOAD         = 0x18,
    ILOAD_0       = 0x1A,
    ILOAD_1       = 0x1B,
    ILOAD_2       = 0x1C,
    ILOAD_3       = 0x1D,
    LLOAD_0       = 0x1E,
    LLOAD_1       = 0x1F,
    LLOAD_2       = 0x20,
    LLOAD_3       = 0x21,
    DLOAD_3       = 0x29,
    ALOAD_0       = 0x2A,
    ALOAD_1       = 0x2B,
    ALOAD_2       = 0x2C,
    ALOAD_3       = 0x2D,
    IALOAD        = 0x2E,
    AALOAD        = 0x32,
    ISTORE        = 0x36,
    LSTORE        = 0x37,
    DSTORE        = 0x39,
    ISTORE_0      = 0x3B,
    ISTORE_1      = 0x3C,
    ISTORE_2      = 0x3D,
    ISTORE_3      = 0x3E,
    LSTORE_0      = 0x3F,
    LSTORE_1      = 0x40,
    LSTORE_2      = 0x41,
    LSTORE_3      = 0x42,
    DSTORE_3      = 0x4A,
    ASTORE_0      = 0x4B,
    ASTORE_1      = 0x4C,
    ASTORE_2      = 0x4D,
    ASTORE_3      = 0x4E,
    IASTORE       = 0x4F,
    AASTORE       = 0x53,
    POP           = 0x57,
    DUP           = 0x59,
    IADD          = 0x60,
    LADD          = 0x61,
    DADD          = 0x63,
    ISUB          = 0x64,
    DSUB          = 0x67,
    IMUL          = 0x68,
    DMUL          = 0x6B,
    DDIV          = 0x6F,
    IREM          = 0x70,
    IINC          = 0x84,
    I2D           = 0x87,
    I2C           = 0x92,
    DCMPG         = 0x98,
    IFNE          = 0x9A,
    IFLT          = 0x9B,
    IFGE          = 0x9C,
    IFLE          = 0x9E,
    IF_ICMPLT     = 0xA1,
    IF_ICMPGE     = 0xA2,
    IF_ICMPGT     = 0xA3,
    IF_ICMPLE     = 0xA4,
    GOTO          = 0xA7,
    IRET          = 0xAC,
    LRET          = 0xAD,
    DRETURN       = 0xAF,
    ARETURN       = 0xB0,
    RETURN        = 0xB1,
    GETSTATIC     = 0xB2,
    PUTSTATIC     = 0xB3,
    GETFIELD      = 0xB4,
    PUTFIELD      = 0xB5,
    INVOKEVIRTUAL = 0xB6,
    INVOKESPECIAL = 0xB7,
    INVOKESTATIC  = 0xB8,
    NEW           = 0xBB,
    NEWARRAY      = 0xBC,
    ANEWARRAY     = 0xBD,
    ARRAYLENGTH   = 0xBE
}OPCODENAMES;


#endif

================================================
FILE: include/printStream.h
================================================
#ifndef PRINTSTREAM_H_
#define PRINTSTREAM_H_
#include <inttypes.h>
#include "frame.h"
#include "classFile.h"

void handlePrintStream(uint64_t* localVariables, Frame* frame, CONSTANT_Utf8_info name_utf8, CONSTANT_Utf8_info desc_utf8);
 
#endif

================================================
FILE: include/stack.h
================================================
#ifndef STACK_H_
#define STACK_H_
#include <stdint.h>
#include "frame.h"

typedef enum StackType{
    TYPE_OPERANDSTACK = sizeof(uint64_t),
    TYPE_JVMSTACK = sizeof(struct Frame)
}StackType;

typedef struct Stack{
    unsigned char* stack;
    StackType stackType;
    uint64_t top;
    uint64_t maxSize;
}Stack;

Stack initStack(uint64_t numItems, StackType stackType);
// size is given as numItems here

void* popStack(Stack* stack);
void pushStack(void* val, Stack* stack);
void* peekStack(Stack* stack);

void destroyStack(Stack* stack);
#endif 

================================================
FILE: include/stringBuilder.h
================================================
#ifndef STRINGBUILDER_H_
#define STRINGBUILDER_H_
#include <inttypes.h>
#include "frame.h"
#include "classFile.h"


void handleStringBuilder(uint64_t* localVariables, Frame* frame, CONSTANT_Utf8_info name_utf8, CONSTANT_Utf8_info desc_utf8);
 
#endif

================================================
FILE: makefile
================================================
SRCDIR	= src
HDRDIR  = include
OBJDIR	= build
BINDIR	= bin
DEPDIR	= dep

CC	= gcc
TARGET	= main
CFLAGS	= -g -O0 -std=c99 -I$(HDRDIR) #-DDEBUG=1
LFLAGS	= -lm

SOURCES	:= $(wildcard $(SRCDIR)/*.c)
HEADERS := $(wildcard $(HDRDIR)/*.h)
OBJECTS	:= $(SOURCES:$(SRCDIR)/%.c=$(OBJDIR)/%.o)
DEPS	:= $(OBJECTS:$(OBJDIR)/%.o=$(DEPDIR)/%.d)

REMOVE	:= rm -rf

# Linking
$(BINDIR)/$(TARGET): $(OBJECTS) $(CMN_OBJ)
	mkdir -p $(BINDIR)
	$(CC) $(LFLAGS) -o $@ $(OBJECTS) $(CMN_OBJ)
	@echo "Linking complete"

-include $(DEPS)

# Compilation
$(OBJECTS): $(OBJDIR)/%.o : $(SRCDIR)/%.c
	mkdir -p $(OBJDIR)
	mkdir -p $(DEPDIR)
	$(CC) -c $(CFLAGS) $< -o $@
	$(CC) -I$(HDRDIR) -MM -MT '$(OBJDIR)/$*.o' $(SRCDIR)/$*.c > $(DEPDIR)/$*.d
	@echo "Compiled $<"

# Generate file list for cscope
cscope.files: $(SOURCES) $(HEADERS)
	echo $(SOURCES) $(HEADERS) > cscope.files

# Generate cscope database
cscope.out: cscope.files
	cscope -q -R -b -i cscope.files

.PHONY: clean
clean:
	$(REMOVE) $(OBJECTS) $(OBJDIR) $(BINDIR) $(DEPDIR)
	@echo "Deleted $<"

.PHONY: remove
remove:
	$(REMOVE) $(BINDIR)/$(TARGET)
	$(REMOVE) $(OBJECTS)
	$(REMOVE) $(DEPS)
	$(REMOVE) cscope.*
	@echo "Deleted $<"

.PHONY: cscope
cscope: cscope.out

.PHONY: all
all: $(BINDIR)/$(TARGET)


================================================
FILE: readme.md
================================================
# ToyJVM

Experimental Java Bytecode Interpreter written in C to understand Java concepts better.

## Getting Started

These instructions will get you a copy of the project up and running on your local machine for development and testing purposes.

## Prerequisites


```Javac``` is required to compile Java codes into Java bytecodes.

## Running the tests

You can run the tests with the ```test.sh``` script. As the project grows up, new tests will be added.

## Running the software

You need to give the class name without extension to the executable. For example ```./bin/main test/HelloWorld``` will run the HelloWorld.class file.

================================================
FILE: src/attribute.c
================================================
#include "attribute.h"
#include <stdlib.h>
#include "endianness.h"
#include <string.h>
attribute_info getAttribute_Info(FILE* fd){
    attribute_info attribute;
    fread(&attribute.attribute_name_index,sizeof(attribute.attribute_name_index),1,fd);
    attribute.attribute_name_index = be16toh(attribute.attribute_name_index);

    fread(&attribute.attribute_length,sizeof(attribute.attribute_length),1,fd);
    attribute.attribute_length = be32toh(attribute.attribute_length);

    attribute.info = malloc(attribute.attribute_length); // leak
    fread(attribute.info,attribute.attribute_length,1,fd);
    return attribute;
}

void destroyAttribute_Info(attribute_info* attribute){
    free(attribute->info);
}

Code_attribute getCode_AttributeFromAttribute_info(attribute_info attributeInfo){
    Code_attribute attribute;
    /*
    uint16_t attribute_name_index;
    uint32_t attribute_length;
    uint16_t max_stack;
    uint16_t max_locals;
    uint32_t code_length;
    uint8_t* code;
    uint16_t exception_table_lenght;
    exception_table* exceptionTable;
    uint16_t attributes_count;
    attribute_info* attributes;
    */
    attribute.attribute_name_index = attributeInfo.attribute_name_index;
    attribute.attribute_length = attributeInfo.attribute_length;

    int memOffset=0;
    memcpy(&attribute.max_stack, attributeInfo.info+memOffset,sizeof(attribute.max_stack));
    attribute.max_stack = be16toh(attribute.max_stack);
    memOffset +=sizeof(attribute.max_stack);

    memcpy(&attribute.max_locals, attributeInfo.info+memOffset,sizeof(attribute.max_locals));
    attribute.max_locals = be16toh(attribute.max_locals);
    memOffset +=sizeof(attribute.max_locals);

    memcpy(&attribute.code_length, attributeInfo.info+memOffset,sizeof(attribute.code_length));
    attribute.code_length = be32toh(attribute.code_length);
    memOffset +=sizeof(attribute.code_length);

    attribute.code = attributeInfo.info+memOffset; // leak
    memOffset +=attribute.code_length;

    // remainings will be implemented later. 
    return attribute;
}


================================================
FILE: src/classFile.c
================================================
#include "classFile.h"
#include <stdio.h>
#include <stdlib.h>
#include "endianness.h"
#include "field.h"
#include "method.h"
#include "constantPool.h"
#include "string.h"
#include "debug.h"

ClassFile classFromFile(const char* filename){
    FILE *fd;
    fd = fopen(filename, "r");

    if (fd == NULL){
        printf("File: %s\n",filename);
        perror("Error while opening the file.\n");
        exit(EXIT_FAILURE);
    }

    /*
    uint32_t       magic;
    uint16_t       minor_version;
    uint16_t       major_version;
    uint16_t       constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    */
    ClassFile classFile;
    fread(&classFile.magic,sizeof(classFile.magic),1,fd);
    classFile.magic = be32toh(classFile.magic); // 0xCAFEBABE

    fread(&classFile.minor_version,sizeof(classFile.minor_version),1,fd);
    classFile.minor_version = be16toh(classFile.minor_version);

    fread(&classFile.major_version,sizeof(classFile.major_version),1,fd);
    classFile.major_version = be16toh(classFile.major_version);

    fread(&classFile.constant_pool_count,sizeof(classFile.constant_pool_count),1,fd);
    classFile.constant_pool_count = be16toh(classFile.constant_pool_count);

    classFile.constant_pool = malloc (sizeof(cp_info) * (classFile.constant_pool_count-1)); // leak
    // The value of the constant_pool_count item is equal to the number of entries in the constant_pool table plus one.
    //A constant_pool index is considered valid if it is greater than zero and less than constant_pool_count, 
    //with the exception for constants of type long and double noted in §4.4.5.

    for (int poolCount=0; poolCount < classFile.constant_pool_count-1; poolCount++){ // -1 same reason above
        classFile.constant_pool[poolCount] = cp_infoFromFile(fd); // leak 
        if (classFile.constant_pool[poolCount].tag == CONSTANT_Long || classFile.constant_pool[poolCount].tag == CONSTANT_Double){
            // all 8 byte types in cp takes two indexes. So increase extra.
            classFile.constant_pool[++poolCount].tag=0;
        } 
    }

    /*
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    */

    fread(&classFile.access_flags,sizeof(classFile.access_flags),1,fd);
    classFile.access_flags = be16toh(classFile.access_flags);

    fread(&classFile.this_class,sizeof(classFile.this_class),1,fd);
    classFile.this_class = be16toh(classFile.this_class);

    fread(&classFile.super_class,sizeof(classFile.super_class),1,fd);
    classFile.super_class = be16toh(classFile.super_class);

    fread(&classFile.interfaces_count,sizeof(classFile.interfaces_count),1,fd);
    classFile.interfaces_count = be16toh(classFile.interfaces_count);

    classFile.interfaces = malloc(classFile.interfaces_count * sizeof (uint16_t)); // leak
    for (int interfaceCount=0; interfaceCount < classFile.interfaces_count; interfaceCount++){
        uint16_t interface;
        fread(&interface,sizeof(interface),1,fd);
        classFile.interfaces[interfaceCount] = be16toh(interface);
    }
    
    fread(&classFile.fields_count,sizeof(classFile.fields_count),1,fd);
    classFile.fields_count = be16toh(classFile.fields_count);

    classFile.fields = malloc(sizeof(field_info) * classFile.fields_count); // leak
    for (int fieldCount=0; fieldCount < classFile.fields_count; fieldCount++){
        classFile.fields[fieldCount] = getField_Info(fd); // leak
    }

    /*
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
    */

    fread(&classFile.methods_count,sizeof(classFile.methods_count),1,fd);
    classFile.methods_count = be16toh(classFile.methods_count);

    classFile.methods = malloc (sizeof(method_info) * classFile.methods_count); // leak
    for (int methodCount = 0; methodCount<classFile.methods_count; methodCount++){
        classFile.methods[methodCount] = getMethod_Info(fd); // leak
    }

    fread(&classFile.attributes_count,sizeof(classFile.attributes_count),1,fd);
    classFile.attributes_count = be16toh(classFile.attributes_count);

    classFile.attributes = malloc (sizeof(attribute_info) * classFile.attributes_count); // leak
    for (int attributeCount = 0; attributeCount<classFile.attributes_count; attributeCount++){
        classFile.attributes[attributeCount] = getAttribute_Info(fd); // leak
    }

    classFile.initalized = 0; // false

    fclose(fd);
    return classFile;
}

int isUtf8EqualsToString(CONSTANT_Utf8_info s1, const char* s2){
    if (s1.length != strlen(s2))
        return 0;
    return !strncmp(s1.bytes,s2,s1.length);    
}

int isUtf8Equal(CONSTANT_Utf8_info s1, CONSTANT_Utf8_info s2){
    if (s1.length != s2.length)
        return 0; // false
    return !strncmp(s1.bytes,s2.bytes,s1.length);
}

int getNumArgs(ClassFile* cf, CONSTANT_Ref_info methodOrInterfaceRef){
    CONSTANT_NameAndType_info* nameAndType = &cf->constant_pool[methodOrInterfaceRef.name_and_type_index-1].info.nameAndType_info;
    CONSTANT_Utf8_info descriptor_utf8 = cf->constant_pool[nameAndType->descriptor_index-1].info.utf8_info;
    int numArgs = 0;
    for (int index=0; index < descriptor_utf8.length; index++){
        switch (descriptor_utf8.bytes[index]){
            // todo check for array types
            case 'L':
                for (; descriptor_utf8.bytes[index] != ';'; index++){
                }
                numArgs++;
                break;
            case '(':
                break;
            case ')':
                return numArgs;
            default:
                numArgs++;
                break;
        }
    }
    return numArgs;
}

ClassFile* getClassFromUtf8(CONSTANT_Utf8_info className_utf8, Machine* machine){
    // to C string
    char className[className_utf8.length+1];
    memcpy(&className,className_utf8.bytes,className_utf8.length);
    className[className_utf8.length] = '\0';

    return getClassFromName(className, machine);
}

ClassFile* getClassFromName(const char* className, Machine* machine){
    // todo BTree
    for (int classId=0; classId<machine->numClasses; classId++){
        ClassFile* class = &machine->classFiles[classId];
        CONSTANT_Class_info classInfo = class->constant_pool[class->this_class - 1].info.class_info;
        CONSTANT_Utf8_info _className = class->constant_pool[classInfo.name_index-1].info.utf8_info;
        if (isUtf8EqualsToString(_className, className)){
            return class;
        }
        //printf("checked a class, id: %d : %.*s\n",class->this_class,class->constant_pool[class->this_class-1].info.utf8_info.length,class->constant_pool[class->this_class-1].info.utf8_info.bytes);
        // todo
        
    }
    // This is a hack in order to run System.out.println()
    // check if its a native class
    if (!strcmp(className, "java/lang/System") || !strcmp(className, "java/io/PrintStream") || !strcmp(className, "java/lang/StringBuilder"))
        return NULL;
    // create if not exists
    char buf[strlen(className)+strlen(".class")+1];
    strcpy(buf, className);
    strcat(buf, ".class");
    machine->classFiles[machine->numClasses++] = classFromFile(buf);
    return &machine->classFiles[machine->numClasses-1];
}

method_info* getMethodByName(ClassFile* cf, const char* name, const char* desc){
    for (int methodId=0; methodId < cf->methods_count; methodId++){
        CONSTANT_Utf8_info classMethodName_utf8 = cf->constant_pool[cf->methods[methodId].name_index-1].info.utf8_info; // todo possibly optimize this func
        CONSTANT_Utf8_info classMethodDesc_utf8 = cf->constant_pool[cf->methods[methodId].descriptor_index-1].info.utf8_info; // todo possibly optimize this func
        if (isUtf8EqualsToString(classMethodName_utf8, name) && isUtf8EqualsToString(classMethodDesc_utf8, desc)){
            DEBUG_PRINT( ("Found Method Name: %.*s\n",classMethodName_utf8.length,classMethodName_utf8.bytes));
            return &cf->methods[methodId];
        }
    }
    return NULL;
}

void initClass(ClassFile* cf, Frame* frame){
    if (!cf->initalized){
        method_info* method = getMethodByName(cf, "<clinit>","()V");
        //DEBUG_PRINT( ("Method's Class Name: %.*s\n",name_utf8.length,name_utf8.bytes));
        Code_attribute code;
        if (method != NULL){ 
            code = getCode_AttributeFromAttribute_info(method->attributes[0]);
            //method->attributes[0]
            cf->initalized = 1;
            Frame newFrame = createNewFrame(code, cf, frame->machine);
            pushStack(&newFrame, frame->machine->JVMSTACK);
            frame->pc++;
        }else{
            // todo method not found
            DEBUG_PRINT(("<clinit> method not found \n"));
        }
    }
}

void destroyClass(ClassFile* cf){
    for (--cf->constant_pool_count; cf->constant_pool_count>0; cf->constant_pool_count--)
        destroyCp_Info(&cf->constant_pool[cf->constant_pool_count-1]);

    free(cf->constant_pool);

    free(cf->interfaces);

    for (; cf->fields_count>0; cf->fields_count--)
        destroyField_Info(&cf->fields[cf->fields_count-1]);
    free(cf->fields);

    for (; cf->methods_count>0; cf->methods_count--)
        destroyMethod_Info(&cf->methods[cf->methods_count-1]);
    free(cf->methods);

    for (; cf->attributes_count>0; cf->attributes_count--)
        destroyAttribute_Info(&cf->attributes[cf->attributes_count-1]);
    free(cf->attributes);
}

method_info* canClassHandleMethod(ClassFile* cf, CONSTANT_Utf8_info name_utf8, CONSTANT_Utf8_info descriptor_utf8){
    DEBUG_PRINT( ("Invoked Method Name: %.*s, %.*s\n",name_utf8.length,name_utf8.bytes, descriptor_utf8.length,descriptor_utf8.bytes));
    for (int methodId=0; methodId < cf->methods_count; methodId++){
        CONSTANT_Utf8_info classMethodName_utf8 = cf->constant_pool[cf->methods[methodId].name_index-1].info.utf8_info; // todo possibly optimize this func
        CONSTANT_Utf8_info classMethodDesc_utf8 = cf->constant_pool[cf->methods[methodId].descriptor_index-1].info.utf8_info; // todo possibly optimize this func
        if (isUtf8Equal(name_utf8, classMethodName_utf8) && isUtf8Equal(descriptor_utf8, classMethodDesc_utf8)){
            DEBUG_PRINT( ("Found Method Name: %.*s\n",classMethodName_utf8.length,classMethodName_utf8.bytes));
            return &cf->methods[methodId];
        }
    }
    return NULL; // method is not in this class
}

int checkFormat(ClassFile* cf){
    //1
    if (cf->magic != 0xCAFEBABE)
        return 0;
    
    //2
    for (int attributeCount=0; attributeCount<cf->attributes_count; attributeCount++){
        uint16_t utf8Index = cf->attributes[attributeCount].attribute_name_index;
        if (cf->constant_pool[utf8Index-1].tag != CONSTANT_Utf8){ // constant pool starts from 1 (lol, bcz oracle said)
            //The constant_pool entry at attribute_name_index must be a CONSTANT_Utf8_info structure
            return 0;
        }
    }
    //4
    for (int constantPoolCount=0; constantPoolCount < cf->constant_pool_count-1; constantPoolCount++){
        switch (cf->constant_pool[constantPoolCount].tag){
            case CONSTANT_Double:
            case CONSTANT_Long:
                // oracle's stupid ideas. see double_info in constantpool.c
                constantPoolCount++;
                break;
            case CONSTANT_Class:; // empty statement ;
                uint16_t utf8Index = cf->constant_pool[constantPoolCount].info.class_info.name_index;
                if (cf->constant_pool[utf8Index-1].tag != CONSTANT_Utf8)
                    return 0;
                break;
            case CONSTANT_Fieldref:;
                // The class_index item of a CONSTANT_Fieldref_info structure may be either a class type or an interface type. 
                CONSTANT_Ref_info fieldref = cf->constant_pool[constantPoolCount].info.ref_info;
                if (!(cf->constant_pool[fieldref.class_index-1].tag == CONSTANT_Class || cf->constant_pool[fieldref.class_index-1].tag == CONSTANT_InterfaceMethodref))
                    return 0;
                break;
            case CONSTANT_InterfaceMethodref:;
                CONSTANT_Ref_info interfaceMethodref = cf->constant_pool[constantPoolCount].info.ref_info;
                if (cf->constant_pool[interfaceMethodref.class_index-1].tag != CONSTANT_InterfaceMethodref)
                    return 0;
                break;
            case CONSTANT_Methodref:;
                // The class_index item of a CONSTANT_Fieldref_info structure may be either a class type or an interface type. 
                CONSTANT_Ref_info methodref = cf->constant_pool[constantPoolCount].info.ref_info;
                if (cf->constant_pool[methodref.class_index-1].tag != CONSTANT_Class)
                    return 0;
                break;
            default:
                break;
        }
    }
    return 1;
}

================================================
FILE: src/constantPool.c
================================================
#include "constantPool.h"
#include <stdio.h>
#include <stdlib.h>
#include "endianness.h"
/*
Constant Pool Indexes written in the class file starts from 1; 
to access a constant, please get the (index - 1)th value.
*/
cp_info cp_infoFromFile(FILE* fd){
    cp_info info;
    fread(&info.tag,1,1,fd); // tag len is 1
    switch (info.tag){
        case CONSTANT_Class:
            fread(&info.info.class_info.name_index,sizeof(info.info.class_info.name_index),1,fd);
            info.info.class_info.name_index = be16toh(info.info.class_info.name_index); // big order to host
            break;
        case CONSTANT_Fieldref:
        case CONSTANT_Methodref:
        case CONSTANT_InterfaceMethodref:
            fread(&info.info.ref_info.class_index,sizeof(info.info.ref_info.class_index),1,fd);
            fread(&info.info.ref_info.name_and_type_index,sizeof(info.info.ref_info.name_and_type_index),1,fd);
            info.info.ref_info.class_index = be16toh(info.info.ref_info.class_index);
            info.info.ref_info.name_and_type_index = be16toh(info.info.ref_info.name_and_type_index);
            break;
        case CONSTANT_String:
            fread(&info.info.string_info.string_index,sizeof(info.info.string_info.string_index),1,fd);
            info.info.string_info.string_index = be16toh(info.info.string_info.string_index);
            break;
        case CONSTANT_Integer:
        case CONSTANT_Float:
            fread(&info.info._4BYTES_info.bytes,sizeof(info.info._4BYTES_info.bytes),1,fd);
            info.info._4BYTES_info.bytes = be32toh(info.info._4BYTES_info.bytes);
            break;
        case CONSTANT_Long:
        case CONSTANT_Double:
            // 8 byte types takes two indexes in constant pool. So increase the counter by one extra.
            fread(&info.info._8BYTES_info.bytes,sizeof(info.info._8BYTES_info.bytes),1,fd);
            info.info._8BYTES_info.bytes = be64toh(info.info._8BYTES_info.bytes);
            break;
        case CONSTANT_NameAndType:
            fread(&info.info.nameAndType_info.name_index,sizeof(info.info.nameAndType_info.name_index),1,fd);
            fread(&info.info.nameAndType_info.descriptor_index,sizeof(info.info.nameAndType_info.descriptor_index),1,fd);
            info.info.nameAndType_info.name_index = be16toh(info.info.nameAndType_info.name_index);
            info.info.nameAndType_info.descriptor_index = be16toh(info.info.nameAndType_info.descriptor_index);
            break;
        case CONSTANT_Utf8:; // compiler wants a statement after label.
            fread(&info.info.utf8_info.length,sizeof(info.info.utf8_info.length),1,fd); // len
            info.info.utf8_info.length = be16toh(info.info.utf8_info.length);
            info.info.utf8_info.bytes = malloc(info.info.utf8_info.length); //leak
            fread(info.info.utf8_info.bytes,info.info.utf8_info.length,1,fd); // offsetting 2 bytes + reading utf8
            //printf("len: %d, s: %.*s\n",info.info.utf8_info.length,info.info.utf8_info.length, info.info.utf8_info.bytes);
            break;
        case CONSTANT_MethodHandle:; // compiler wants a statement after label.
            fread(&info.info.methodHandle_info.reference_kind,sizeof(info.info.methodHandle_info.reference_kind),1,fd); // reference kind
            fread(&info.info.methodHandle_info.reference_index,sizeof(info.info.methodHandle_info.reference_index),1,fd); // ref index
            info.info.methodHandle_info.reference_index = be16toh(info.info.methodHandle_info.reference_index);
            break;
        case CONSTANT_MethodType:
            fread(&info.info.methodType_info.descriptor_index,sizeof(info.info.methodType_info.descriptor_index),1,fd);
            info.info.methodType_info.descriptor_index = be16toh(info.info.methodType_info.descriptor_index);
            break;
        case CONSTANT_InvokeDynamic:
            fread(&info.info.invodeDynamic_info.bootstrap_method_attr_index,sizeof(info.info.invodeDynamic_info.bootstrap_method_attr_index),1,fd);
            fread(&info.info.invodeDynamic_info.name_and_type_index,sizeof(info.info.invodeDynamic_info.name_and_type_index),1,fd);
            info.info.invodeDynamic_info.bootstrap_method_attr_index = be16toh(info.info.invodeDynamic_info.bootstrap_method_attr_index);
            info.info.invodeDynamic_info.name_and_type_index = be16toh(info.info.invodeDynamic_info.name_and_type_index);
            break;

        default:
            //tag err
            break;
    }
    return info;

}

void destroyCp_Info(cp_info* info){
    if (info->tag == CONSTANT_Utf8)
        free(info->info.utf8_info.bytes);
}

================================================
FILE: src/field.c
================================================
#include "field.h"
#include <stdio.h>
#include "endianness.h"
#include <stdlib.h>
#include "classFile.h"
#include "constantPool.h"
#include "javaClass.h"

field_info getField_Info(FILE* fd){
    field_info field;
    fread(&field.access_flags,sizeof(field.access_flags),1,fd);
    field.access_flags = be16toh(field.access_flags);

    fread(&field.name_index,sizeof(field.name_index),1,fd);
    field.name_index = be16toh(field.name_index);

    fread(&field.descriptor_index,sizeof(field.descriptor_index),1,fd);
    field.descriptor_index = be16toh(field.descriptor_index);

    fread(&field.attributes_count,sizeof(field.attributes_count),1,fd);
    field.attributes_count = be16toh(field.attributes_count);

    field.attributes = malloc (sizeof(attribute_info) * field.attributes_count);
    for (int attributeCount=0; attributeCount<field.attributes_count; attributeCount++){
        field.attributes[attributeCount] = getAttribute_Info(fd); // leak
    }
    field.value = 0;
    return field;

}

void destroyField_Info(field_info* field){
    for (; field->attributes_count > 0; field->attributes_count--)
        destroyAttribute_Info(&field->attributes[field->attributes_count-1]);
    free(field->attributes);
}

void putField(JavaClass* instance, CONSTANT_Utf8_info fieldName, CONSTANT_Utf8_info fieldDesc, uint64_t val){
    field_info* field = getField(instance, fieldName, fieldDesc);
    field->value = val;
}


field_info* getField(JavaClass* jc, CONSTANT_Utf8_info fieldName, CONSTANT_Utf8_info fieldDesc){
    for (uint16_t fieldId=0; fieldId<jc->classFile->fields_count; fieldId++){
        field_info* field = &jc->fields[fieldId];
        CONSTANT_Utf8_info _fieldName = jc->classFile->constant_pool[field->name_index-1].info.utf8_info;
        CONSTANT_Utf8_info _fieldDesc = jc->classFile->constant_pool[field->descriptor_index-1].info.utf8_info;
        if (isUtf8Equal(fieldName,_fieldName) && isUtf8Equal(fieldDesc,_fieldDesc)){
            return field;
        }
    }
    return NULL;
}

field_info* getStaticField(ClassFile* cf, CONSTANT_Utf8_info fieldName, CONSTANT_Utf8_info fieldDesc){
    for (uint16_t fieldId=0; fieldId<cf->fields_count; fieldId++){
        field_info* field = &cf->fields[fieldId];
        CONSTANT_Utf8_info _fieldName = cf->constant_pool[field->name_index-1].info.utf8_info;
        CONSTANT_Utf8_info _fieldDesc = cf->constant_pool[field->descriptor_index-1].info.utf8_info;
        if (isUtf8Equal(fieldName,_fieldName) && isUtf8Equal(fieldDesc,_fieldDesc)){
            return field;
        }
    }
    return NULL;
}

================================================
FILE: src/frame.c
================================================
#include "frame.h"
#include <stdlib.h>
#include "classFile.h"
#include "attribute.h"

Frame createNewFrame (Code_attribute code, ClassFile* cf, Machine* machine){
    Frame newFrame;
    newFrame.code = malloc (sizeof(Code_attribute));
    *newFrame.code = code;

    newFrame.localVariables = malloc (sizeof(LocalVariable) * newFrame.code->max_locals);

    newFrame.operandStack = malloc (sizeof(Stack));
    *newFrame.operandStack = initStack(newFrame.code->max_stack, TYPE_OPERANDSTACK);

    newFrame.pc = 0;
    newFrame.classRef = cf;
    newFrame.machine = machine;
    return newFrame;
}

void destroyFrame (Frame* frame){
    free(frame->localVariables);
    free(frame->code);
    destroyStack(frame->operandStack);
    // dont free the frame struct itself. It contains an address into JVMStack.
    // JVMStack is responsible for freeing or overwriting it.
}

================================================
FILE: src/heap.c
================================================
#include "heap.h"

Heap initHeap(size_t size){
    Heap heap;
    heap.heap = calloc(size,sizeof(HeapObject));
    heap.size = size;
    heap.top = 1; // 0 is for null object refs. 
    return heap;
}

void* hGet(uint64_t addr, Heap* heap){
    return heap->heap[addr].addr;
}

uint64_t hAlloc(size_t size, Heap* heap){
    for (size_t mem=0; mem<heap->top; mem++){
        // this gets slower and sloooower as the number of object in heap increases.
        if (!heap->heap[mem].isUsed){
            heap->heap[mem].isUsed=1;
            heap->heap[mem].size = size;
            free(heap->heap[mem].addr);
            heap->heap[mem].addr = malloc(heap->heap[mem].size);
            return (mem);
        }
    }
    if(heap->top + 1 > heap->size){
        heap->heap = realloc(heap->heap,heap->size+=1024); // realloc 1024 more
    }
    heap->heap[heap->top].isUsed = 1;
    heap->heap[heap->top].size = size;
    heap->heap[heap->top].addr = malloc(size);
    return (heap->top++);
}

uint64_t hExtend(uint64_t addr, size_t size, Heap* heap){
    heap->heap[addr].size += size;
    heap->heap[addr].addr = realloc(heap->heap[addr].addr,heap->heap[addr].size);
    return addr;
}

void* hFree(uint64_t addr, Heap* heap){
    heap->heap[addr].isUsed = 0;
    return NULL;
}

void destroyHeap(Heap* heap){
    for(;heap->top > 0; heap->top--)
        free(heap->heap[heap->top -1].addr);
    free(heap->heap);
    free(heap);
}

================================================
FILE: src/javaClass.c
================================================
#include "javaClass.h"
#include <stdlib.h>
#include "heap.h"
#include <string.h>

void initInstanceFields(JavaClass* instance){
    instance->fields = malloc(instance->classFile->fields_count * sizeof(field_info));
    memcpy(instance->fields, instance->classFile->fields, instance->classFile->fields_count * sizeof(field_info));
}

================================================
FILE: src/machine.c
================================================
#include "machine.h"
#include "frame.h"
#include "opcode.h"
#include "stack.h"
#include "debug.h"
#include "classFile.h"

void* executeCode(Machine* JVM, OPCODE** opcodes){ // anything can be returned from an execution

    Frame* frame;
    void* retCode;
    while (1){
        frame = (Frame*)peekStack(JVM->JVMSTACK);
        DEBUG_PRINT(("---------------\n"));
        DEBUG_PRINT(("peeked stack is %p\n",frame));

        #ifdef DEBUG
        printf("---Code Dump---\n");
        for (int qq=0; qq<frame->code->code_length; qq++)
            printf("%d: 0x%1x\n", qq,frame->code->code[qq]);
        printf("-----DUMP------\n");
        #endif

        for (; frame->pc < frame->code->code_length; frame->pc++){
            retCode = NULL;
            DEBUG_PRINT(("pc: %d -> 0x%1x, opStackTop: %d\n",frame->pc , frame->code->code[frame->pc],frame->operandStack->top));
            retCode = opcodes[frame->code->code[frame->pc]](frame);
            if (retCode != NULL){
                // the opcode returned something to push
                // to the invoker operand stack
                //DEBUG_PRINT(("retcode is not null\n"));
                break;
            }
            if (frame != (Frame*)peekStack(JVM->JVMSTACK)){
                break; // frame changed, break!
            }
        }
        if (retCode != NULL){
            DEBUG_PRINT(("returned something, in num: %d\n", *(uint64_t*) retCode));
            destroyFrame((Frame*)popStack(JVM->JVMSTACK)); //destroy completely
            Frame* frameInvoker = (Frame*)peekStack(JVM->JVMSTACK);
            pushStack(retCode,frameInvoker->operandStack); // frame returned something to push
            free(retCode); // iret mallocs it.
            // into previous frames operand stack
        }else if (frame->pc > frame->code->code_length){
            DEBUG_PRINT(("no code left to execute in this frame pc: %d, codelen: %d\n", frame->pc, frame->code->code_length));
            destroyFrame((Frame*)popStack(JVM->JVMSTACK)); //destroy completely
            // this frame finished without returning anything
        }
        if (peekStack(JVM->JVMSTACK) == NULL){
            DEBUG_PRINT(("no frame left to execute\n"));
            free(opcodes);
            return NULL;
        }
    }
}

void destroyMachine(Machine* machine){
    for (;machine->numClasses>0; machine->numClasses--)
        destroyClass(&machine->classFiles[machine->numClasses-1]);

    free(machine->classFiles);
    destroyStack(machine->JVMSTACK);
    destroyHeap(machine->heap);
}

================================================
FILE: src/main.c
================================================
#include <stdio.h>
#include <stdlib.h>
#include "machine.h"
#include "classFile.h"
#include <assert.h>
#include "opcode.h" // gecici
#include "stack.h"
#include "attribute.h"
#include "constantPool.h"
#include "machine.h"
#include "heap.h"
#include "debug.h"

void main(int argc, char* argv[]){
    Machine JVM;
    JVM.numClasses = 0;
    JVM.classFiles = malloc(sizeof(ClassFile) * 255);
    ClassFile* mainClass = getClassFromName(argv[1], &JVM);

    assert(checkFormat(mainClass)); // file format check
    //DEBUG_PRINT(("%x\n",mainClass->magic));
    DEBUG_PRINT(("Minor: %d, Major: %d\n", mainClass->minor_version,mainClass->major_version));
    DEBUG_PRINT(("constant_pool_count: %d\n",mainClass->constant_pool_count));
    DEBUG_PRINT(("access_flags: %d\n",mainClass->access_flags));
    DEBUG_PRINT(("this_class: %d\n",mainClass->this_class));
    DEBUG_PRINT(("super_class: %d\n",mainClass->super_class));
    DEBUG_PRINT(("interfaces_count: %d\n",mainClass->interfaces_count));
    DEBUG_PRINT(("fields_count: %d\n",mainClass->fields_count));
    DEBUG_PRINT(("methods_count: %d\n",mainClass->methods_count));
    DEBUG_PRINT(("attributes_count: %d\n",mainClass->attributes_count));

    cp_info info = mainClass->constant_pool[mainClass->this_class-1];
    CONSTANT_Class_info classInfo = info.info.class_info;

    if (info.tag == CONSTANT_Class){
        CONSTANT_Utf8_info utf8 = mainClass->constant_pool[classInfo.name_index-1].info.utf8_info;
        DEBUG_PRINT( ("This Class Name: %.*s\n",utf8.length,utf8.bytes));
    }

    JVM.heap = malloc(sizeof(Heap));
    *JVM.heap = initHeap(512);

    JVM.JVMSTACK = malloc(sizeof(Stack));
    *JVM.JVMSTACK = initStack(255,TYPE_JVMSTACK);

    Frame newFrame;

    method_info* method = getMethodByName(mainClass, "main","([Ljava/lang/String;)V");
    Code_attribute* code = malloc(sizeof(Code_attribute));
    if (method != NULL){
        *code = getCode_AttributeFromAttribute_info(method->attributes[0]);
        //method->attributes[0]
    }else{
        printf("main method not found \n");
        return;
    }

    newFrame.code = code;
    newFrame.localVariables = malloc (sizeof(LocalVariable) * code->max_locals);

    //Stack* operandStack = ;
    newFrame.operandStack = malloc(sizeof(Stack));
    *newFrame.operandStack = initStack(code->max_stack, TYPE_OPERANDSTACK);

    newFrame.pc = 0;
    newFrame.classRef = mainClass;
    newFrame.machine = &JVM;

    pushStack(&newFrame, JVM.JVMSTACK);
    void* retCode = executeCode(&JVM, initOpcodes());
    if (retCode == NULL){
        DEBUG_PRINT(("Execution Stack Finished\n"));
    }
    destroyMachine(&JVM);
}

================================================
FILE: src/opcode.c
================================================
#include "opcode.h"
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
#include "endianness.h"
#include "constantPool.h"
#include "frame.h"
#include "classFile.h"
#include <string.h>
#include "javaClass.h"
#include "debug.h"
#include "printStream.h"
#include "stringBuilder.h"
#include <math.h>

uint8_t read1Byte(Frame* frame){
    return *(uint8_t*)&frame->code->code[++frame->pc]; // to get the first arg. of the opcode
}
uint16_t read2Bytes(Frame* frame){
    /*
    OP  A1  A2
    00  01  02
    ^
    */
    uint16_t val=be16toh(*(uint16_t*)&frame->code->code[frame->pc+1]);
    frame->pc += 2;
    return val;
}
uint32_t read4Bytes(Frame* frame){
    uint32_t val=be32toh(*(uint32_t*)&frame->code->code[frame->pc+1]);
    frame->pc += 4;
    return val;
}
uint64_t read8Bytes(Frame* frame){
    uint64_t val=be64toh(*(uint64_t*)&frame->code->code[frame->pc+1]);
    frame->pc += 8;
    return val;
}
void* OPCODE_ICONST_M1(Frame* frame){
    uint64_t val = -1;
    pushStack(&val,frame->operandStack);
	return NULL;
}
void* OPCODE_ICONST_0(Frame* frame){
    uint64_t val = 0;
    pushStack(&val,frame->operandStack);
	return NULL;
}
void* OPCODE_ICONST_1(Frame* frame){
    uint64_t val = 1;
    pushStack(&val,frame->operandStack);
	return NULL;
}
void* OPCODE_ICONST_2(Frame* frame){
    uint64_t val = 2;
    pushStack(&val,frame->operandStack);
	return NULL;
}
void* OPCODE_ICONST_3(Frame* frame){
    uint64_t val = 3;
    pushStack(&val,frame->operandStack);
	return NULL;
}
void* OPCODE_ICONST_4(Frame* frame){
    uint64_t val = 4;
    pushStack(&val,frame->operandStack);
	return NULL;
}
void* OPCODE_ICONST_5(Frame* frame){
    uint64_t val = 5;
    pushStack(&val,frame->operandStack);
	return NULL;
}
void* OPCODE_DCONST_0(Frame* frame){
    double val = 0.0;
    pushStack(&val,frame->operandStack);
	return NULL;
}
void* OPCODE_DCONST_1(Frame* frame){
    double val = 1.0;
    pushStack(&val,frame->operandStack);
	return NULL;
}
void* OPCODE_DCONST_2(Frame* frame){
    double val = 2.0;
    pushStack(&val,frame->operandStack);
	return NULL;
}

void* OPCODE_BIPUSH(Frame* frame){
    uint64_t val = read1Byte(frame);
    pushStack(&val,frame->operandStack);
	return NULL;
}
void* OPCODE_SIPUSH(Frame* frame){
    uint64_t val = read2Bytes(frame);
    pushStack(&val,frame->operandStack);
	return NULL;
}
void* OPCODE_LDC(Frame* frame){
    uint8_t index = read1Byte(frame);
    cp_info* aConstant = &frame->classRef->constant_pool[index-1];
    if (aConstant->tag == CONSTANT_Integer || aConstant->tag == CONSTANT_Float){
        uint64_t val;
        val = aConstant->info._4BYTES_info.bytes;
        pushStack(&val, frame->operandStack);
    }else{
        pushStack(&aConstant, frame->operandStack);
        /*
        Otherwise, if the run-time constant pool entry is a reference to an instance of class 
        String representing a string literal (§5.1), then a reference to that instance, value,
        is pushed onto the operand stack.
        
        Otherwise, if the run-time constant pool entry is a symbolic reference to a class (§5.1),
        then the named class is resolved (§5.4.3.1) and a reference to the Class object 
        representing that class, value, is pushed onto the operand stack.

        Otherwise, the run-time constant pool entry must be a symbolic reference to a method type
        or a method handle (§5.1). The method type or method handle is resolved (§5.4.3.5) and a
        reference to the resulting instance of java.lang.invoke.MethodType or 
        java.lang.invoke.MethodHandle, value, is pushed onto the operand stack. 
        */
    }
    return NULL;
}
void* OPCODE_LDC_W(Frame* frame){
    uint16_t index = read2Bytes(frame);
    cp_info* aConstant = &frame->classRef->constant_pool[index-1];
    if (aConstant->tag == CONSTANT_Integer || aConstant->tag == CONSTANT_Float){
        uint64_t val;
        val = aConstant->info._4BYTES_info.bytes;
        pushStack(&val, frame->operandStack);
    }else if(aConstant->tag == CONSTANT_Long || aConstant->tag == CONSTANT_Double){
        uint64_t val;
        val = aConstant->info._8BYTES_info.bytes;
        pushStack(&val, frame->operandStack);
    }else{
        pushStack(&aConstant, frame->operandStack);
    }
	return NULL;
}
void* OPCODE_NLOAD(Frame* frame){ // N represents I,L or D
    uint8_t index = read1Byte(frame);
    pushStack(&frame->localVariables[index], frame->operandStack);
	return NULL;
}
void* OPCODE_NLOAD_0(Frame* frame){
    pushStack(&frame->localVariables[0], frame->operandStack);
	return NULL;
}
void* OPCODE_NLOAD_1(Frame* frame){
    pushStack(&frame->localVariables[1], frame->operandStack);
	return NULL;
}
void* OPCODE_NLOAD_2(Frame* frame){
    pushStack(&frame->localVariables[2], frame->operandStack);
	return NULL;
}
void* OPCODE_NLOAD_3(Frame* frame){
    pushStack(&frame->localVariables[3], frame->operandStack);
	return NULL;
}
void* OPCODE_NSTORE(Frame* frame){
    uint8_t index = read1Byte(frame);
    uint64_t val = *(uint64_t*)popStack(frame->operandStack);
    frame->localVariables[index] = val;
	return NULL;
}
void* OPCODE_NSTORE_0(Frame* frame){
    uint64_t val = *(uint64_t*)popStack(frame->operandStack);
    frame->localVariables[0] = val;
	return NULL;
}
void* OPCODE_NSTORE_1(Frame* frame){
    uint64_t val = *(uint64_t*)popStack(frame->operandStack);
    frame->localVariables[1] = val;
	return NULL;
}
void* OPCODE_NSTORE_2(Frame* frame){
    uint64_t val = *(uint64_t*)popStack(frame->operandStack);
    frame->localVariables[2] = val;
	return NULL;
}
void* OPCODE_NSTORE_3(Frame* frame){
    uint64_t val = *(uint64_t*)popStack(frame->operandStack);
    frame->localVariables[3] = val;
	return NULL;
}
void* OPCODE_POP(Frame* frame){
    //popStack(frame->operandStack);
    int64_t discardedRetVal = *(int64_t*) popStack(frame->operandStack);
    DEBUG_PRINT(("Discarded Return Value is %d\n",discardedRetVal));
	return NULL;
}
void* OPCODE_DUP(Frame* frame){
    uint64_t val = *(uint64_t*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_DUP_X1(Frame* frame){
    uint64_t val1 = *(uint64_t*)popStack(frame->operandStack);
    uint64_t val2 = *(uint64_t*)popStack(frame->operandStack);
    pushStack(&val1, frame->operandStack);
    pushStack(&val2, frame->operandStack);
    pushStack(&val1, frame->operandStack);
	return NULL;
}

/////////////
// INTEGER //
/////////////
void* OPCODE_IADD(Frame* frame){
    int64_t val = (int32_t)*(int64_t*)popStack(frame->operandStack) + (int32_t)*(int64_t*)popStack(frame->operandStack); // java has no unsigned types, lol
    // the stacks are 64 bit but the int size is 32 bit
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_ISUB(Frame* frame){
    int32_t val2 = *(int64_t*) popStack(frame->operandStack);
    int32_t val1 = *(int64_t*) popStack(frame->operandStack);
    int64_t val = val1 - val2;
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_IMUL(Frame* frame){
    int64_t val = (int32_t)*(int64_t*)popStack(frame->operandStack) * (int32_t)*(int64_t*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_IDIV(Frame* frame){
    int32_t val2 = *(int64_t*) popStack(frame->operandStack);
    int32_t val1 = *(int64_t*) popStack(frame->operandStack);
    int64_t val = val1 / val2;
    pushStack(&val, frame->operandStack);
	return NULL;
}
/////////////
///  LONG ///
/////////////
void* OPCODE_LADD(Frame* frame){
    int64_t val = *(int64_t*)popStack(frame->operandStack) + *(int64_t*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_LSUB(Frame* frame){
    int64_t val2 = *(int64_t*) popStack(frame->operandStack);
    int64_t val1 = *(int64_t*) popStack(frame->operandStack);
    int64_t val = val1-val2;
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_LMUL(Frame* frame){
    int64_t val = *(int64_t*)popStack(frame->operandStack) * *(int64_t*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_LDIV(Frame* frame){
    int64_t val2 = *(int64_t*) popStack(frame->operandStack);
    int64_t val1 = *(int64_t*) popStack(frame->operandStack);
    int64_t val = val1 / val2;
    pushStack(&val, frame->operandStack);
	return NULL;
}
/////////////
/// DOUBLE //
/////////////
void* OPCODE_DADD(Frame* frame){
    double val = *(double*)popStack(frame->operandStack) + *(double*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_DSUB(Frame* frame){
    double val2 = *(double*) popStack(frame->operandStack);
    double val1 = *(double*) popStack(frame->operandStack);
    double val = val1-val2;
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_DMUL(Frame* frame){
    double val = *(double*)popStack(frame->operandStack) * *(double*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_DDIV(Frame* frame){
    double val2 = *(double*) popStack(frame->operandStack);
    double val1 = *(double*) popStack(frame->operandStack);
    double val = val1 / val2;
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_D2F(Frame* frame){
    float val = (float)*(double*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_D2I(Frame* frame){
    int64_t val = (int32_t)*(double*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_D2L(Frame* frame){
    int64_t val = (int64_t)*(double*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_DNEG(Frame* frame){
    double val = -*(double*) popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}
void* OPCODE_DREM(Frame* frame){
    double val2 = *(double*) popStack(frame->operandStack);
    double val1 = *(double*) popStack(frame->operandStack);
    double val = fmod(val1,val2);
    pushStack(&val, frame->operandStack);
	return NULL;
}

///////////////

void* OPCODE_I2D(Frame* frame){
    double val = (double)(int32_t)*(int64_t*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}

void* OPCODE_I2F(Frame* frame){
    float val = (float)(int32_t)*(int64_t*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}

void* OPCODE_I2B(Frame* frame){
    int64_t val = (int8_t)*(int64_t*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}

void* OPCODE_I2C(Frame* frame){
    //char, whose values are 16-bit unsigned integers representing Unicode code points ...
    uint64_t val = (uint16_t)*(int64_t*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}

void* OPCODE_I2L(Frame* frame){
    uint64_t val = (int32_t)*(int64_t*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}

void* OPCODE_I2S(Frame* frame){
    uint64_t val = (int16_t)*(int64_t*)popStack(frame->operandStack);
    pushStack(&val, frame->operandStack);
	return NULL;
}

///////////////

void* OPCODE_LCMP(Frame* frame){
    uint64_t val2 = *(uint64_t*) popStack(frame->operandStack);
    uint64_t val1 = *(uint64_t*) popStack(frame->operandStack);
    int64_t val = 0;
    if (val1 > val2){
        val = 1;
    }else if (val1 == val2){
        val = 0;
    }else {
        val = -1;
    }
    pushStack(&val, frame->operandStack);
	return NULL;
}

void* OPCODE_IFEQ(Frame* frame){
    uint16_t offset = read2Bytes(frame);
    int64_t val1 = (int32_t)*(int64_t*) popStack(frame->operandStack);
    if (val1 == 0){
        frame->pc += offset - 3;
    }
    return NULL;
}
void* OPCODE_IFNE(Frame* frame){
    uint16_t offset = read2Bytes(frame);
    int64_t val1 = (int32_t)*(int64_t*) popStack(frame->operandStack);
    if (val1 != 0){
        frame->pc += offset - 3;
    }
    return NULL;
}
void* OPCODE_IFLT(Frame* frame){
    uint16_t offset = read2Bytes(frame);
    int64_t val1 = (int32_t)*(int64_t*) popStack(frame->operandStack);
    if (val1 < 0){
        frame->pc += offset - 3;
    }
    return NULL;
}
void* OPCODE_IFLE(Frame* frame){
    uint16_t offset = read2Bytes(frame);
    int64_t val1 = (int32_t)*(int64_t*) popStack(frame->operandStack);
    if (val1 <= 0){
        frame->pc += offset - 3;
    }
    return NULL;
}
void* OPCODE_IFGT(Frame* frame){
    uint16_t offset = read2Bytes(frame);
    int64_t val1 = (int32_t)*(int64_t*) popStack(frame->operandStack);
    if (val1 > 0){
        frame->pc += offset - 3;
    }
    return NULL;
}
void* OPCODE_IFGE(Frame* frame){
    uint16_t offset = read2Bytes(frame);
    int64_t val1 = (int32_t)*(int64_t*) popStack(frame->operandStack);
    if (val1 >= 0){
        frame->pc += offset - 3;
    }
    return NULL;
}

void* OPCODE_DCMPG(Frame* frame){
    double val2 = *(double*) popStack(frame->operandStack);
    double val1 = *(double*) popStack(frame->operandStack);
    int64_t val = 0;
    if (val1 > val2){
        val = 1;
    }else if (val1 == val2){
        val = 0;
    }else {
        val = -1;
    }
    pushStack(&val, frame->operandStack);
	return NULL;
}

void* OPCODE_IF_ICMPGE(Frame* frame){
    uint16_t offset = read2Bytes(frame);
    int64_t val2 = (int32_t)*(int64_t*) popStack(frame->operandStack);
    int64_t val1 = (int32_t)*(int64_t*) popStack(frame->operandStack);
    if (val1 >= val2){
        frame->pc += offset - 3;
        // -1 because the main loop will increase 1 after this opcode to
        // get the next opcode. Extra -2 because we moved 2 more bytes while
        // reading the offset
    }
	return NULL;
}

void* OPCODE_IF_ICMPGT(Frame* frame){
    uint16_t offset = read2Bytes(frame);
    int64_t val2 = (int32_t)*(int64_t*) popStack(frame->operandStack);
    int64_t val1 = (int32_t)*(int64_t*) popStack(frame->operandStack);
    if (val1 > val2){
        frame->pc += offset - 3;
        // -1 because the main loop will increase 1 after this opcode to
        // get the next opcode. Extra -2 because we moved 2 more bytes while
        // reading the offset
    }
	return NULL;
}

void* OPCODE_IINC(Frame* frame){
    uint8_t index = read1Byte(frame);
    uint8_t incrementAmount = read1Byte(frame);
    *(int64_t*)&frame->localVariables[index] = (int32_t)(*(int64_t*)&frame->localVariables[index] + *(int8_t*)&incrementAmount);
    return NULL;
}

void* OPCODE_GOTO(Frame* frame){
    uint16_t offset = read2Bytes(frame); // branch offset
    frame->pc += *(int16_t*)&offset - 3;
    // -1 because the main loop will increase 1 after this opcode to
    // get the next opcode Extra -2 because we moved 2 more bytes while
    // reading the offset
    return NULL;
}

void* OPCODE_GETSTATIC(Frame* frame){
    uint16_t index = read2Bytes(frame);
    CONSTANT_Ref_info fieldRefInfo = frame->classRef->constant_pool[index-1].info.ref_info;

    CONSTANT_NameAndType_info nameAndType = frame->classRef->constant_pool[fieldRefInfo.name_and_type_index-1].info.nameAndType_info;
    CONSTANT_Utf8_info name_utf8 = frame->classRef->constant_pool[nameAndType.name_index-1].info.utf8_info;
    CONSTANT_Utf8_info desc_utf8 = frame->classRef->constant_pool[nameAndType.descriptor_index-1].info.utf8_info;

    CONSTANT_Class_info class = frame->classRef->constant_pool[fieldRefInfo.class_index -1].info.class_info;
    CONSTANT_Utf8_info className_utf8 = frame->classRef->constant_pool[class.name_index-1].info.utf8_info;
    
    ClassFile* cf = getClassFromUtf8(className_utf8,frame->machine);
    if (cf != NULL){
        initClass(cf, frame);
        field_info* field = getStaticField(cf, name_utf8, desc_utf8);
        pushStack(&field->value, frame->operandStack);
    }else{
        uint64_t val = 0;
        pushStack(&val, frame->operandStack);
    }
    return NULL;
}

void* OPCODE_NEW(Frame* frame){
    uint16_t index = read2Bytes(frame);
    CONSTANT_Class_info class = frame->classRef->constant_pool[index-1].info.class_info; // class or interface ref info

    CONSTANT_Utf8_info className_utf8 = frame->classRef->constant_pool[class.name_index-1].info.utf8_info;
    ClassFile* cf = getClassFromUtf8(className_utf8,frame->machine);
    uint64_t objectRef;
    if (cf != NULL){
        objectRef = hAlloc(sizeof(JavaClass),frame->machine->heap);
        JavaClass* newObject = hGet(objectRef,frame->machine->heap);
        newObject->classFile = cf;
        initClass(cf, frame);
        initInstanceFields(newObject);
        pushStack(&objectRef, frame->operandStack);
    }else{
        uint64_t objectRef = (uint64_t)NULL;
        if (isUtf8EqualsToString(className_utf8,"java/lang/StringBuilder")){
            objectRef = hAlloc(sizeof(cp_info), frame->machine->heap);
            cp_info* str = hGet(objectRef, frame->machine->heap);
            str->tag = CONSTANT_Utf8;
            uint64_t bytesRef = hAlloc(1,frame->machine->heap);
            str->info.utf8_info.bytes=(char*)bytesRef;
            char* bytes = hGet(bytesRef, frame->machine->heap);
            bytes[0]='\0';
            str->info.utf8_info.length=1;
        }
        pushStack(&objectRef, frame->operandStack);
    }
    
    return NULL;
}

void* OPCODE_PUTFIELD(Frame* frame){
    uint16_t index = read2Bytes(frame);
    CONSTANT_Ref_info fieldRefInfo = frame->classRef->constant_pool[index-1].info.ref_info;

    CONSTANT_NameAndType_info nameAndType = frame->classRef->constant_pool[fieldRefInfo.name_and_type_index-1].info.nameAndType_info;
    CONSTANT_Utf8_info name_utf8 = frame->classRef->constant_pool[nameAndType.name_index-1].info.utf8_info;
    CONSTANT_Utf8_info desc_utf8 = frame->classRef->constant_pool[nameAndType.descriptor_index-1].info.utf8_info;

    uint64_t val = *(uint64_t*)popStack(frame->operandStack);
    JavaClass* obj = (JavaClass*)hGet(*(uint64_t*)popStack(frame->operandStack),frame->machine->heap);

    DEBUG_PRINT(("%x, put val is %d, objRef is %p \n", obj->classFile->magic, val, obj));
    putField(obj, name_utf8, desc_utf8, val);

    return NULL;
}

void* OPCODE_NRETURN(Frame* frame){
    uint64_t* val = malloc(sizeof(val)); // freed later
    *val = *(uint64_t*)popStack(frame->operandStack);
    DEBUG_PRINT(("iret val : %d, stackTop: %d\n", *val, frame->operandStack->top));
    return val;
}
void* OPCODE_RETURN(Frame* frame){
    frame->pc = frame->code->code_length;
    // current frame is discarded
    return NULL;
}

void* OPCODE_GETFIELD(Frame* frame){
    
    JavaClass* obj = (JavaClass*)hGet(*(uint64_t*)popStack(frame->operandStack),frame->machine->heap);
    uint16_t index = read2Bytes(frame);
    CONSTANT_Ref_info fieldRef = frame->classRef->constant_pool[index-1].info.ref_info;

    CONSTANT_NameAndType_info* nameAndType = &frame->classRef->constant_pool[fieldRef.name_and_type_index-1].info.nameAndType_info;
    CONSTANT_Utf8_info name_utf8 = frame->classRef->constant_pool[nameAndType->name_index-1].info.utf8_info;
    CONSTANT_Utf8_info desc_utf8 = frame->classRef->constant_pool[nameAndType->descriptor_index-1].info.utf8_info;

    // different type fields can have the same name in bytecode but not in java.
    field_info* field = getField(obj,name_utf8, desc_utf8);
    pushStack(&field->value, frame->operandStack);
    return NULL;
}

void* OPCODE_INVOKEVIRTUAL(Frame* frame){
    uint16_t index = read2Bytes(frame);
    if (!(frame->classRef->constant_pool[index-1].tag == CONSTANT_Methodref || frame->classRef->constant_pool[index-1].tag == CONSTANT_InterfaceMethodref)){
        printf("invoked method ref is invalid, index is %d\n",index);
    }
    CONSTANT_Ref_info methodOrInterfaceRef = frame->classRef->constant_pool[index-1].info.ref_info;
    
    CONSTANT_NameAndType_info* nameAndType = &frame->classRef->constant_pool[methodOrInterfaceRef.name_and_type_index-1].info.nameAndType_info;
    CONSTANT_Utf8_info name_utf8 = frame->classRef->constant_pool[nameAndType->name_index-1].info.utf8_info;
    CONSTANT_Utf8_info desc_utf8 = frame->classRef->constant_pool[nameAndType->descriptor_index-1].info.utf8_info;
    DEBUG_PRINT( ("Method's Name: %.*s\n",name_utf8.length,name_utf8.bytes));

    CONSTANT_Class_info methodClass = frame->classRef->constant_pool[methodOrInterfaceRef.class_index - 1].info.class_info;
    CONSTANT_Utf8_info className_utf8 = frame->classRef->constant_pool[methodClass.name_index-1].info.utf8_info;
    DEBUG_PRINT( ("Class's Name: %.*s\n",className_utf8.length,className_utf8.bytes));
    ClassFile* cf = getClassFromUtf8(className_utf8, frame->machine);


    method_info* method = NULL;

    int numArgs = getNumArgs(frame->classRef, methodOrInterfaceRef) + 1; // +1 for ObjectRef which will be at localVars[0]

    uint64_t tempLocalVars[numArgs];
    for (int argId = numArgs-1; argId >= 0; argId--){
        tempLocalVars[argId] = *(uint64_t*) popStack(frame->operandStack);
    }
 

    // hack to run Println
    if (isUtf8EqualsToString(className_utf8,"java/io/PrintStream") && isUtf8EqualsToString(name_utf8,"println")){
        handlePrintStream(tempLocalVars, frame, name_utf8, desc_utf8);
        return NULL;
    }
    if (isUtf8EqualsToString(className_utf8,"java/lang/StringBuilder")){
        handleStringBuilder(tempLocalVars,frame, name_utf8, desc_utf8);
        return NULL;
    }

    ////  Let C be the class of objectref. The actual method to be invoked
    //// is selected by the following lookup procedure:
    
    // If C contains a declaration for an instance method m that overrides (§5.4.5)
    // the resolved method, then m is the method to be invoked.
    JavaClass* obj = (JavaClass*)hGet(tempLocalVars[0],frame->machine->heap);
    method_info* mPointer = canClassHandleMethod(obj->classFile, name_utf8, desc_utf8);

    if (mPointer){
        method = (mPointer)?(mPointer):method;
        DEBUG_PRINT(("first overrider runned\n"));
    }else{

        // Otherwise, if C has a superclass, a search for a declaration of an instance
        // method that overrides the resolved method is performed, starting with the
        // direct superclass of C and continuing with the direct superclass of that
        // class, and so forth, until an overriding method is found or no further
        // superclasses exist. If an overriding method is found, it is the method to be invoked. 
        ClassFile* superClass = obj->classFile;
        mPointer = NULL;
        while (superClass->super_class != 0){
            CONSTANT_Class_info superClassInfo = superClass -> constant_pool [superClass->super_class-1].info.class_info;
            CONSTANT_Utf8_info superClassName = superClass -> constant_pool [superClassInfo.name_index-1].info.utf8_info;
            superClass = getClassFromUtf8 (superClassName, frame->machine);
            mPointer = canClassHandleMethod(superClass, name_utf8, desc_utf8);
            if (mPointer){
                method = (mPointer)?(mPointer):method;
                DEBUG_PRINT(("found in superclass runned\n"));
                break;
            }
        }
        if (mPointer == NULL){
            DEBUG_PRINT(("fallBack runned\n"));
            mPointer = canClassHandleMethod(cf, name_utf8, desc_utf8);
            method = (mPointer)?(mPointer):method;
        }
    }

    if (method->access_flags != M_ACC_NATIVE){
        // todo: error? 
    }

    Code_attribute code;
    if (method != NULL){
        code = getCode_AttributeFromAttribute_info(method->attributes[0]);
    }else{
        printf("method not found \n");
    }
    Frame newFrame = createNewFrame(code, cf, frame->machine);

    memcpy(newFrame.localVariables, tempLocalVars, numArgs * sizeof(tempLocalVars[0]));

    pushStack(&newFrame, frame->machine->JVMSTACK);

    frame->pc++;
    return NULL;
}

void* OPCODE_INVOKESPECIAL(Frame* frame){
    uint16_t index = read2Bytes(frame);
    if (!(frame->classRef->constant_pool[index-1].tag == CONSTANT_Methodref || frame->classRef->constant_pool[index-1].tag == CONSTANT_InterfaceMethodref)){
        printf("invoked method ref is invalid, index is %d\n",index);
    }
    CONSTANT_Ref_info methodOrInterfaceRef = frame->classRef->constant_pool[index-1].info.ref_info;
    
    CONSTANT_NameAndType_info* nameAndType = &frame->classRef->constant_pool[methodOrInterfaceRef.name_and_type_index-1].info.nameAndType_info;
    CONSTANT_Utf8_info name_utf8 = frame->classRef->constant_pool[nameAndType->name_index-1].info.utf8_info;
    CONSTANT_Utf8_info desc_utf8 = frame->classRef->constant_pool[nameAndType->descriptor_index-1].info.utf8_info;
    DEBUG_PRINT( ("Method's Name: %.*s\n",name_utf8.length,name_utf8.bytes));

    CONSTANT_Class_info methodClass = frame->classRef->constant_pool[methodOrInterfaceRef.class_index - 1].info.class_info;
    CONSTANT_Utf8_info className_utf8 = frame->classRef->constant_pool[methodClass.name_index-1].info.utf8_info;
    DEBUG_PRINT( ("Class's Name: %.*s\n",className_utf8.length,className_utf8.bytes));
    ClassFile* cf = getClassFromUtf8(className_utf8, frame->machine);
    int numArgs = getNumArgs(frame->classRef, methodOrInterfaceRef) + 1; // +1 for ObjectRef which will be at localVars[0]

    if (cf == NULL){
        // clear stack for special methods of native classes.
        for (int i=0; i<numArgs; i++)
            popStack(frame->operandStack); // pop numArgs times
        return NULL;
    }

    method_info* method = canClassHandleMethod(cf, name_utf8, desc_utf8);
    Code_attribute code;
    if (method != NULL){
        code = getCode_AttributeFromAttribute_info(method->attributes[0]);
    }else{
        printf("method not found \n");
    }
    Frame newFrame = createNewFrame(code, cf, frame->machine);

    if (method->access_flags != M_ACC_NATIVE){
        for (int argId = numArgs-1; argId >= 0; argId--){
            newFrame.localVariables[argId] = *(uint64_t*) popStack(frame->operandStack);
        }

    }

    pushStack(&newFrame, frame->machine->JVMSTACK);

    frame->pc++;
    return NULL;
}

void* OPCODE_INVOKESTATIC(Frame* frame){
    uint16_t index = read2Bytes(frame);

    if (!(frame->classRef->constant_pool[index-1].tag == CONSTANT_Methodref || frame->classRef->constant_pool[index-1].tag == CONSTANT_InterfaceMethodref)){
        // index must be a symbolic reference to a method or an interface method
        // if the resolved method is an instance method, the invokestatic instruction throws an IncompatibleClassChangeError. 
        printf("invoked method ref is invalid, index is %d\n",index);
    }
    CONSTANT_Ref_info methodOrInterfaceRef = frame->classRef->constant_pool[index-1].info.ref_info;
    //DEBUG_PRINT( ("Method's Class Name: %.*s\n",name_utf8.length,name_utf8.bytes));

    CONSTANT_Class_info methodClass = frame->classRef->constant_pool[methodOrInterfaceRef.class_index - 1].info.class_info;
    CONSTANT_Utf8_info className_utf8 = frame->classRef->constant_pool[methodClass.name_index-1].info.utf8_info;
    DEBUG_PRINT( ("Class's Name: %.*s\n",className_utf8.length,className_utf8.bytes));
    ClassFile* cf = getClassFromUtf8(className_utf8, frame->machine);

    CONSTANT_NameAndType_info* nameAndType = &frame->classRef->constant_pool[methodOrInterfaceRef.name_and_type_index-1].info.nameAndType_info;
    CONSTANT_Utf8_info name_utf8 = frame->classRef->constant_pool[nameAndType->name_index-1].info.utf8_info;
    CONSTANT_Utf8_info desc_utf8 = frame->classRef->constant_pool[nameAndType->descriptor_index-1].info.utf8_info;

    method_info* method = canClassHandleMethod(cf, name_utf8, desc_utf8);
    Code_attribute code;
    if (method != NULL){
        code = getCode_AttributeFromAttribute_info(method->attributes[0]);
        //method->attributes[0]
    }else{
        // todo method not found
        printf("method not found \n");
    }
    Frame newFrame = createNewFrame(code, cf, frame->machine);


    if (method->access_flags != M_ACC_NATIVE){
        // On successful resolution of the method, the class or interface that declared the resolved method is initialized (§5.5) if that class or interface has not already been initialized. 
        int numArgs = getNumArgs(frame->classRef, methodOrInterfaceRef);
        for (int argId = numArgs-1; argId >= 0; argId--){
            newFrame.localVariables[argId] = *(uint64_t*) popStack(frame->operandStack);
        }

    }

    pushStack(&newFrame, frame->machine->JVMSTACK);

    frame->pc++;
    return NULL;
}
OPCODE** initOpcodes(){
    // jumptable
    OPCODE** opcodes = malloc (sizeof(OPCODE*) * 255); // leak, consider static

    opcodes[0x1] = OPCODE_ICONST_0; // null
    opcodes[0x2] = OPCODE_ICONST_M1;
    opcodes[0x3] = OPCODE_ICONST_0;
    opcodes[0x4] = OPCODE_ICONST_1;
    opcodes[0x5] = OPCODE_ICONST_2;
    opcodes[0x6] = OPCODE_ICONST_3;
    opcodes[0x7] = OPCODE_ICONST_4;
    opcodes[0x8] = OPCODE_ICONST_5;
    opcodes[0x9] = OPCODE_ICONST_0;
    opcodes[0xa] = OPCODE_ICONST_1;

    opcodes[0xb] = OPCODE_DCONST_0;
    opcodes[0xc] = OPCODE_DCONST_1;
    opcodes[0xd] = OPCODE_DCONST_2;
    opcodes[0xe] = OPCODE_DCONST_0; // double
    opcodes[0xf] = OPCODE_DCONST_1;

    opcodes[0x10] = OPCODE_BIPUSH;
    opcodes[0x11] = OPCODE_SIPUSH;
    
    opcodes[0x12] = OPCODE_LDC;
    opcodes[0x13] = OPCODE_LDC_W;
    opcodes[0x14] = OPCODE_LDC_W; // same but for 8 bytes. 

    opcodes[0x15] = OPCODE_NLOAD; //iload
    opcodes[0x16] = OPCODE_NLOAD; //lload
    opcodes[0x18] = OPCODE_NLOAD; //dload
    opcodes[0x19] = OPCODE_NLOAD; //aload
    
    // iload
    opcodes[0x1a] = OPCODE_NLOAD_0;
    opcodes[0x1b] = OPCODE_NLOAD_1;
    opcodes[0x1c] = OPCODE_NLOAD_2;
    opcodes[0x1d] = OPCODE_NLOAD_3;
    // lload
    opcodes[0x1e] = OPCODE_NLOAD_0;
    opcodes[0x1f] = OPCODE_NLOAD_1;
    opcodes[0x20] = OPCODE_NLOAD_2;
    opcodes[0x21] = OPCODE_NLOAD_3;
    // dload
    opcodes[0x26] = OPCODE_NLOAD_0;
    opcodes[0x27] = OPCODE_NLOAD_1;
    opcodes[0x28] = OPCODE_NLOAD_2;
    opcodes[0x29] = OPCODE_NLOAD_3;
    // aload
    opcodes[0x2a] = OPCODE_NLOAD_0;
    opcodes[0x2b] = OPCODE_NLOAD_1;
    opcodes[0x2c] = OPCODE_NLOAD_2;
    opcodes[0x2d] = OPCODE_NLOAD_3;


    opcodes[0x36] = OPCODE_NSTORE; // istore
    opcodes[0x37] = OPCODE_NSTORE; // lstore

    opcodes[0x3a] = OPCODE_NSTORE; // astore

    // istore
    opcodes[0x3b] = OPCODE_NSTORE_0;
    opcodes[0x3c] = OPCODE_NSTORE_1;
    opcodes[0x3d] = OPCODE_NSTORE_2;
    opcodes[0x3e] = OPCODE_NSTORE_3;

    // lstore
    opcodes[0x3f] = OPCODE_NSTORE_0;

    opcodes[0x39] = OPCODE_NSTORE; // dstore

    opcodes[0x40] = OPCODE_NSTORE_1;
    opcodes[0x41] = OPCODE_NSTORE_2;
    opcodes[0x42] = OPCODE_NSTORE_3;

    // dstore
    opcodes[0x47] = OPCODE_NSTORE_0;
    opcodes[0x48] = OPCODE_NSTORE_1;
    opcodes[0x49] = OPCODE_NSTORE_2;
    opcodes[0x4a] = OPCODE_NSTORE_3;

    // astore
    opcodes[0x4b] = OPCODE_NSTORE_0;
    opcodes[0x4c] = OPCODE_NSTORE_1;
    opcodes[0x4d] = OPCODE_NSTORE_2;
    opcodes[0x4e] = OPCODE_NSTORE_3;

    opcodes[0x57] = OPCODE_POP;
    opcodes[0x59] = OPCODE_DUP;
    
    opcodes[0x61] = OPCODE_LADD;

    opcodes[0x67] = OPCODE_DSUB;

    opcodes[0x68] = OPCODE_IMUL;

    opcodes[0x6b] = OPCODE_DMUL;
    opcodes[0x6d] = OPCODE_LDIV;
    opcodes[0x6f] = OPCODE_DDIV;

    opcodes[0x73] = OPCODE_DREM;
    opcodes[0x77] = OPCODE_DNEG;

    opcodes[0x84] = OPCODE_IINC;
    opcodes[0x85] = OPCODE_I2L;

    opcodes[0x8e] = OPCODE_D2I;
    opcodes[0x8f] = OPCODE_D2L;

    opcodes[0x90] = OPCODE_D2F;

    opcodes[0x94] = OPCODE_LCMP;

    opcodes[0x97] = OPCODE_DCMPG; //dcmpl
    opcodes[0x98] = OPCODE_DCMPG; //dcmpg

    opcodes[0x99] = OPCODE_IFEQ;
    opcodes[0x9a] = OPCODE_IFNE;
    opcodes[0x9b] = OPCODE_IFLT;
    opcodes[0x9c] = OPCODE_IFGE;
    opcodes[0x9d] = OPCODE_IFGT;
    opcodes[0x9e] = OPCODE_IFLE;


    opcodes[0xa2] = OPCODE_IF_ICMPGE;
    opcodes[0xa3] = OPCODE_IF_ICMPGT;
    opcodes[0xa7] = OPCODE_GOTO;
        
    opcodes[0xaf] = OPCODE_NRETURN; // d

    opcodes[0xb0] = OPCODE_NRETURN;
    opcodes[0xb1] = OPCODE_RETURN;
    opcodes[0xb2] = OPCODE_GETSTATIC;
    opcodes[0xb4] = OPCODE_GETFIELD;
    opcodes[0xb5] = OPCODE_PUTFIELD;
    opcodes[0xb6] = OPCODE_INVOKEVIRTUAL;
    opcodes[0xb7] = OPCODE_INVOKESPECIAL;
    opcodes[0xb8] = OPCODE_INVOKESTATIC;

    opcodes[0xbb] = OPCODE_NEW;
    
    opcodes[0x60] = OPCODE_IADD;
    opcodes[0xac] = OPCODE_NRETURN;
    return opcodes;
}

================================================
FILE: src/printStream.c
================================================
#include "printStream.h"
#include <inttypes.h>
#include "constantPool.h"
#include "frame.h"
#include <stdlib.h>


void handlePrintStream(uint64_t* localVariables, Frame* frame, CONSTANT_Utf8_info name_utf8, CONSTANT_Utf8_info desc_utf8){
    if (isUtf8EqualsToString(desc_utf8,"(I)V")){
        printf("%d\n",localVariables[1]);
        return;
    }
    cp_info* printArg = (cp_info*)localVariables[1]; // 0 is ref, 1 is arg1
    switch (printArg->tag)
    {
        case CONSTANT_Utf8: // created from native toStrings, needs to be freed after use.
            printf("%.*s\n",printArg->info.utf8_info.length,printArg->info.utf8_info.bytes);
            free(printArg);
            break;
        case CONSTANT_String:;
            CONSTANT_Utf8_info str = frame->classRef->constant_pool[printArg->info.string_info.string_index-1].info.utf8_info;
            printf("%.*s\n",str.length,str.bytes);
            break;
        default:
            printf("OBJECT, TYPE: %d, @ %p\n", printArg->tag, printArg);
            break;
    }
}

================================================
FILE: src/stack.c
================================================
#include "stack.h"
#include "frame.h"
#include <inttypes.h>
#include <stdlib.h>
#include "javaClass.h"
Stack initStack(uint64_t numItems, StackType stackType){ // size is in operands
    //The maximum depth of the operand stack of a frame is determined at compile-time and 
    //is supplied along with the code for the method associated with the frame
    Stack stack;
    stack.maxSize = stackType * numItems; // in bytes
    stack.top = 0; // in bytes, again
    stack.stackType = stackType;
    stack.stack = malloc(stackType * numItems); // afaik all stacks in here are frame sized. leak
    return stack;
}
 
void pushStack(void* val, Stack* stack){
    if (stack->top + stack->stackType <= stack->maxSize){
        if (stack->stackType == TYPE_JVMSTACK){
            *(Frame*)(&stack->stack[stack->top])=*(Frame*)val;
        }else if(stack->stackType == TYPE_OPERANDSTACK){
            *(uint64_t*)(&stack->stack[stack->top])=*(uint64_t*)val; 
            // this stack is implemented at DWORD size on 32 bit machines
            // QWORD size on 64 bit machines. On the other hand, the values we 
            // push on operand stack always 16 bit.
        } 
        stack->top += stack->stackType;
    }else{
        // todo stackoverflow err
        printf("StackOverFlow Error\n");
    }
}

void* popStack(Stack* stack){
    if ((int64_t)stack->top - stack->stackType >= 0){
        void* val;
        stack->top -= stack->stackType;
        if (stack->stackType == TYPE_JVMSTACK){
            val = (Frame*)(&stack->stack[stack->top]);
        }else if(stack->stackType == TYPE_OPERANDSTACK){
            val = (uint64_t*)(&stack->stack[stack->top]);
        }
        return val;
    }else{
        // todo stack empty
        return NULL;
    }
}

void* peekStack(Stack* stack){
    return (stack->top > 0)?(Stack*)(stack->stack + stack->top - stack->stackType):(NULL);
}

void destroyStack(Stack* stack){
    free(stack->stack);
    free(stack);
}

================================================
FILE: src/stringBuilder.c
================================================
#include "stringBuilder.h"
#include <inttypes.h>
#include "constantPool.h"
#include "frame.h"
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include "debug.h"

void handleStringBuilder(uint64_t* localVariables, Frame* frame, CONSTANT_Utf8_info name_utf8, CONSTANT_Utf8_info desc_utf8){
    cp_info* strRef = (cp_info*)hGet(localVariables[0],frame->machine->heap);
    if (isUtf8EqualsToString(name_utf8,"append")){
        if (isUtf8EqualsToString(desc_utf8,"(I)Ljava/lang/StringBuilder;") || isUtf8EqualsToString(desc_utf8,"(J)Ljava/lang/StringBuilder;")){
            int stringLength = floor((*(int64_t*)&localVariables[1]==0)?0:log10(abs(*(int64_t*)&localVariables[1]))) + 1;
            strRef->info.utf8_info.bytes = (char*)hExtend((uint64_t)(strRef->info.utf8_info.bytes), stringLength, frame->machine->heap);
            char* charRef = hGet((uint64_t)strRef->info.utf8_info.bytes, frame->machine->heap);
            sprintf(charRef,"%s%d",charRef,*(int64_t*)&localVariables[1]);
            strRef->info.utf8_info.length += stringLength;
            DEBUG_PRINT(("append test: %s\n", charRef));

        }else if(isUtf8EqualsToString(desc_utf8,"(Ljava/lang/String;)Ljava/lang/StringBuilder;")){
            cp_info* appendRef = (cp_info*)localVariables[1];
            CONSTANT_Utf8_info appendStrRef;
            if (appendRef->tag == CONSTANT_String){
                appendStrRef = frame->classRef->constant_pool[appendRef->info.string_info.string_index-1].info.utf8_info;
            }else{
                appendStrRef = appendRef->info.utf8_info;
            }
            strRef->info.utf8_info.bytes = (char*)hExtend((uint64_t)(strRef->info.utf8_info.bytes), appendStrRef.length, frame->machine->heap);
            char* charRef = hGet((uint64_t)strRef->info.utf8_info.bytes, frame->machine->heap);
            strncat(charRef,appendStrRef.bytes,appendStrRef.length);
            strRef->info.utf8_info.length += appendStrRef.length;
            DEBUG_PRINT(("append test: %s, strLen: %d, ldc: %.*s\n", charRef,frame->machine->heap->heap[(uint64_t)strRef->info.utf8_info.bytes].size, appendStrRef.length, appendStrRef.bytes));
        }
        pushStack(&localVariables[0], frame->operandStack);
    }else if(isUtf8EqualsToString(name_utf8,"toString")){
        cp_info* asString = malloc(sizeof(cp_info));
        asString->tag = CONSTANT_Utf8;
        asString->info.utf8_info.length = strRef->info.utf8_info.length;
        asString->info.utf8_info.bytes = hGet((uint64_t)strRef->info.utf8_info.bytes, frame->machine->heap);
        pushStack(&asString, frame->operandStack);
    }
}


================================================
FILE: test/Factorial.class.txt
================================================
a13294


================================================
FILE: test/Factorial.java
================================================
public class Factorial
{
	public static void main(String[] args)
	{
		final int NUM_FACTS = 12;
		long test=0;
		for (long a=0; a<100; a++){
			for(int i = 0; i < NUM_FACTS; i++){
				test += a/factorial(i);
			}
		}
		System.out.println("a"+test);
	}
	
	public static int factorial(int n)
	{	int result = 1;
		for(int i = 2; i <= n; i++)
			result *= i;
		return result;
	}
}

================================================
FILE: test/HelloWorld.class.txt
================================================
Hello World!


================================================
FILE: test/HelloWorld.java
================================================
/* HelloWorld.java
 */
public class HelloWorld
{
	public static void main(String[] args) {
		System.out.println("Hello World!");
	}
}

================================================
FILE: test/InstanceTest.class.txt
================================================
12345
12345
54321


================================================
FILE: test/InstanceTest.java
================================================
class InstanceTest {
    public int num;

	public static void main(String[] args) {
		System.out.println(""+test_single());
		System.out.println(""+test_multiple_1());
		System.out.println(""+test_multiple_2());
	}

    public InstanceTest() {
        num = 0;
    }

    public void set_num(int n) {
        num = n;
    }

    public int get_num() {
        return num;
    }

    public static int test_single() {
        InstanceTest i = new InstanceTest();

        i.set_num(12345);

        return i.get_num();
    }

    public static int test_multiple_1() {
        InstanceTest i1 = new InstanceTest();
        InstanceTest i2 = new InstanceTest();

        i1.set_num(12345);
        i2.set_num(54321);

        return i1.get_num();
    }

    public static int test_multiple_2() {
        InstanceTest i1 = new InstanceTest();
        InstanceTest i2 = new InstanceTest();

        i1.set_num(12345);
        i2.set_num(54321);

        return i2.get_num();
    }
}


================================================
FILE: test/StringExample.class.txt
================================================
s1: Computer Science
s2: Computer Science 307
s4: is fun
s5: Computer Science 307is fun
s6: 8total
s7: total 35
s8:  35total


================================================
FILE: test/StringExample.java
================================================
public class StringExample
{	public static void main(String[] args)
	{	String s1 = "Computer Science";
		int x = 307;
		String s2 = s1 + " " + x;
		//String s3 = s2.substring(10,17);
		String s4 = "is fun";
		String s5 = s2 + s4;
		
		System.out.println("s1: " + s1);
		System.out.println("s2: " + s2);
		//System.out.println("s3: " + s3);
		System.out.println("s4: " + s4);
		System.out.println("s5: " + s5);
		
		//showing effect of precedence
		
		x = 3;
		int y = 5;
		String s6 = x + y + "total";
		String s7 = "total " + x + y;
		String s8 = " " + x + y + "total";
		System.out.println("s6: " + s6);
		System.out.println("s7: " + s7);
		System.out.println("s8: " + s8);
	}
}

================================================
FILE: test/returnTest.class.txt
================================================
75


================================================
FILE: test/returnTest.java
================================================
public class returnTest {

    public static void main(String[] args) {
        System.out.println(topla(11,4));
    }

    public static int topla(int a, int b){
        int var = 0;
        for (int i=0; i<5; i++){
            var += a+b;
        }
        return var;
    }
}

================================================
FILE: test.sh
================================================
#!/bin/sh
cd test
rm *.class
rm test/*.out
javac *.java
cd ..

for classFile in test/*.class; do
    echo "Running ${classFile}"
    ./bin/main "${classFile%.class}" > "${classFile}.out"
    
    if diff "${classFile}.txt" "${classFile}.out"; then
        echo "succeeded"
    else
        echo "${classFile} failed"
        exit 1
    fi

done
Download .txt
gitextract_j969pa58/

├── .gitignore
├── LICENSE
├── README.md
├── include/
│   ├── attribute.h
│   ├── classFile.h
│   ├── constantPool.h
│   ├── debug.h
│   ├── endianness.h
│   ├── field.h
│   ├── frame.h
│   ├── heap.h
│   ├── javaClass.h
│   ├── machine.h
│   ├── method.h
│   ├── opcode.h
│   ├── printStream.h
│   ├── stack.h
│   └── stringBuilder.h
├── makefile
├── readme.md
├── src/
│   ├── attribute.c
│   ├── classFile.c
│   ├── constantPool.c
│   ├── field.c
│   ├── frame.c
│   ├── heap.c
│   ├── javaClass.c
│   ├── machine.c
│   ├── main.c
│   ├── opcode.c
│   ├── printStream.c
│   ├── stack.c
│   └── stringBuilder.c
├── test/
│   ├── Factorial.class.txt
│   ├── Factorial.java
│   ├── HelloWorld.class.txt
│   ├── HelloWorld.java
│   ├── InstanceTest.class.txt
│   ├── InstanceTest.java
│   ├── StringExample.class.txt
│   ├── StringExample.java
│   ├── returnTest.class.txt
│   └── returnTest.java
└── test.sh
Download .txt
SYMBOL INDEX (95 symbols across 29 files)

FILE: include/attribute.h
  type attribute_info (line 6) | typedef struct attribute_info {
  type exception_table (line 12) | typedef struct exception_table{ // aligned.
  type Code_attribute (line 22) | typedef struct Code_attribute {

FILE: include/classFile.h
  type field_info (line 9) | typedef struct field_info field_info;
  type ClassFile (line 11) | typedef struct ClassFile{

FILE: include/constantPool.h
  type cp_tags (line 6) | typedef enum cp_tags{
  type CONSTANT_Class_info (line 37) | typedef struct CONSTANT_Class_info {
  type CONSTANT_Ref_info (line 41) | typedef struct CONSTANT_Ref_info{
  type CONSTANT_String_info (line 48) | typedef struct CONSTANT_String_info {
  type CONSTANT_4BYTES_info (line 52) | typedef struct CONSTANT_4BYTES_info {
  type CONSTANT_8BYTES_info (line 56) | typedef struct CONSTANT_8BYTES_info {
  type CONSTANT_NameAndType_info (line 60) | typedef struct CONSTANT_NameAndType_info {
  type CONSTANT_Utf8_info (line 65) | typedef struct CONSTANT_Utf8_info {  // not aligned
  type CONSTANT_MethodHandle_info (line 71) | typedef struct CONSTANT_MethodHandle_info { // not aligned
  type CONSTANT_MethodType_info (line 77) | typedef struct CONSTANT_MethodType_info {
  type CONSTANT_InvokeDynamic_info (line 83) | typedef struct CONSTANT_InvokeDynamic_info {
  type array_type (line 88) | typedef enum array_type{
  type CONSTANT_Array_info (line 99) | typedef struct CONSTANT_Array_info{  // custom
  type cp_info (line 118) | typedef struct cp_info {

FILE: include/field.h
  type JavaClass (line 9) | typedef struct JavaClass JavaClass;
  type access_flags (line 10) | typedef enum field_access_flags{
  type field_info (line 22) | typedef struct field_info {

FILE: include/frame.h
  type ClassFile (line 8) | typedef struct ClassFile ClassFile;
  type Machine (line 9) | typedef struct Machine Machine;
  type LocalVariable (line 10) | typedef uint64_t LocalVariable;
  type Operand (line 14) | typedef uint64_t Operand;
  type Frame (line 17) | typedef struct Frame{

FILE: include/heap.h
  type HeapObject (line 6) | typedef struct HeapObject{
  type Heap (line 12) | typedef struct Heap{

FILE: include/javaClass.h
  type JavaClass (line 5) | typedef struct JavaClass{

FILE: include/machine.h
  type Machine (line 7) | typedef struct Machine{

FILE: include/method.h
  type method_info (line 6) | typedef struct field_info method_info;
  type method_access_flags (line 8) | typedef enum method_access_flags{

FILE: include/opcode.h
  type Frame (line 6) | struct Frame
  type OPCODENAMES (line 11) | typedef enum OPCODENAMES{

FILE: include/stack.h
  type StackType (line 6) | typedef enum StackType{
  type Stack (line 11) | typedef struct Stack{

FILE: src/attribute.c
  function attribute_info (line 5) | attribute_info getAttribute_Info(FILE* fd){
  function destroyAttribute_Info (line 18) | void destroyAttribute_Info(attribute_info* attribute){
  function Code_attribute (line 22) | Code_attribute getCode_AttributeFromAttribute_info(attribute_info attrib...

FILE: src/classFile.c
  function ClassFile (line 11) | ClassFile classFromFile(const char* filename){
  function isUtf8EqualsToString (line 120) | int isUtf8EqualsToString(CONSTANT_Utf8_info s1, const char* s2){
  function isUtf8Equal (line 126) | int isUtf8Equal(CONSTANT_Utf8_info s1, CONSTANT_Utf8_info s2){
  function getNumArgs (line 132) | int getNumArgs(ClassFile* cf, CONSTANT_Ref_info methodOrInterfaceRef){
  function ClassFile (line 156) | ClassFile* getClassFromUtf8(CONSTANT_Utf8_info className_utf8, Machine* ...
  function ClassFile (line 165) | ClassFile* getClassFromName(const char* className, Machine* machine){
  function method_info (line 190) | method_info* getMethodByName(ClassFile* cf, const char* name, const char...
  function initClass (line 202) | void initClass(ClassFile* cf, Frame* frame){
  function destroyClass (line 221) | void destroyClass(ClassFile* cf){
  function method_info (line 242) | method_info* canClassHandleMethod(ClassFile* cf, CONSTANT_Utf8_info name...
  function checkFormat (line 255) | int checkFormat(ClassFile* cf){

FILE: src/constantPool.c
  function cp_info (line 9) | cp_info cp_infoFromFile(FILE* fd){
  function destroyCp_Info (line 77) | void destroyCp_Info(cp_info* info){

FILE: src/field.c
  function field_info (line 9) | field_info getField_Info(FILE* fd){
  function destroyField_Info (line 32) | void destroyField_Info(field_info* field){
  function putField (line 38) | void putField(JavaClass* instance, CONSTANT_Utf8_info fieldName, CONSTAN...
  function field_info (line 44) | field_info* getField(JavaClass* jc, CONSTANT_Utf8_info fieldName, CONSTA...
  function field_info (line 56) | field_info* getStaticField(ClassFile* cf, CONSTANT_Utf8_info fieldName, ...

FILE: src/frame.c
  function Frame (line 6) | Frame createNewFrame (Code_attribute code, ClassFile* cf, Machine* machi...
  function destroyFrame (line 22) | void destroyFrame (Frame* frame){

FILE: src/heap.c
  function Heap (line 3) | Heap initHeap(size_t size){
  function hAlloc (line 15) | uint64_t hAlloc(size_t size, Heap* heap){
  function hExtend (line 35) | uint64_t hExtend(uint64_t addr, size_t size, Heap* heap){
  function destroyHeap (line 46) | void destroyHeap(Heap* heap){

FILE: src/javaClass.c
  function initInstanceFields (line 6) | void initInstanceFields(JavaClass* instance){

FILE: src/machine.c
  function destroyMachine (line 58) | void destroyMachine(Machine* machine){

FILE: src/main.c
  function main (line 14) | void main(int argc, char* argv[]){

FILE: src/opcode.c
  function read1Byte (line 16) | uint8_t read1Byte(Frame* frame){
  function read2Bytes (line 19) | uint16_t read2Bytes(Frame* frame){
  function read4Bytes (line 29) | uint32_t read4Bytes(Frame* frame){
  function read8Bytes (line 34) | uint64_t read8Bytes(Frame* frame){
  function OPCODE (line 771) | OPCODE** initOpcodes(){

FILE: src/printStream.c
  function handlePrintStream (line 8) | void handlePrintStream(uint64_t* localVariables, Frame* frame, CONSTANT_...

FILE: src/stack.c
  function Stack (line 6) | Stack initStack(uint64_t numItems, StackType stackType){ // size is in o...
  function pushStack (line 17) | void pushStack(void* val, Stack* stack){
  function destroyStack (line 54) | void destroyStack(Stack* stack){

FILE: src/stringBuilder.c
  function handleStringBuilder (line 10) | void handleStringBuilder(uint64_t* localVariables, Frame* frame, CONSTAN...

FILE: test/Factorial.java
  class Factorial (line 1) | public class Factorial
    method main (line 3) | public static void main(String[] args)
    method factorial (line 15) | public static int factorial(int n)

FILE: test/HelloWorld.java
  class HelloWorld (line 3) | public class HelloWorld
    method main (line 5) | public static void main(String[] args) {

FILE: test/InstanceTest.java
  class InstanceTest (line 1) | class InstanceTest {
    method main (line 4) | public static void main(String[] args) {
    method InstanceTest (line 10) | public InstanceTest() {
    method set_num (line 14) | public void set_num(int n) {
    method get_num (line 18) | public int get_num() {
    method test_single (line 22) | public static int test_single() {
    method test_multiple_1 (line 30) | public static int test_multiple_1() {
    method test_multiple_2 (line 40) | public static int test_multiple_2() {

FILE: test/StringExample.java
  class StringExample (line 1) | public class StringExample
    method main (line 2) | public static void main(String[] args)

FILE: test/returnTest.java
  class returnTest (line 1) | public class returnTest {
    method main (line 3) | public static void main(String[] args) {
    method topla (line 7) | public static int topla(int a, int b){
Condensed preview — 44 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (114K chars).
[
  {
    "path": ".gitignore",
    "chars": 262,
    "preview": "# Ignore the build and lib dirs\nbuild\ndep/*\n\n# Ignore any executables\nbin/*\n\n# Ignore Mac specific files\n.DS_Store \n\n# I"
  },
  {
    "path": "LICENSE",
    "chars": 18092,
    "preview": "                    GNU GENERAL PUBLIC LICENSE\n                       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Fr"
  },
  {
    "path": "README.md",
    "chars": 642,
    "preview": "# ToyJVM\n\nExperimental Java Bytecode Interpreter written in C to understand Java concepts better.\n\n## Getting Started\n\nT"
  },
  {
    "path": "include/attribute.h",
    "chars": 1132,
    "preview": "#ifndef ATTRIBUTE_H_\n#define ATTRIBUTE_H_\n#include <inttypes.h>\n#include <stdio.h>\n\ntypedef struct attribute_info {\n    "
  },
  {
    "path": "include/classFile.h",
    "chars": 2492,
    "preview": "#ifndef CLASSFILE_H_\n#define CLASSFILE_H_\n#include <inttypes.h>\n#include \"machine.h\"\n#include \"constantPool.h\"\n#include "
  },
  {
    "path": "include/constantPool.h",
    "chars": 3138,
    "preview": "#ifndef CONSTANTPOOL_H_\n#define CONSTANTPOOL_H_\n#include <inttypes.h>\n#include <stdio.h>\n\ntypedef enum cp_tags{\n    CONS"
  },
  {
    "path": "include/debug.h",
    "chars": 97,
    "preview": "#ifdef DEBUG\n# define DEBUG_PRINT(x) printf x\n#else\n# define DEBUG_PRINT(x) do {} while(0)\n#endif"
  },
  {
    "path": "include/endianness.h",
    "chars": 505,
    "preview": "#ifndef ENDIAN_H_\n#define ENDIAN_H_\n\n// endian.h was not cross platform and was under a different\n// name in different O"
  },
  {
    "path": "include/field.h",
    "chars": 1621,
    "preview": "#ifndef FIELD_H_\n#define FIELD_H_\n#include <inttypes.h>\n#include \"attribute.h\"\n#include <stdio.h>\n#include \"classFile.h\""
  },
  {
    "path": "include/frame.h",
    "chars": 1313,
    "preview": "#ifndef FRAME_H_\n#define FRAME_H_\n#include <inttypes.h>\n//#include \"stack.h\"\n#include \"attribute.h\"\n#include \"constantPo"
  },
  {
    "path": "include/heap.h",
    "chars": 501,
    "preview": "#ifndef HEAP_H_\n#define HEAP_H_\n#include <inttypes.h>\n#include <stdlib.h>\n\ntypedef struct HeapObject{\n    void* addr;\n  "
  },
  {
    "path": "include/javaClass.h",
    "chars": 208,
    "preview": "#ifndef JAVACLASS_H_\n#define JAVACLASS_H_\n#include \"classFile.h\"\n\ntypedef struct JavaClass{\n    ClassFile* classFile;\n  "
  },
  {
    "path": "include/machine.h",
    "chars": 328,
    "preview": "#ifndef MACHINE_H_\n#define MACHINE_H_\n#include \"opcode.h\"\n#include \"stack.h\"\n#include \"heap.h\"\n\ntypedef struct Machine{\n"
  },
  {
    "path": "include/method.h",
    "chars": 1405,
    "preview": "#ifndef METHOD_H_\n#define METHOD_H_\n#include \"attribute.h\"\n#include \"field.h\"\n\ntypedef struct field_info method_info; //"
  },
  {
    "path": "include/opcode.h",
    "chars": 2555,
    "preview": "#ifndef OPCODE_H_\n#define OPCODE_H_\n#include <inttypes.h>\n#include \"frame.h\"\n\ntypedef void* OPCODE(struct Frame*);\n\nOPCO"
  },
  {
    "path": "include/printStream.h",
    "chars": 243,
    "preview": "#ifndef PRINTSTREAM_H_\n#define PRINTSTREAM_H_\n#include <inttypes.h>\n#include \"frame.h\"\n#include \"classFile.h\"\n\nvoid hand"
  },
  {
    "path": "include/stack.h",
    "chars": 551,
    "preview": "#ifndef STACK_H_\n#define STACK_H_\n#include <stdint.h>\n#include \"frame.h\"\n\ntypedef enum StackType{\n    TYPE_OPERANDSTACK "
  },
  {
    "path": "include/stringBuilder.h",
    "chars": 250,
    "preview": "#ifndef STRINGBUILDER_H_\n#define STRINGBUILDER_H_\n#include <inttypes.h>\n#include \"frame.h\"\n#include \"classFile.h\"\n\n\nvoid"
  },
  {
    "path": "makefile",
    "chars": 1234,
    "preview": "SRCDIR\t= src\nHDRDIR  = include\nOBJDIR\t= build\nBINDIR\t= bin\nDEPDIR\t= dep\n\nCC\t= gcc\nTARGET\t= main\nCFLAGS\t= -g -O0 -std=c99"
  },
  {
    "path": "readme.md",
    "chars": 636,
    "preview": "# ToyJVM\n\nExperimental Java Bytecode Interpreter written in C to understand Java concepts better.\n\n## Getting Started\n\nT"
  },
  {
    "path": "src/attribute.c",
    "chars": 2062,
    "preview": "#include \"attribute.h\"\n#include <stdlib.h>\n#include \"endianness.h\"\n#include <string.h>\nattribute_info getAttribute_Info("
  },
  {
    "path": "src/classFile.c",
    "chars": 13081,
    "preview": "#include \"classFile.h\"\n#include <stdio.h>\n#include <stdlib.h>\n#include \"endianness.h\"\n#include \"field.h\"\n#include \"metho"
  },
  {
    "path": "src/constantPool.c",
    "chars": 4617,
    "preview": "#include \"constantPool.h\"\n#include <stdio.h>\n#include <stdlib.h>\n#include \"endianness.h\"\n/*\nConstant Pool Indexes writte"
  },
  {
    "path": "src/field.c",
    "chars": 2581,
    "preview": "#include \"field.h\"\n#include <stdio.h>\n#include \"endianness.h\"\n#include <stdlib.h>\n#include \"classFile.h\"\n#include \"const"
  },
  {
    "path": "src/frame.c",
    "chars": 870,
    "preview": "#include \"frame.h\"\n#include <stdlib.h>\n#include \"classFile.h\"\n#include \"attribute.h\"\n\nFrame createNewFrame (Code_attribu"
  },
  {
    "path": "src/heap.c",
    "chars": 1429,
    "preview": "#include \"heap.h\"\n\nHeap initHeap(size_t size){\n    Heap heap;\n    heap.heap = calloc(size,sizeof(HeapObject));\n    heap."
  },
  {
    "path": "src/javaClass.c",
    "chars": 331,
    "preview": "#include \"javaClass.h\"\n#include <stdlib.h>\n#include \"heap.h\"\n#include <string.h>\n\nvoid initInstanceFields(JavaClass* ins"
  },
  {
    "path": "src/machine.c",
    "chars": 2539,
    "preview": "#include \"machine.h\"\n#include \"frame.h\"\n#include \"opcode.h\"\n#include \"stack.h\"\n#include \"debug.h\"\n#include \"classFile.h\""
  },
  {
    "path": "src/main.c",
    "chars": 2641,
    "preview": "#include <stdio.h>\n#include <stdlib.h>\n#include \"machine.h\"\n#include \"classFile.h\"\n#include <assert.h>\n#include \"opcode."
  },
  {
    "path": "src/opcode.c",
    "chars": 32444,
    "preview": "#include \"opcode.h\"\n#include <stdio.h>\n#include <stdlib.h>\n#include \"stack.h\"\n#include \"endianness.h\"\n#include \"constant"
  },
  {
    "path": "src/printStream.c",
    "chars": 1035,
    "preview": "#include \"printStream.h\"\n#include <inttypes.h>\n#include \"constantPool.h\"\n#include \"frame.h\"\n#include <stdlib.h>\n\n\nvoid h"
  },
  {
    "path": "src/stack.c",
    "chars": 1964,
    "preview": "#include \"stack.h\"\n#include \"frame.h\"\n#include <inttypes.h>\n#include <stdlib.h>\n#include \"javaClass.h\"\nStack initStack(u"
  },
  {
    "path": "src/stringBuilder.c",
    "chars": 2617,
    "preview": "#include \"stringBuilder.h\"\n#include <inttypes.h>\n#include \"constantPool.h\"\n#include \"frame.h\"\n#include <stdlib.h>\n#inclu"
  },
  {
    "path": "test/Factorial.class.txt",
    "chars": 7,
    "preview": "a13294\n"
  },
  {
    "path": "test/Factorial.java",
    "chars": 376,
    "preview": "public class Factorial\n{\n\tpublic static void main(String[] args)\n\t{\n\t\tfinal int NUM_FACTS = 12;\n\t\tlong test=0;\n\t\tfor (lo"
  },
  {
    "path": "test/HelloWorld.class.txt",
    "chars": 13,
    "preview": "Hello World!\n"
  },
  {
    "path": "test/HelloWorld.java",
    "chars": 140,
    "preview": "/* HelloWorld.java\r\n */\r\npublic class HelloWorld\r\n{\r\n\tpublic static void main(String[] args) {\r\n\t\tSystem.out.println(\"He"
  },
  {
    "path": "test/InstanceTest.class.txt",
    "chars": 18,
    "preview": "12345\n12345\n54321\n"
  },
  {
    "path": "test/InstanceTest.java",
    "chars": 978,
    "preview": "class InstanceTest {\n    public int num;\n\n\tpublic static void main(String[] args) {\n\t\tSystem.out.println(\"\"+test_single("
  },
  {
    "path": "test/StringExample.class.txt",
    "chars": 125,
    "preview": "s1: Computer Science\ns2: Computer Science 307\ns4: is fun\ns5: Computer Science 307is fun\ns6: 8total\ns7: total 35\ns8:  35t"
  },
  {
    "path": "test/StringExample.java",
    "chars": 680,
    "preview": "public class StringExample\n{\tpublic static void main(String[] args)\n\t{\tString s1 = \"Computer Science\";\n\t\tint x = 307;\n\t\t"
  },
  {
    "path": "test/returnTest.class.txt",
    "chars": 3,
    "preview": "75\n"
  },
  {
    "path": "test/returnTest.java",
    "chars": 278,
    "preview": "public class returnTest {\n\n    public static void main(String[] args) {\n        System.out.println(topla(11,4));\n    }\n\n"
  },
  {
    "path": "test.sh",
    "chars": 344,
    "preview": "#!/bin/sh\ncd test\nrm *.class\nrm test/*.out\njavac *.java\ncd ..\n\nfor classFile in test/*.class; do\n    echo \"Running ${cla"
  }
]

About this extraction

This page contains the full source code of the ozy/ToyJVM GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 44 files (105.8 KB), approximately 29.3k tokens, and a symbol index with 95 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!