Remove bytecode compilation. Add feature to enable verbose logging in vm.

This commit is contained in:
Windel Bouwman committed 2019-07-07 15:23:43 +02:00
1 parent cc24b73031
commit 310f89ec21
9 files changed
+29 -92

No files matched your search

-60
View File
@@ -1,60 +0,0 @@
import bytecode
import sys
import json
import types
class CodeEncoder(json.JSONEncoder):
def default(self, obj):
if (isinstance(obj, types.CodeType)):
return serialize_code(obj)
return json.JSONEncoder.default(self, obj)
def serialize_code(code):
c = bytecode.Bytecode().from_code(code).to_concrete_bytecode()
return (
{
"co_consts": consts_to_rust_enum(c.consts),
"co_names": c.names,
"co_name": c.name,
"co_code": parse_co_code_to_str(c),
"co_varnames": c.varnames
}
)
def consts_to_rust_enum(consts):
def capitalize_first(s):
return s[0].upper() + s[1:]
def const_to_rust_enum(const):
if type(const).__name__ == "tuple":
return {capitalize_first(str(type(const).__name__)): list(map(const_to_rust_enum, const))}
else:
return {capitalize_first(str(type(const).__name__)): const}
return list(map(const_to_rust_enum, consts))
def parse_co_code_to_str(c):
return list(
map(lambda op: (op.size, op.name, op.arg if op.arg != bytecode.UNSET else None),
c)
)
def compile_to_bytecode(filename, out_file=None):
with open(filename, 'rU') as f:
code = f.read()
code = compile(code, filename, "exec")
print(CodeEncoder(indent=4).encode(code), file=out_file)
def main():
filename = sys.argv[1]
compile_to_bytecode(filename)
if __name__ == "__main__":
main()
-19
View File
@@ -13,8 +13,6 @@ import enum
from pathlib import Path
import shutil
import compile_code
class _TestType(enum.Enum):
functional = 1
@@ -40,8 +38,6 @@ def perform_test(filename, method, test_type):
logger.info("Running %s via %s", filename, method)
if method == "cpython":
run_via_cpython(filename)
elif method == "cpython_bytecode":
run_via_cpython_bytecode(filename, test_type)
elif method == "rustpython":
run_via_rustpython(filename, test_type)
else:
@@ -54,20 +50,6 @@ def run_via_cpython(filename):
subprocess.check_call([sys.executable, filename], env=env)
def run_via_cpython_bytecode(filename, test_type):
# Step1: Create bytecode file:
bytecode_filename = filename + ".bytecode"
with open(bytecode_filename, "w") as f:
compile_code.compile_to_bytecode(filename, out_file=f)
# Step2: run cpython bytecode:
env = os.environ.copy()
env["RUST_LOG"] = "info,cargo=error,jobserver=error"
env["RUST_BACKTRACE"] = "1"
with pushd(CPYTHON_RUNNER_DIR):
subprocess.check_call(["cargo", "run", bytecode_filename], env=env)
def run_via_rustpython(filename, test_type):
env = os.environ.copy()
env['RUST_LOG'] = 'info,cargo=error,jobserver=error'
@@ -142,7 +124,6 @@ def generate_slices(path):
@populate("cpython")
# @populate('cpython_bytecode')
@populate("rustpython")
class SampleTestCase(unittest.TestCase):
@classmethod
+1
View File
@@ -9,6 +9,7 @@ edition = "2018"
[features]
default = ["rustpython-parser", "rustpython-compiler"]
vm-tracing-logging = []
[dependencies]
# Crypto:
+4 -1
View File
@@ -295,7 +295,7 @@ impl Frame {
let traceback = vm
.get_attribute(exception.clone(), "__traceback__")
.unwrap();
trace!("Adding to traceback: {:?} {:?}", traceback, lineno);
vm_trace!("Adding to traceback: {:?} {:?}", traceback, lineno);
let raise_location = vm.ctx.new_tuple(vec![
vm.ctx.new_str(filename.clone()),
vm.ctx.new_int(lineno.row()),
@@ -335,6 +335,8 @@ impl Frame {
/// Execute a single instruction.
fn execute_instruction(&self, vm: &VirtualMachine) -> FrameResult {
let instruction = self.fetch_instruction();
#[cfg(feature = "vm-tracing-logging")]
{
trace!("=======");
/* TODO:
@@ -1142,6 +1144,7 @@ impl Frame {
fn jump(&self, label: bytecode::Label) {
let target_pc = self.code.label_map[&label];
#[cfg(feature = "vm-tracing-logging")]
trace!("jump from {:?} to {:?}", self.lasti, target_pc);
*self.lasti.borrow_mut() = target_pc;
}
+11
View File
@@ -256,3 +256,14 @@ macro_rules! match_class {
}
};
}
/// Super detailed logging. Might soon overflow your logbuffers
/// Default, this logging is discarded, except when a the `vm-tracing-logging`
/// build feature is enabled.
macro_rules! vm_trace {
($($arg:tt)+) => {
#[cfg(feature = "vm-tracing-logging")]
trace!($($arg)+);
}
}
+1 -1
View File
@@ -43,7 +43,7 @@ impl PyNoneRef {
}
fn get_attribute(self, name: PyStringRef, vm: &VirtualMachine) -> PyResult {
trace!("None.__getattribute__({:?}, {:?})", self, name);
vm_trace!("None.__getattribute__({:?}, {:?})", self, name);
let cls = self.class();
// Properties use a comparision with None to determine if they are either invoked by am
+2 -2
View File
@@ -66,7 +66,7 @@ fn object_setattr(
value: PyObjectRef,
vm: &VirtualMachine,
) -> PyResult<()> {
trace!("object.__setattr__({:?}, {}, {:?})", obj, attr_name, value);
vm_trace!("object.__setattr__({:?}, {}, {:?})", obj, attr_name, value);
let cls = obj.class();
if let Some(attr) = objtype::class_get_attr(&cls, &attr_name.value) {
@@ -220,7 +220,7 @@ fn object_dict_setter(
fn object_getattribute(obj: PyObjectRef, name_str: PyStringRef, vm: &VirtualMachine) -> PyResult {
let name = &name_str.value;
trace!("object.__getattribute__({:?}, {:?})", obj, name);
vm_trace!("object.__getattribute__({:?}, {:?})", obj, name);
let cls = obj.class();
if let Some(attr) = objtype::class_get_attr(&cls, &name) {
+4 -4
View File
@@ -114,7 +114,7 @@ impl PyClassRef {
fn getattribute(self, name_ref: PyStringRef, vm: &VirtualMachine) -> PyResult {
let name = &name_ref.value;
trace!("type.__getattribute__({:?}, {:?})", self, name);
vm_trace!("type.__getattribute__({:?}, {:?})", self, name);
let mcl = self.class();
if let Some(attr) = class_get_attr(&mcl, &name) {
@@ -241,7 +241,7 @@ pub fn issubclass(subclass: &PyClassRef, cls: &PyClassRef) -> bool {
}
pub fn type_new(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
debug!("type.__new__ {:?}", args);
vm_trace!("type.__new__ {:?}", args);
if args.args.len() == 2 {
Ok(args.args[1].class().into_object())
} else if args.args.len() == 4 {
@@ -265,7 +265,7 @@ pub fn type_new_class(
}
pub fn type_call(class: PyClassRef, args: Args, kwargs: KwArgs, vm: &VirtualMachine) -> PyResult {
debug!("type_call: {:?}", class);
vm_trace!("type_call: {:?}", class);
let new = class_get_attr(&class, "__new__").expect("All types should have a __new__.");
let new_wrapped = vm.call_get_descriptor(new, class.into_object())?;
let obj = vm.invoke(new_wrapped, (&args, &kwargs))?;
@@ -353,7 +353,7 @@ fn take_next_base(mut bases: Vec<Vec<PyClassRef>>) -> Option<(PyClassRef, Vec<Ve
}
fn linearise_mro(mut bases: Vec<Vec<PyClassRef>>) -> Option<Vec<PyClassRef>> {
debug!("Linearising MRO: {:?}", bases);
vm_trace!("Linearising MRO: {:?}", bases);
let mut result = vec![];
loop {
if (&bases).iter().all(Vec::is_empty) {
+6 -5
View File
@@ -170,7 +170,7 @@ impl VirtualMachine {
fn new_exception_obj(&self, exc_type: PyClassRef, args: Vec<PyObjectRef>) -> PyResult {
// TODO: add repr of args into logging?
info!("New exception created: {}", exc_type.name);
vm_trace!("New exception created: {}", exc_type.name);
self.invoke(exc_type.into_object(), args)
}
@@ -377,7 +377,7 @@ impl VirtualMachine {
let cls = obj.class();
match objtype::class_get_attr(&cls, method_name) {
Some(func) => {
trace!(
vm_trace!(
"vm.call_method {:?} {:?} {:?} -> {:?}",
obj,
cls,
@@ -392,7 +392,8 @@ impl VirtualMachine {
}
fn _invoke(&self, func_ref: PyObjectRef, args: PyFuncArgs) -> PyResult {
trace!("Invoke: {:?} {:?}", func_ref, args);
vm_trace!("Invoke: {:?} {:?}", func_ref, args);
if let Some(PyFunction {
ref code,
ref scope,
@@ -411,7 +412,7 @@ impl VirtualMachine {
value(self, args)
} else {
// TODO: is it safe to just invoke __call__ otherwise?
trace!("invoke __call__ for: {:?}", &func_ref.payload);
vm_trace!("invoke __call__ for: {:?}", &func_ref.payload);
self.call_method(&func_ref, "__call__", args)
}
}
@@ -630,7 +631,7 @@ impl VirtualMachine {
T: TryIntoRef<PyString>,
{
let attr_name = attr_name.try_into_ref(self)?;
trace!("vm.__getattribute__: {:?} {:?}", obj, attr_name);
vm_trace!("vm.__getattribute__: {:?} {:?}", obj, attr_name);
self.call_method(&obj, "__getattribute__", vec![attr_name.into_object()])
}