Skip to main content

module lang::flybytes::Syntax

rascal-0.42.0
org.rascalmpl.flybytes-0.2.11

Usage​

import lang::flybytes::Syntax;

Dependencies​

import List;

data Class​

The top-level compilation unit for flybytes is the class or the interface

data Class (list[Annotation] annotations = [], loc src = |unknown:///|) 
= class(Type \type /* object(str name) */,
set[Modifier] modifiers = {\public()},
Type super = object(),
list[Type] interfaces = [],
list[Field] fields = [],
list[Method] methods = []
//list[Class] children = [],
)
| interface(Type \type /* object(str name) */,
list[Type] interfaces = [],
list[Field] fields = [],
list[Method] methods = []
)
;

data Modifier​

data Modifier  
= \public()
| \private()
| \protected()
| \friendly()
| \static()
| \final()
| \synchronized()
| \abstract()
;

data Field​

Class fields members have optional initialization expressions.

data Field (list[Annotation] annotations = [], set[Modifier] modifiers = {\private()}, loc src=|unknown:///|) 
= field(Type \type, str name, Exp init = defVal(\type))
;

data Method​

Four kinds of methods can be generated

data Method (list[Annotation] annotations = [], loc src=|unknown:///|) 
= method(Signature desc, list[Formal] formals, list[Stat] block, set[Modifier] modifiers = {\public()})
| procedure(Signature desc, list[Formal] formals, list[Instruction] instructions, set[Modifier] modifiers = {\public()})
| method(Signature desc, set[Modifier] modifiers={\abstract(), \public()})
| static(list[Stat] block)
;
  • procedure is a special extension since it contains only JVM bytecode instructions as a body, instead of high-level programming constructs like expressions and statements.
  • one alternative of method is abstract methods, which do not have a body, the other is methods
  • static blocks are also modeled as methods but without a signature.
  • normal static methods are methods with a static Modifier.

The src field is important for stack traces and other debugging features.

function method​

Shorthand for directly producing a method with its signature and code block.

Method method(Modifier access, Type ret, str name, list[Formal] formals, list[Stat] block)

data Signature​

Method and constructor signatures

data Signature  
= methodDesc(Type \return, str name, list[Type] formals)
| constructorDesc(list[Type] formals)
;

data Type​

JVM type symbols

data Type  
= byte()
| boolean()
| short()
| character()
| integer()
| float()
| double()
| long()
| object(str name)
| array(Type arg)
| \void()
| string()
;

data Annotation​

data Annotation (RetentionPolicy retention=runtime()) 
= \anno(str annoClass, Type \type, value val, str name = "value")
| \tag(str annoClass)
;

data RetentionPolicy​

data RetentionPolicy  
= class()
| runtime()
| source()
;

data Formal​

optional init expressions will be used at run-time if null is passed as actual parameter

data Formal  
= var(Type \type, str name, Exp init = defVal(\type))
;

data Stat​

Structured programming with statements, OO primitives like new, and JVM monitor blocks and breakpoints

data Stat (loc src = |unknown:///|) 
= \store(str name, Exp \value)
| \decl(Type \type, str name, Exp init = defVal(\type))
| \astore(Exp array, Exp index, Exp arg)
| \do(Exp exp)
| \return()
| \return(Exp arg)
| \putField(Type class, Exp receiver, Type \type, str name, Exp arg)
| \putStatic(Type class, str name, Type \type, Exp arg)
| \if(Exp condition, list[Stat] thenBlock)
| \if(Exp condition, list[Stat] thenBlock, list[Stat] elseBlock)
| \for(list[Stat] init,
Exp condition,
list[Stat] next,
list[Stat] statements, str label = "")
| \block(list[Stat] block, str label = "")
| \break(str label = "")
| \continue(str label = "")
| \while(Exp condition, list[Stat] block, str label = "")
| \doWhile(list[Stat] block, Exp condition, str label = "")
| \throw(Exp arg)
| \monitor(Exp arg, list[Stat] block)
| \acquire(Exp arg)
| \release(Exp arg)
| \try(list[Stat] block, list[Handler] \catch)
| \switch(Exp arg, list[Case] cases, SwitchOption option = lookup(/*for best performance on current JVMs*/))
| invokeSuper(Signature desc, list[Exp] args)
| \asm(list[Instruction] instructions)
;
  • invokeSuper is typically only used as the first statement of a constructor
  • monitor guarantees release of the lock in case of exceptions, break and continue that break out of the block, but only if release and acquire are not used on the same lock object anywhere.
  • asm allows for inling raw bytecode instructions, but please understand that the monitor blocks' semantics can be broken by jumping out of the block unseen.

data SwitchOption​

data SwitchOption  
= table()
| lookup()
| auto()
;

data Case​

data Case  
= \case(int key, list[Stat] block)
| \default(list[Stat] block)
;

data Handler​

data Handler  
= \catch(Type \type, str name, list[Stat] block)
| \finally(list[Stat] block)
;

data Exp​

JVM bytecode instructions lifted to the expression level.

data Exp (loc src = |unknown:///|) 
= null()
| \true()
| \false()
| load(str name)
| aload(Exp array, Exp index)
| \const(Type \type, value constant)
| sblock(list[Stat] statements, Exp arg)
| invokeStatic(Type class, Signature desc, list[Exp] args)
| invokeSpecial(Type class, Exp receiver, Signature desc, list[Exp] args)
| invokeVirtual(Type class, Exp receiver, Signature desc, list[Exp] args)
| invokeInterface(Type class, Exp receiver, Signature desc, list[Exp] args)
| invokeDynamic(BootstrapCall handle, Signature desc, list[Exp] args)
| newInstance(Type class, Signature desc, list[Exp] args)
| getField(Type class, Exp receiver, Type \type, str name)
| getStatic(Type class, Type \type, str name)
| instanceof(Exp arg, Type class)
| eq(Exp lhs, Exp rhs)
| ne(Exp lhs, Exp rhs)
| le(Exp lhs, Exp rhs)
| gt(Exp lhs, Exp rhs)
| ge(Exp lhs, Exp rhs)
| lt(Exp lhs, Exp rhs)
| newArray(Type \type, Exp size)
| newInitArray(Type \type, list[Exp] args)
| alength(Exp arg)
| checkcast(Exp arg, Type \type)
| coerce(Type from, Type to, Exp arg)
| shr(Exp lhs, Exp shift)
| shl(Exp lhs, Exp shift)
| ushr(Exp lhs, Exp shift)
| and(Exp lhs, Exp rhs)
| sand(Exp lhs, Exp rhs)
| or(Exp lhs, Exp rhs)
| sor(Exp lhs, Exp rhs)
| xor(Exp lhs, Exp rhs)
| add(Exp lhs, Exp rhs)
| sub(Exp lhs, Exp rhs)
| div(Exp lhs, Exp rhs)
| rem(Exp lhs, Exp rhs)
| mul(Exp lhs, Exp rhs)
| neg(Exp arg)
| inc(str name, int inc)
| cond(Exp condition, Exp thenExp, Exp elseExp)
;

The Exp syntax allows for expression all JVM bytecode expression stackmachine operations but with a nested recursive syntax that is closer to programming languages.

  • with load, name resolution is limited to local variables and parameter names.
  • method invocation always requires the full method signature.
  • field access and update also require the full class name and field name.
  • about invokving methods:
    • invokeStatic must be used when invoking methods with the static modifier.
    • invokeSpecial can be used when no dynamic dispatch is needed, or searching superclasses is required, and you know which class implements the method. Use this to invoke a method for efficiency's sake. The invocation is type-checked at class load time.
    • invokeVirtual should be used if you do need dynamic dispatch, or the method is implemented in a superclass, and this is not a default method of an interface, use this invocation method. You need to be sure the method exists somewhere reachable from the \class reference type. The invocation is type-checked at class load time.
    • invokeInterface is for invoking methods you know only from interfaces, such as default methods. The method can even be absent at runtime in which case this throws a RuntimeException. The type-check occurs at the first invocation at run-time.
    • invokeDynamic is very special. It generates a new call site at run-time using a static "bootstrap" method, then caches the site and invokes it. Depending on the semantics of the bootstrap method the call site has the samen semantics or a different semantics the next time it is invoked.
      • The first type in desc of `invokeDynamic must be the receiver type if the method is not static.
      • The first argument in args is then also the receiver itself and not one of the method's arguments.

data Instruction​

The JVM low-level instruction set

data Instruction  
= LABEL(str label)
| LINENUMBER(int line, str label)
| LOCALVARIABLE(str name, Type \type, str \start, str end, int var)
| TRYCATCH(Type \type, str \start, str end, str handler)
| NOP()
| ACONST_NULL()
| ICONST_M1()
| ICONST_0()
| ICONST_1()
| ICONST_2()
| ICONST_3()
| ICONST_4()
| ICONST_5()
| LCONST_0()
| LCONST_1()
| FCONST_0()
| FCONST_1()
| FCONST_2()
| DCONST_0()
| DCONST_1()
| IALOAD()
| LALOAD()
| FALOAD()
| DALOAD()
| AALOAD()
| BALOAD()
| CALOAD()
| SALOAD()
| IASTORE()
| LASTORE()
| FASTORE()
| DASTORE()
| AASTORE()
| BASTORE()
| CASTORE()
| SASTORE()
| POP()
| POP2()
| DUP()
| DUP_X1()
| DUP_X2()
| DUP2()
| DUP2_X1()
| DUP2_X2()
| SWAP()
| IADD()
| LADD()
| FADD()
| DADD()
| ISUB()
| LSUB()
| FSUB()
| DSUB()
| IMUL()
| LMUL()
| FMUL()
| DMUL()
| IDIV()
| LDIV()
| FDIV()
| DDIV()
| IREM()
| LREM()
| FREM()
| DREM()
| INEG()
| LNEG()
| FNEG()
| DNEG()
| ISHL()
| LSHL()
| ISHR()
| LSHR()
| IUSHR()
| LUSHR()
| IAND()
| LAND()
| IOR()
| LOR()
| IXOR()
| LXOR()
| I2L()
| I2F()
| I2D()
| L2I()
| L2F()
| L2D()
| F2I()
| F2L()
| F2D()
| D2I()
| D2L()
| D2F()
| I2B()
| I2C()
| I2S()
| LCMP()
| FCMPL()
| FCMPG()
| DCMPL()
| DCMPG()
| IRETURN()
| LRETURN()
| FRETURN()
| DRETURN()
| ARETURN()
| RETURN()
| ARRAYLENGTH()
| ATHROW()
| MONITORENTER()
| MONITOREXIT()
| ILOAD(int var)
| LLOAD(int var)
| FLOAD(int var)
| DLOAD(int var)
| ALOAD(int var)
| ISTORE(int var)
| LSTORE(int var)
| FSTORE(int var)
| DSTORE(int var)
| ASTORE(int var)
| RET(int var)
| BIPUSH(int val)
| SIPUSH(int val)
| NEWARRAY(Type element)
| LDC(Type \type, value constant)
| IINC(int var, int inc)
| IFEQ(str label)
| IFNE(str label)
| IFLT(str label)
| IFGE(str label)
| IFGT(str label)
| IFLE(str label)
| IF_ICMPEQ(str label)
| IF_ICMPNE(str label)
| IF_ICMPLT(str label)
| IF_ICMPGE(str label)
| IF_ICMPGT(str label)
| IF_ICMPLE(str label)
| IF_ACMPEQ(str label)
| IF_ACMPNE(str label)
| GOTO(str label)
| JSR(str label)
| IFNULL(str label)
| IFNONNULL(str label)
| TABLESWITCH(int min, int max, str defaultLabel, list[str] labels)
| LOOKUPSWITCH(str defaultLabel, list[int] keys, list[str] labels)
| GETSTATIC(Type class, str name, Type \type)
| PUTSTATIC(Type class, str name, Type \type)
| GETFIELD(Type class, str name, Type \type)
| PUTFIELD(Type class, str name, Type \type)
| INVOKEVIRTUAL(Type class, Signature desc, bool isInterface)
| INVOKESPECIAL(Type class, Signature desc, bool isInterface)
| INVOKESTATIC(Type class, Signature desc, bool isInterface)
| INVOKEINTERFACE(Type class, Signature desc, bool isInterface)
| INVOKEDYNAMIC(Signature desc, BootstrapCall handle)
| NEW(Type \type)
| ANEWARRAY(Type \type)
| CHECKCAST(Type \type)
| INSTANCEOF(Type \type)
| MULTIANEWARRAY(Type \type, int numDimensions)
| exp(Exp expression, str label="")
| stat(Stat statement, str label="")
;

function defVal​

Exp defVal(boolean())

Exp defVal(integer())

Exp defVal(long())

Exp defVal(byte())

Exp defVal(character())

Exp defVal(short())

Exp defVal(float())

Exp defVal(double())

Exp defVal(object(str _))

Exp defVal(array(Type _))

Exp defVal(string())

function object​

Object is the top of the JVMs type system

Type object()

function incr​

Generates name+=i;

Stat incr(str name, int i)

function invokeSuper​

Generates super(f1, f2); for a given anonymous constructor of type (F1 f1, F2 f2)

Stat invokeSuper(list[Type] formals, list[Exp] args)

function invokeSuper​

Generates super();

Stat invokeSuper()

function main​

Generates a main method public static final void main(String[] args) { block }

Method main(str args, list[Stat] block)

function method​

Short-hand for generating a normal method

Method method(Modifier access, Type ret, str name, list[Formal] args, list[Stat] block)

function method​

Short-hand for generating a normal public method

Method method(Type ret, str name, list[Formal] args, list[Stat] block)

function staticMethod​

Short-hand for generating a static method

Method staticMethod(Modifier access, Type ret, str name, list[Formal] args, list[Stat] block)

function staticMethod​

Short-hand for generating a public static method

Method staticMethod(Type ret, str name, list[Formal] args, list[Stat] block)

function constructor​

Short-hand for generating a constructor.

Method constructor(Modifier access, list[Formal] formals, list[Stat] block)

Pitfalls​

Don't forgot to generate a super call.

function new​

"new" short-hand with parameters

Exp new(Type class, list[Type] argTypes, list[Exp] args)

function new​

"new" short-hand, without parameters

Exp new(Type class)

function this​

Load the standard "this" reference for every object.

Exp this()

Pitfalls​

This works only inside non-static methods and inside constructors

function current​

the <current> class refers to the class currently being compiled, for convenience's sake.

Type current()

function getField​

Load a field from the currently compiled class

Exp getField(Type \type, str name)

function getStatic​

Load a static field from the currently compiled class

Exp getStatic(Type \type, str name)

function putField​

Store a field in the currently compiled class

Stat putField(Type \type, str name, Exp arg)

function putStatic​

Store a static field in the currently defined class

Stat putStatic(Type \type, str name, Exp arg)

function invokeStatic​

Invoke a static method on the currently defined class

Exp invokeStatic(Signature desc, list[Exp] args)

function invokeSpecial​

Invoke a method on the currently defined class using invokeSpecial

Exp invokeSpecial(Exp receiver, Signature desc, list[Exp] args)

function invokeVirtual​

Invoke a method on the currently defined class using invokeVirtual

Exp invokeVirtual(Exp receiver, Signature desc, list[Exp] args)

function invokeInterface​

Invoke a method on the currently defined interface using invokeInterface

Exp invokeInterface(Exp receiver, Signature desc, list[Exp] args)

function iconst​

Exp iconst(int i)

function sconst​

Exp sconst(int i)

function bconst​

Exp bconst(int i)

function cconst​

Exp cconst(int i)

function zconst​

Exp zconst(bool i)

function jconst​

Exp jconst(int i)

function sconst​

Exp sconst(str i)

function dconst​

Exp dconst(real i)

function fconst​

Exp fconst(real i)

data BootstrapCall​

A bootstrap handle is a name of a static method (as defined by its host class, its name and its type signature), and a list of "constant" arguments.

data BootstrapCall  
= bootstrap(Type class, Signature desc, list[CallSiteInfo] args)
;

These constant arguments can be used to declare properties of the call site which can then be used by the bootstrap method to define in which way the dynamic call must be resolved. So these argument help to avoid having to define a combinatorially large number of bootstrap methods (one for each call site situation).

It's advisable to use the convenience function below to create a BootstrapCall instance:

  • bootstrap(Type class, str name, list[BootstrapInfo] args)

That function makes sure to line up the additional information in the extra arguments about the call site with the static type of the static bootstrap method.

function bootstrap​

generate a bootstrap call with all the required standard parameters, and optionally more.

BootstrapCall bootstrap(Type class, str name, list[CallSiteInfo] args)

Benefits​

  • A raw BootstrapCall must return a CallSite and take a MethodHandle.Lookup, a string and a MethodType as the first three parameters.
    This convenience function guarantees that this the true, but allows for adding additional static information about the call site.
  • The types of the additional parameters are inferred automatically from the CallSiteInfo structures, so you do not have to distribute this information during code generation.

Pitfalls​

  • the signature of the bootstrap method name in class (which you might have written in Java, or generated in a different part of your compiler) must be the exactly the same as generated here.

function bootstrap​

Generate a basic bootstrap caller with only the minimally required information for a dynamic invoke.

BootstrapCall bootstrap(str name, list[CallSiteInfo] args)

Benefits​

This is the starting point for any use of invokeDynamic. Get this working first and add additional information later

Pitfalls​

Writing bootstrap method implementations is hard.

function bootstrapMethod​

Convenience function to use existing BootstrapCall information to generate a fitting bootstrap method to call.

Method bootstrapMethod(BootstrapCall b, list[Stat] body)

This function mirrors the bootstrap function; it generates the method referenced by the output of that function.

Benefits​

  • the bootstrap method and the bootstrapCall information have to be aligned perfectly. If you use the pair of functions bootstrapMethod and bootstrap together then this alignment is guaranteed.

Pitfalls​

  • generating the body of a bootstrap method can be challenging. It is recommended to first write the example in Java and decompile the resulting method, and copy the result into the body parameter of this function.
  • another solution is to keep the source of the bootstrap method completely in Java, but making sure the signatures keep matching inside the BootstrapCall data. This is usually possible; when the bootstrap method is generic enough.

data CallSiteInfo​

data CallSiteInfo  
= stringInfo(str s)
| classInfo(str name)
| integerInfo(int i)
| longInfo(int l)
| floatInfo(real f)
| doubleInfo(real d)
| methodTypeInfo(Signature desc)
| virtualHandle(Type class, str name, Signature desc)
| specialHandle(Type class, str name, Signature desc, Type caller)
| getterHandle(Type class, str name, Type \type)
| setterHandle(Type class, str name, Type \type)
| staticGetterHandle(Type class, str name, Type \type)
| staticSetterHandle(Type class, str name, Type \type)
| constructorHandle(Type class, Signature desc)
;

function callsiteInfoType​

Type inference for callsiteInfo parameters to bootstrap methods.

Type callsiteInfoType(stringInfo(_))

Type callsiteInfoType(classInfo(_))

Type callsiteInfoType(integerInfo(_))

Type callsiteInfoType(longInfo(_))

Type callsiteInfoType(floatInfo(_))

Type callsiteInfoType(doubleInfo(_))

Type callsiteInfoType(virtualHandle(_,_,_))

Type callsiteInfoType(specialHandle(_,_,_,_))

Type callsiteInfoType(getterHandle(_,_,_))

Type callsiteInfoType(setterHandle(_,_,_))

Type callsiteInfoType(staticGetterHandle(_,_,_))

Type callsiteInfoType(staticSetterHandle(_,_,_))

Type callsiteInfoType(constructorHandle(_,_))

Type callsiteInfoType(methodTypeInfo(_))