firefly icon indicating copy to clipboard operation
firefly copied to clipboard

Subbinaries are being stored as HeapBinary in compiled code

Open KronicDeth opened this issue 5 years ago • 0 comments

Subbinaries are being stored as HeapBinary in compiled code, so that the bit-count is lost.

init.erl

-module(init).
-export([start/0]).
-import(erlang, [binary_part/2, byte_size/1, display/1]).

start() ->
  Binary = <<0, 1, 2, 3 : 2>>,
  Start = 0,
  FullByteCount = bit_size(Binary) div 8,
  Length = FullByteCount,
  StartLength = {Start, Length},
  display(bit_size(Binary)),
  display(Binary),
  display(StartLength),
  BinaryPart = binary_part(Binary, StartLength),
  display(BinaryPart).

native_implemented/otp/lib/erlang/bit_size_1.rs

With modifications these modifications to show the type of the binary passed to bit_size/1

#[cfg(all(not(target_arch = "wasm32"), test))]
mod test;

use anyhow::*;

use liblumen_alloc::erts::exception;
use liblumen_alloc::erts::process::Process;
use liblumen_alloc::erts::term::prelude::*;

#[native_implemented::function(erlang:bit_size/1)]
pub fn result(process: &Process, bitstring: Term) -> exception::Result<Term> {
    let option_total_bit_len = match bitstring.decode()? {
        TypedTerm::BinaryLiteral(binary_literal) =>  {
            println!("{} is a binary literal", bitstring);
            Some(binary_literal.total_bit_len())
        },
        TypedTerm::HeapBinary(heap_binary) => {
            println!("{} is a heap binary", bitstring);
            Some(heap_binary.total_bit_len())
        },
        TypedTerm::ProcBin(process_binary) => {
            println!("{} is a procbin", bitstring);
            Some(process_binary.total_bit_len())
        },
        TypedTerm::SubBinary(subbinary) => {
            println!("{} is a subbinary", bitstring);
            Some(subbinary.total_bit_len())
        },
        TypedTerm::MatchContext(match_context) => Some(match_context.total_bit_len()),
        _ => None,
    };

    match option_total_bit_len {
        Some(total_bit_len) => Ok(process.integer(total_bit_len)?),
        None => Err(TypeError)
            .context(format!("bitstring ({}) is not a bitstring", bitstring))
            .map_err(From::from),
    }
}

STDER

---- erlang::binary_part_2::with_bitstring::with_tuple_with_arity_2::with_bit_count::with_zero_start_and_byte_count_length_returns_subbinary_without_bit_count stdout ----
thread 'erlang::binary_part_2::with_bitstring::with_tuple_with_arity_2::with_bit_count::with_zero_start_and_byte_count_length_returns_subbinary_without_bit_count' panicked at 'assertion failed: `(left == right)`
  left: `"<<0, 1, 2, 192>> is a heap binary\n<<0, 1, 2, 192>> is a heap binary\n32\n<<0, 1, 2, 192>>\n{0, 4}\n<<0, 1, 2, 192>>\n"`,
 right: `"<<0,1,2>>\n"`: 
stdout = <<0, 1, 2, 192>> is a heap binary
<<0, 1, 2, 192>> is a heap binary
32
<<0, 1, 2, 192>>
{0, 4}
<<0, 1, 2, 192>>
  • is a heap binary should be is a subbinary
  • 32 (the bit size) should be 26, but since it's a heap binary, the bit count is lost from the literal <<0, 1, 2, 3 : 2>> (3 * 8 + 2)

init.llvm.mlir



