From 7e0354965955b910ca1d4a9c8f1c4dd99f5bec59 Mon Sep 17 00:00:00 2001 From: "Jake Bailey (Hacklang)" Date: Mon, 19 Aug 2019 11:42:31 -0700 Subject: [PATCH] Modularize Summary: Break lib.rs up into modules. Use pub(crate) visibility to expose some fields and methods only within the ocamlrep crate (when made necessary by the new module boundaries). Reviewed By: jewelpit Differential Revision: D16846589 fbshipit-source-id: 074f9d52d9d750347e1cef08355b00b1441a75d6 --- hphp/hack/src/ocamlrep/block.rs | 113 +++++++ hphp/hack/src/ocamlrep/{lib.rs => impls.rs} | 223 ++----------- hphp/hack/src/ocamlrep/lib.rs | 480 +--------------------------- hphp/hack/src/ocamlrep/value.rs | 64 ++++ 4 files changed, 224 insertions(+), 656 deletions(-) create mode 100644 hphp/hack/src/ocamlrep/block.rs copy hphp/hack/src/ocamlrep/{lib.rs => impls.rs} (62%) rewrite hphp/hack/src/ocamlrep/lib.rs (97%) create mode 100644 hphp/hack/src/ocamlrep/value.rs diff --git a/hphp/hack/src/ocamlrep/block.rs b/hphp/hack/src/ocamlrep/block.rs new file mode 100644 index 00000000000..ebb87fddb31 --- /dev/null +++ b/hphp/hack/src/ocamlrep/block.rs @@ -0,0 +1,113 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. + +use std::borrow::Cow; +use std::fmt::{self, Debug}; +use std::mem; +use std::ops::{Index, IndexMut}; + +use crate::value::Value; + +pub const STRING_TAG: u8 = 252; +pub const DOUBLE_TAG: u8 = 253; + +#[repr(transparent)] +pub struct BlockBuilder<'arena: 'builder, 'builder>(pub(crate) &'builder mut [Value<'arena>]); + +impl<'a, 'b> BlockBuilder<'a, 'b> { + pub fn new(size: usize, tag: u8, block: &'b mut [Value<'a>]) -> Self { + if size == 0 { + panic!() + } + let header_bytes = size << 10 | (tag as usize); + let header = Value::bits(header_bytes); + block[0] = header; + BlockBuilder(block) + } + + pub fn build(self) -> Value<'a> { + Value::bits(unsafe { mem::transmute(self.0.as_ptr().offset(1)) }) + } +} + +impl<'a, 'b> Index for BlockBuilder<'a, 'b> { + type Output = Value<'a>; + + fn index(&self, index: usize) -> &Self::Output { + &self.0[index + 1] + } +} + +impl IndexMut for BlockBuilder<'_, '_> { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.0[index + 1] + } +} + +#[repr(transparent)] +pub struct Block<'arena>(pub(crate) &'arena [Value<'arena>]); + +impl<'a> Block<'a> { + fn header_bits(&self) -> usize { + self.0[0].0 + } + + pub fn size(&self) -> usize { + self.header_bits() >> 10 + } + + pub fn tag(&self) -> u8 { + self.header_bits() as u8 + } + + pub fn as_str(&self) -> Option> { + if self.tag() != STRING_TAG { + return None; + } + let slice = unsafe { + let size = self.size() * mem::size_of::(); + let ptr: *mut u8 = mem::transmute(self.0.as_ptr().offset(1)); + let last_byte = ptr.offset(size as isize - 1); + let padding = *last_byte; + let size = size - padding as usize - 1; + std::slice::from_raw_parts(ptr, size) + }; + Some(String::from_utf8_lossy(slice)) + } + + pub fn as_float(&self) -> Option { + if self.tag() != DOUBLE_TAG { + return None; + } + Some(f64::from_bits(self.0[1].0 as u64)) + } + + pub fn as_values(&self) -> Option<&[Value]> { + if self.tag() == STRING_TAG || self.tag() == DOUBLE_TAG { + return None; + } + Some(&self.0[1..]) + } +} + +impl<'a> Index for Block<'a> { + type Output = Value<'a>; + + fn index(&self, index: usize) -> &Self::Output { + &self.0[index + 1] + } +} + +impl Debug for Block<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.tag() == STRING_TAG { + write!(f, "{:?}", self.as_str().unwrap()) + } else if self.tag() == DOUBLE_TAG { + write!(f, "{:?}", self.as_float().unwrap()) + } else { + write!(f, "{:?}", self.as_values().unwrap()) + } + } +} diff --git a/hphp/hack/src/ocamlrep/lib.rs b/hphp/hack/src/ocamlrep/impls.rs similarity index 62% copy from hphp/hack/src/ocamlrep/lib.rs copy to hphp/hack/src/ocamlrep/impls.rs index 37e12ebffae..704192f450b 100644 --- a/hphp/hack/src/ocamlrep/lib.rs +++ b/hphp/hack/src/ocamlrep/impls.rs @@ -3,221 +3,78 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the "hack" directory of this source tree. -use std::borrow::Cow; -use std::fmt::{self, Debug}; -use std::marker::PhantomData; use std::mem; -use std::ops::{Index, IndexMut}; -pub mod arena; +use crate::arena::Arena; +use crate::block; +use crate::value::Value; +use crate::IntoOcamlRep; -pub use arena::Arena; - -const STRING_TAG: u8 = 252; -const DOUBLE_TAG: u8 = 253; - -pub trait IntoOcamlRep { - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a>; -} - -#[repr(transparent)] -pub struct BlockBuilder<'arena: 'builder, 'builder>(&'builder mut [Value<'arena>]); - -impl<'a, 'b> BlockBuilder<'a, 'b> { - pub fn new(size: usize, tag: u8, block: &'b mut [Value<'a>]) -> Self { - if size == 0 { - panic!() - } - let header_bytes = size << 10 | (tag as usize); - let header = Value::bits(header_bytes); - block[0] = header; - BlockBuilder(block) - } - - pub fn build(self) -> Value<'a> { - Value::bits(unsafe { mem::transmute(self.0.as_ptr().offset(1)) }) - } -} - -impl<'a, 'b> Index for BlockBuilder<'a, 'b> { - type Output = Value<'a>; - - fn index(&self, index: usize) -> &Self::Output { - &self.0[index + 1] - } -} - -impl IndexMut for BlockBuilder<'_, '_> { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.0[index + 1] - } -} - -#[repr(transparent)] -pub struct Block<'arena>(&'arena [Value<'arena>]); - -impl<'a> Block<'a> { - fn header_bits(&self) -> usize { - self.0[0].0 - } - - fn size(&self) -> usize { - self.header_bits() >> 10 - } - - fn tag(&self) -> u8 { - self.header_bits() as u8 - } - - fn as_str(&self) -> Option> { - if self.tag() != STRING_TAG { - return None; - } - let slice = unsafe { - let size = self.size() * mem::size_of::(); - let ptr: *mut u8 = mem::transmute(self.0.as_ptr().offset(1)); - let last_byte = ptr.offset(size as isize - 1); - let padding = *last_byte; - let size = size - padding as usize - 1; - std::slice::from_raw_parts(ptr, size) - }; - Some(String::from_utf8_lossy(slice)) - } - - fn as_float(&self) -> Option { - if self.tag() != DOUBLE_TAG { - return None; - } - Some(f64::from_bits(self.0[1].0 as u64)) - } - - fn as_values(&self) -> Option<&[Value]> { - if self.tag() == STRING_TAG || self.tag() == DOUBLE_TAG { - return None; - } - Some(&self.0[1..]) - } -} - -impl<'a> Index for Block<'a> { - type Output = Value<'a>; - - fn index(&self, index: usize) -> &Self::Output { - &self.0[index + 1] - } -} - -impl Debug for Block<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.tag() == STRING_TAG { - write!(f, "{:?}", self.as_str().unwrap()) - } else if self.tag() == DOUBLE_TAG { - write!(f, "{:?}", self.as_float().unwrap()) - } else { - write!(f, "{:?}", self.as_values().unwrap()) - } +impl IntoOcamlRep for () { + fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { + Value::int(0) } } -#[repr(transparent)] -#[derive(Clone, Copy)] -pub struct Value<'arena>(usize, PhantomData<&'arena ()>); - -impl<'a> Value<'a> { - fn is_immediate(&self) -> bool { - self.0 & 1 == 1 - } - - pub fn int(value: isize) -> Value<'static> { - Value(((value as usize) << 1) | 1, PhantomData) - } - - fn bits(value: usize) -> Value<'a> { - Value(value, PhantomData) - } - - fn as_int(&self) -> isize { - if !self.is_immediate() { - panic!() - } - (self.0 as isize) >> 1 - } - - fn as_block(&self) -> Option> { - if self.is_immediate() { - return None; - } - let block = unsafe { - let ptr: *const Value = mem::transmute(self.0); - let header = ptr.offset(-1); - let size = ((*header).0 >> 10) + 1; - std::slice::from_raw_parts(header, size) - }; - Some(Block(block)) - } - - /// This method is unsafe because it decouples the value from the lifetime - /// of the arena. Take care that the returned value does not outlive the - /// arena. - pub unsafe fn as_usize(&self) -> usize { - self.0 +impl IntoOcamlRep for isize { + fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { + Value::int(self) } } -impl Debug for Value<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.as_block() { - None => write!(f, "{}", self.as_int()), - Some(block) => write!(f, "{:?}", block), - } +impl IntoOcamlRep for usize { + fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { + Value::int(self as isize) } } -impl IntoOcamlRep for bool { +impl IntoOcamlRep for i64 { fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { Value::int(self as isize) } } -impl IntoOcamlRep for char { +impl IntoOcamlRep for u64 { fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { Value::int(self as isize) } } -impl IntoOcamlRep for isize { +impl IntoOcamlRep for i32 { fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { - Value::int(self) + Value::int(self as isize) } } -impl IntoOcamlRep for usize { +impl IntoOcamlRep for u32 { fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { Value::int(self as isize) } } -impl IntoOcamlRep for u64 { +impl IntoOcamlRep for bool { fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { Value::int(self as isize) } } -impl IntoOcamlRep for i64 { +impl IntoOcamlRep for char { fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { Value::int(self as isize) } } -impl IntoOcamlRep for u32 { - fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { - Value::int(self as isize) +impl IntoOcamlRep for f64 { + fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { + let mut block = arena.block_with_size_and_tag(1, block::DOUBLE_TAG); + block[0] = Value::bits(self.to_bits() as usize); + block.build() } } -impl IntoOcamlRep for i32 { - fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { - Value::int(self as isize) +impl IntoOcamlRep for Box { + fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { + arena.add(*self) } } @@ -251,7 +108,7 @@ impl IntoOcamlRep for Vec { impl IntoOcamlRep for String { fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - self.as_str().into_ocamlrep(arena) + arena.add(self.as_str()) } } @@ -260,7 +117,7 @@ impl IntoOcamlRep for &str { let bytes_in_word = mem::size_of::(); let blocks_length = 1 + (self.len() / bytes_in_word); let padding: usize = bytes_in_word - 1 - (self.len() % bytes_in_word); - let mut block = arena.block_with_size_and_tag(blocks_length, STRING_TAG); + let mut block = arena.block_with_size_and_tag(blocks_length, block::STRING_TAG); block[blocks_length - 1] = Value::bits(padding << ((bytes_in_word - 1) * 8)); @@ -274,26 +131,6 @@ impl IntoOcamlRep for &str { } } -impl IntoOcamlRep for f64 { - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - let mut block = arena.block_with_size_and_tag(1, DOUBLE_TAG); - block[0] = Value::bits(self.to_bits() as usize); - block.build() - } -} - -impl IntoOcamlRep for () { - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - 0isize.into_ocamlrep(arena) - } -} - -impl IntoOcamlRep for Box { - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - (*self).into_ocamlrep(arena) - } -} - impl IntoOcamlRep for (T0, T1) where T0: IntoOcamlRep, diff --git a/hphp/hack/src/ocamlrep/lib.rs b/hphp/hack/src/ocamlrep/lib.rs dissimilarity index 97% index 37e12ebffae..d371ce25f87 100644 --- a/hphp/hack/src/ocamlrep/lib.rs +++ b/hphp/hack/src/ocamlrep/lib.rs @@ -1,463 +1,17 @@ -// Copyright (c) Facebook, Inc. and its affiliates. -// -// This source code is licensed under the MIT license found in the -// LICENSE file in the "hack" directory of this source tree. - -use std::borrow::Cow; -use std::fmt::{self, Debug}; -use std::marker::PhantomData; -use std::mem; -use std::ops::{Index, IndexMut}; - -pub mod arena; - -pub use arena::Arena; - -const STRING_TAG: u8 = 252; -const DOUBLE_TAG: u8 = 253; - -pub trait IntoOcamlRep { - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a>; -} - -#[repr(transparent)] -pub struct BlockBuilder<'arena: 'builder, 'builder>(&'builder mut [Value<'arena>]); - -impl<'a, 'b> BlockBuilder<'a, 'b> { - pub fn new(size: usize, tag: u8, block: &'b mut [Value<'a>]) -> Self { - if size == 0 { - panic!() - } - let header_bytes = size << 10 | (tag as usize); - let header = Value::bits(header_bytes); - block[0] = header; - BlockBuilder(block) - } - - pub fn build(self) -> Value<'a> { - Value::bits(unsafe { mem::transmute(self.0.as_ptr().offset(1)) }) - } -} - -impl<'a, 'b> Index for BlockBuilder<'a, 'b> { - type Output = Value<'a>; - - fn index(&self, index: usize) -> &Self::Output { - &self.0[index + 1] - } -} - -impl IndexMut for BlockBuilder<'_, '_> { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.0[index + 1] - } -} - -#[repr(transparent)] -pub struct Block<'arena>(&'arena [Value<'arena>]); - -impl<'a> Block<'a> { - fn header_bits(&self) -> usize { - self.0[0].0 - } - - fn size(&self) -> usize { - self.header_bits() >> 10 - } - - fn tag(&self) -> u8 { - self.header_bits() as u8 - } - - fn as_str(&self) -> Option> { - if self.tag() != STRING_TAG { - return None; - } - let slice = unsafe { - let size = self.size() * mem::size_of::(); - let ptr: *mut u8 = mem::transmute(self.0.as_ptr().offset(1)); - let last_byte = ptr.offset(size as isize - 1); - let padding = *last_byte; - let size = size - padding as usize - 1; - std::slice::from_raw_parts(ptr, size) - }; - Some(String::from_utf8_lossy(slice)) - } - - fn as_float(&self) -> Option { - if self.tag() != DOUBLE_TAG { - return None; - } - Some(f64::from_bits(self.0[1].0 as u64)) - } - - fn as_values(&self) -> Option<&[Value]> { - if self.tag() == STRING_TAG || self.tag() == DOUBLE_TAG { - return None; - } - Some(&self.0[1..]) - } -} - -impl<'a> Index for Block<'a> { - type Output = Value<'a>; - - fn index(&self, index: usize) -> &Self::Output { - &self.0[index + 1] - } -} - -impl Debug for Block<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.tag() == STRING_TAG { - write!(f, "{:?}", self.as_str().unwrap()) - } else if self.tag() == DOUBLE_TAG { - write!(f, "{:?}", self.as_float().unwrap()) - } else { - write!(f, "{:?}", self.as_values().unwrap()) - } - } -} - -#[repr(transparent)] -#[derive(Clone, Copy)] -pub struct Value<'arena>(usize, PhantomData<&'arena ()>); - -impl<'a> Value<'a> { - fn is_immediate(&self) -> bool { - self.0 & 1 == 1 - } - - pub fn int(value: isize) -> Value<'static> { - Value(((value as usize) << 1) | 1, PhantomData) - } - - fn bits(value: usize) -> Value<'a> { - Value(value, PhantomData) - } - - fn as_int(&self) -> isize { - if !self.is_immediate() { - panic!() - } - (self.0 as isize) >> 1 - } - - fn as_block(&self) -> Option> { - if self.is_immediate() { - return None; - } - let block = unsafe { - let ptr: *const Value = mem::transmute(self.0); - let header = ptr.offset(-1); - let size = ((*header).0 >> 10) + 1; - std::slice::from_raw_parts(header, size) - }; - Some(Block(block)) - } - - /// This method is unsafe because it decouples the value from the lifetime - /// of the arena. Take care that the returned value does not outlive the - /// arena. - pub unsafe fn as_usize(&self) -> usize { - self.0 - } -} - -impl Debug for Value<'_> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self.as_block() { - None => write!(f, "{}", self.as_int()), - Some(block) => write!(f, "{:?}", block), - } - } -} - -impl IntoOcamlRep for bool { - fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { - Value::int(self as isize) - } -} - -impl IntoOcamlRep for char { - fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { - Value::int(self as isize) - } -} - -impl IntoOcamlRep for isize { - fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { - Value::int(self) - } -} - -impl IntoOcamlRep for usize { - fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { - Value::int(self as isize) - } -} - -impl IntoOcamlRep for u64 { - fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { - Value::int(self as isize) - } -} - -impl IntoOcamlRep for i64 { - fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { - Value::int(self as isize) - } -} - -impl IntoOcamlRep for u32 { - fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { - Value::int(self as isize) - } -} - -impl IntoOcamlRep for i32 { - fn into_ocamlrep<'a>(self, _arena: &mut Arena<'a>) -> Value<'a> { - Value::int(self as isize) - } -} - -impl IntoOcamlRep for Option { - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - match self { - None => Value::int(0), - Some(val) => { - let val = arena.add(val); - let mut block = arena.block_with_size(1); - block[0] = val; - block.build() - } - } - } -} - -impl IntoOcamlRep for Vec { - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - let mut hd = arena.add(()); - for val in self.into_iter().rev() { - let val = arena.add(val); - let mut current_block = arena.block_with_size(2); - current_block[0] = val; - current_block[1] = hd; - hd = current_block.build(); - } - hd - } -} - -impl IntoOcamlRep for String { - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - self.as_str().into_ocamlrep(arena) - } -} - -impl IntoOcamlRep for &str { - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - let bytes_in_word = mem::size_of::(); - let blocks_length = 1 + (self.len() / bytes_in_word); - let padding: usize = bytes_in_word - 1 - (self.len() % bytes_in_word); - let mut block = arena.block_with_size_and_tag(blocks_length, STRING_TAG); - - block[blocks_length - 1] = Value::bits(padding << ((bytes_in_word - 1) * 8)); - - let slice: &mut [u8] = unsafe { - let ptr: *mut u8 = mem::transmute(block.0.as_ptr().offset(1)); - std::slice::from_raw_parts_mut(ptr, self.len()) - }; - slice.copy_from_slice(self.as_bytes()); - - block.build() - } -} - -impl IntoOcamlRep for f64 { - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - let mut block = arena.block_with_size_and_tag(1, DOUBLE_TAG); - block[0] = Value::bits(self.to_bits() as usize); - block.build() - } -} - -impl IntoOcamlRep for () { - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - 0isize.into_ocamlrep(arena) - } -} - -impl IntoOcamlRep for Box { - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - (*self).into_ocamlrep(arena) - } -} - -impl IntoOcamlRep for (T0, T1) -where - T0: IntoOcamlRep, - T1: IntoOcamlRep, -{ - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - let v0 = arena.add(self.0); - let v1 = arena.add(self.1); - let mut block = arena.block_with_size(2); - block[0] = v0; - block[1] = v1; - block.build() - } -} - -impl IntoOcamlRep for (T0, T1, T2) -where - T0: IntoOcamlRep, - T1: IntoOcamlRep, - T2: IntoOcamlRep, -{ - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - let v0 = arena.add(self.0); - let v1 = arena.add(self.1); - let v2 = arena.add(self.2); - let mut block = arena.block_with_size(3); - block[0] = v0; - block[1] = v1; - block[2] = v2; - block.build() - } -} - -impl IntoOcamlRep for (T0, T1, T2, T3) -where - T0: IntoOcamlRep, - T1: IntoOcamlRep, - T2: IntoOcamlRep, - T3: IntoOcamlRep, -{ - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - let v0 = arena.add(self.0); - let v1 = arena.add(self.1); - let v2 = arena.add(self.2); - let v3 = arena.add(self.3); - let mut block = arena.block_with_size(4); - block[0] = v0; - block[1] = v1; - block[2] = v2; - block[3] = v3; - block.build() - } -} - -impl IntoOcamlRep for (T0, T1, T2, T3, T4) -where - T0: IntoOcamlRep, - T1: IntoOcamlRep, - T2: IntoOcamlRep, - T3: IntoOcamlRep, - T4: IntoOcamlRep, -{ - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - let v0 = arena.add(self.0); - let v1 = arena.add(self.1); - let v2 = arena.add(self.2); - let v3 = arena.add(self.3); - let v4 = arena.add(self.4); - let mut block = arena.block_with_size(5); - block[0] = v0; - block[1] = v1; - block[2] = v2; - block[3] = v3; - block[4] = v4; - block.build() - } -} - -impl IntoOcamlRep for (T0, T1, T2, T3, T4, T5) -where - T0: IntoOcamlRep, - T1: IntoOcamlRep, - T2: IntoOcamlRep, - T3: IntoOcamlRep, - T4: IntoOcamlRep, - T5: IntoOcamlRep, -{ - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - let v0 = arena.add(self.0); - let v1 = arena.add(self.1); - let v2 = arena.add(self.2); - let v3 = arena.add(self.3); - let v4 = arena.add(self.4); - let v5 = arena.add(self.5); - let mut block = arena.block_with_size(6); - block[0] = v0; - block[1] = v1; - block[2] = v2; - block[3] = v3; - block[4] = v4; - block[5] = v5; - block.build() - } -} - -impl IntoOcamlRep for (T0, T1, T2, T3, T4, T5, T6) -where - T0: IntoOcamlRep, - T1: IntoOcamlRep, - T2: IntoOcamlRep, - T3: IntoOcamlRep, - T4: IntoOcamlRep, - T5: IntoOcamlRep, - T6: IntoOcamlRep, -{ - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - let v0 = arena.add(self.0); - let v1 = arena.add(self.1); - let v2 = arena.add(self.2); - let v3 = arena.add(self.3); - let v4 = arena.add(self.4); - let v5 = arena.add(self.5); - let v6 = arena.add(self.6); - let mut block = arena.block_with_size(7); - block[0] = v0; - block[1] = v1; - block[2] = v2; - block[3] = v3; - block[4] = v4; - block[5] = v5; - block[6] = v6; - block.build() - } -} - -impl IntoOcamlRep for (T0, T1, T2, T3, T4, T5, T6, T7) -where - T0: IntoOcamlRep, - T1: IntoOcamlRep, - T2: IntoOcamlRep, - T3: IntoOcamlRep, - T4: IntoOcamlRep, - T5: IntoOcamlRep, - T6: IntoOcamlRep, - T7: IntoOcamlRep, -{ - fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a> { - let v0 = arena.add(self.0); - let v1 = arena.add(self.1); - let v2 = arena.add(self.2); - let v3 = arena.add(self.3); - let v4 = arena.add(self.4); - let v5 = arena.add(self.5); - let v6 = arena.add(self.6); - let v7 = arena.add(self.7); - let mut block = arena.block_with_size(8); - block[0] = v0; - block[1] = v1; - block[2] = v2; - block[3] = v3; - block[4] = v4; - block[5] = v5; - block[6] = v6; - block[7] = v7; - block.build() - } -} +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. + +mod arena; +mod block; +mod impls; +mod value; + +pub use arena::Arena; +pub use block::{Block, BlockBuilder}; +pub use value::Value; + +pub trait IntoOcamlRep { + fn into_ocamlrep<'a>(self, arena: &mut Arena<'a>) -> Value<'a>; +} diff --git a/hphp/hack/src/ocamlrep/value.rs b/hphp/hack/src/ocamlrep/value.rs new file mode 100644 index 00000000000..abb16559f11 --- /dev/null +++ b/hphp/hack/src/ocamlrep/value.rs @@ -0,0 +1,64 @@ +// Copyright (c) Facebook, Inc. and its affiliates. +// +// This source code is licensed under the MIT license found in the +// LICENSE file in the "hack" directory of this source tree. + +use std::fmt::{self, Debug}; +use std::marker::PhantomData; +use std::mem; + +use crate::block::Block; + +#[repr(transparent)] +#[derive(Clone, Copy)] +pub struct Value<'arena>(pub(crate) usize, PhantomData<&'arena ()>); + +impl<'a> Value<'a> { + fn is_immediate(&self) -> bool { + self.0 & 1 == 1 + } + + pub fn int(value: isize) -> Value<'static> { + Value(((value as usize) << 1) | 1, PhantomData) + } + + pub(crate) fn bits(value: usize) -> Value<'a> { + Value(value, PhantomData) + } + + pub fn as_int(&self) -> isize { + if !self.is_immediate() { + panic!() + } + (self.0 as isize) >> 1 + } + + pub fn as_block(&self) -> Option> { + if self.is_immediate() { + return None; + } + let block = unsafe { + let ptr: *const Value = mem::transmute(self.0); + let header = ptr.offset(-1); + let size = ((*header).0 >> 10) + 1; + std::slice::from_raw_parts(header, size) + }; + Some(Block(block)) + } + + /// This method is unsafe because it decouples the value from the lifetime + /// of the arena. Take care that the returned value does not outlive the + /// arena. + pub unsafe fn as_usize(&self) -> usize { + self.0 + } +} + +impl Debug for Value<'_> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self.as_block() { + None => write!(f, "{}", self.as_int()), + Some(block) => write!(f, "{:?}", block), + } + } +} -- 2.11.4.GIT