{"id":16374978,"url":"https://github.com/moderocky/foundation","last_synced_at":"2025-06-24T07:08:47.590Z","repository":{"id":43341003,"uuid":"379598321","full_name":"Moderocky/Foundation","owner":"Moderocky","description":"A framework for building compiled class files and bytecode.","archived":false,"fork":false,"pushed_at":"2025-03-10T07:08:30.000Z","size":951,"stargazers_count":7,"open_issues_count":0,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-12T18:09:53.459Z","etag":null,"topics":["bytecode","class-builder","framework","java"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Moderocky.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-06-23T12:38:28.000Z","updated_at":"2025-03-10T07:08:35.000Z","dependencies_parsed_at":"2024-03-06T14:48:13.121Z","dependency_job_id":"3a850824-0b2e-4804-94f1-6f24c94c3661","html_url":"https://github.com/Moderocky/Foundation","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Moderocky/Foundation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moderocky%2FFoundation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moderocky%2FFoundation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moderocky%2FFoundation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moderocky%2FFoundation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Moderocky","download_url":"https://codeload.github.com/Moderocky/Foundation/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Moderocky%2FFoundation/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261624959,"owners_count":23186118,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bytecode","class-builder","framework","java"],"created_at":"2024-10-11T03:19:01.880Z","updated_at":"2025-06-24T07:08:47.569Z","avatar_url":"https://github.com/Moderocky.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"Foundation\n=====\n\n## Note\n\nFoundation 3 is currently in the testing phase and may undergo changes without notice.\nFoundation 3 aims to be semi-compatible with Foundation 2 projects, but due to the change in its backing library,\nfull compatibility cannot be guaranteed.\n\n### Opus #7\n\nFoundation is a tool for writing virtual machine code, a class file assembler, and a library for creating compilers that\ntarget JVM bytecode.\n\nFoundation 3 is modularised into the following libraries:\n\n- foundation-assembler: for assembling class files in a linear format (like [ASM](https://asm.ow2.io)).\n- foundation-factory: a helper layer for building method code in the Java paradigm.\n- foundation-legacy: the former Foundation 2, for preserving compatibility.\n\n## Motivations\n\nFoundation is designed to simplify the process of building classes and methods with bytecode.\nTools like [ASM](https://asm.ow2.io)'s 'visitor' are very effective but make simple tasks unnecessarily difficult and\nadd\ncumbersome boilerplate.\n\nThis over-complication makes writing simple bytecode-generating utilities more difficult than it needs to be and makes\nthe process unpleasant for beginners, leading people to rely on tools such as 'ASMifier' to create the\nbytecode-generating code.\n\nWhile such tools are undoubtedly useful (and appropriate in many situations) users can develop an unnecessary dependency\non them and find themselves incapable of designing the bytecode without a tool to generate it for them.\n\nFoundation is designed to set a balance between doing too much and too little, while also matching the line format and\nstructure of Java code.\n\n# Foundation 3: Assembler\n\nFoundation 3 entirely removes the dependency on ObjectWeb's [ASM](https://asm.ow2.io) library, and contains its own\nfully-supported class file assembler.\n\n## Design Goals\n\nIn order to achieve its speed and low memory footprint, ASM has some incredibly strict design limitations:\n\n- Elements have to be visited in a specific order.\n- Operation codes have to be entered with a particular method.\n- Once visited, an element cannot be re-visited, accessed or altered in any way.\n- Safety checking and verification are left to the user.\n- Errors (particularly in frame calculation) are almost impossible to trace.\n\nFoundation versions 1 and 2 attempted to overcome some of these limitations by storing all the details and then building\nthe class file in a single pass at the end. While this was effective for overcoming the ordering constraints,\nit could not address any of the other problems listed above.\n\nFoundation 3 includes its own assembler (a replacement for ASM) that was designed with overcoming these limitations in\nmind.\n\n## Ordering of Access \u0026 Creation\n\nA key requirement for Foundation 3's assembler was not to limit the order in which class and code members could be\ncreated, as much as was feasibly possible.\nSince the class file itself has a fixed order in which elements appear (meta, fields, methods, attributes), this meant\nthat the builder could not write the class bytes _directly_ to the file, since a user might create a method and then go\nback and make a field.\n\nThe solution was to create a data graph format that was flexible enough to be edited.\nThis brought with it an additional problem: lots of class file elements use indices to reference each other (e.g.\nconstant index 3, jump forward 4 spaces), and if elements can be re-ordered then these indices will be invalidated.\n\nThis is most relevant to the class file's constant pool, which stores everything from the class names to the literal\nvalues used in code. The easiest solution (which ASM uses) is to enter things as they appear and then save the index\nat which they were entered. However, this has a drawback of leaving the constant pool in a very untidy state with\nno proper ordering, and also creates a forward referencing issue (where a constant pool entry might reference something\nthat was entered after it, e.g. `3: class named #4, 4: 'java/lang/String'`). This in itself is not prohibited by the\nvirtual machine specification, but it *is* a problem for anything that is searching for a pool entry in order.\n\nFoundation's solution to all of these problems is the tabular reference; a two-byte dynamic pointer to an entry in a\ntable, such as a constant pool entry or an instruction in a code vector.\nThese references mean the constant pool can be sorted, re-ordered or can have items added or removed without breaking\nany of the elements that reference it.\nDuring a phase called 'finalisation', which occurs before the class code is built, the references can be baked into\ntheir actual number format since no more changes to the table will occur.\n\n## Operation Codes\n\n\u003e Definition: a 'well-formed instruction' consists of an operation code (opcode) followed by the\n\u003e bytes required to complete the instruction.\n\nMethod code is written in a sequence of operation codes. Some codes are atomic (followed by nothing else) and\nwell-formed instructions in their own right, (e.g. `iload_0/26`) whereas others are followed by a fixed number of data\nbytes\n(e.g. `iload/21 \u003cindex\u003e` or `goto/167 \u003cindex\u003e`), and need other data to be provided in order to constitute a\nwell-formed instruction (i.e. writing `goto` on its own does nothing, it **must** be followed by two branch bytes).\n\nAs a result, the process to write a bytecode changes according to the opcode used. This gives the designer a choice:\neither the designer allows the user to write _whatever_ they want (e.g. `write(byte opcode, byte... bytes)`,\nin which case it becomes the user's responsibility to read and understand the virtual machine specification and what\neach opcode requires, or the designer has to create individual processes for opcodes based on the information they\nrequire (e.g. `writeJump(byte opcode, short target)`). ASM follows the latter option, having individual visit methods\nfor different instruction types.\n\nThe approach used by Foundation's assembler is a combination of the two. A single form of the `write(Element)` method\nis provided, and the process to create a well-formed instruction is attached to the opcode constants in\n`mx.kenzie.foundation.assembler.code.OpCode`.\n\nFor atomic codes, where the opcode alone is a well-formed instruction, the opcode constant can be entered as-is:\n\n```java\nimport mx.kenzie.foundation.assembler.tool.CodeBuilder;\n\nclass Example {\n\n    void example(CodeBuilder builder) {\n        builder.write(POP);\n        builder.write(ALOAD_0, ILOAD_1);\n        builder.write(SWAP);\n    }\n\n}\n```\n\nIn the other case, a well-formed instruction can be created from a non-atomic opcode constant:\n\n```java\nimport mx.kenzie.foundation.assembler.tool.CodeBuilder;\n\nclass Example {\n\n    void example(CodeBuilder builder) {\n        builder.write(ALOAD.var(6), CHECKCAST.type(String.class));\n    }\n\n}\n```\n\nThe advantage of this approach is that a well-formed instruction can be stored (or provided by some other part of a\nprogram) and then be entered into the code vector as-is without having to know which entry method to use.\n\n## Safety and Verification\n\n# Foundation 2 \u0026 Legacy Library\n\nSince Foundation 2, instructions for the class builder do **not** directly correspond to JVM 'opcodes'.\nThis was changed to make it easier and more intuitive to write code.\n\nFoundation 2 aims to reflect Java code line structure, so that users do not need to worry about managing the stack.\n\n```\n// java\nObject var1 = \"hello there\"\n// builder\nSTORE_VAR.object(1, CONSTANT.of(\"hello there\"))\n```\n\n```\n// java\nreturn var1\n// builder\nRETURN.object(LOAD_VAR.object(1)))\n```\n\n### Maven Information\n\n```xml\n\n\u003crepository\u003e\n    \u003cid\u003ekenzie\u003c/id\u003e\n    \u003curl\u003ehttps://repo.kenzie.mx/releases\u003c/url\u003e\n\u003c/repository\u003e\n``` \n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003emx.kenzie\u003c/groupId\u003e\n    \u003cartifactId\u003efoundation\u003c/artifactId\u003e\n    \u003cversion\u003e3.0.0\u003c/version\u003e\n    \u003cscope\u003ecompile\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\n### Supported Functionality\n\nFoundation supports almost all basic instructions from Java, including variable and field access, method calls,\nbranches, arithmetic and instantiation.\n\nFoundation 2 has dropped support for individual bytecode instructions to provide more safety for beginners handling\nstack operations.\n\n### Examples\n\nGenerate and load a very simple class.\n\n```java\nclass MyClass {\n\n    Class\u003c?\u003e test() {\n        final PreClass builder = new PreClass(\"org.example\", \"Thing\");\n        final PreMethod method = new PreMethod(PUBLIC, STATIC, VOID, \"main\", String[].class);\n        method.line(RETURN.none());\n        builder.add(method);\n        return builder.load(Loader.DEFAULT); // built-in basic class loader\n    }\n\n}\n ```\n\nThis would generate the code:\n\n```java\npublic class Thing {\n\n    public static void main(String[] args) {\n        return;\n    }\n\n}\n```\n\nGenerate a runnable class.\n\n```java\nclass MyClass {\n\n    Class\u003c?\u003e test() {\n        // references to System.out and out.println(..)\n        final CallMethod.Stub target = METHOD.of(PrintStream.class, \"println\", String.class);\n        final AccessField.Stub field = FIELD.of(System.class, \"out\", PrintStream.class);\n\n        final PreClass builder = new PreClass(\"org.example\", \"Thing\");\n        builder.addInterfaces(Runnable.class);\n        final PreMethod method = new PreMethod(PUBLIC, VOID, \"run\");\n        method.line(target.call(field.get(), CONSTANT.of(\"hello there!\")));\n        method.line(RETURN.none());\n        builder.add(method);\n        return builder.load(Loader.DEFAULT); // built-in basic class loader\n    }\n\n}\n```\n\nThis would be the equivalent of:\n\n```java\nclass Thing implements Runnable {\n\n    @Override // Overrides are implicit.\n    public void run() {\n        System.out.println(\"hello there!\");\n    }\n\n}\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoderocky%2Ffoundation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoderocky%2Ffoundation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoderocky%2Ffoundation/lists"}