Optimization experiments
This commit is contained in:
parent
9bd88483c4
commit
95c811f3b5
10
Cargo.lock
generated
10
Cargo.lock
generated
@ -196,6 +196,7 @@ dependencies = [
|
|||||||
"rand",
|
"rand",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
|
"smallvec",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -486,6 +487,15 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "smallvec"
|
||||||
|
version = "1.13.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "spin"
|
name = "spin"
|
||||||
version = "0.9.8"
|
version = "0.9.8"
|
||||||
|
@ -121,8 +121,9 @@ assigning each argument a register and associating the register with the local.
|
|||||||
|
|
||||||
When generating instructions for a register-based virtual machine, there are opportunities to
|
When generating instructions for a register-based virtual machine, there are opportunities to
|
||||||
optimize the generated code by using fewer instructions or fewer registers. While it is best to
|
optimize the generated code by using fewer instructions or fewer registers. While it is best to
|
||||||
output optimal code in the first place, it is not always possible. Dust's compiler uses simple
|
output optimal code in the first place, it is not always possible. Dust's compiler modifies the
|
||||||
functions that modify isolated sections of the instruction list through a mutable reference.
|
instruction list during parsing to apply optimizations before the chunk is completed. There is no
|
||||||
|
separate optimization pass, and the compiler cannot be run in a mode that disables optimizations.
|
||||||
|
|
||||||
#### Type Checking
|
#### Type Checking
|
||||||
|
|
||||||
|
5
bench/assets/count_to_one_billion.ds
Normal file
5
bench/assets/count_to_one_billion.ds
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
let mut i = 0
|
||||||
|
|
||||||
|
while i < 100_000_000 {
|
||||||
|
i += 1
|
||||||
|
}
|
5
bench/assets/count_to_one_billion.js
Normal file
5
bench/assets/count_to_one_billion.js
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
var i = 0;
|
||||||
|
|
||||||
|
while (i < 1_000_000_000) {
|
||||||
|
i++;
|
||||||
|
}
|
@ -18,6 +18,7 @@ serde_json = "1.0.117"
|
|||||||
getrandom = { version = "0.2", features = [
|
getrandom = { version = "0.2", features = [
|
||||||
"js",
|
"js",
|
||||||
] } # Indirect dependency, for wasm builds
|
] } # Indirect dependency, for wasm builds
|
||||||
|
smallvec = { version = "1.13.2", features = ["serde"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
env_logger = "0.11.5"
|
env_logger = "0.11.5"
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
use std::fmt::{self, Debug, Display, Write};
|
use std::fmt::{self, Debug, Display, Write};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{ConcreteValue, Disassembler, FunctionType, Instruction, Scope, Span, Type};
|
use crate::{ConcreteValue, Disassembler, FunctionType, Instruction, Scope, Span, Type};
|
||||||
|
|
||||||
@ -18,18 +19,18 @@ pub struct Chunk {
|
|||||||
name: Option<String>,
|
name: Option<String>,
|
||||||
r#type: FunctionType,
|
r#type: FunctionType,
|
||||||
|
|
||||||
instructions: Vec<(Instruction, Span)>,
|
instructions: SmallVec<[(Instruction, Span); 32]>,
|
||||||
constants: Vec<ConcreteValue>,
|
constants: SmallVec<[ConcreteValue; 16]>,
|
||||||
locals: Vec<Local>,
|
locals: SmallVec<[Local; 8]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Chunk {
|
impl Chunk {
|
||||||
pub fn new(name: Option<String>) -> Self {
|
pub fn new(name: Option<String>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
instructions: Vec::new(),
|
instructions: SmallVec::new(),
|
||||||
constants: Vec::new(),
|
constants: SmallVec::new(),
|
||||||
locals: Vec::new(),
|
locals: SmallVec::new(),
|
||||||
r#type: FunctionType {
|
r#type: FunctionType {
|
||||||
type_parameters: None,
|
type_parameters: None,
|
||||||
value_parameters: None,
|
value_parameters: None,
|
||||||
@ -48,9 +49,9 @@ impl Chunk {
|
|||||||
Self {
|
Self {
|
||||||
name,
|
name,
|
||||||
r#type,
|
r#type,
|
||||||
instructions,
|
instructions: instructions.into(),
|
||||||
constants,
|
constants: constants.into(),
|
||||||
locals,
|
locals: locals.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,18 +71,32 @@ impl Chunk {
|
|||||||
self.instructions.is_empty()
|
self.instructions.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn constants(&self) -> &Vec<ConcreteValue> {
|
pub fn constants(&self) -> &SmallVec<[ConcreteValue; 16]> {
|
||||||
&self.constants
|
&self.constants
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn instructions(&self) -> &Vec<(Instruction, Span)> {
|
pub fn instructions(&self) -> &SmallVec<[(Instruction, Span); 32]> {
|
||||||
&self.instructions
|
&self.instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn locals(&self) -> &Vec<Local> {
|
pub fn locals(&self) -> &SmallVec<[Local; 8]> {
|
||||||
&self.locals
|
&self.locals
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn stack_size(&self) -> usize {
|
||||||
|
self.instructions()
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.find_map(|(instruction, _)| {
|
||||||
|
if instruction.yields_value() {
|
||||||
|
Some(instruction.a() as usize)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.unwrap_or(0)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn disassembler(&self) -> Disassembler {
|
pub fn disassembler(&self) -> Disassembler {
|
||||||
Disassembler::new(self)
|
Disassembler::new(self)
|
||||||
}
|
}
|
||||||
|
@ -505,13 +505,19 @@ impl<'src> Compiler<'src> {
|
|||||||
if let Token::Integer(text) = self.current_token {
|
if let Token::Integer(text) = self.current_token {
|
||||||
self.advance()?;
|
self.advance()?;
|
||||||
|
|
||||||
let integer = text
|
let mut integer_value = 0_i64;
|
||||||
.parse::<i64>()
|
|
||||||
.map_err(|error| CompileError::ParseIntError {
|
for digit in text.chars() {
|
||||||
error,
|
let digit = if let Some(digit) = digit.to_digit(10) {
|
||||||
position: self.previous_position,
|
digit as i64
|
||||||
})?;
|
} else {
|
||||||
let value = ConcreteValue::Integer(integer);
|
continue;
|
||||||
|
};
|
||||||
|
|
||||||
|
integer_value = integer_value * 10 + digit;
|
||||||
|
}
|
||||||
|
|
||||||
|
let value = ConcreteValue::Integer(integer_value);
|
||||||
|
|
||||||
self.emit_constant(value, position)?;
|
self.emit_constant(value, position)?;
|
||||||
|
|
||||||
@ -1519,7 +1525,7 @@ impl<'src> Compiler<'src> {
|
|||||||
self.current_position = function_compiler.current_position;
|
self.current_position = function_compiler.current_position;
|
||||||
|
|
||||||
let function =
|
let function =
|
||||||
ConcreteValue::Function(function_compiler.finish(None, value_parameters.clone()));
|
ConcreteValue::function(function_compiler.finish(None, value_parameters.clone()));
|
||||||
let constant_index = self.push_or_get_constant(function);
|
let constant_index = self.push_or_get_constant(function);
|
||||||
let register = self.next_register();
|
let register = self.next_register();
|
||||||
let function_type = FunctionType {
|
let function_type = FunctionType {
|
||||||
|
@ -239,7 +239,7 @@ impl<'src> Lexer<'src> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if c.is_ascii_digit() {
|
if c.is_ascii_digit() || c == '_' {
|
||||||
self.next_char();
|
self.next_char();
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
|
@ -19,7 +19,7 @@ impl AbstractValue {
|
|||||||
|
|
||||||
pub fn to_concrete_owned(&self, vm: &Vm) -> Result<ConcreteValue, VmError> {
|
pub fn to_concrete_owned(&self, vm: &Vm) -> Result<ConcreteValue, VmError> {
|
||||||
match self {
|
match self {
|
||||||
AbstractValue::FunctionSelf => Ok(ConcreteValue::Function(vm.chunk().clone())),
|
AbstractValue::FunctionSelf => Ok(ConcreteValue::function(vm.chunk().clone())),
|
||||||
AbstractValue::List { items, .. } => {
|
AbstractValue::List { items, .. } => {
|
||||||
let mut resolved_items = Vec::with_capacity(items.len());
|
let mut resolved_items = Vec::with_capacity(items.len());
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ pub enum ConcreteValue {
|
|||||||
Byte(u8),
|
Byte(u8),
|
||||||
Character(char),
|
Character(char),
|
||||||
Float(f64),
|
Float(f64),
|
||||||
Function(Chunk),
|
Function(Box<Chunk>),
|
||||||
Integer(i64),
|
Integer(i64),
|
||||||
List(Vec<ConcreteValue>),
|
List(Vec<ConcreteValue>),
|
||||||
Range(RangeValue),
|
Range(RangeValue),
|
||||||
@ -28,6 +28,10 @@ impl ConcreteValue {
|
|||||||
ValueRef::Concrete(self)
|
ValueRef::Concrete(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn function(chunk: Chunk) -> Self {
|
||||||
|
ConcreteValue::Function(Box::new(chunk))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn list<T: Into<Vec<ConcreteValue>>>(into_list: T) -> Self {
|
pub fn list<T: Into<Vec<ConcreteValue>>>(into_list: T) -> Self {
|
||||||
ConcreteValue::List(into_list.into())
|
ConcreteValue::List(into_list.into())
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ impl ValueRef<'_> {
|
|||||||
pub fn add(&self, other: ValueRef) -> Result<Value, ValueError> {
|
pub fn add(&self, other: ValueRef) -> Result<Value, ValueError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
||||||
left.add(right).map(|result| result.to_value())
|
left.add(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotAdd(self.to_owned(), other.to_owned())),
|
_ => Err(ValueError::CannotAdd(self.to_owned(), other.to_owned())),
|
||||||
}
|
}
|
||||||
@ -89,7 +89,7 @@ impl ValueRef<'_> {
|
|||||||
pub fn subtract(&self, other: ValueRef) -> Result<Value, ValueError> {
|
pub fn subtract(&self, other: ValueRef) -> Result<Value, ValueError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
||||||
left.subtract(right).map(|result| result.to_value())
|
left.subtract(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotSubtract(
|
_ => Err(ValueError::CannotSubtract(
|
||||||
self.to_owned(),
|
self.to_owned(),
|
||||||
@ -101,7 +101,7 @@ impl ValueRef<'_> {
|
|||||||
pub fn multiply(&self, other: ValueRef) -> Result<Value, ValueError> {
|
pub fn multiply(&self, other: ValueRef) -> Result<Value, ValueError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
||||||
left.multiply(right).map(|result| result.to_value())
|
left.multiply(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotMultiply(
|
_ => Err(ValueError::CannotMultiply(
|
||||||
self.to_owned(),
|
self.to_owned(),
|
||||||
@ -113,7 +113,7 @@ impl ValueRef<'_> {
|
|||||||
pub fn divide(&self, other: ValueRef) -> Result<Value, ValueError> {
|
pub fn divide(&self, other: ValueRef) -> Result<Value, ValueError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
||||||
left.divide(right).map(|result| result.to_value())
|
left.divide(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotDivide(self.to_owned(), other.to_owned())),
|
_ => Err(ValueError::CannotDivide(self.to_owned(), other.to_owned())),
|
||||||
}
|
}
|
||||||
@ -122,7 +122,7 @@ impl ValueRef<'_> {
|
|||||||
pub fn modulo(&self, other: ValueRef) -> Result<Value, ValueError> {
|
pub fn modulo(&self, other: ValueRef) -> Result<Value, ValueError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
||||||
left.modulo(right).map(|result| result.to_value())
|
left.modulo(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotModulo(self.to_owned(), other.to_owned())),
|
_ => Err(ValueError::CannotModulo(self.to_owned(), other.to_owned())),
|
||||||
}
|
}
|
||||||
@ -130,18 +130,14 @@ impl ValueRef<'_> {
|
|||||||
|
|
||||||
pub fn negate(&self) -> Result<Value, ValueError> {
|
pub fn negate(&self) -> Result<Value, ValueError> {
|
||||||
match self {
|
match self {
|
||||||
ValueRef::Concrete(concrete_value) => {
|
ValueRef::Concrete(concrete_value) => concrete_value.negate().map(Value::Concrete),
|
||||||
concrete_value.negate().map(|result| result.to_value())
|
|
||||||
}
|
|
||||||
_ => Err(ValueError::CannotNegate(self.to_owned())),
|
_ => Err(ValueError::CannotNegate(self.to_owned())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn not(&self) -> Result<Value, ValueError> {
|
pub fn not(&self) -> Result<Value, ValueError> {
|
||||||
match self {
|
match self {
|
||||||
ValueRef::Concrete(concrete_value) => {
|
ValueRef::Concrete(concrete_value) => concrete_value.not().map(Value::Concrete),
|
||||||
concrete_value.not().map(|result| result.to_value())
|
|
||||||
}
|
|
||||||
_ => Err(ValueError::CannotNot(self.to_owned())),
|
_ => Err(ValueError::CannotNot(self.to_owned())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,7 +145,7 @@ impl ValueRef<'_> {
|
|||||||
pub fn equal(&self, other: ValueRef) -> Result<Value, ValueError> {
|
pub fn equal(&self, other: ValueRef) -> Result<Value, ValueError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
||||||
left.equal(right).map(|result| result.to_value())
|
left.equal(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
|
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
|
||||||
}
|
}
|
||||||
@ -158,7 +154,7 @@ impl ValueRef<'_> {
|
|||||||
pub fn less_than(&self, other: ValueRef) -> Result<Value, ValueError> {
|
pub fn less_than(&self, other: ValueRef) -> Result<Value, ValueError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
||||||
left.less_than(right).map(|result| result.to_value())
|
left.less_than(right).map(Value::Concrete)
|
||||||
}
|
}
|
||||||
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
|
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
|
||||||
}
|
}
|
||||||
@ -166,9 +162,9 @@ impl ValueRef<'_> {
|
|||||||
|
|
||||||
pub fn less_than_or_equal(&self, other: ValueRef) -> Result<Value, ValueError> {
|
pub fn less_than_or_equal(&self, other: ValueRef) -> Result<Value, ValueError> {
|
||||||
match (self, other) {
|
match (self, other) {
|
||||||
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => left
|
(ValueRef::Concrete(left), ValueRef::Concrete(right)) => {
|
||||||
.less_than_or_equal(right)
|
left.less_than_or_equal(right).map(Value::Concrete)
|
||||||
.map(|result| result.to_value()),
|
}
|
||||||
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
|
_ => Err(ValueError::CannotCompare(self.to_owned(), other.to_owned())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ use std::{
|
|||||||
io,
|
io,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
compile, instruction::*, AbstractValue, AnnotatedError, Argument, Chunk, ConcreteValue,
|
compile, instruction::*, AbstractValue, AnnotatedError, Argument, Chunk, ConcreteValue,
|
||||||
Destination, DustError, Instruction, NativeFunctionError, Operation, Span, Value, ValueError,
|
Destination, DustError, Instruction, NativeFunctionError, Operation, Span, Value, ValueError,
|
||||||
@ -25,9 +27,9 @@ pub fn run(source: &str) -> Result<Option<ConcreteValue>, DustError> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Vm<'a> {
|
pub struct Vm<'a> {
|
||||||
chunk: &'a Chunk,
|
chunk: &'a Chunk,
|
||||||
stack: Vec<Register>,
|
stack: SmallVec<[Register; 64]>,
|
||||||
parent: Option<&'a Vm<'a>>,
|
parent: Option<&'a Vm<'a>>,
|
||||||
local_definitions: Vec<Option<u16>>,
|
local_definitions: SmallVec<[Option<u16>; 16]>,
|
||||||
|
|
||||||
ip: usize,
|
ip: usize,
|
||||||
last_assigned_register: Option<u16>,
|
last_assigned_register: Option<u16>,
|
||||||
@ -35,14 +37,14 @@ pub struct Vm<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Vm<'a> {
|
impl<'a> Vm<'a> {
|
||||||
const STACK_LIMIT: usize = u16::MAX as usize;
|
const STACK_LIMIT: u16 = u16::MAX;
|
||||||
|
|
||||||
pub fn new(chunk: &'a Chunk, parent: Option<&'a Vm<'a>>) -> Self {
|
pub fn new(chunk: &'a Chunk, parent: Option<&'a Vm<'a>>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
chunk,
|
chunk,
|
||||||
stack: Vec::new(),
|
stack: smallvec![Register::Empty; chunk.stack_size()],
|
||||||
parent,
|
parent,
|
||||||
local_definitions: vec![None; chunk.locals().len()],
|
local_definitions: smallvec![None; chunk.locals().len()],
|
||||||
ip: 0,
|
ip: 0,
|
||||||
last_assigned_register: None,
|
last_assigned_register: None,
|
||||||
current_position: Span(0, 0),
|
current_position: Span(0, 0),
|
||||||
@ -643,11 +645,9 @@ impl<'a> Vm<'a> {
|
|||||||
Ok(value_ref)
|
Ok(value_ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn set_register(&mut self, to_register: u16, register: Register) -> Result<(), VmError> {
|
fn set_register(&mut self, to_register: u16, register: Register) -> Result<(), VmError> {
|
||||||
self.last_assigned_register = Some(to_register);
|
let length = self.stack.len() as u16;
|
||||||
|
|
||||||
let length = self.stack.len();
|
|
||||||
let to_register = to_register as usize;
|
|
||||||
|
|
||||||
if length == Self::STACK_LIMIT {
|
if length == Self::STACK_LIMIT {
|
||||||
return Err(VmError::StackOverflow {
|
return Err(VmError::StackOverflow {
|
||||||
@ -659,16 +659,12 @@ impl<'a> Vm<'a> {
|
|||||||
Ordering::Less => {
|
Ordering::Less => {
|
||||||
log::trace!("Change R{to_register} to {register}");
|
log::trace!("Change R{to_register} to {register}");
|
||||||
|
|
||||||
self.stack[to_register] = register;
|
self.stack[to_register as usize] = register;
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
Ordering::Equal => {
|
Ordering::Equal => {
|
||||||
log::trace!("Set R{to_register} to {register}");
|
log::trace!("Set R{to_register} to {register}");
|
||||||
|
|
||||||
self.stack.push(register);
|
self.stack.push(register);
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
Ordering::Greater => {
|
Ordering::Greater => {
|
||||||
let difference = to_register - length;
|
let difference = to_register - length;
|
||||||
@ -682,10 +678,12 @@ impl<'a> Vm<'a> {
|
|||||||
log::trace!("Set R{to_register} to {register}");
|
log::trace!("Set R{to_register} to {register}");
|
||||||
|
|
||||||
self.stack.push(register);
|
self.stack.push(register);
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.last_assigned_register = Some(to_register);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_constant(&self, constant_index: u16) -> Result<&ConcreteValue, VmError> {
|
fn get_constant(&self, constant_index: u16) -> Result<&ConcreteValue, VmError> {
|
||||||
|
@ -6,7 +6,7 @@ fn function() {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
run(source),
|
run(source),
|
||||||
Ok(Some(ConcreteValue::Function(Chunk::with_data(
|
Ok(Some(ConcreteValue::function(Chunk::with_data(
|
||||||
None,
|
None,
|
||||||
FunctionType {
|
FunctionType {
|
||||||
type_parameters: None,
|
type_parameters: None,
|
||||||
@ -70,7 +70,7 @@ fn function_call() {
|
|||||||
(Instruction::r#return(true), Span(41, 41)),
|
(Instruction::r#return(true), Span(41, 41)),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
ConcreteValue::Function(Chunk::with_data(
|
ConcreteValue::function(Chunk::with_data(
|
||||||
None,
|
None,
|
||||||
FunctionType {
|
FunctionType {
|
||||||
type_parameters: None,
|
type_parameters: None,
|
||||||
@ -126,7 +126,7 @@ fn function_declaration() {
|
|||||||
(Instruction::r#return(false), Span(40, 40))
|
(Instruction::r#return(false), Span(40, 40))
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
ConcreteValue::Function(Chunk::with_data(
|
ConcreteValue::function(Chunk::with_data(
|
||||||
Some("add".to_string()),
|
Some("add".to_string()),
|
||||||
FunctionType {
|
FunctionType {
|
||||||
type_parameters: None,
|
type_parameters: None,
|
||||||
|
@ -1,5 +0,0 @@
|
|||||||
var i = 0;
|
|
||||||
|
|
||||||
while (i < 10000) {
|
|
||||||
i++;
|
|
||||||
}
|
|
491
flamegraph.svg
Normal file
491
flamegraph.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 23 KiB |
22
perf.data.old
Normal file
22
perf.data.old
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
# started on Tue Dec 3 23:57:01 2024
|
||||||
|
|
||||||
|
|
||||||
|
Performance counter stats for 'target/release/dust bench/assets/count_to_one_billion.ds':
|
||||||
|
|
||||||
|
3,821.33 msec task-clock:u # 1.000 CPUs utilized
|
||||||
|
0 context-switches:u # 0.000 /sec
|
||||||
|
0 cpu-migrations:u # 0.000 /sec
|
||||||
|
128 page-faults:u # 33.496 /sec
|
||||||
|
19,568,365,731 cycles:u # 5.121 GHz
|
||||||
|
22,811,191 stalled-cycles-frontend:u # 0.12% frontend cycles idle
|
||||||
|
70,300,518,284 instructions:u # 3.59 insn per cycle
|
||||||
|
# 0.00 stalled cycles per insn
|
||||||
|
12,500,111,636 branches:u # 3.271 G/sec
|
||||||
|
19,795 branch-misses:u # 0.00% of all branches
|
||||||
|
|
||||||
|
3.822391878 seconds time elapsed
|
||||||
|
|
||||||
|
3.811230000 seconds user
|
||||||
|
0.000999000 seconds sys
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user