Chasm is a java bytecode transformer designed to handle collision between transformers wherever possible.

Overview

NOTE: This project is still in its early development. There's guaranteed bugs and missing functionality.

Chasm - Collision Handling ASM

What is Chasm?

Chasm is a Java bytecode transformation tool. In its base functionality, it's similar to ASM. However, ASM is intended for single programs transforming some bytecode, whereas the goal of Chasm is to allow multiple users to transform the same code. This is useful in modding Java based games, where multiple mods might want to change the same code.

Why use Chasm?

There are other options for transforming bytecode. Two popular ones are Mixins and access-wideners. While they both perform well in their respective tasks, they are both limiting: Access wideners do one thing only and Mixin tries its best to be safe, preventing many useful transformations like changing control flow.

Chasm aims to provide the full power of ASM without restrictions. This means that using Chasm directly might be tricky, but the goal of Chasm is to allow reimplementing Mixin and access wideners on top of Chasm.

This greatly simplifies the toolchain, since only one bytecode transformation library needs to be applied. Additionally, if Mixin and AW are insufficient, people can implement another "frontend" for Chasm without requiring special toolchain support.

Comments
  • Immutable Nodes for Transformers

    Immutable Nodes for Transformers

    While transformers should take care to not modify the nodes that are passed to them, we can probably avoid some future bugs by passing immutable nodes to Transformers and Transformations.

    There is already an attempt at immutability made, but it is fairly minimal and there is also no easy way to create a mutable node again (if that is something that is needed).

    Alternatively, it might make more sense to instead provide some sort of ImmutableNodeView, so that we can provide immutability without copying.

    enhancement 
    opened by CheaterCodes 14
  • Boolean Operators and Short Circuiting

    Boolean Operators and Short Circuiting

    As mentioned in #42, we could merge the operators && and || with & and | respectively. The reason they are currently split up is because the boolean operator supports short-circuiting. As @Earthcomputer correctly said, all operators can be short-circuiting, so there's no need for this differentiation. However, I'm not entirely sure how to implement this properly and safely.

    If anyone feels like tackling this problem, please discuss it here before opening a PR.

    enhancement help wanted chassembly 
    opened by CheaterCodes 10
  • Changing the JavaCC21 grammar so that it uses the full JavaCC21

    Changing the JavaCC21 grammar so that it uses the full JavaCC21

    I have not tested this functionally, just that you can compile. I commented out some jetbrains annotations that I didn't know where they come from so it would compile.

    But the thing to look at is the way the grammar is refactored so that all the various Nodes are just generated with the code injected. Actually, this could be refactored/simplified much further from this point, but this provides a starting point, I daresay.

    opened by revusky 8
  • Language rework

    Language rework

    A big, general rework of chasm-lang.

    Notable changes:

    • More sound general implementation
    • Changed .[] indexing operator to []
    • Changed .<> filtering operator to [] (index with function)
    • Changed = equality operator to == (unsure about this one)
    • References now get resolved in the smallest enclosing scope defining the identifier (no more $.)
    • References prefixed with $ get resolved in the largest enclosing scope defining the identifier (i.e. for globals/intrinsics)
    • Expression reductions and function calls are now cached in a non-jank manner
    • All expressions reference an (optional) ParseTree to alolow better erorrs

    Missing stuff:

    • Additional types like long, float and double
    • Fail on errors
    • Good error reporting

    It passes the currently defined test cases, although those aren't necessarily great tests. I know this is a huge PR, but if anyone would like to test the branch and give feedback, it would be highly appreciated.

    opened by CheaterCodes 8
  • Degenerify `ValueNode`

    Degenerify `ValueNode`

    Closes #33.

    This also adds getValueAs(Class), which allows getting the value with checked casting. getValueAsInt(), getValueAsBoolean(), and getValueAsString() are convenience methods which call getValueAs(Class) (and also handle unboxing, in the case of the former two).

    opened by Leo40Git 8
  • API javadoc

    API javadoc

    I wrote some API javadoc, but I'm confused about sources (javadoc'ed sources) It'll probably need some cleaning up, but checkstyle is fine with it. Edit: This should help with #15.

    opened by cplir-c 8
  • Add checkstyle workflow action

    Add checkstyle workflow action

    This PR adds a GitHub workflow action that checks the style of new code in PRs, as mentioned in #18 - using nikitasavinov/checkstyle-action.

    Here's how it looks in action (:wink:), on a testing repo: image

    opened by thoughtcommet 7
  • Consider switching to JavaCC21

    Consider switching to JavaCC21

    The chasm-lang module currently uses ANTLR to generate its lexer and parser. While this is fine in principle, it introduces both an additoinal compile time dependency and a runtime dependency. Since I expect the chasm-lang module to be used in gradle plugins, having many dependencies is undesirable. Besides ANTLR, there is currently also a dependency on ASM and Chasm as well, which would be removed as described in #49. This means that by dropping ANTLR, we could remove all runtime dependencies from the module.

    The suggested alternative is JavaCC21. It works very similar to ANTLR in principle, so the conversion shouldn't be particularly hard. The advantage is that it generates all reuired classes that are required for runtime.

    Note that shadowing ANTLR would be possible, however I am still unsure about licensing behaviour when shadowing libraries. JavaCC21 on the contrary requires no particular licensing, since the files geneated by it belong to us.

    enhancement chassembly 
    opened by CheaterCodes 6
  • Missing Doc Comments

    Missing Doc Comments

    None of the files in the org.quiltmc.chasm.asm package have method documentation, but the ClassWriter class has some line comments in its methods. In the org.quiltmc.chasm.transformer package, only the Target interface has method documentation. In the org.quiltmc.chasm.tree package, only the Node interface has a method doc comment, and it's only one. In the org.quiltmc.chasm package, the ChasmProcessor class, the SliceManager class, and the TransformationSorter class have line comments in one method, and none of the classes have method doc comments.

    I'm making this because I don't know what the path is in this for example, and I thought doc comments would help anyone reading the code. I could ask more specific questions, but I'm not sure if that would be more helpful.

    documentation help wanted 
    opened by cplir-c 6
  • Label Representation

    Label Representation

    ASM represent labels as pseudo-instructions. Right now, CHASM instead attaches label information to instructions.

    While I personally prefer it this way, it comes with it's own issue: There might be trailing labels in the ASM representation that can't be expressed in CHASM.

    Right now this is solved by inserting a trailing NOP instruction at the end of each method. This seems to work fine for now, adn we might also be able to strip this trailing NOP when writing the class file.

    However, I feel like this might require additional discussion.

    design decision 
    opened by CheaterCodes 6
  • Parameter Representation

    Parameter Representation

    Parameter information is provided via ASM in different ways. However, CHASM might want to represent them differently.

    Ideally I'd like to provide a parameters list for each method, where each entry represents a parameter and their type.

    However, there are two issues with this:

    • Assigning parameter annotations to parameters seems to not be clearly defined
    • Type information would be duplicated between the method descriptor and the parameter type information

    I'm not sure how to solve this issue, any feedback would be welcome.

    design decision 
    opened by CheaterCodes 4
  • Fix checkstyle to not require Javadoc on internal and test files, and…

    Fix checkstyle to not require Javadoc on internal and test files, and…

    … add missing Javadocs elsewhere.

    Closes #88

    Also replaced NullNode instances with a singleton, like BooleanNode already has two singletons. Should save a tiny bit of memory.

    opened by Earthcomputer 0
  • Inspect Local Variable Representation

    Inspect Local Variable Representation

    Let's have a look at the following java method:

    private void localTest(int parameter1, String parameter2, List<String> parameter3) {
        int local1 = 5;
        System.out.println(local1);
        int local2 = 42;
        System.out.println(local2);
    }
    

    The following is the Chasm-Internal representation of said method:

    {
    	access: 2, 
    	name: "localTest", 
    	parameters: [{
    			type: "I", 
    			name: "P0", 
    		},{
    			type: "Ljava/lang/String;", 
    			name: "P1", 
    		},{
    			type: "Ljava/util/List;", 
    			name: "P2", 
    		},], 
    	returnType: "V", 
    	signature: "(ILjava/lang/String;Ljava/util/List<Ljava/lang/String;>;)V", 
    	exceptions: [], 
    	annotations: [], 
    	code: {
    		instructions: [{
    				label: "L0", 
    			},{
    				opcode: 8, 
    			},{
    				opcode: 54, 
    				var: "V3", 
    			},{
    				label: "L1", 
    			},{
    				opcode: 178, 
    				owner: "java/lang/System", 
    				name: "out", 
    				descriptor: "Ljava/io/PrintStream;", 
    			},{
    				opcode: 21, 
    				var: "V3", 
    			},{
    				opcode: 182, 
    				owner: "java/io/PrintStream", 
    				name: "println", 
    				descriptor: "(I)V", 
    				isInterface: false, 
    			},{
    				label: "L2", 
    			},{
    				opcode: 16, 
    				operand: 42, 
    			},{
    				opcode: 54, 
    				var: "V12", 
    			},{
    				label: "L3", 
    			},{
    				opcode: 178, 
    				owner: "java/lang/System", 
    				name: "out", 
    				descriptor: "Ljava/io/PrintStream;", 
    			},{
    				opcode: 21, 
    				var: "V12", 
    			},{
    				opcode: 182, 
    				owner: "java/io/PrintStream", 
    				name: "println", 
    				descriptor: "(I)V", 
    				isInterface: false, 
    			},{
    				label: "L4", 
    			},{
    				opcode: 177, 
    			},{
    				label: "L5", 
    			},], 
    		sourceLocals: [{
    				name: "this", 
    				descriptor: "Lorg/quiltmc/chasm/Main$Inner;", 
    				signature: null, 
    				start: "L0", 
    				end: "L5", 
    				index: 0, 
    			},{
    				name: "parameter1", 
    				descriptor: "I", 
    				signature: null, 
    				start: "L0", 
    				end: "L5", 
    				index: 1, 
    			},{
    				name: "parameter2", 
    				descriptor: "Ljava/lang/String;", 
    				signature: null, 
    				start: "L0", 
    				end: "L5", 
    				index: 2, 
    			},{
    				name: "parameter3", 
    				descriptor: "Ljava/util/List;", 
    				signature: "Ljava/util/List<Ljava/lang/String;>;", 
    				start: "L0", 
    				end: "L5", 
    				index: 3, 
    			},{
    				name: "local1", 
    				descriptor: "I", 
    				signature: null, 
    				start: "L1", 
    				end: "L5", 
    				index: 4, 
    			},{
    				name: "local2", 
    				descriptor: "I", 
    				signature: null, 
    				start: "L3", 
    				end: "L5", 
    				index: 5, 
    			},], 
    		tryCatchBlocks: [], 
    		lineNumbers: [{
    				line: 23, 
    				label: "L0", 
    			},{
    				line: 24, 
    				label: "L1", 
    			},{
    				line: 25, 
    				label: "L2", 
    			},{
    				line: 26, 
    				label: "L3", 
    			},{
    				line: 27, 
    				label: "L4", 
    			},], 
    	}, 
    }
    

    First, let's observe:

    • The local variable analysis assigns V3 as the name for local1
    • The local variable analysis assigns V12 as the name for local2

    However, the debug information provided in sourceLocals is not in any way associated with said locals. I want to investigate the possibility and usefulness of merging these representations somehow.

    One problem is currently that it is very hard to impossible to match a local by it's type, which is very common with mixin. Another possible problem is duplicate information shared between signature and descriptor.

    Please suggest different representations below.

    opened by CheaterCodes 4
  • Allow Specifying Dependencies in Chassembly Transformers

    Allow Specifying Dependencies in Chassembly Transformers

    ChasmLangTransformer currently doesn't have a way to specify depoendencies. Please discuss how these dependencies should be represented in Chassembly files.

    opened by CheaterCodes 0
  • Shallow Write Locks

    Shallow Write Locks

    Currently all locks in Chasm are "deep lock". However, in most cases, shallow locks would be preferred.

    Imagine targeting a single instruction in a method. If a transformation applies a write lock to said instruction, all other transformations are not allow to change anything about it.

    However, in most cases the intended behavior will be that noone modifies the location of said instruction. Shallow locks provide that option, allowing other transformations to modify childrens of the target, but not the target itself.

    opened by CheaterCodes 0
  • Allow Transformers to Depend on Undefined Transformers

    Allow Transformers to Depend on Undefined Transformers

    Transformers are allowed to declare ordering dependencies on each other. However, Chasm currently doens't handle transformers depending on undefined transformers. The intended behavior is described here:

    Transitive Dependencies

    Imagine the transformer ids A and C are defined, but B isn't. Given the dependencies

    • A mustRunAfter B
    • B mustRunAfter C

    The following should behave equivalently

    • A mustRunAfter C

    Missing dependencies

    Imagine the transformer ids A and C are defined, but B isn't. Given the dependencies

    • A mustRunAfter B
    • A mustRunAfter C

    The following should behave equivalently

    • A mustRunAfter C
    opened by CheaterCodes 0
  • Transformation and Transformer Locking

    Transformation and Transformer Locking

    Background and Terminology

    At the start of Chasm, all Transformers are created, usually read from Chassembly files. They can declare ordering relative to other transformers. According to the specified ordering, Transformers are sorted into (as few as possible!) so-called "Rounds". The rounds are then applied one after the other. Therefore, a Transformer experiences the following relevant steps in its lifetime:

    1. Creation (Start of Chasm)
    2. Application (Start of Round)
    3. Completion (End of Round)
    4. Destruction (End of Chasm)

    At the start of a round, during transformer application, a Transformer can create any number of Transformations. A Transformation declares during creation which segments of code it requires read access to, called Sources, as well as one primary Target it will replace on application. The Transformations of all Transformers that are running in the current round are then sorted to ordering implied by the Sources and the Target.

    Analog to the Transformer, a Transformation at most lives through the following steps during its lifetime:

    1. Creation (Transformer application)
    2. Application (Replacing Target)
    3. Completion (End of Round)
    4. Destruction (End of Chasm)

    Internally, Chasm only differentiates between Target and Sources by their writability. For the remainder of this discussion, Target therefore either refers to the single writeable Target or any one of the read-only Sources.

    Locking

    The idea of locking is, to allow a Transformation to declare restrictions on which Targets and Sources may be modified by other Transformations. In theory, locking can be performed on different levels:

    • Transformer-level locking
    • Transformation-level locking More granular targets are preferable, but a lock may only use lifetime events from its current level.

    Affects on Ordering

    The fundamental goal of Chasm is to apply as many Transformations as possible without violating any contracts. Some contracts are implied by the specified Targets (write inner before outer), but many of them are defined via locking. Therefore, locking on Transformation-level is a fundamental requirement as it is the primary way to affect ordering.

    Locking on Transformer-level would allow the possibility to also affect ordering of Transformers, but it is unclear if this is something that is wanted.

    Current Locking

    Currently, we only use Transformation-level locking. Additionally, Locks can't outlive a Transformation, so we're limited to the following lock options:

    • Lock from start of round until Transformation application (Lock.Before)
    • Lock from Transformation application until end of round (Lock.After)

    Questions

    With this background, the following questions require discussion

    Is current locking sufficient?

    Imagine a mod that has only a single transformer for it's entire functionality. A different mod might modify the same code, silently overwriting the original mod. This is a conflict that would be currently detected, but only if they both run in the same round.

    The current solution would be to have the first mod generate an additional transformer running in the very last round, which verifies correct application or crashes otherwise.

    Do we want longer lived locking?

    This would allow us to create locks that last past the end of the current round. The above example could instead create a lock that last from after application to the very end of Chasm.

    Do we want Transformer-level locking?

    Declaring locks on Transformer-level would allow us to create earlier locks, e.g. from that start of Chasm until Transformer application. I'm not sure this is sueful in any way, but if someone has a usecase, let me know.

    design decision 
    opened by CheaterCodes 0