module @init {
  llvm.func @"erlang:binary_part/2"(!llvm.i64, !llvm.i64) -> !llvm.i64
  llvm.func @__lumen_builtin_malloc(!llvm.i32, !llvm.i64) -> !llvm<"i8*">
  llvm.func @"erlang:display/1"(!llvm.i64) -> !llvm.i64
  llvm.func @__lumen_builtin_math.div(!llvm.i64, !llvm.i64) -> !llvm.i64
  llvm.func @"erlang:bit_size/1"(!llvm.i64) -> !llvm.i64
  llvm.func @__lumen_builtin_binary_finish(!llvm.i64) -> !llvm.i64
  llvm.func @__lumen_builtin_binary_push_integer(!llvm.i64, !llvm.i64, !llvm.i64, !llvm.i8, !llvm.i1, !llvm.i32) -> !llvm<"%binary.pushed = type { i64, i1 }">
  llvm.func @__lumen_builtin_binary_start() -> !llvm.i64
  llvm.func @__lumen_builtin_yield()
  llvm.mlir.global external local_exec @CURRENT_REDUCTION_COUNT() : !llvm.i32
  llvm.func @lumen_eh_personality(...) -> !llvm.i32
  llvm.func @"init:start/0"() -> !llvm.i64 attributes {personality = @lumen_eh_personality} {
    %0 = llvm.mlir.constant(20 : i32) : !llvm.i32
    %1 = llvm.mlir.addressof @CURRENT_REDUCTION_COUNT : !llvm<"i32*">
    %2 = llvm.load %1 : !llvm<"i32*">
    %3 = llvm.icmp "uge" %2, %0 : !llvm.i32
    llvm.cond_br %3, ^bb1, ^bb2
  ^bb1:  // pred: ^bb0
    llvm.call @__lumen_builtin_yield() : () -> ()
    llvm.br ^bb2
  ^bb2:  // 2 preds: ^bb0, ^bb1
    %4 = llvm.call @__lumen_builtin_binary_start() : () -> !llvm.i64
    %5 = llvm.mlir.constant(140737488355328 : i64) : !llvm.i64
    %6 = llvm.mlir.constant(140737488355336 : i64) : !llvm.i64
    %7 = llvm.mlir.constant(1 : i8) : !llvm.i8
    %8 = llvm.mlir.constant(false) : !llvm.i1
    %9 = llvm.mlir.constant(0 : i32) : !llvm.i32
    %10 = llvm.call @__lumen_builtin_binary_push_integer(%4, %5, %6, %7, %8, %9) : (!llvm.i64, !llvm.i64, !llvm.i64, !llvm.i8, !llvm.i1, !llvm.i32) -> !llvm<"%binary.pushed = type { i64, i1 }">
    %11 = llvm.extractvalue %10[0] : !llvm<"%binary.pushed = type { i64, i1 }">
    %12 = llvm.extractvalue %10[1] : !llvm<"%binary.pushed = type { i64, i1 }">
    llvm.cond_br %12, ^bb3(%11 : !llvm.i64), ^bb4
  ^bb3(%13: !llvm.i64):  // pred: ^bb2
    %14 = llvm.mlir.constant(140737488355329 : i64) : !llvm.i64
    %15 = llvm.call @__lumen_builtin_binary_push_integer(%13, %14, %6, %7, %8, %9) : (!llvm.i64, !llvm.i64, !llvm.i64, !llvm.i8, !llvm.i1, !llvm.i32) -> !llvm<"%binary.pushed = type { i64, i1 }">
    %16 = llvm.extractvalue %15[0] : !llvm<"%binary.pushed = type { i64, i1 }">
    %17 = llvm.extractvalue %15[1] : !llvm<"%binary.pushed = type { i64, i1 }">
    llvm.cond_br %17, ^bb5(%16 : !llvm.i64), ^bb4
  ^bb4:  // 4 preds: ^bb2, ^bb3, ^bb5, ^bb6
    llvm.unreachable
  ^bb5(%18: !llvm.i64):  // pred: ^bb3
    %19 = llvm.mlir.constant(140737488355330 : i64) : !llvm.i64
    %20 = llvm.call @__lumen_builtin_binary_push_integer(%18, %19, %6, %7, %8, %9) : (!llvm.i64, !llvm.i64, !llvm.i64, !llvm.i8, !llvm.i1, !llvm.i32) -> !llvm<"%binary.pushed = type { i64, i1 }">
    %21 = llvm.extractvalue %20[0] : !llvm<"%binary.pushed = type { i64, i1 }">
    %22 = llvm.extractvalue %20[1] : !llvm<"%binary.pushed = type { i64, i1 }">
    llvm.cond_br %22, ^bb6(%21 : !llvm.i64), ^bb4
  ^bb6(%23: !llvm.i64):  // pred: ^bb5
    %24 = llvm.mlir.constant(140737488355331 : i64) : !llvm.i64
    %25 = llvm.call @__lumen_builtin_binary_push_integer(%23, %24, %19, %7, %8, %9) : (!llvm.i64, !llvm.i64, !llvm.i64, !llvm.i8, !llvm.i1, !llvm.i32) -> !llvm<"%binary.pushed = type { i64, i1 }">
    %26 = llvm.extractvalue %25[0] : !llvm<"%binary.pushed = type { i64, i1 }">
    %27 = llvm.extractvalue %25[1] : !llvm<"%binary.pushed = type { i64, i1 }">
    llvm.cond_br %27, ^bb7(%26 : !llvm.i64), ^bb4
  ^bb7(%28: !llvm.i64):  // pred: ^bb6
    %29 = llvm.call @__lumen_builtin_binary_finish(%28) : (!llvm.i64) -> !llvm.i64
    %30 = llvm.mlir.addressof @CURRENT_REDUCTION_COUNT : !llvm<"i32*">
    %31 = llvm.mlir.constant(1 : i32) : !llvm.i32
    %32 = llvm.atomicrmw add %30, %31 monotonic  : !llvm.i32
    %33 = llvm.call @"erlang:bit_size/1"(%29) {tail} : (!llvm.i64) -> !llvm.i64
    %34 = llvm.call @__lumen_builtin_math.div(%33, %6) : (!llvm.i64, !llvm.i64) -> !llvm.i64
    %35 = llvm.mlir.addressof @CURRENT_REDUCTION_COUNT : !llvm<"i32*">
    %36 = llvm.atomicrmw add %35, %31 monotonic  : !llvm.i32
    %37 = llvm.call @"erlang:bit_size/1"(%29) {tail} : (!llvm.i64) -> !llvm.i64
    %38 = llvm.mlir.addressof @CURRENT_REDUCTION_COUNT : !llvm<"i32*">
    %39 = llvm.atomicrmw add %38, %31 monotonic  : !llvm.i32
    %40 = llvm.call @"erlang:display/1"(%37) {tail} : (!llvm.i64) -> !llvm.i64
    %41 = llvm.mlir.addressof @CURRENT_REDUCTION_COUNT : !llvm<"i32*">
    %42 = llvm.atomicrmw add %41, %31 monotonic  : !llvm.i32
    %43 = llvm.call @"erlang:display/1"(%29) {tail} : (!llvm.i64) -> !llvm.i64
    %44 = llvm.mlir.constant(2 : i64) : !llvm.i64
    %45 = llvm.mlir.constant(12 : i32) : !llvm.i32
    %46 = llvm.call @__lumen_builtin_malloc(%45, %44) : (!llvm.i32, !llvm.i64) -> !llvm<"i8*">
    %47 = llvm.bitcast %46 : !llvm<"i8*"> to !llvm<"%"type 0x7fd043836d20"*">
    %48 = llvm.getelementptr %47[%9, %9] : (!llvm<"%"type 0x7fd043836d20"*">, !llvm.i32, !llvm.i32) -> !llvm<"i64*">
    %49 = llvm.mlir.constant(985162418487298 : i64) : !llvm.i64
    llvm.store %49, %48 : !llvm<"i64*">
    %50 = llvm.getelementptr %47[%9, %31] : (!llvm<"%"type 0x7fd043836d20"*">, !llvm.i32, !llvm.i32) -> !llvm<"i64*">
    llvm.store %5, %50 : !llvm<"i64*">
    %51 = llvm.mlir.constant(2 : i32) : !llvm.i32
    %52 = llvm.getelementptr %47[%9, %51] : (!llvm<"%"type 0x7fd043836d20"*">, !llvm.i32, !llvm.i32) -> !llvm<"i64*">
    llvm.store %34, %52 : !llvm<"i64*">
    %53 = llvm.ptrtoint %47 : !llvm<"%"type 0x7fd043836d20"*"> to !llvm.i64
    %54 = llvm.mlir.addressof @CURRENT_REDUCTION_COUNT : !llvm<"i32*">
    %55 = llvm.atomicrmw add %54, %31 monotonic  : !llvm.i32
    %56 = llvm.call @"erlang:display/1"(%53) {tail} : (!llvm.i64) -> !llvm.i64
    %57 = llvm.mlir.addressof @CURRENT_REDUCTION_COUNT : !llvm<"i32*">
    %58 = llvm.atomicrmw add %57, %31 monotonic  : !llvm.i32
    %59 = llvm.call @"erlang:binary_part/2"(%29, %53) {tail} : (!llvm.i64, !llvm.i64) -> !llvm.i64
    %60 = llvm.mlir.addressof @CURRENT_REDUCTION_COUNT : !llvm<"i32*">
    %61 = llvm.atomicrmw add %60, %31 monotonic  : !llvm.i32
    %62 = llvm.call @"erlang:display/1"(%59) {tail} : (!llvm.i64) -> !llvm.i64
    llvm.return %62 : !llvm.i64
  }
}

KronicDeth avatar Aug 09 '20 16:08 KronicDeth