Skip to content

Commit 1b8278a

Browse files
authored
Fix bug where a duplicate code table is added (#37)
1 parent e2ca88e commit 1b8278a

File tree

2 files changed

+90
-1
lines changed

2 files changed

+90
-1
lines changed

crates/codegen/src/irgen/statements.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,10 @@ pub fn statement_gen<'a>(
115115
}
116116
table_instances.extend(res.table_instances);
117117
label_indices.extend(res.label_indices);
118-
utilized_tables.extend(res.utilized_tables);
118+
// Only add tables that are not already in the utilized tables
119+
let res_unique_tables =
120+
res.utilized_tables.iter().filter(|t| !utilized_tables.contains(t)).cloned().collect::<Vec<TableDefinition>>();
121+
utilized_tables.extend(res_unique_tables);
119122

120123
// Increase offset by byte length of recursed macro
121124
*offset += res.bytes.iter().map(|(_, b)| b.0.len()).sum::<usize>() / 2;

crates/core/tests/code_table.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,3 +286,89 @@ fn test_code_table_all_features() {
286286
.replace(" ", "")
287287
);
288288
}
289+
290+
#[test]
291+
fn test_reuse_code_table_multiple_times() {
292+
let source: &str = r#"
293+
#define table CODE_TABLE {
294+
0x1234
295+
}
296+
297+
#define macro MAIN() = takes(0) returns (0) {
298+
__tablesize(CODE_TABLE)
299+
__tablestart(CODE_TABLE)
300+
301+
__tablesize(CODE_TABLE)
302+
__tablestart(CODE_TABLE)
303+
}
304+
"#;
305+
306+
// Parse tokens
307+
let flattened_source = FullFileSource { source, file: None, spans: vec![] };
308+
let lexer = Lexer::new(flattened_source);
309+
let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
310+
let mut parser = Parser::new(tokens, None);
311+
312+
// Parse the AST
313+
let mut contract = parser.parse().unwrap();
314+
315+
// Derive storage pointers
316+
contract.derive_storage_pointers();
317+
318+
// Instantiate Codegen
319+
let cg = Codegen::new();
320+
321+
// The codegen instance should have no artifact
322+
assert!(cg.artifact.is_none());
323+
324+
// Have the Codegen create the constructor bytecode
325+
let mbytes = Codegen::generate_main_bytecode(&EVMVersion::default(), &contract, None).unwrap();
326+
327+
// Two times: 60 = PUSH1, 02 = 2 bytes table size, 61 = PUSH2, 000a = 10 bytes table start
328+
// Plus the 0x1234
329+
assert_eq!(mbytes, "600261000a 600261000a 1234".replace(" ", ""));
330+
}
331+
332+
#[test]
333+
fn test_reuse_code_table_multiple_times_macro() {
334+
let source: &str = r#"
335+
#define table CODE_TABLE {
336+
0x1234
337+
}
338+
339+
#define macro MAIN() = takes(0) returns (0) {
340+
TEST_TABLE()
341+
TEST_TABLE()
342+
}
343+
344+
#define macro TEST_TABLE() = takes(0) returns (0) {
345+
__tablesize(CODE_TABLE)
346+
__tablestart(CODE_TABLE)
347+
}
348+
"#;
349+
350+
// Parse tokens
351+
let flattened_source = FullFileSource { source, file: None, spans: vec![] };
352+
let lexer = Lexer::new(flattened_source);
353+
let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
354+
let mut parser = Parser::new(tokens, None);
355+
356+
// Parse the AST
357+
let mut contract = parser.parse().unwrap();
358+
359+
// Derive storage pointers
360+
contract.derive_storage_pointers();
361+
362+
// Instantiate Codegen
363+
let cg = Codegen::new();
364+
365+
// The codegen instance should have no artifact
366+
assert!(cg.artifact.is_none());
367+
368+
// Have the Codegen create the constructor bytecode
369+
let mbytes = Codegen::generate_main_bytecode(&EVMVersion::default(), &contract, None).unwrap();
370+
371+
// Two times: 60 = PUSH1, 02 = 2 bytes table size, 61 = PUSH2, 000a = 10 bytes table start
372+
// Plus the 0x1234
373+
assert_eq!(mbytes, "600261000a 600261000a 1234".replace(" ", ""));
374+
}

0 commit comments

Comments
 (0)