Owner
null
Mixin is a trait/mixin and bytecode weaving framework for Java using ASM

Mixin is a trait/mixin framework for Java using ASM and hooking into the runtime classloading process via a set of pluggable built-in or user-provided

SpongePowered 1.1k Jan 7, 2023
Jitescript - Java API for Bytecode

Jitescript - Java API for Bytecode This project is inspired by @headius's BiteScript. The goal is to produce a Java library with a similar API so that

Doug Campos 182 Dec 7, 2022
The modern Java bytecode editor

Recaf An easy to use modern Java bytecode editor that abstracts away the complexities of Java programs. Recaf abstracts away: Constant pool Stack fram

Matt 4.5k Dec 31, 2022
A Java 8+ Jar & Android APK Reverse Engineering Suite (Decompiler, Editor, Debugger & More)

Bytecode Viewer Bytecode Viewer - a lightweight user friendly Java Bytecode Viewer. New Features WAR & JSP Loading JADX-Core Decompiler Fixed APK & de

Kalen (Konloch) Kinloch 13.5k Jan 7, 2023
cglib - Byte Code Generation Library is high level API to generate and transform Java byte code. It is used by AOP, testing, data access frameworks to generate dynamic proxy objects and intercept field access.

cglib Byte Code Generation Library is high level API to generate and transform JAVA byte code. It is used by AOP, testing, data access frameworks to g

