IRFlags.java

  1. package org.jruby.ir;

  2. public enum IRFlags {
  3.     // Does this scope require a binding to be materialized?
  4.     // Yes if any of the following holds true:
  5.     // - calls 'Proc.new'
  6.     // - calls 'eval'
  7.     // - calls 'call' (could be a call on a stored block which could be local!)
  8.     // - calls 'send' and we cannot resolve the message (method name) that is being sent!
  9.     // - calls methods that can access the caller's binding
  10.     // - calls a method which we cannot resolve now!
  11.     // - has a call whose closure requires a binding
  12.     BINDING_HAS_ESCAPED,
  13.     // Does this execution scope (applicable only to methods) receive a block and use it in such a way that
  14.     // all of the caller's local variables need to be materialized into a heap binding?
  15.     // Ex:
  16.     //   def foo(&b)
  17.     //      eval 'puts a', b
  18.     //    end
  19.     //
  20.     //    def bar
  21.     //      a = 1
  22.     //      foo {} # prints out '1'
  23.     //    end
  24.     //
  25.     // Here, 'foo' can access all of bar's variables because it captures the caller's closure.
  26.     //
  27.     // There are 2 scenarios when this can happen (even this is conservative -- but, good enough for now)
  28.     // 1. This method receives an explicit block argument (in this case, the block can be stored, passed around,
  29.     //   eval'ed against, called, etc.).
  30.     //    CAVEAT: This is conservative ... it may not actually be stored & passed around, evaled, called, ...
  31.     // 2. This method has a 'super' call (ZSuper AST node -- ZSuperInstr IR instruction)
  32.     //    In this case, the parent (in the inheritance hierarchy) can access the block and store it, etc.  So, in reality,
  33.     //    rather than assume that the parent will always do this, we can query the parent, if we can precisely identify
  34.     //    the parent method (which in the face of Ruby's dynamic hierarchy, we cannot).  So, be pessimistic.
  35.     //
  36.     // This logic was extracted from an email thread on the JRuby mailing list -- Yehuda Katz & Charles Nutter
  37.     // contributed this analysis above.
  38.     CAN_CAPTURE_CALLERS_BINDING,
  39.     CAN_RECEIVE_BREAKS,           // may receive a break during execution
  40.     CAN_RECEIVE_NONLOCAL_RETURNS, // may receive a non-local return during execution
  41.     HAS_BREAK_INSTRS,             // contains at least one break
  42.     HAS_END_BLOCKS,               // has an end block. big de-opt flag
  43.     HAS_EXPLICIT_CALL_PROTOCOL,   // contains call protocol instrs => we don't need to manage bindings frame implicitly
  44.     HAS_LOOPS,                    // has a loop
  45.     HAS_NONLOCAL_RETURNS,         // has a non-local return
  46.     HAS_UNUSED_IMPLICIT_BLOCK_ARG,// Is %block implicit block arg unused?
  47.     RECEIVES_CLOSURE_ARG,         // This scope (or parent receives a closure
  48.     RECEIVES_KEYWORD_ARGS,        // receives keyword args
  49.     REQUIRES_DYNSCOPE,            // does this scope require a dynamic scope?
  50.     USES_BACKREF_OR_LASTLINE,     // Since backref ($~) and lastline ($_) vars are allocated space on the dynamic scope
  51.     USES_EVAL,                    // calls eval
  52.     USES_ZSUPER,                  // has zsuper instr
  53.     REQUIRES_FRAME,               // callee may read/write caller's frame elements
  54.     REQUIRES_VISIBILITY,          // callee may read/write caller's visibility

  55.     DYNSCOPE_ELIMINATED,          // local var load/stores have been converted to tmp var accesses
  56.     REUSE_PARENT_DYNSCOPE,        // for closures -- reuse parent's dynscope
  57. }