Guards

Guards are pieces of code that protect, or "guard" other pieces of code. The code that they protect is usually specialised, and would not be safe to execute for the wrong types. The guards prevent this happening. Guards come in two forms:

  • Inline guards
  • Out-of-line guards

Inline Guards

Inline guards are inserted directly before the protected code.

Out-of-line guards are inserted into code that may violate assumptions made when optimising code. The place where the guard is inserted, is not directly related to the protected code. In other words, rather than protect the code that makes assumptions, all code that could violate this assumption must be guarded instead.

Inline guards are conceptually simple. As an example, the Python code

c = a + b

could be replaced by the code:

if type(a) is not int or type(b) is not int:
    exit_trace
()
c
= int_add(a, b)

Provided that type tests are cheap, and that a and b are both ints, then the second piece of code will be faster. The guard is the piece of code

if type(a) is not int or type(b) is not int:
    exit_trace
()

Inline guards can be inserted by the Tracing or Specialisation passes.

Out-of-line Guards

Out-of-line guards are more complex than inline guards.

An out-of-line guard exists in one place, but guards code somewhere else. For example, consider the following code snippet:

class MyList:
def __len__(self):
   
return self._len

Elsewhere in the program, this code is used:

   l = len(mylist)

The Tracing pass will inline the MyList.__len__ method:

#inline guard:
if type(mylist) != MyList:
   exit_trace
()
# Out-of-line guard -- MyList.__len__ is unchanged
#enter MyList.__len__ method
l
= self._len
#exit MyList.__len__ method

Note that the guard is not in the code. In fact it is attached to the dictionary of the MyList class. If the MyList.__len__ attribute is changed, then the trace will be invalidated, and will not be used again.

Out-of-line guards are used to guard against changes in class and module dictionaries. If an attribute is changed which has guards attached then all traces depending on that attribute are invalidated and all guards that are guarding the invalidated traces are deleted.

Out-of-line guards are inserted only by the Specialiser pass.

Comments