Code Generation Library 4.5k Jan 8, 2023
Quick and dirty framework for on-the-fly patching of classes via the java attach api and transformers.

Nuclear Quick and easy framework for on the fly patching of running java applications. Inspiration from an idea of an injectable minecraft cheat. What

0x150 8 Dec 28, 2021
A sample repo to help you handle basic auth for automation test in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to handle basic auth for automation test in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Windows - htt

null 12 Jul 13, 2022
A sample repo to help you handle cookies for automation test in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to handle cookies for automation test in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Windows - https:

null 13 Jul 13, 2022
A sample repo to help you handle basic auth for automation test in Java-TestNG on LambdaTest. Run Selenium tests with TestNG on LambdaTest platform.

How to handle basic auth for automation test in Java-TestNG on LambdaTest Environment Setup Global Dependencies Install Maven Or Install Maven with Ho

null 11 Jul 13, 2022
Lib-Tile is a multi Maven project written in JavaFX and NetBeans IDE 8 and provides the functionalities to use and handle easily Tiles in your JavaFX application.

Lib-Tile Intention Lib-Tile is a multi Maven project written in JavaFX and NetBeans IDE and provides the functionalities to use and handle easily Tile

Peter Rogge 13 Apr 13, 2022
A declarative API to handle Android runtime permissions.

