Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactoring interpreter and paranoid mode, introducing traits to allo… #15350

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

ziaptos
Copy link
Contributor

@ziaptos ziaptos commented Nov 21, 2024

Description

Refactoring interpreter and paranoid mode, introducing traits to allow generic interpreter as well as compile time switch for the runtime type checks (formerly called paranoid mode)

How Has This Been Tested?

Existing tests

Key Areas to Review

Should focus on making sure that the high level logic has not changed!

Type of Change

  • New feature
  • Bug fix
  • Breaking change
  • Performance improvement
  • Refactoring
  • Dependency update
  • Documentation update
  • Tests

Which Components or Systems Does This Change Impact?

  • Validator Node
  • Full Node (API, Indexer, etc.)
  • Move/Aptos Virtual Machine
  • Aptos Framework
  • Aptos CLI/SDK
  • Developer Infrastructure
  • Move Compiler
  • Other (specify)

Checklist

  • I have read and followed the CONTRIBUTING doc
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I identified and added all stakeholders and component owners affected by this change as reviewers
  • I tested both happy and unhappy path of the functionality
  • I have made corresponding changes to the documentation

…w generic interpreter as well as compile time switch for the runtime type checks (formerly called paranoid mode)
Copy link

trunk-io bot commented Nov 21, 2024

⏱️ 31m total CI duration on this PR
Job Cumulative Duration Recent Runs
rust-move-tests 12m 🟩
rust-move-tests 10m
rust-cargo-deny 4m 🟩🟩
check-dynamic-deps 3m 🟩🟩
general-lints 53s 🟩🟩
semgrep/ci 44s 🟩🟩
file_change_determinator 19s 🟩🟩
permission-check 6s 🟩🟩
permission-check 4s 🟩🟩

settingsfeedbackdocs ⋅ learn more about trunk.io

@@ -72,7 +72,7 @@ pub(crate) fn trace(
pc: u16,
instr: &Bytecode,
resolver: &Resolver,
interp: &Interpreter,
interp: &InterpreterImpl,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: interp --> interpreter

struct_variant_instantiation_type:
BTreeMap<StructVariantInstantiationIndex, (Type, NumTypeNodes)>,
/// For a given field instantiation, the:
/// ((Type of the field, size of the field type) and (Type of its defining struct, size of its defining struct)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line too long, break at 100?

/// ((Type of the field, size of the field type) and (Type of its defining struct, size of its defining struct)
field_instantiation:
BTreeMap<FieldInstantiationIndex, ((Type, NumTypeNodes), (Type, NumTypeNodes))>,
/// Same as above, bot for variant field instantiations
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: bot --> but?

}

#[inline(always)]
pub(crate) fn get_field_type_and_struct_type(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are just copy-paste, right?

Ok(((field_ty, *field_ty_count), (struct_ty, *struct_ty_count)))
}

pub(crate) fn get_variant_field_type_and_struct_type(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency, #[inline(always)]?😄

operand_stack.push_ty(output_ty)
}

pub(crate) struct NullRuntimeTypeCheck;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See some C++ here ahah, NoRuntimeTypeCheck maybe?


/// Paranoid type checks to perform after instruction execution.
///
/// This function and `pre_execution_type_stack_transition` should constitute the full type stack transition for the paranoid mode.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think lines are > 100 chars again?

| Bytecode::Call(_)
| Bytecode::CallGeneric(_)
| Bytecode::Abort => {
// Invariants hold because all of the instructions above will force VM to break from the interpreter loop and thus not hit this code path.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

again, multiple lines

) -> PartialVMResult<()>;
}

/// Paranoid type checks to perform before instruction execution.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is meant for the module, you can do //! Your description here on top of the file? This also seems like a good documentation to add to trait definition?

.into_iter()
.zip(field_tys)
{
// Fields ability should be a subset of the struct ability because abilities can be weakened but not the other direction.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lines too long


/// Main loop for the execution of a function.
///
/// This function sets up a `Frame` and calls `execute_code_unit` to execute code of the
/// function represented by the frame. Control comes back to this function on return or
/// on call. When that happens the frame is changes to a new one (call) or to the one
/// at the top of the stack (return). If the call stack is empty execution is completed.
fn execute_main(
fn execute_main<RTTCheck: RuntimeTypeCheck>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the generic bound name :)

@@ -1147,7 +1204,7 @@ const CALL_STACK_SIZE_LIMIT: usize = 1024;
pub(crate) const ACCESS_STACK_SIZE_LIMIT: usize = 256;

/// The operand stack.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: "operand and type"?

}

impl InterpreterDebugInterface for InterpreterImpl {
#[allow(dead_code)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use some cfg(any(...)) or so? Seems like this is only used if some cfg feature is on

active_modules: HashSet::new(),
};

if loader.vm_config().paranoid_type_checks {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is beautiful! One thing to note: we also have some paranoid checks inside execution loop (e.g., for functions). These can also be moved to this generic, but maybe you have a separate PR for that?

@@ -57,9 +57,21 @@ macro_rules! set_err_info {
///
/// An `Interpreter` instance is a stand alone execution context for a function.
/// It mimics execution on a single thread, with an call stack and an operand stack.
pub(crate) struct Interpreter {
pub(crate) struct Interpreter;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is this used? I see only Impl

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants