jon.recoil.org

Module Blambda

blambda is designed to be a lambda-like expression language where every primitive is also a bytecode primitive. This allows us to separate the bytecode backend into two stages:

First, Lambda -> Blambda: Preserves the expression structure, but compiles all complex primitives down to ones with corresponding bytecode instructions. This will become more important as we continue to add more primitives to Lambda which have no corresponding bytecode instruction.

Second, Blambda -> Instructions: Only has to deal with linearizing the Lambda-like control flow. The comparatively fragile stack size maintenance and stack index computations can remain in their own module which doesn't need to be modified every time we change Lambda.

type constant = Lambda.constant
type structured_constant = Lambda.structured_constant =
  1. | Const_base of Blambda.constant
  2. | Const_block of int * Blambda.structured_constant list
  3. | Const_mixed_block of int * Lambda.mixed_block_shape * Blambda.structured_constant list
  4. | Const_float_array of string list
  5. | Const_immstring of string
  6. | Const_float_block of string list
  7. | Const_null

structured_constant needs to match the cmo file format

type direction_flag = Asttypes.direction_flag =
  1. | Upto
  2. | Downto
type raise_kind = Lambda.raise_kind =
  1. | Raise_regular
  2. | Raise_reraise
  3. | Raise_notrace
type static_label = Lambda.static_label
type event = Lambda.lambda_event
type context_switch =
  1. | Perform
  2. | Reperform
  3. | Runstack
  4. | Resume
type comparison = Instruct.comparison =
  1. | Eq
  2. | Neq
  3. | Ltint
  4. | Gtint
  5. | Leint
  6. | Geint
  7. | Ultint
  8. | Ugeint
type method_kind =
  1. | Self
  2. | Public
type primitive =
  1. | Getglobal of Compilation_unit.t
  2. | Getpredef of Ident.t
  3. | Boolnot
  4. | Isint
  5. | Vectlength
  6. | Setglobal of Compilation_unit.t
  7. | Getfield of int
  8. | Getfloatfield of int
  9. | Raise of Blambda.raise_kind
  10. | Offsetint of int
  11. | Offsetref of int
  12. | Negint
  13. | Addint
  14. | Subint
  15. | Mulint
  16. | Divint
  17. | Modint
  18. | Andint
  19. | Orint
  20. | Xorint
  21. | Lslint
  22. | Lsrint
  23. | Asrint
  24. | Intcomp of Blambda.comparison
  25. | Getstringchar
  26. | Getbyteschar
  27. | Getvectitem
  28. | Setfield of int
  29. | Setfloatfield of int
  30. | Setvectitem
  31. | Setbyteschar
  32. | Ccall of string
  33. | Makeblock of {
    1. tag : int;
    }
  34. | Makefloatblock
  35. | Make_faux_mixedblock of {
    1. total_len : int;
    2. tag : int;
    }
  36. | Check_signals

primitives that correspond to bytecode instructions that don't affect control flow

and rec_binding = {
  1. id : Ident.t;
  2. def : Blambda.bfunction;
}
and bfunction = {
  1. params : Ident.t list;
  2. body : Blambda.blambda;
  3. free_variables : Ident.Set.t;
    (*

    if we ever intended to do optimizations/transformations on blambda, this would be better as a function than a field

    *)
}
and blambda =
  1. | Var of Ident.t
  2. | Const of Blambda.structured_constant
  3. | Apply of {
    1. func : Blambda.blambda;
    2. args : Blambda.blambda list;
    3. nontail : bool;
    }
  4. | Function of Blambda.bfunction
  5. | Let of {
    1. id : Ident.t;
    2. arg : Blambda.blambda;
    3. body : Blambda.blambda;
    }
  6. | Letrec of {
    1. decls : Blambda.rec_binding list;
    2. free_variables_of_decls : Ident.Set.t;
      (*

      if we ever intended to do optimizations/transformations on blambda, this would be better as a function than a field

      *)
    3. body : Blambda.blambda;
    }
  7. | Prim of Blambda.primitive * Blambda.blambda list
  8. | Switch of {
    1. arg : Blambda.blambda;
    2. const_cases : int array;
      (*

      indexes into cases, indexed by the value of the immediate

      *)
    3. block_cases : int array;
      (*

      indexes into cases, indexed by the the block tag

      *)
    4. cases : Blambda.blambda array;
    }
  9. | Staticraise of Blambda.static_label * Blambda.blambda list
  10. | Staticcatch of {
    1. id : Blambda.static_label;
    2. body : Blambda.blambda;
    3. args : Ident.t list;
    4. handler : Blambda.blambda;
    }
  11. | Trywith of {
    1. body : Blambda.blambda;
    2. param : Ident.t;
    3. handler : Blambda.blambda;
    }
  12. | Sequence of Blambda.blambda * Blambda.blambda
  13. | Assign of Ident.t * Blambda.blambda
  14. | Send of {
    1. method_kind : Blambda.method_kind;
    2. met : Blambda.blambda;
    3. obj : Blambda.blambda;
    4. args : Blambda.blambda list;
    5. nontail : bool;
    }
  15. | Context_switch of Blambda.context_switch * Blambda.blambda list
  16. | Ifthenelse of {
    1. cond : Blambda.blambda;
    2. ifso : Blambda.blambda;
    3. ifnot : Blambda.blambda;
    }
  17. | While of {
    1. cond : Blambda.blambda;
    2. body : Blambda.blambda;
    }
  18. | For of {
    1. id : Ident.t;
    2. from : Blambda.blambda;
    3. to_ : Blambda.blambda;
    4. dir : Blambda.direction_flag;
    5. body : Blambda.blambda;
    }
  19. | Sequand of Blambda.blambda * Blambda.blambda
  20. | Sequor of Blambda.blambda * Blambda.blambda
  21. | Event of Blambda.blambda * Lambda.lambda_event
  22. | Pseudo_event of Blambda.blambda * Debuginfo.Scoped_location.t
    (*

    Pseudo events are ignored by the debugger. They are only used for generating backtraces.

    We prefer adding this event here rather than in lambda generation because:

    1. There are many different situations where a Pmakeblock can be generated.
    2. We prefer inserting a pseudo event rather than an event after to prevent the debugger to stop at every single allocation.

    Having Event and/or Pseudo_event make effective pattern-matching on blambda hard. However, blambda is only meant to go immediately before the code generator, so it shouldn't really be matched on anyway.

    In the future, we could simplify things a bit and use a new Lev_pseudo_after event kind in the Event constructor instead of Pseudo_event, to generate during lambda to blambda conversion if !Clflags.debug is true.

    *)