use failure::Error;
use log::debug;
use std::collections::HashMap;
use python_object::opcode;
use wasm_gen;
use wasm_gen::{FuncCode, Imm, WasmCodeGen};
mod error;
mod heap;
mod op;
mod python_frame;
pub mod python_stack;
mod symbol;
#[cfg(test)]
pub mod test_runner;
use heap::{HeapDict, HeapString, HeapTuple};
use python_frame::PythonFrame;
use symbol::{Linkage, Symbol};
const PYTHON_STACK_SIZE: u32 = 64 * 1024;
type SymbolMap = HashMap<String, Symbol>;
#[derive(PartialEq, Hash)]
pub enum StaticType {
String(u8),
Tuple(u8),
}
impl Eq for StaticType {}
type StaticSymbolMap = HashMap<StaticType, u32>;
pub enum Builtin {
_Start = 1,
PythonStackGrow,
PythonStackShrink,
PythonStackPop,
PythonStackPeakLastN,
PythonStackPeakLast,
PythonStackPush,
PythonStackSize,
CallDynamic0,
CallDynamic1,
CallDynamic5,
GetTag,
BoxValue,
UnboxValue,
TrapPythonStackUnderflow,
TrapPythonStackOverflow,
TrapUnsupportedCallLinkage,
TrapUnsupportedHeapObject,
}
const SIGNATURE_RI32: i32 = 0;
const SIGNATURE_I32_RI32: i32 = 1;
const SIGNATURE_I32I32_RI32: i32 = 2;
const SIGNATURE: i32 = 3;
const SIGNATURE_I32: i32 = 4;
const SIGNATURE_I32_I32_I32_I32_I32: i32 = 5;
pub const PYTHON_STACK_POINTER: i32 = 0;
const PYTHON_FUNC: u32 = 1;
pub fn compile(program: python_object::Program) -> Result<WasmCodeGen, Error> {
let mut wasm_module = WasmCodeGen::new();
wasm_module.add_table(wasm_gen::TableElemType::Funcref, 10, 10);
let mem = wasm_module.add_memory(64 * 100, 64 * 100);
wasm_module.add_export("mem".to_string(), mem, wasm_gen::ExportType::Mem);
let mut end_of_data_offset = 0;
let mut end_of_elem_offset = 0;
end_of_data_offset += PYTHON_STACK_SIZE;
let mut symbols = HashMap::new();
build_types(&mut wasm_module);
build_globals(&mut wasm_module);
build_imports(&mut wasm_module, &mut end_of_elem_offset, &mut symbols);
build_exports(&mut wasm_module);
build_builtins(&mut wasm_module);
build_intrinsics(&mut symbols);
for code_object in &program.funcs {
let f = compile_code_object(
&code_object,
&mut wasm_module,
&mut symbols,
&mut end_of_data_offset,
&mut end_of_elem_offset,
)?;
let main = wasm_module.add_func_with_type(f, SIGNATURE as u32);
wasm_module.set_name(main, code_object.name()?);
wasm_module.add_export("main".to_string(), main, wasm_gen::ExportType::Func);
}
Ok(wasm_module)
}
pub fn generate_call_dynamic(nargs: i32) -> wasm_gen::Func {
let mut code = vec![];
let target_signature = match nargs {
0 => SIGNATURE,
1 => SIGNATURE_I32,
5 => SIGNATURE_I32_I32_I32_I32_I32,
n => panic!("{}", n),
};
code.append(&mut vec![
FuncCode::new1(wasm_gen::GLOBAL_GET, Imm::I32(PYTHON_FUNC as i32)),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::GetTag as i32)),
FuncCode::new1(wasm_gen::I32_CONST, Imm::I32(heap::TAG_JS_LINKAGE as i32)),
FuncCode::new0(wasm_gen::I32_EQ),
FuncCode::new_control(wasm_gen::IF, wasm_gen::NONE),
]);
for _ in 0..nargs {
code.append(&mut vec![FuncCode::new1(
wasm_gen::CALL,
Imm::I32(Builtin::PythonStackPeakLast as i32),
)]);
}
code.append(&mut vec![
FuncCode::new1(wasm_gen::GLOBAL_GET, Imm::I32(PYTHON_FUNC as i32)),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::UnboxValue as i32)),
FuncCode::new2(
wasm_gen::CALL_INDIRECT,
Imm::I32(target_signature),
Imm::RESERVED,
),
FuncCode::new0(wasm_gen::RETURN),
FuncCode::new0(wasm_gen::END),
]);
code.append(&mut vec![
FuncCode::new1(wasm_gen::GLOBAL_GET, Imm::I32(PYTHON_FUNC as i32)),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::GetTag as i32)),
FuncCode::new1(
wasm_gen::I32_CONST,
Imm::I32(heap::TAG_PYTHON_LINKAGE as i32),
),
FuncCode::new0(wasm_gen::I32_EQ),
FuncCode::new_control(wasm_gen::IF, wasm_gen::NONE),
FuncCode::new1(wasm_gen::GLOBAL_GET, Imm::I32(PYTHON_FUNC as i32)),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::UnboxValue as i32)),
FuncCode::new2(wasm_gen::CALL_INDIRECT, Imm::I32(SIGNATURE), Imm::RESERVED),
FuncCode::new0(wasm_gen::RETURN),
FuncCode::new0(wasm_gen::END),
]);
code.append(&mut vec![FuncCode::new1(
wasm_gen::CALL,
Imm::I32(Builtin::TrapUnsupportedCallLinkage as i32),
)]);
wasm_gen::Func {
sig: wasm_gen::FuncType {
params: vec![],
results: vec![],
},
locals: vec![
(1, wasm_gen::I32),
],
code,
}
}
fn serialize_python_object(
object: &python_object::Object,
const_index: u8,
wasm_module: &mut WasmCodeGen,
end_of_data_offset: &mut u32,
static_allocs: &mut StaticSymbolMap,
allocated_strings: &mut HashMap<String, u32>,
) {
match object {
python_object::Object::Ascii(string) => {
if let Some(allocated_string) = allocated_strings.get(string) {
static_allocs.insert(StaticType::String(const_index), *allocated_string);
} else {
let mut ptr = end_of_data_offset.clone();
ptr = ptr | (heap::TAG_DATA as u32) << 28;
allocated_strings.insert(string.to_string(), ptr);
static_allocs.insert(StaticType::String(const_index), ptr);
let data = HeapString::serialize(string.to_string());
*end_of_data_offset += wasm_module.add_data(end_of_data_offset.clone(), data);
}
}
python_object::Object::Tuple(tuple_object) => {
for item in &tuple_object.data {
serialize_python_object(
item,
255,
wasm_module,
end_of_data_offset,
static_allocs,
allocated_strings,
);
}
let mut ptr = end_of_data_offset.clone();
ptr = ptr | (heap::TAG_TUPLE as u32) << 28;
static_allocs.insert(StaticType::Tuple(const_index), ptr);
let data = HeapTuple::serialize(&allocated_strings, tuple_object);
*end_of_data_offset += wasm_module.add_data(end_of_data_offset.clone(), data);
}
_ => {
}
}
}
fn allocate_static_data(
code_object: &python_object::CodeObject,
wasm_module: &mut WasmCodeGen,
end_of_data_offset: &mut u32,
) -> StaticSymbolMap {
let mut static_allocs = HashMap::new();
let mut allocated_strings = HashMap::new();
let mut i: u8 = 0;
for object in &code_object.consts.clone().into_inner().data {
serialize_python_object(
object,
i,
wasm_module,
end_of_data_offset,
&mut static_allocs,
&mut allocated_strings,
);
i += 1;
}
static_allocs
}
pub fn build_types(wasm_module: &mut WasmCodeGen) {
debug_assert_eq!(
wasm_module.add_type(wasm_gen::FuncType {
params: vec![],
results: vec![wasm_gen::I32],
}),
SIGNATURE_RI32 as usize
);
debug_assert_eq!(
wasm_module.add_type(wasm_gen::FuncType {
params: vec![wasm_gen::I32],
results: vec![wasm_gen::I32],
}),
SIGNATURE_I32_RI32 as usize
);
debug_assert_eq!(
wasm_module.add_type(wasm_gen::FuncType {
params: vec![wasm_gen::I32, wasm_gen::I32],
results: vec![wasm_gen::I32],
}),
SIGNATURE_I32I32_RI32 as usize
);
debug_assert_eq!(
wasm_module.add_type(wasm_gen::FuncType {
params: vec![],
results: vec![],
}),
SIGNATURE as usize
);
debug_assert_eq!(
wasm_module.add_type(wasm_gen::FuncType {
params: vec![wasm_gen::I32],
results: vec![],
}),
SIGNATURE_I32 as usize
);
debug_assert_eq!(
wasm_module.add_type(wasm_gen::FuncType {
params: vec![wasm_gen::I32],
results: vec![],
}),
SIGNATURE_I32_I32_I32_I32_I32 as usize
);
}
pub fn build_globals(wasm_module: &mut WasmCodeGen) {
debug_assert_eq!(
wasm_module.add_mutable_global(wasm_gen::I32, 0) as i32,
PYTHON_STACK_POINTER
);
debug_assert_eq!(
wasm_module.add_mutable_global(wasm_gen::I32, 0) as u32,
PYTHON_FUNC
);
}
pub fn build_imports(
wasm_module: &mut WasmCodeGen,
end_of_elem_offset: &mut u32,
symbols: &mut HashMap<String, Symbol>,
) {
macro_rules! import_func {
($module:expr, $name:expr, $t:expr) => {{
let idx = wasm_module.add_import(
$module.to_string(),
$name.to_string(),
wasm_gen::ImportType::Func,
$t as usize,
);
symbols.insert($name.to_string(), Symbol::FuncElem(idx as u32, Linkage::JS));
let elem_offset = end_of_elem_offset.clone();
wasm_module.add_element(0, elem_offset, vec![idx as u32]) as u32;
*end_of_elem_offset += 1;
wasm_module.set_name(idx, format!("{}.{}", $module, $name).to_string());
}};
}
import_func!("lib", "dump_python_stack", SIGNATURE);
import_func!("lib", "print", SIGNATURE_I32);
}
pub fn build_intrinsics(symbols: &mut SymbolMap) {
symbols.insert(
"_dump_stack".to_string(),
Symbol::Intrinsic(python_stack::dump()),
);
}
pub fn build_exports(wasm_module: &mut WasmCodeGen) {
wasm_module.add_export(
"python_sp".to_string(),
PYTHON_STACK_POINTER as usize,
wasm_gen::ExportType::Global,
);
wasm_module.add_export(
"python_func".to_string(),
PYTHON_FUNC as usize,
wasm_gen::ExportType::Global,
);
}
pub fn build_builtins(wasm_module: &mut WasmCodeGen) {
macro_rules! build {
($builtin:expr, $sig:expr, $f:expr) => {
debug_assert_eq!(
wasm_module.add_func_with_type($f, $sig as u32),
$builtin as usize
);
wasm_module.set_name($builtin as usize, stringify!($builtin).to_string());
};
}
build!(
Builtin::PythonStackGrow,
SIGNATURE_I32_RI32,
python_stack::generate_grow()
);
build!(
Builtin::PythonStackShrink,
SIGNATURE_I32,
python_stack::generate_shrink()
);
build!(
Builtin::PythonStackPop,
SIGNATURE_RI32,
python_stack::generate_pop()
);
build!(
Builtin::PythonStackPeakLastN,
SIGNATURE_I32_RI32,
python_stack::generate_peak_last_n()
);
build!(
Builtin::PythonStackPeakLast,
SIGNATURE_RI32,
python_stack::generate_peak_last()
);
build!(
Builtin::PythonStackPush,
SIGNATURE_I32,
python_stack::generate_push()
);
build!(
Builtin::PythonStackSize,
SIGNATURE_RI32,
python_stack::generate_stack_size()
);
build!(Builtin::CallDynamic0, SIGNATURE, generate_call_dynamic(0));
build!(Builtin::CallDynamic1, SIGNATURE, generate_call_dynamic(1));
build!(Builtin::CallDynamic5, SIGNATURE, generate_call_dynamic(5));
build!(
Builtin::GetTag,
SIGNATURE_I32_RI32,
heap::generate_get_tag()
);
build!(
Builtin::BoxValue,
SIGNATURE_I32I32_RI32,
heap::generate_box_value()
);
build!(
Builtin::UnboxValue,
SIGNATURE_I32_RI32,
heap::generate_unbox_value()
);
build!(
Builtin::TrapPythonStackUnderflow,
SIGNATURE,
error::generate_trap()
);
build!(
Builtin::TrapPythonStackOverflow,
SIGNATURE,
error::generate_trap()
);
build!(
Builtin::TrapUnsupportedCallLinkage,
SIGNATURE,
error::generate_trap()
);
build!(
Builtin::TrapUnsupportedHeapObject,
SIGNATURE,
error::generate_trap()
);
}
pub fn load_func(id: u32, linkage: Linkage) -> Vec<FuncCode> {
match linkage {
Linkage::JS => vec![
FuncCode::new1(wasm_gen::I32_CONST, Imm::I32(id as i32)),
FuncCode::new1(wasm_gen::I32_CONST, Imm::I32(heap::TAG_JS_LINKAGE as i32)),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::BoxValue as i32)),
FuncCode::new1(wasm_gen::GLOBAL_SET, Imm::I32(PYTHON_FUNC as i32)),
],
Linkage::Python => vec![
FuncCode::new1(wasm_gen::I32_CONST, Imm::I32(id as i32)),
FuncCode::new1(
wasm_gen::I32_CONST,
Imm::I32(heap::TAG_PYTHON_LINKAGE as i32),
),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::BoxValue as i32)),
FuncCode::new1(wasm_gen::GLOBAL_SET, Imm::I32(PYTHON_FUNC as i32)),
],
}
}
fn compile_code_object(
code_object: &python_object::CodeObject,
wasm_module: &mut WasmCodeGen,
symbols: &mut HashMap<String, Symbol>,
end_of_data_offset: &mut u32,
end_of_elem_offset: &mut u32,
) -> Result<wasm_gen::Func, Error> {
let scratch_local0 = Imm::I32(1);
let scratch_local1 = Imm::I32(2);
let _scratch_local2 = Imm::I32(3);
let _scratch_local3 = Imm::I32(4);
debug!("------- start {} function --------", code_object.name()?);
let static_allocs = allocate_static_data(code_object, wasm_module, end_of_data_offset);
let names_tuple = code_object.names_tuple()?;
let mut code = vec![];
let mut stack = vec![];
let python_frame = PythonFrame::new(&code_object);
code.append(&mut python_frame.save_sp());
for opcode in &code_object.code {
code.append(&mut match opcode.op {
opcode::LOAD_NAME => {
let name = names_tuple.get(opcode.arg);
let symbol = find_symbol_from_python_object(symbols, &name)?;
debug!("LOAD_NAME {:?} -> {:?}", name, symbol);
match symbol {
Symbol::FuncElem(id, linkage) => load_func(id, linkage),
_ => python_stack::push(symbol),
}
}
opcode::LOAD_CONST => {
let consts = code_object.consts.clone().into_inner();
let data = consts.data.clone();
let obj = data[opcode.arg as usize].clone();
let symbol = match obj {
python_object::Object::None => Symbol::None,
python_object::Object::Int(n) => Symbol::Int32(n),
python_object::Object::Code(_) => {
stack.push(obj);
Symbol::None
}
python_object::Object::Ref(_) => {
panic!("ref should have been removed during decoding")
}
python_object::Object::Ascii(_) => {
Symbol::Data(
static_allocs
.get(&StaticType::String(opcode.arg))
.expect("could not find statically allocated string")
.clone(),
)
}
python_object::Object::Tuple(_) => {
Symbol::HeapObject(
static_allocs
.get(&StaticType::Tuple(opcode.arg))
.expect("could not find statically allocated tuple")
.clone(),
)
}
e => unimplemented!("{:?}", e),
};
debug!("LOAD_CONST {} {:?}", opcode.arg, symbol);
python_stack::push(symbol)
}
opcode::CALL_FUNCTION => {
debug!("CALL_FUNCTION, nargs {}", opcode.arg);
let target = match opcode.arg {
0 => Builtin::CallDynamic0,
1 => Builtin::CallDynamic1,
5 => Builtin::CallDynamic5,
n => panic!("{}", n),
};
let mut code = vec![];
code.append(&mut vec![
FuncCode::new1(wasm_gen::CALL, Imm::I32(target as i32)),
]);
code.append(&mut python_stack::push(Symbol::None));
code
}
opcode::LOAD_GLOBAL => {
let name = names_tuple.get(opcode.arg);
let symbol = find_symbol_from_python_object(symbols, &name)?;
debug!("LOAD_GLOBAL, target {:?}", symbol);
match symbol {
Symbol::FuncElem(id, linkage) => load_func(id, linkage),
_ => python_stack::push(symbol),
}
}
opcode::MAKE_FUNCTION => {
debug!("MAKE_FUNCTION {}", opcode.arg);
if opcode.arg & 0x08 != 0 {
unimplemented!();
}
if opcode.arg & 0x04 != 0 {
unimplemented!();
}
if opcode.arg & 0x02 != 0 {
unimplemented!();
}
if opcode.arg & 0x01 != 0 {
unimplemented!();
}
let mut code = vec![];
code.append(&mut vec![
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::PythonStackPop as i32)),
FuncCode::new0(wasm_gen::DROP),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::PythonStackPop as i32)),
FuncCode::new0(wasm_gen::DROP),
]);
code.append(&mut python_stack::push(Symbol::None));
let code_object = match stack.pop() {
Some(python_object::Object::Code(code)) => code,
_ => panic!("code not found"),
};
let func = compile_code_object(
&code_object,
wasm_module,
symbols,
end_of_data_offset,
end_of_elem_offset,
)?;
let idx = wasm_module.add_func_with_type(func, SIGNATURE as u32);
wasm_module.set_name(idx, code_object.name()?);
let elem_offset = end_of_elem_offset.clone();
wasm_module.add_element(0, elem_offset, vec![idx as u32]) as u32;
let symbol = Symbol::FuncElem(elem_offset, Linkage::Python);
symbols.insert(code_object.name()?, symbol.clone());
*end_of_elem_offset += 1;
code
}
opcode::STORE_NAME => {
let name = names_tuple.get(opcode.arg);
let mut code = vec![];
code.append(&mut vec![FuncCode::new1(
wasm_gen::CALL,
Imm::I32(Builtin::PythonStackPop as i32),
)]);
let symbol = if let Ok(symbol) = find_symbol_from_python_object(symbols, &name) {
symbol.clone()
} else {
let globalidx = wasm_module.add_mutable_global(wasm_gen::I32, 0) as u32;
let symbol = Symbol::Global(globalidx);
debug!("new symbol {} refers to {:?}", name.as_string()?, symbol);
symbols.insert(name.as_string()?, symbol.clone());
symbol
};
debug!("STORE_NAME in {:?}", symbol);
match symbol {
Symbol::Global(idx) => {
code.append(&mut vec![FuncCode::new1(
wasm_gen::GLOBAL_SET,
Imm::I32(idx as i32),
)]);
}
Symbol::FuncElem(_, _) => {
code.append(&mut vec![FuncCode::new0(wasm_gen::DROP)]);
}
_ => panic!("unsupported storage for name"),
};
code
}
opcode::POP_TOP => {
debug!("POP_TOP");
vec![
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::PythonStackPop as i32)),
FuncCode::new0(wasm_gen::DROP),
]
}
opcode::LOAD_FAST => {
debug!("LOAD_FAST {}", opcode.arg);
let mut code = vec![];
code.append(&mut python_frame.load_local(opcode.arg));
code.append(&mut vec![FuncCode::new1(
wasm_gen::CALL,
Imm::I32(Builtin::PythonStackPush as i32),
)]);
code
}
opcode::RETURN_VALUE => {
debug!("RETURN_VALUE");
vec![
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::PythonStackPop as i32)),
FuncCode::new0(wasm_gen::DROP),
]
}
opcode::STORE_FAST => {
debug!("STORE_FAST {}", opcode.arg);
python_frame.store_local(opcode.arg)
}
opcode::DELETE_FAST => {
let name = code_object.varnames_tuple()?.get(opcode.arg).as_string()?;
debug!("DELETE_FAST {} {:?}", opcode.arg, name);
python_frame.del_local(opcode.arg)
}
opcode::BUILD_CONST_KEY_MAP => {
let size = opcode.arg;
let mut code = vec![];
code.append(&mut vec![
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::PythonStackPop as i32)),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::UnboxValue as i32)),
FuncCode::new1(wasm_gen::LOCAL_SET, scratch_local0),
]);
let keys = HeapTuple::from_symbol(Symbol::WasmLocal(scratch_local0));
let unboxed_ptr = end_of_data_offset.clone();
let boxed_ptr = unboxed_ptr | (heap::TAG_DICT as u32) << 28;
let dict_symbol = Symbol::HeapObject(boxed_ptr);
debug!("BUILD_CONST_KEY_MAP {} at {:?}", size, dict_symbol.clone());
let dict = HeapDict::from_symbol(Symbol::Data(unboxed_ptr));
*end_of_data_offset +=
wasm_module.add_data(end_of_data_offset.clone(), dict.serialize_empty(size));
code.append(&mut dict.build_const_key_map(&keys, size));
for _ in 0..size {
code.append(&mut vec![
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::PythonStackPop as i32)),
FuncCode::new0(wasm_gen::DROP),
]);
}
code.append(&mut python_stack::push(dict_symbol));
code
}
opcode::BINARY_SUBSCR => {
debug!("BINARY_SUBSCR");
let mut code = vec![];
code.append(&mut vec![
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::PythonStackPop as i32)),
FuncCode::new1(wasm_gen::LOCAL_SET, scratch_local0),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::PythonStackPop as i32)),
FuncCode::new1(wasm_gen::LOCAL_SET, scratch_local1),
]);
code.append(&mut vec![
FuncCode::new1(wasm_gen::LOCAL_GET, scratch_local1),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::GetTag as i32)),
FuncCode::new1(wasm_gen::I32_CONST, Imm::I32(heap::TAG_TUPLE as i32)),
FuncCode::new0(wasm_gen::I32_EQ),
FuncCode::new_control(wasm_gen::IF, wasm_gen::NONE),
FuncCode::new1(wasm_gen::LOCAL_GET, scratch_local1),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::UnboxValue as i32)),
FuncCode::new1(wasm_gen::LOCAL_SET, scratch_local1),
]);
let tuple = HeapTuple::from_symbol(Symbol::WasmLocal(scratch_local1));
code.append(&mut tuple.get_item(Symbol::WasmLocal(scratch_local0)));
code.append(&mut python_stack::push(Symbol::WasmTopOfStack));
code.append(&mut vec![
FuncCode::new0(wasm_gen::END),
]);
code.append(&mut vec![
FuncCode::new1(wasm_gen::LOCAL_GET, scratch_local1),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::GetTag as i32)),
FuncCode::new1(wasm_gen::I32_CONST, Imm::I32(heap::TAG_DICT as i32)),
FuncCode::new0(wasm_gen::I32_EQ),
FuncCode::new_control(wasm_gen::IF, wasm_gen::NONE),
FuncCode::new1(wasm_gen::LOCAL_GET, scratch_local1),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::UnboxValue as i32)),
FuncCode::new1(wasm_gen::LOCAL_SET, scratch_local1),
]);
let dict = HeapDict::from_symbol(Symbol::WasmLocal(scratch_local1));
code.append(&mut dict.get(Symbol::WasmLocal(scratch_local0)));
code.append(&mut python_stack::push(Symbol::WasmTopOfStack));
code.append(&mut vec![
FuncCode::new0(wasm_gen::END),
]);
code
}
opcode::COMPARE_OP => {
debug!("COMPARE_OP {}", opcode.arg);
let mut code = vec![];
code.append(&mut vec![
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::PythonStackPop as i32)),
FuncCode::new1(wasm_gen::LOCAL_SET, scratch_local0),
FuncCode::new1(wasm_gen::CALL, Imm::I32(Builtin::PythonStackPop as i32)),
FuncCode::new1(wasm_gen::LOCAL_SET, scratch_local1),
]);
code.append(&mut op::compare(
opcode.arg.into(),
Symbol::WasmLocal(scratch_local1),
Symbol::WasmLocal(scratch_local0),
));
code.append(&mut python_stack::push(Symbol::WasmTopOfStack));
code
}
op => unimplemented!("compile {}", opcode::to_string(op)),
})
}
code.append(&mut python_frame.restore_sp());
debug!("------- end {} function --------", code_object.name()?);
Ok(wasm_gen::Func {
sig: wasm_gen::FuncType {
params: vec![],
results: vec![],
},
locals: vec![
(1, wasm_gen::I32),
(4, wasm_gen::I32),
],
code,
})
}
fn find_symbol_from_python_object(
symbols: &SymbolMap,
obj: &python_object::Object,
) -> Result<Symbol, Error> {
let symbol_name = match obj {
python_object::Object::Ascii(s) => s.to_string(),
python_object::Object::Ref(_) => panic!("ref should have been removed during decoding"),
e => panic!("{:?}", e),
};
find_symbol(symbols, &symbol_name)
}
fn find_symbol<'a>(symbols: &HashMap<String, Symbol>, name: &'a str) -> Result<Symbol, Error> {
if let Some(symbol) = symbols.get(name) {
Ok(symbol.clone())
} else {
failure::bail!("symbol {} not found", name);
}
}