Skip to content

Commit

Permalink
Handle invokedynamic in packetinstructions
Browse files Browse the repository at this point in the history
This isn't a very good implementation, but it's enough to get 1.16.2-pre3 working.
  • Loading branch information
Pokechu22 committed Nov 12, 2020
1 parent bdf05da commit 76dca37
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 0 deletions.
4 changes: 4 additions & 0 deletions burger/toppings/packetinstructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
from jawa.transforms import simple_swap

from .topping import Topping
from burger.util import stringify_invokedynamic

class PacketInstructionsTopping(Topping):
"""Provides the instructions used to construct network packets."""
Expand Down Expand Up @@ -390,6 +391,9 @@ def operations(classloader, classname, classes, verbose, args=None,
args=_PIT.join(arguments)))
break

elif mnemonic == "invokedynamic":
stack.append(stringify_invokedynamic(stack.pop(), instruction, cf))

# Conditional statements and loops
elif mnemonic.startswith("if"):
if "icmp" in mnemonic or "acmp" in mnemonic:
Expand Down
21 changes: 21 additions & 0 deletions burger/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,27 @@ def class_from_invokedynamic(ins, cf):
# from the constructor.
return methodhandle.reference.class_.name.value

def stringify_invokedynamic(obj, ins, cf):
"""
Converts an invokedynamic instruction into a string.
This is a rather limited implementation for now, only handling obj::method.
"""
const = cf.constants[ins.operands[0].value] # Hack due to packetinstructions not expanding constants
bootstrap = cf.bootstrap_methods[const.method_attr_index]
method = cf.constants.get(bootstrap.method_ref)
# Make sure this is a reference to LambdaMetafactory
assert method.reference_kind == 6 # REF_invokeStatic
assert method.reference.class_.name == "java/lang/invoke/LambdaMetafactory"
assert method.reference.name_and_type.name == "metafactory"
assert len(bootstrap.bootstrap_args) == 3 # Num arguments
# Actual implementation.
methodhandle = cf.constants.get(bootstrap.bootstrap_args[1])
if methodhandle.reference_kind == 7: # REF_invokeSpecial
return "%s::%s" % (obj, methodhandle.reference.name_and_type.name.value)
else:
raise Exception("Unhandled reference_kind %d" % methodhandle.reference_kind)

def try_eval_lambda(ins, args, cf):
"""
Attempts to call a lambda function that returns a constant value.
Expand Down

0 comments on commit 76dca37

Please sign in to comment.