From 57c67cae9e98753e37d9127a557c9058b15b7e51 Mon Sep 17 00:00:00 2001 From: yukirij Date: Tue, 26 Sep 2023 17:33:40 -0700 Subject: [PATCH] Add conversion and bitfield operations to Block. --- src/interface/block.rs | 181 ++++++++++++++++++++++++----------------- src/runtime/lib.cc | 111 +++++++++++++++++++++++++ src/runtime/lib.h | 6 ++ src/runtime/mod.rs | 8 +- 4 files changed, 231 insertions(+), 75 deletions(-) diff --git a/src/interface/block.rs b/src/interface/block.rs index 19d461e..7d7901b 100644 --- a/src/interface/block.rs +++ b/src/interface/block.rs @@ -1,74 +1,107 @@ -use crate::runtime::{ - Reference, - acquire, release, - type_inner, type_key, - block_length, - block_set, block_get, -}; -use crate::tag; -use super::block; - -pub struct Block { - managed:bool, - addr:Reference, -} -impl Block { - pub fn new(size:usize) -> Self - { - Self { - managed:true, - addr:unsafe {acquire(block(size))}, - } - } - - pub fn with(size:usize, data:Vec) -> Self - { - let mut obj = Self::new(size); - obj.set(data); - return obj; - } - - pub fn size(&self) -> usize - { - unsafe {block_length(self.addr)} - } - - pub fn set(&mut self, data:Vec) - { - let length = unsafe {type_key(type_inner(self.addr.class))}; - for index in 0..usize::min(data.len(), length) { - unsafe {block_set(self.addr, index, data[index])}; - } - } - - pub fn get(&self) -> Vec - { - let mut result = Vec::::new(); - let length = unsafe {type_key(type_inner(self.addr.class))}; - if length > 0 { - result.resize(length, 0); - for index in 0..length { - result[index] = unsafe {block_get(self.addr, index)}; - } - } - return result; - } -} -impl TryFrom for Block { - type Error = (); - fn try_from(addr:Reference) -> Result { - return if(unsafe {type_key(addr.class)} == tag::BLOCK) { - Ok(Self { managed:false, addr:addr }) - } - else { - Err(()) - } - } -} -impl std::ops::Deref for Block { - type Target = Reference; - fn deref(&self) -> &Self::Target { return &self.addr; } -} -impl Drop for Block { - fn drop(&mut self) { if self.managed { unsafe {release(self.addr)}; } } -} +use crate::runtime::{ + Reference, + acquire, release, + type_inner, type_key, + block_length, + block_set, block_get, + block_set_natural, block_get_natural, + block_set_integer, block_get_integer, + block_set_field, block_get_field, +}; +use crate::tag; +use super::block; + +pub struct Block { + managed:bool, + addr:Reference, +} +impl Block { + pub fn new(size:usize) -> Self + { + Self { + managed:true, + addr:unsafe {acquire(block(size))}, + } + } + + pub fn with(size:usize, data:Vec) -> Self + { + let mut obj = Self::new(size); + obj.set(data); + return obj; + } + + pub fn size(&self) -> usize + { + unsafe {block_length(self.addr)} + } + + pub fn set(&mut self, data:Vec) + { + let length = unsafe {type_key(type_inner(self.addr.class))}; + for index in 0..usize::min(data.len(), length) { + unsafe {block_set(self.addr, index, data[index])}; + } + } + + pub fn set_u64(&self, data:u64) + { + unsafe {block_set_natural(self.addr, data)} + } + + pub fn set_i64(&self, data:i64) + { + unsafe {block_set_integer(self.addr, data)} + } + + pub fn set_field(&mut self, index:usize, length:usize, data:u64) + { + unsafe { block_set_field(self.addr, index, length, data); } + } + + pub fn get(&self) -> Vec + { + let mut result = Vec::::new(); + let length = unsafe {type_key(type_inner(self.addr.class))}; + if length > 0 { + result.resize(length, 0); + for index in 0..length { + result[index] = unsafe {block_get(self.addr, index)}; + } + } + return result; + } + + pub fn get_u64(&self) -> u64 + { + unsafe {block_get_natural(self.addr)} + } + + pub fn get_i64(&self) -> i64 + { + unsafe {block_get_integer(self.addr)} + } + + pub fn get_field(&self, index:usize, length:usize) -> u64 + { + unsafe {block_get_field(self.addr, index, length)} + } +} +impl TryFrom for Block { + type Error = (); + fn try_from(addr:Reference) -> Result { + return if(unsafe {type_key(addr.class)} == tag::BLOCK) { + Ok(Self { managed:false, addr:addr }) + } + else { + Err(()) + } + } +} +impl std::ops::Deref for Block { + type Target = Reference; + fn deref(&self) -> &Self::Target { return &self.addr; } +} +impl Drop for Block { + fn drop(&mut self) { if self.managed { unsafe {release(self.addr)}; } } +} diff --git a/src/runtime/lib.cc b/src/runtime/lib.cc index 619e7b8..8b96450 100644 --- a/src/runtime/lib.cc +++ b/src/runtime/lib.cc @@ -549,6 +549,60 @@ extern "C" uint8_t block_get(Reference addr, size_t index) return 0; } +extern "C" uint64_t block_get_natural(Reference addr) +{ + size_t length = type_innerkey(addr.type); + uint8_t* data = reinterpret_cast(addr.address); + uint64_t result = 0; + + for(size_t i = 0; i < length; ++i) { + result <<= 8; + result |= data[i]; + } + + return result; +} + +extern "C" int64_t block_get_integer(Reference addr) +{ + size_t length = type_innerkey(addr.type); + uint8_t* data = reinterpret_cast(addr.address); + int64_t result = 0; + + for(size_t i = 0; i < length; ++i) { + result <<= 8; + result |= data[i]; + } + + return result; +} + +extern "C" uint64_t block_get_field(Reference addr, size_t index, size_t length) +{ + size_t data_length = type_innerkey(addr.type); + size_t byte_start = index >> 3; + size_t bit_offset = index & 0x07; + size_t byte_length = 1 + ((bit_offset + length) >> 3); + size_t byte_end = byte_start + byte_length; + size_t mask_offset = ((8 * byte_length) - (length + bit_offset)); + + uint64_t mask = ((1 << length) - 1) << mask_offset; + uint64_t bits = 0; + + uint8_t* data = reinterpret_cast(addr.address); + + size_t i = byte_start; + for(; i < data_length && i < byte_end; ++i) { + bits <<= 8; + bits |= data[i]; + } + for(; i < byte_end; ++i) { + bits <<= 8; + } + + return (bits & mask) >> mask_offset; +} + extern "C" void block_set(Reference addr, size_t index, uint8_t value) { size_t length = type_innerkey(addr.type); @@ -557,6 +611,63 @@ extern "C" void block_set(Reference addr, size_t index, uint8_t value) } } +extern "C" void block_set_natural(Reference addr, uint64_t data) +{ + size_t length = type_innerkey(addr.type); + uint8_t* dest = reinterpret_cast(addr.address); + + for(size_t i = length; i > 0; --i) { + dest[i - 1] = data & 0xFF; + data >>= 8; + } +} + +extern "C" void block_set_integer(Reference addr, int64_t data) +{ + size_t length = type_innerkey(addr.type); + uint8_t* dest = reinterpret_cast(addr.address); + + for(size_t i = length; i > 0; --i) { + dest[i - 1] = data & 0xFF; + data >>= 8; + } +} + +extern "C" void block_set_field(Reference addr, size_t index, size_t length, uint64_t value) +{ + size_t data_length = type_innerkey(addr.type); + size_t byte_start = index >> 3; + size_t bit_offset = index & 0x07; + size_t byte_length = 1 + ((bit_offset + length) >> 3); + size_t byte_end = byte_start + byte_length; + size_t mask_offset = ((8 * byte_length) - (length + bit_offset)); + + uint64_t mask = ((1 << length) - 1) << mask_offset; + uint64_t bits = 0; + + uint8_t* data = reinterpret_cast(addr.address); + + size_t byte_index = byte_start; + for(; byte_index < data_length && byte_index < byte_end; ++byte_index) { + bits <<= 8; + bits |= data[byte_index]; + } + for(; byte_index < byte_end; ++byte_index) { + bits <<= 8; + } + + bits &= ~mask; + bits |= mask & (value << mask_offset); + + for(; byte_index > data_length; --byte_index) { + bits >>= 8; + } + for(; byte_index > byte_start; --byte_index) { + data[byte_index - 1] = bits & 0xFF; + bits >>= 8; + } +} + // Sequence // diff --git a/src/runtime/lib.h b/src/runtime/lib.h index 0289352..6e7327f 100644 --- a/src/runtime/lib.h +++ b/src/runtime/lib.h @@ -67,7 +67,13 @@ extern "C" Type::Significant significant_get(Reference addr); // Block // extern "C" size_t block_length(Reference addr); extern "C" uint8_t block_get(Reference addr, size_t index); +extern "C" uint64_t block_get_natural(Reference addr); +extern "C" int64_t block_get_integer(Reference addr); +extern "C" uint64_t block_get_field(Reference addr, size_t index, size_t length); extern "C" void block_set(Reference addr, size_t index, uint8_t value); +extern "C" void block_set_natural(Reference addr, uint64_t data); +extern "C" void block_set_integer(Reference addr, int64_t data); +extern "C" void block_set_field(Reference addr, size_t index, size_t length, uint64_t value); // Sequence // extern "C" size_t sequence_capacity(Reference addr); diff --git a/src/runtime/mod.rs b/src/runtime/mod.rs index 0114152..81143ce 100644 --- a/src/runtime/mod.rs +++ b/src/runtime/mod.rs @@ -83,8 +83,14 @@ extern "C" { pub fn significant_get(addr:Reference) -> f64; pub fn block_length(addr:Reference) -> usize; - pub fn block_set(addr:Reference, index:usize, data:u8); pub fn block_get(addr:Reference, index:usize) -> u8; + pub fn block_get_natural(addr:Reference) -> u64; + pub fn block_get_integer(addr:Reference) -> i64; + pub fn block_get_field(addr:Reference, index:usize, length:usize) -> u64; + pub fn block_set(addr:Reference, index:usize, data:u8); + pub fn block_set_natural(addr:Reference, data:u64); + pub fn block_set_integer(addr:Reference, data:i64); + pub fn block_set_field(addr:Reference, index:usize, length:usize, data:u64); pub fn sequence_capacity(addr:Reference) -> usize; pub fn sequence_length(addr:Reference) -> usize;