Add take_value_list and put_value_list methods.

Any code that needs to manipulate a variable argument list on an
instruction will need to remove the instruction's value list first,
change the list, and then put it back on the instruction. This is
required to avoid fighting the borrow checker over mutable locks on the
DataFlowGraph and its value list pool.

Add a generated InstructionData::take_value_list() method which lifts
out and existing value list and returns it, levaing an empty list in its
place, like Option::take() does it.

Add a generated InstructionData::put_value_list() which puts it back,
verifying that no existing value list is overwritten.
This commit is contained in:
Jakob Stoklund Olesen
2017-03-13 14:07:14 -07:00
parent 404a88f581
commit 5f2e37e05c
2 changed files with 49 additions and 0 deletions

View File

@@ -111,6 +111,8 @@ def gen_instruction_data_impl(fmt):
- `pub fn second_result_mut(&mut self) -> Option<&mut PackedOption<Value>>`
- `pub fn arguments(&self, &pool) -> &[Value]`
- `pub fn arguments_mut(&mut self, &pool) -> &mut [Value]`
- `pub fn take_value_list(&mut self) -> Option<ValueList>`
- `pub fn put_value_list(&mut self, args: ValueList>`
"""
# The `opcode` and `first_type` methods simply read the `opcode` and `ty`
@@ -221,6 +223,45 @@ def gen_instruction_data_impl(fmt):
""")
gen_arguments_method(fmt, True)
fmt.doc_comment(
"""
Take out the value list with all the value arguments and return
it.
This leaves the value list in the instruction empty. Use
`put_value_list` to put the value list back.
""")
with fmt.indented(
'pub fn take_value_list(&mut self) -> Option<ValueList> {',
'}'):
with fmt.indented('match *self {', '}'):
for f in InstructionFormat.all_formats:
n = 'InstructionData::' + f.name
if f.has_value_list:
fmt.line(
n + ' { ref mut args, .. } => Some(args.take()),')
fmt.line('_ => None,')
fmt.doc_comment(
"""
Put back a value list.
After removing a value list with `take_value_list()`, use this
method to put it back. It is required that this instruction has
a format that accepts a value list, and that the existing value
list is empty. This avoids leaking list pool memory.
""")
with fmt.indented(
'pub fn put_value_list(&mut self, vlist: ValueList) {', '}'):
with fmt.indented('let args = match *self {', '};'):
for f in InstructionFormat.all_formats:
n = 'InstructionData::' + f.name
if f.has_value_list:
fmt.line(n + ' { ref mut args, .. } => args,')
fmt.line('_ => panic!("No value list: {:?}", self),')
fmt.line('assert!(args.is_empty(), "Value list already in use");')
fmt.line('*args = vlist;')
def collect_instr_groups(isas):
seen = set()