PermissionsDispatcher Fully Kotlin/Java support Special permissions support 100% reflection-free PermissionsDispatcher provides a simple annotation-ba

PermissionsDispatcher 11.1k Jan 5, 2023
InterfaceMaker is a modern plugin to handle and customize join items, hotbars and menus with a developer and administrator friendly API.

Interface Maker InterfaceMaker is a modern plugin to handle and customize join items, hotbars and menus with a developer friendly API. Features Simple

2LStudios - Minecraft 10 Nov 27, 2022
The shortest possible maven template / quickstarter for Java 16

The shortest possible Java 16 maven quickstarter The shortest possible Apache Maven template for Java 16 usage git clone https://github.com/AdamBien/j

Adam Bien 6 Nov 8, 2021
Tools for tracking down memory / JVM problems & generating predictable-as-possible VM behaviour

Hawkshaw Tools for tracking down memory / JVM problems & generating predictable-as-possible VM behaviour You can Use Hawkshaw to mimic application obj

Martijn Verburg 40 Jan 9, 2021
fabric-carpet extension mod which attempts to fix as many vanilla bugs as possible. Feel free to add as many fixes as you want!

Carpet-Fixes Fabric Carpet extension mod which attempts to fix as many vanilla bugs as possible! Feel free to contribute by adding as many fixes as yo

Fx Morin 90 Jan 6, 2023
🟪 TommyBox is a single-file executable that makes it possible to launch web apps on a desktop.

?? TommyBox About: TommyBox is a standalone executable container that makes it possible to launch static and dynamic web apps on a desktop by providin

null 19 May 28, 2022
Sometimes people say that playing on anarchy servers far away from spawn is like Singleplayer with chat, so this mod just makes the exact thing possible.

Singleplayer With Chat Sometimes people say that playing on anarchy servers far away from spawn is like singleplayer with chat, so this mod just makes

null 5 Dec 2, 2022
A singular file to protect as many Minecraft servers and clients as possible from the Log4j exploit (CVE-2021-44228).

MC-Log4J-Patcher The goal of this project is to provide Minecraft players, and server owners, peace of mind in regards to the recently discovered Log4

Koupa Taylor 4 Jan 4, 2022
Library that makes it possible to read, edit and write CSV files

AdaptiveTableLayout Welcome the new CSV Library AdaptiveTableLayout for Android by Cleveroad Pay your attention to our new library that makes it possi

Cleveroad 1.9k Jan 6, 2023