diff --git a/derive/src/pystructseq.rs b/derive/src/pystructseq.rs
index 236f10efdd..0da5fa3831 100644
--- a/derive/src/pystructseq.rs
+++ b/derive/src/pystructseq.rs
@@ -36,7 +36,7 @@ pub(crate) fn impl_pystruct_sequence(
                     self.#field_names,
                     vm,
                 )),*];
-                ::rustpython_vm::builtins::tuple::PyTuple::_new(items.into_boxed_slice())
+                ::rustpython_vm::builtins::tuple::PyTuple::new_unchecked(items.into_boxed_slice())
             }
         }
         impl ::rustpython_vm::IntoPyObject for #ty {
diff --git a/vm/src/builtins/memory.rs b/vm/src/builtins/memory.rs
index 4e3f23218d..eaf8539c77 100644
--- a/vm/src/builtins/memory.rs
+++ b/vm/src/builtins/memory.rs
@@ -11,7 +11,7 @@ use crate::{
     protocol::{BufferInternal, BufferOptions, PyBuffer},
     sliceable::{convert_slice, wrap_index, SequenceIndex},
     slots::{AsBuffer, Comparable, Hashable, PyComparisonOp, SlotConstructor},
-    stdlib::pystruct::_struct::FormatSpec,
+    stdlib::pystruct::FormatSpec,
     utils::Either,
     IdProtocol, IntoPyObject, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef,
     PyResult, PyValue, TryFromBorrowedObject, TryFromObject, TypeProtocol, VirtualMachine,
diff --git a/vm/src/builtins/mod.rs b/vm/src/builtins/mod.rs
index 29d96cd0e6..9dc9f94ba9 100644
--- a/vm/src/builtins/mod.rs
+++ b/vm/src/builtins/mod.rs
@@ -63,7 +63,7 @@ pub use pytype::{PyType, PyTypeRef};
 pub(crate) mod range;
 pub use range::PyRange;
 pub(crate) mod set;
-pub use set::PySet;
+pub use set::{PyFrozenSet, PySet};
 pub(crate) mod singletons;
 pub use singletons::{PyNone, PyNotImplemented};
 pub(crate) mod slice;
@@ -84,7 +84,4 @@ pub use zip::PyZip;
 pub use float::try_to_bigint as try_f64_to_bigint;
 pub use int::try_to_float as try_bigint_to_f64;
 
-mod make_module;
-pub use make_module::{ascii, make_module, print};
-
 pub use crate::exceptions::types::*;
diff --git a/vm/src/builtins/pystr.rs b/vm/src/builtins/pystr.rs
index e29939296b..38be33ecde 100644
--- a/vm/src/builtins/pystr.rs
+++ b/vm/src/builtins/pystr.rs
@@ -477,7 +477,7 @@ impl PyStr {
     }
 
     #[pymethod(magic)]
-    pub(crate) fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
+    pub fn repr(&self, vm: &VirtualMachine) -> PyResult<String> {
         let in_len = self.byte_len();
         let mut out_len = 0usize;
         // let mut max = 127;
diff --git a/vm/src/builtins/pytype.rs b/vm/src/builtins/pytype.rs
index 6d494ca5d3..71a27a327a 100644
--- a/vm/src/builtins/pytype.rs
+++ b/vm/src/builtins/pytype.rs
@@ -302,7 +302,7 @@ impl PyType {
     #[pyproperty(name = "__mro__")]
     fn get_mro(zelf: PyRef<Self>) -> PyTuple {
         let elements: Vec<PyObjectRef> = zelf.iter_mro().map(|x| x.as_object().clone()).collect();
-        PyTuple::_new(elements.into_boxed_slice())
+        PyTuple::new_unchecked(elements.into_boxed_slice())
     }
 
     #[pyproperty(magic)]
diff --git a/vm/src/builtins/tuple.rs b/vm/src/builtins/tuple.rs
index c10f30420b..65666cbf2e 100644
--- a/vm/src/builtins/tuple.rs
+++ b/vm/src/builtins/tuple.rs
@@ -115,7 +115,7 @@ impl PyTuple {
     /// Creating a new tuple with given boxed slice.
     /// NOTE: for usual case, you probably want to use PyTupleRef::with_elements.
     /// Calling this function implies trying micro optimization for non-zero-sized tuple.
-    pub(crate) fn _new(elements: Box<[PyObjectRef]>) -> Self {
+    pub fn new_unchecked(elements: Box<[PyObjectRef]>) -> Self {
         Self { elements }
     }
 
diff --git a/vm/src/format.rs b/vm/src/format.rs
index ddbda3ee99..30eb286393 100644
--- a/vm/src/format.rs
+++ b/vm/src/format.rs
@@ -1,8 +1,9 @@
 use crate::{
-    builtins::{self, PyBaseExceptionRef, PyStrRef},
+    builtins::{PyBaseExceptionRef, PyStrRef},
     common::float_ops,
     exceptions::IntoPyException,
     function::FuncArgs,
+    stdlib::builtins,
     ItemProtocol, PyObjectRef, PyResult, TypeProtocol, VirtualMachine,
 };
 use itertools::{Itertools, PeekingNext};
diff --git a/vm/src/frame.rs b/vm/src/frame.rs
index 9c7c28dab3..2d77e3eae6 100644
--- a/vm/src/frame.rs
+++ b/vm/src/frame.rs
@@ -1,8 +1,6 @@
 use crate::common::{boxvec::BoxVec, lock::PyMutex};
 use crate::{
-    builtins::PyBaseExceptionRef,
     builtins::{
-        self,
         asyncgenerator::PyAsyncGenWrappedValue,
         coroutine::PyCoroutine,
         function::{PyCell, PyCellRef, PyFunction},
@@ -10,7 +8,7 @@ use crate::{
         list, pystr, set,
         traceback::PyTraceback,
         tuple::{PyTuple, PyTupleTyped},
-        PyCode, PyDict, PyDictRef, PySlice, PyStr, PyStrRef, PyTypeRef,
+        PyBaseExceptionRef, PyCode, PyDict, PyDictRef, PySlice, PyStr, PyStrRef, PyTypeRef,
     },
     bytecode,
     coroutine::Coro,
@@ -20,6 +18,7 @@ use crate::{
     protocol::PyIter,
     scope::Scope,
     slots::PyComparisonOp,
+    stdlib::builtins,
     IdProtocol, ItemProtocol, PyMethod, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
     TypeProtocol, VirtualMachine,
 };
diff --git a/vm/src/lib.rs b/vm/src/lib.rs
index 5b089dafea..e0ee8068e9 100644
--- a/vm/src/lib.rs
+++ b/vm/src/lib.rs
@@ -60,7 +60,7 @@ mod frozen;
 pub mod function;
 pub mod import;
 pub mod iterator;
-mod protocol;
+pub mod protocol;
 pub mod py_io;
 pub mod py_serde;
 mod pyobject;
@@ -69,12 +69,12 @@ pub mod readline;
 pub mod scope;
 mod sequence;
 mod signal;
-mod sliceable;
+pub mod sliceable;
 pub mod slots;
 pub mod stdlib;
 pub mod types;
 pub mod utils;
-mod version;
+pub mod version;
 mod vm;
 
 // pub use self::Executor;
diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs
index fe2ef73971..0eabfe0d76 100644
--- a/vm/src/pyobject.rs
+++ b/vm/src/pyobject.rs
@@ -106,7 +106,7 @@ impl PyContext {
         let false_value = create_object(PyInt::from(0), &types.bool_type);
 
         let empty_tuple = create_object(
-            PyTuple::_new(Vec::new().into_boxed_slice()),
+            PyTuple::new_unchecked(Vec::new().into_boxed_slice()),
             &types.tuple_type,
         );
         let empty_frozenset =
diff --git a/vm/src/sliceable.rs b/vm/src/sliceable.rs
index b366d9b4bf..0eb5fd1bea 100644
--- a/vm/src/sliceable.rs
+++ b/vm/src/sliceable.rs
@@ -404,7 +404,7 @@ pub(crate) fn wrap_index(p: isize, len: usize) -> Option<usize> {
 }
 
 // return pos is in range [0, len] inclusive
-pub(crate) fn saturate_index(p: isize, len: usize) -> usize {
+pub fn saturate_index(p: isize, len: usize) -> usize {
     let mut p = p;
     let len = len.to_isize().unwrap();
     if p < 0 {
diff --git a/vm/src/builtins/make_module.rs b/vm/src/stdlib/builtins.rs
similarity index 99%
rename from vm/src/builtins/make_module.rs
rename to vm/src/stdlib/builtins.rs
index 964da58e6c..8edfea6189 100644
--- a/vm/src/builtins/make_module.rs
+++ b/vm/src/stdlib/builtins.rs
@@ -6,8 +6,8 @@ use crate::{PyObjectRef, VirtualMachine};
 /// Built-in functions, exceptions, and other objects.
 ///
 /// Noteworthy: None is the `nil' object; Ellipsis represents `...' in slices.
-#[pymodule(name = "builtins")]
-mod decl {
+#[pymodule]
+mod builtins {
     use crate::builtins::{
         enumerate::PyReverseSequenceIterator,
         function::{PyCellRef, PyFunctionRef},
@@ -891,12 +891,12 @@ mod decl {
     }
 }
 
-pub use decl::{ascii, print};
+pub use builtins::{ascii, print};
 
 pub fn make_module(vm: &VirtualMachine, module: PyObjectRef) {
     let ctx = &vm.ctx;
 
-    decl::extend_module(vm, &module);
+    builtins::extend_module(vm, &module);
 
     let debug_mode: bool = vm.state.settings.optimize == 0;
     extend_module!(vm, module, {
diff --git a/vm/src/stdlib/fcntl.rs b/vm/src/stdlib/fcntl.rs
index 5a0b0a21b6..f0302dda83 100644
--- a/vm/src/stdlib/fcntl.rs
+++ b/vm/src/stdlib/fcntl.rs
@@ -3,7 +3,7 @@ pub(crate) use fcntl::make_module;
 #[pymodule]
 mod fcntl {
     use crate::{
-        builtins::int,
+        builtins::PyIntRef,
         function::{ArgMemoryBuffer, ArgStrOrBytesLike, OptionalArg},
         stdlib::{io, os},
         utils::Either,
@@ -25,7 +25,7 @@ mod fcntl {
     fn fcntl(
         io::Fildes(fd): io::Fildes,
         cmd: i32,
-        arg: OptionalArg<Either<ArgStrOrBytesLike, int::PyIntRef>>,
+        arg: OptionalArg<Either<ArgStrOrBytesLike, PyIntRef>>,
         vm: &VirtualMachine,
     ) -> PyResult {
         let int = match arg {
diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs
index 548b652058..ba705f7044 100644
--- a/vm/src/stdlib/io.rs
+++ b/vm/src/stdlib/io.rs
@@ -35,7 +35,7 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef {
 #[allow(unused)]
 #[derive(Copy, Clone)]
 #[repr(transparent)]
-pub(crate) struct Fildes(pub i32);
+pub struct Fildes(pub i32);
 
 impl TryFromObject for Fildes {
     fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
diff --git a/vm/src/stdlib/mod.rs b/vm/src/stdlib/mod.rs
index 8861c444ac..f2d73cc6b8 100644
--- a/vm/src/stdlib/mod.rs
+++ b/vm/src/stdlib/mod.rs
@@ -4,6 +4,7 @@ pub(crate) mod ast;
 mod atexit;
 mod binascii;
 mod bisect;
+pub mod builtins;
 mod cmath;
 mod codecs;
 mod collections;
diff --git a/vm/src/stdlib/nt.rs b/vm/src/stdlib/nt.rs
index c55a42f590..3c08219d81 100644
--- a/vm/src/stdlib/nt.rs
+++ b/vm/src/stdlib/nt.rs
@@ -427,3 +427,11 @@ macro_rules! suppress_iph {
         ret
     }};
 }
+
+pub fn init_winsock() {
+    static WSA_INIT: parking_lot::Once = parking_lot::Once::new();
+    WSA_INIT.call_once(|| unsafe {
+        let mut wsa_data = std::mem::MaybeUninit::uninit();
+        let _ = winapi::um::winsock2::WSAStartup(0x0101, wsa_data.as_mut_ptr());
+    })
+}
diff --git a/vm/src/stdlib/posix.rs b/vm/src/stdlib/posix.rs
index 90e3cc7f24..15961965a7 100644
--- a/vm/src/stdlib/posix.rs
+++ b/vm/src/stdlib/posix.rs
@@ -2,7 +2,7 @@ use crate::{PyObjectRef, PyResult, VirtualMachine};
 use nix;
 use std::os::unix::io::RawFd;
 
-pub(crate) fn raw_set_inheritable(fd: RawFd, inheritable: bool) -> nix::Result<()> {
+pub fn raw_set_inheritable(fd: RawFd, inheritable: bool) -> nix::Result<()> {
     use nix::fcntl;
     let flags = fcntl::FdFlag::from_bits_truncate(fcntl::fcntl(fd, fcntl::FcntlArg::F_GETFD)?);
     let mut new_flags = flags;
diff --git a/vm/src/stdlib/pystruct.rs b/vm/src/stdlib/pystruct.rs
index a85a0f3f7d..085f73f92d 100644
--- a/vm/src/stdlib/pystruct.rs
+++ b/vm/src/stdlib/pystruct.rs
@@ -966,4 +966,4 @@ pub(crate) mod _struct {
     }
 }
 
-pub(crate) use _struct::make_module;
+pub(crate) use _struct::{make_module, FormatSpec};
diff --git a/vm/src/stdlib/select.rs b/vm/src/stdlib/select.rs
index a0411ca049..33a2a15e34 100644
--- a/vm/src/stdlib/select.rs
+++ b/vm/src/stdlib/select.rs
@@ -2,7 +2,9 @@ use crate::{PyObjectRef, PyResult, TryFromBorrowedObject, TryFromObject, Virtual
 use std::{io, mem};
 
 pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef {
-    super::socket::init_winsock();
+    #[cfg(windows)]
+    super::nt::init_winsock();
+
     #[cfg(unix)]
     {
         use crate::PyClassImpl;
@@ -171,7 +173,7 @@ mod decl {
                 return Err(vm.new_value_error("timeout must be positive".to_owned()));
             }
         }
-        let deadline = timeout.map(|s| time::get_time(vm).unwrap() + s);
+        let deadline = timeout.map(|s| time::time(vm).unwrap() + s);
 
         let seq2set = |list| -> PyResult<(Vec<Selectable>, FdSet)> {
             let v = vm.extract_elements::<Selectable>(list)?;
@@ -210,7 +212,7 @@ mod decl {
             vm.check_signals()?;
 
             if let Some(ref mut timeout) = timeout {
-                *timeout = deadline.unwrap() - time::get_time(vm).unwrap();
+                *timeout = deadline.unwrap() - time::time(vm).unwrap();
                 if *timeout < 0.0 {
                     r.clear();
                     w.clear();
diff --git a/vm/src/stdlib/signal.rs b/vm/src/stdlib/signal.rs
index 0eff5d1584..c696012d41 100644
--- a/vm/src/stdlib/signal.rs
+++ b/vm/src/stdlib/signal.rs
@@ -192,7 +192,7 @@ pub(crate) mod _signal {
 
         #[cfg(windows)]
         let is_socket = if fd != INVALID_WAKEUP {
-            crate::stdlib::socket::init_winsock();
+            crate::stdlib::nt::init_winsock();
             let mut res = 0i32;
             let mut res_size = std::mem::size_of::<i32>() as i32;
             let res = unsafe {
diff --git a/vm/src/stdlib/socket.rs b/vm/src/stdlib/socket.rs
index 5dd94b1368..63b8778960 100644
--- a/vm/src/stdlib/socket.rs
+++ b/vm/src/stdlib/socket.rs
@@ -1818,7 +1818,8 @@ rustpython_common::static_cell! {
 }
 
 pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
-    init_winsock();
+    #[cfg(windows)]
+    super::nt::init_winsock();
 
     let ctx = &vm.ctx;
     let socket_timeout = TIMEOUT_ERROR
@@ -1978,14 +1979,3 @@ fn extend_module_platform_specific(vm: &VirtualMachine, module: &PyObjectRef) {
         "sethostname" => named_function!(ctx, _socket, sethostname),
     });
 }
-
-pub fn init_winsock() {
-    #[cfg(windows)]
-    {
-        static WSA_INIT: parking_lot::Once = parking_lot::Once::new();
-        WSA_INIT.call_once(|| unsafe {
-            let mut wsa_data = std::mem::MaybeUninit::uninit();
-            let _ = winapi::um::winsock2::WSAStartup(0x0101, wsa_data.as_mut_ptr());
-        })
-    }
-}
diff --git a/vm/src/stdlib/sys.rs b/vm/src/stdlib/sys.rs
index 11cd2d17db..fda309a85d 100644
--- a/vm/src/stdlib/sys.rs
+++ b/vm/src/stdlib/sys.rs
@@ -1,18 +1,20 @@
-use num_traits::ToPrimitive;
-use std::{env, mem, path};
-
-use crate::builtins::{PyStr, PyStrRef, PyTypeRef};
 use crate::common::{
     ascii,
     hash::{PyHash, PyUHash},
 };
-use crate::frame::FrameRef;
-use crate::function::{FuncArgs, OptionalArg, PosArgs};
-use crate::vm::{PySettings, VirtualMachine};
-use crate::{builtins, exceptions, py_io, version};
 use crate::{
+    builtins::{PyStr, PyStrRef, PyTypeRef},
+    exceptions,
+    frame::FrameRef,
+    function::{FuncArgs, OptionalArg, PosArgs},
+    py_io,
+    stdlib::builtins,
+    version,
+    vm::{PySettings, VirtualMachine},
     ItemProtocol, PyClassImpl, PyContext, PyObjectRef, PyRefExact, PyResult, PyStructSequence,
 };
+use num_traits::ToPrimitive;
+use std::{env, mem, path};
 
 /*
  * The magic sys module.
diff --git a/vm/src/stdlib/time.rs b/vm/src/stdlib/time.rs
index 801c164b35..54a7409c45 100644
--- a/vm/src/stdlib/time.rs
+++ b/vm/src/stdlib/time.rs
@@ -2,7 +2,9 @@
 
 // See also:
 // https://docs.python.org/3/library/time.html
-use crate::{PyObjectRef, PyResult, VirtualMachine};
+use crate::{PyObjectRef, VirtualMachine};
+
+pub use time::*;
 
 pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef {
     let module = time::make_module(vm);
@@ -14,32 +16,6 @@ pub(crate) fn make_module(vm: &VirtualMachine) -> PyObjectRef {
     module
 }
 
-#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
-pub(crate) fn get_time(vm: &VirtualMachine) -> PyResult<f64> {
-    Ok(duration_since_system_now(vm)?.as_secs_f64())
-}
-
-#[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
-pub(crate) fn get_time(_vm: &VirtualMachine) -> PyResult<f64> {
-    use wasm_bindgen::prelude::*;
-    #[wasm_bindgen]
-    extern "C" {
-        type Date;
-        #[wasm_bindgen(static_method_of = Date)]
-        fn now() -> f64;
-    }
-    // Date.now returns unix time in milliseconds, we want it in seconds
-    Ok(Date::now() / 1000.0)
-}
-
-fn duration_since_system_now(vm: &VirtualMachine) -> PyResult<std::time::Duration> {
-    use std::time::{SystemTime, UNIX_EPOCH};
-
-    SystemTime::now()
-        .duration_since(UNIX_EPOCH)
-        .map_err(|e| vm.new_value_error(format!("Time error: {:?}", e)))
-}
-
 #[pymodule(name = "time")]
 mod time {
     use crate::{
@@ -70,6 +46,14 @@ mod time {
     #[allow(dead_code)]
     pub(super) const NS_TO_US: i64 = 1000;
 
+    fn duration_since_system_now(vm: &VirtualMachine) -> PyResult<std::time::Duration> {
+        use std::time::{SystemTime, UNIX_EPOCH};
+
+        SystemTime::now()
+            .duration_since(UNIX_EPOCH)
+            .map_err(|e| vm.new_value_error(format!("Time error: {:?}", e)))
+    }
+
     #[cfg(not(unix))]
     #[pyfunction]
     fn sleep(dur: std::time::Duration) {
@@ -79,19 +63,37 @@ mod time {
     #[cfg(not(target_os = "wasi"))]
     #[pyfunction]
     fn time_ns(vm: &VirtualMachine) -> PyResult<u64> {
-        Ok(super::duration_since_system_now(vm)?.as_nanos() as u64)
+        Ok(duration_since_system_now(vm)?.as_nanos() as u64)
     }
 
     #[pyfunction(name = "perf_counter")] // TODO: fix
     #[pyfunction]
-    fn time(vm: &VirtualMachine) -> PyResult<f64> {
-        super::get_time(vm)
+    pub fn time(vm: &VirtualMachine) -> PyResult<f64> {
+        _time(vm)
+    }
+
+    #[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
+    fn _time(vm: &VirtualMachine) -> PyResult<f64> {
+        Ok(duration_since_system_now(vm)?.as_secs_f64())
+    }
+
+    #[cfg(all(target_arch = "wasm32", not(target_os = "wasi")))]
+    fn _time(_vm: &VirtualMachine) -> PyResult<f64> {
+        use wasm_bindgen::prelude::*;
+        #[wasm_bindgen]
+        extern "C" {
+            type Date;
+            #[wasm_bindgen(static_method_of = Date)]
+            fn now() -> f64;
+        }
+        // Date.now returns unix time in milliseconds, we want it in seconds
+        Ok(Date::now() / 1000.0)
     }
 
     #[pyfunction]
     fn monotonic(vm: &VirtualMachine) -> PyResult<f64> {
         // TODO: implement proper monotonic time!
-        Ok(super::duration_since_system_now(vm)?.as_secs_f64())
+        Ok(duration_since_system_now(vm)?.as_secs_f64())
     }
 
     fn pyobj_to_naive_date_time(
diff --git a/vm/src/vm.rs b/vm/src/vm.rs
index 45361bfb99..9aff2a72e0 100644
--- a/vm/src/vm.rs
+++ b/vm/src/vm.rs
@@ -8,13 +8,12 @@
 use crate::compile::{self, CompileError, CompileErrorType, CompileOpts};
 use crate::{
     builtins::{
-        self,
         code::{self, PyCode},
         module, object,
         tuple::{PyTuple, PyTupleRef, PyTupleTyped},
-        PyDictRef, PyInt, PyIntRef, PyList, PyModule, PyStr, PyStrRef, PyTypeRef,
+        PyBaseException, PyBaseExceptionRef, PyDictRef, PyInt, PyIntRef, PyList, PyModule, PyStr,
+        PyStrRef, PyTypeRef,
     },
-    builtins::{PyBaseException, PyBaseExceptionRef},
     bytecode,
     codecs::CodecsRegistry,
     common::{ascii, hash::HashSecret, lock::PyMutex, rc::PyRc},
@@ -325,7 +324,7 @@ impl VirtualMachine {
             panic!("Double Initialize Error");
         }
 
-        builtins::make_module(self, self.builtins.clone());
+        stdlib::builtins::make_module(self, self.builtins.clone());
         stdlib::sys::make_module(self, self.sys_module.clone(), self.builtins.clone());
 
         let mut inner_init = || -> PyResult<()> {