Skip to content

Commit

Permalink
Put source_hash in function hash
Browse files Browse the repository at this point in the history
  • Loading branch information
voltrevo committed Aug 14, 2023
1 parent 4c6b249 commit 31a00cb
Show file tree
Hide file tree
Showing 14 changed files with 135 additions and 35 deletions.
28 changes: 28 additions & 0 deletions inputs/failing/compareFnsWithDifferentRefs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//! test_output(true)
// Should be: false.

export default function () {
// The test functions returned have exactly the same source code, but they should not be equal
// because they reference `content` functions that are not equal.
return foo() === bar();
}

function foo() {
function content() {
return "foo";
}

return function test() {
return content();
};
}

function bar() {
function content() {
return "bar";
}

return function test() {
return content();
};
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
//! test_output(false)
// Should be: true
//! test_output(true)

// When functions (and therefore classes) have the same source (and references), they should compare
// equal due to the content hash system. This isn't implemented yet - the content hash is just faked
// using its location in the bytecode, which means you only get equal comparison when the functions
// are referentially equal (inconsistent with value semantics).
// equal due to the content hash system.

export default () => {
const a = new classes[0](1, 2);
Expand Down
11 changes: 11 additions & 0 deletions inputs/passing/compareFnsWithDifferentBinds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//! test_output(false)

export default function () {
return make("foo") === make("bar");
}

function make(bind: unknown) {
return function test() {
return bind;
};
}
10 changes: 8 additions & 2 deletions valuescript_compiler/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,21 @@ impl std::fmt::Display for Pointer {
#[derive(Default, Debug, Clone)]
pub struct Function {
pub is_generator: bool,
pub metadata: Value,
pub parameters: Vec<Register>,
pub body: Vec<FnLine>,
}

impl std::fmt::Display for Function {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
let metadata_str = match &self.metadata {
Value::Void => "".to_string(),
metadata => format!(" {}", metadata),
};

match self.is_generator {
false => write!(f, "function(")?,
true => write!(f, "function*(")?,
false => write!(f, "function{}(", metadata_str)?,
true => write!(f, "function*{}(", metadata_str)?,
}

for (i, parameter) in self.parameters.iter().enumerate() {
Expand Down
2 changes: 2 additions & 0 deletions valuescript_compiler/src/assembler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ impl Assembler {
true => ValueType::GeneratorFunction,
} as u8);

self.value(&function.metadata);

self.fn_data = Default::default();

self.fn_data.register_count_pos = self.output.len();
Expand Down
11 changes: 10 additions & 1 deletion valuescript_compiler/src/assembly_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,16 @@ impl<'a> AssemblyParser<'a> {
function.is_generator = true;
}

self.parse_exact("(");
self.parse_whitespace();

if self.test_chars("(") {
// Leave metadata as void
self.parse_exact("(");
} else {
function.metadata = self.assemble_value();
self.parse_optional_whitespace();
self.parse_exact("(");
}

loop {
self.parse_optional_whitespace();
Expand Down
48 changes: 46 additions & 2 deletions valuescript_compiler/src/function_compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use std::mem::take;
use swc_common::Spanned;

use crate::asm::{
Builtin, Definition, DefinitionContent, FnLine, Function, Instruction, Label, Pointer, Register,
Value,
Builtin, Definition, DefinitionContent, FnLine, Function, Instruction, Label, Object, Pointer,
Register, Value,
};
use crate::diagnostic::{Diagnostic, DiagnosticContainer, DiagnosticReporter};
use crate::expression_compiler::CompiledExpression;
Expand All @@ -16,6 +16,7 @@ use crate::module_compiler::ModuleCompiler;
use crate::name_allocator::{NameAllocator, RegAllocator};
use crate::scope::{NameId, OwnerId};
use crate::scope_analysis::{fn_to_owner_id, Name};
use crate::source_hash::source_hash_asm;

#[derive(Clone, Debug)]
pub enum Functionish {
Expand All @@ -32,6 +33,40 @@ impl Functionish {
Functionish::Constructor(_, owner_id, _) => owner_id.clone(),
}
}

pub fn metadata(&self, source: &str) -> Value {
match self {
Functionish::Fn(ident, fn_) => Value::Object(Box::new(Object {
properties: vec![
(
Value::String("name".to_string()),
Value::String(
ident
.as_ref()
.map_or_else(|| "".to_string(), |ident| ident.sym.to_string()),
),
),
(
Value::String("hash".to_string()),
source_hash_asm(source, fn_.span),
),
],
})),
Functionish::Arrow(arrow) => Value::Object(Box::new(Object {
properties: vec![
(
Value::String("name".to_string()),
Value::String("".to_string()),
),
(
Value::String("hash".to_string()),
source_hash_asm(source, arrow.span),
),
],
})),
Functionish::Constructor(_, _, _) => Value::Void,
}
}
}

#[derive(Clone, Debug)]
Expand Down Expand Up @@ -203,6 +238,10 @@ impl<'a> FunctionCompiler<'a> {
Functionish::Constructor(..) => false,
};

let metadata_pointer = self.mc.allocate_defn_numbered("meta");
let metadata = functionish.metadata(&self.mc.source);
self.fn_.metadata = Value::Pointer(metadata_pointer.clone());

self.set_owner_id(functionish.owner_id());

let capture_params = self
Expand Down Expand Up @@ -289,6 +328,11 @@ impl<'a> FunctionCompiler<'a> {
pointer: definition_pointer,
content: DefinitionContent::Function(take(&mut self.fn_)),
});

self.mc.module.definitions.push(Definition {
pointer: metadata_pointer,
content: DefinitionContent::Value(metadata),
});
}

fn handle_block_body(&mut self, block: &swc_ecma_ast::BlockStmt) {
Expand Down
14 changes: 13 additions & 1 deletion valuescript_compiler/src/source_hash.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use swc_common::BytePos;
use tiny_keccak::{Hasher, Keccak};

#[allow(dead_code)]
use crate::asm::Value;

pub fn source_hash(source: &str, span: swc_common::Span) -> [u8; 32] {
let BytePos(start) = span.lo;
let BytePos(end) = span.hi;
Expand All @@ -19,3 +20,14 @@ pub fn source_hash(source: &str, span: swc_common::Span) -> [u8; 32] {

output
}

pub fn source_hash_asm(source: &str, span: swc_common::Span) -> Value {
let mut result = String::with_capacity(66);
result.push_str("0x");

for byte in &source_hash(source, span) {
result.push_str(&format!("{:02x}", byte));
}

Value::String(result)
}
1 change: 1 addition & 0 deletions valuescript_compiler/src/visit_pointers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ where

match &mut definition.content {
DefinitionContent::Function(function) => {
self.value(Some(&definition.pointer), &mut function.metadata);
self.body(&definition.pointer, &mut function.body);
}
DefinitionContent::Value(value) => {
Expand Down
17 changes: 5 additions & 12 deletions valuescript_vm/src/bytecode_decoder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ use crate::builtins::BUILTIN_VALS;
use crate::bytecode::Bytecode;
use crate::vs_class::VsClass;
use crate::vs_function::VsFunction;
use crate::vs_function_metadata::VsFunctionMetadata;
use crate::vs_object::VsObject;
use crate::vs_symbol::VsSymbol;
use crate::vs_value::ToVal;
Expand Down Expand Up @@ -134,7 +133,7 @@ impl BytecodeDecoder {
}
.to_val()
}
BytecodeType::Function => self.decode_function(false),
BytecodeType::Function => self.decode_function(false, registers),
BytecodeType::Pointer => self.decode_pointer(registers),
BytecodeType::Register => match registers[self.decode_register_index().unwrap()].clone() {
Val::Void => Val::Undefined,
Expand All @@ -152,7 +151,7 @@ impl BytecodeDecoder {
}
.to_val(),
BytecodeType::BigInt => self.decode_bigint().to_val(),
BytecodeType::GeneratorFunction => self.decode_function(true),
BytecodeType::GeneratorFunction => self.decode_function(true, registers),
BytecodeType::Unrecognized => panic!("Unrecognized bytecode type at {}", self.pos - 1),
}
}
Expand Down Expand Up @@ -281,22 +280,16 @@ impl BytecodeDecoder {
}
}

pub fn decode_function(&mut self, is_generator: bool) -> Val {
// TODO: Use actual content hash
let mut hash = [0u8; 32];
hash[0] = (self.pos & 0xff) as u8;
hash[1] = ((self.pos >> 8) & 0xff) as u8;
pub fn decode_function(&mut self, is_generator: bool, registers: &mut Vec<Val>) -> Val {
let metadata = self.decode_val(registers);

// TODO: Support >256
let register_count = self.decode_byte() as usize;
let parameter_count = self.decode_byte() as usize;

VsFunction {
bytecode: self.bytecode.clone(),
metadata: VsFunctionMetadata {
name: Rc::from(""),
hash,
},
metadata,
is_generator,
register_count,
parameter_count,
Expand Down
1 change: 0 additions & 1 deletion valuescript_vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ mod virtual_machine;
pub mod vs_array;
pub mod vs_class;
mod vs_function;
mod vs_function_metadata;
pub mod vs_object;
mod vs_symbol;
pub mod vs_value;
Expand Down
10 changes: 8 additions & 2 deletions valuescript_vm/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,10 @@ pub fn op_eq_impl(left: &Val, right: &Val) -> Result<bool, Val> {
}
}

left.metadata.hash == right.metadata.hash
op_triple_eq_impl(
&left.metadata.sub(&"hash".to_val())?,
&right.metadata.sub(&"hash".to_val())?,
)?
}
_ => {
if left.is_truthy() != right.is_truthy() {
Expand Down Expand Up @@ -316,7 +319,10 @@ pub fn op_triple_eq_impl(left: &Val, right: &Val) -> Result<bool, Val> {
}
}

left.metadata.hash == right.metadata.hash
op_triple_eq_impl(
&left.metadata.sub(&"hash".to_val())?,
&right.metadata.sub(&"hash".to_val())?,
)?
}
#[allow(clippy::vtable_address_comparisons)] // TODO: Is this ok?
(Val::Static(left), Val::Static(right)) => std::ptr::eq(&**left, &**right),
Expand Down
3 changes: 1 addition & 2 deletions valuescript_vm/src/vs_function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::rc::Rc;

use crate::bytecode::Bytecode;
use crate::make_generator_frame::MakeGeneratorFrame;
use crate::vs_function_metadata::VsFunctionMetadata;
use crate::vs_value::ToVal;

use super::bytecode_decoder::BytecodeDecoder;
Expand All @@ -13,7 +12,7 @@ use super::vs_value::Val;
#[derive(Debug, Clone)]
pub struct VsFunction {
pub bytecode: Rc<Bytecode>,
pub metadata: VsFunctionMetadata,
pub metadata: Val,
pub is_generator: bool,
pub register_count: usize,
pub parameter_count: usize,
Expand Down
7 changes: 0 additions & 7 deletions valuescript_vm/src/vs_function_metadata.rs

This file was deleted.

0 comments on commit 31a00cb

Please sign in to comment.