Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Berry bytes solidification #21558

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.

## [14.1.0.1]
### Added
- Berry solidification of `bytes` instances

### Breaking Changed

Expand Down
105 changes: 64 additions & 41 deletions lib/libesp32/berry/src/be_byteslib.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,7 @@
#include "be_constobj.h"
#include <string.h>
#include <ctype.h>

#define BYTES_DEFAULT_SIZE 28 // default pre-reserved size for buffer (keep 4 bytes for len/size)
#define BYTES_OVERHEAD 4 // bytes overhead to be added when allocating (used to store len and size)
#define BYTES_HEADROOM 8 // keep a natural headroom of 8 bytes when resizing

#define BYTES_SIZE_FIXED -1 // if size is -1, then the bytes object cannot be reized
#define BYTES_SIZE_MAPPED -2 // if size is -2, then the bytes object is mapped to a fixed memory region, i.e. cannot be resized

#define BYTES_RESIZE_ERROR "attribute_error"
#define BYTES_RESIZE_MESSAGE "bytes object size if fixed and cannot be resized"
/* be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); */

typedef struct buf_impl {
int32_t size; // size in bytes of the buffer
int32_t len; // current size of the data in buffer. Invariant: len <= size
uint8_t *bufptr; // the actual data
int32_t prev_size; // previous value read from the instance
int32_t prev_len; // previous value read from the instance
uint8_t *prev_bufptr;
bbool fixed; // is size fixed? (actually encoded as negative size)
bbool mapped;
} buf_impl;
#include "be_byteslib.h"

/********************************************************************
** Base64 lib from https://github.com/Densaugeo/base64_arduino
Expand Down Expand Up @@ -481,7 +460,16 @@ static void buf_add_hex(buf_impl* attr, const char *hex, size_t len)
********************************************************************/

/* if the bufptr is null, don't try to dereference and raise an exception instead */
static void check_ptr(bvm *vm, buf_impl* attr) {
static void check_ptr(bvm *vm, const buf_impl* attr) {
if (!attr->bufptr) {
be_raise(vm, "value_error", "operation not allowed on <null> pointer");
}
}

static void check_ptr_modifiable(bvm *vm, const buf_impl* attr) {
if (attr->solidified) {
be_raise(vm, "value_error", BYTES_READ_ONLY_MESSAGE);
}
if (!attr->bufptr) {
be_raise(vm, "value_error", "operation not allowed on <null> pointer");
}
Expand All @@ -504,10 +492,14 @@ buf_impl m_read_attributes(bvm *vm, int idx)
int32_t signed_size = be_toint(vm, -1);
attr.fixed = bfalse;
attr.mapped = bfalse;
attr.solidified = bfalse;
if (signed_size < 0) {
if (signed_size == BYTES_SIZE_MAPPED) {
attr.mapped = btrue;
}
if (signed_size == BYTES_SIZE_SOLIDIFIED) {
attr.solidified = btrue;
}
signed_size = attr.len;
attr.fixed = btrue;
}
Expand All @@ -516,10 +508,18 @@ buf_impl m_read_attributes(bvm *vm, int idx)
return attr;
}

static void m_assert_not_readlonly(bvm *vm, const buf_impl* attr)
{
if (attr->solidified) {
be_raise(vm, "value_error", BYTES_READ_ONLY_MESSAGE);
}
}

/* Write back attributes to the bytes instance, only if values changed after loading */
/* stack item 1 must contain the instance */
void m_write_attributes(bvm *vm, int rel_idx, const buf_impl * attr)
{
m_assert_not_readlonly(vm, attr);
int idx = be_absindex(vm, rel_idx);
if (attr->bufptr != attr->prev_bufptr) {
be_pushcomptr(vm, attr->bufptr);
Expand Down Expand Up @@ -549,6 +549,7 @@ void m_write_attributes(bvm *vm, int rel_idx, const buf_impl * attr)
// buf_impl * bytes_realloc(bvm *vm, buf_impl *oldbuf, int32_t size)
void bytes_realloc(bvm *vm, buf_impl * attr, int32_t size)
{
m_assert_not_readlonly(vm, attr);
if (!attr->fixed && size < 4) { size = 4; }
if (size > vm->bytesmaxsize) { size = vm->bytesmaxsize; }
size_t oldsize = attr->bufptr ? attr->size : 0;
Expand Down Expand Up @@ -590,7 +591,7 @@ static void bytes_new_object(bvm *vm, size_t size)
static int m_init(bvm *vm)
{
int argc = be_top(vm);
buf_impl attr = { 0, 0, NULL, 0, -1, NULL, bfalse, bfalse }; /* initialize prev_values to invalid to force a write at the end */
buf_impl attr = { 0, 0, NULL, 0, -1, NULL, bfalse, bfalse, bfalse }; /* initialize prev_values to invalid to force a write at the end */
/* size cannot be 0, len cannot be negative */
const char * hex_in = NULL;

Expand Down Expand Up @@ -713,7 +714,7 @@ buf_impl bytes_check_data(bvm *vm, size_t add_size) {
return attr;
}

static size_t tohex(char * out, size_t outsz, const uint8_t * in, size_t insz) {
size_t be_bytes_tohex(char * out, size_t outsz, const uint8_t * in, size_t insz) {
static const char * hex = "0123456789ABCDEF";
const uint8_t * pin = in;
char * pout = out;
Expand Down Expand Up @@ -745,7 +746,7 @@ static int m_tostring(bvm *vm)

char * hex_out = be_pushbuffer(vm, hex_len);
size_t l = be_strlcpy(hex_out, "bytes('", hex_len);
l += tohex(&hex_out[l], hex_len - l, attr.bufptr, len);
l += be_bytes_tohex(&hex_out[l], hex_len - l, attr.bufptr, len);
if (truncated) {
l += be_strlcpy(&hex_out[l], "...", hex_len - l);
}
Expand All @@ -767,7 +768,7 @@ static int m_tohex(bvm *vm)
size_t hex_len = len * 2 + 1;

char * hex_out = be_pushbuffer(vm, hex_len);
size_t l = tohex(hex_out, hex_len, attr.bufptr, len);
size_t l = be_bytes_tohex(hex_out, hex_len, attr.bufptr, len);

be_pushnstring(vm, hex_out, l); /* make escape string from buffer */
be_remove(vm, -2); /* remove buffer */
Expand Down Expand Up @@ -795,7 +796,7 @@ static int m_fromstring(bvm *vm)
const char *s = be_tostring(vm, 2);
int32_t len = be_strlen(vm, 2); /* calling be_strlen to support null chars in string */
buf_impl attr = bytes_check_data(vm, 0);
check_ptr(vm, &attr);
check_ptr_modifiable(vm, &attr);
if (attr.fixed && attr.len != len) {
be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE);
}
Expand Down Expand Up @@ -823,7 +824,7 @@ static int m_add(bvm *vm)
{
int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 4); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr);
check_ptr_modifiable(vm, &attr);
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
if (argc >= 2 && be_isint(vm, 2)) {
int32_t v = be_toint(vm, 2);
Expand Down Expand Up @@ -949,7 +950,7 @@ static int m_set(bvm *vm)
{
int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr);
check_ptr_modifiable(vm, &attr);
if (argc >=3 && be_isint(vm, 2) && be_isint(vm, 3)) {
int32_t idx = be_toint(vm, 2);
int32_t value = be_toint(vm, 3);
Expand Down Expand Up @@ -985,7 +986,7 @@ static int m_setfloat(bvm *vm)
{
int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr);
check_ptr_modifiable(vm, &attr);
if (argc >=3 && be_isint(vm, 2) && (be_isint(vm, 3) || be_isreal(vm, 3))) {
int32_t idx = be_toint(vm, 2);
float val_f = (float) be_toreal(vm, 3);
Expand All @@ -1011,7 +1012,7 @@ static int m_addfloat(bvm *vm)
{
int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 4); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr);
check_ptr_modifiable(vm, &attr);
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
if (argc >=2 && (be_isint(vm, 2) || be_isreal(vm, 2))) {
float val_f = (float) be_toreal(vm, 2);
Expand Down Expand Up @@ -1040,7 +1041,7 @@ static int m_setbytes(bvm *vm)
{
int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr);
check_ptr_modifiable(vm, &attr);
if (argc >=3 && be_isint(vm, 2) && (be_isbytes(vm, 3))) {
int32_t idx = be_toint(vm, 2);
size_t from_len_total;
Expand Down Expand Up @@ -1084,7 +1085,7 @@ static int m_reverse(bvm *vm)
{
int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr);
check_ptr_modifiable(vm, &attr);

int32_t idx = 0; /* start from index 0 */
int32_t len = attr.len; /* entire len */
Expand Down Expand Up @@ -1135,7 +1136,7 @@ static int m_setitem(bvm *vm)
{
int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr);
check_ptr_modifiable(vm, &attr);
if (argc >=3 && be_isint(vm, 2) && be_isint(vm, 3)) {
int index = be_toint(vm, 2);
int val = be_toint(vm, 3);
Expand All @@ -1153,7 +1154,7 @@ static int m_item(bvm *vm)
{
int argc = be_top(vm);
buf_impl attr = bytes_check_data(vm, 0); /* we reserve 4 bytes anyways */
check_ptr(vm, &attr);
check_ptr_modifiable(vm, &attr);
if (argc >=2 && be_isint(vm, 2)) { /* single byte */
int index = be_toint(vm,2);
if (index < 0) {
Expand Down Expand Up @@ -1215,6 +1216,7 @@ static int m_resize(bvm *vm)
{
int argc = be_top(vm);
buf_impl attr = m_read_attributes(vm, 1);
check_ptr_modifiable(vm, &attr);

if (argc <= 1 || !be_isint(vm, 2)) {
be_raise(vm, "type_error", "size must be of type 'int'");
Expand All @@ -1237,6 +1239,7 @@ static int m_resize(bvm *vm)
static int m_clear(bvm *vm)
{
buf_impl attr = m_read_attributes(vm, 1);
check_ptr_modifiable(vm, &attr);
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
attr.len = 0;
m_write_attributes(vm, 1, &attr); /* update instance */
Expand Down Expand Up @@ -1293,7 +1296,7 @@ static int m_connect(bvm *vm)
{
int argc = be_top(vm);
buf_impl attr = m_read_attributes(vm, 1);
check_ptr(vm, &attr);
check_ptr_modifiable(vm, &attr);
if (attr.fixed) { be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); }
if (argc >= 2 && (be_isbytes(vm, 2) || be_isint(vm, 2) || be_isstring(vm, 2))) {
if (be_isint(vm, 2)) {
Expand Down Expand Up @@ -1390,7 +1393,7 @@ static int m_fromb64(bvm *vm)
int32_t bin_len = decode_base64_length((unsigned char*)s); /* do a first pass to calculate the buffer size */

buf_impl attr = m_read_attributes(vm, 1);
check_ptr(vm, &attr);
check_ptr_modifiable(vm, &attr);
if (attr.fixed && attr.len != bin_len) {
be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE);
}
Expand Down Expand Up @@ -1429,7 +1432,7 @@ static int m_fromhex(bvm *vm)
int32_t bin_len = (s_len - from) / 2;

buf_impl attr = m_read_attributes(vm, 1);
check_ptr(vm, &attr);
check_ptr_modifiable(vm, &attr);
if (attr.fixed && attr.len != bin_len) {
be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE);
}
Expand Down Expand Up @@ -1483,6 +1486,18 @@ static int m_is_mapped(bvm *vm)
be_return(vm);
}

/*
* Returns `btrue` if the buffer is solidified and read only
*
* `isreadonly() -> bool`
*/
static int m_is_readonly(bvm *vm)
{
buf_impl attr = m_read_attributes(vm, 1);
be_pushbool(vm, attr.solidified);
be_return(vm);
}

/*
* Change the pointer to a mapped buffer.
*
Expand All @@ -1497,6 +1512,9 @@ static int m_change_buffer(bvm *vm)
int argc = be_top(vm);
if (argc >= 2 && be_iscomptr(vm, 2)) {
buf_impl attr = m_read_attributes(vm, 1);
if (attr.solidified) {
be_raise(vm, "value_error", BYTES_READ_ONLY_MESSAGE);
}
if (!attr.mapped) {
be_raise(vm, "type_error", "bytes() object must be mapped");
}
Expand Down Expand Up @@ -1764,11 +1782,12 @@ void be_load_byteslib(bvm *vm)
{
static const bnfuncinfo members[] = {
{ ".p", NULL },
{ ".size", NULL },
{ ".len", NULL },
{ ".size", NULL },
{ "_buffer", m_buffer },
{ "_change_buffer", m_change_buffer },
{ "ismapped", m_is_mapped },
{ "isreadonly", m_is_readonly },
{ "init", m_init },
{ "deinit", m_deinit },
{ "tostring", m_tostring },
Expand Down Expand Up @@ -1810,14 +1829,18 @@ void be_load_byteslib(bvm *vm)
be_regclass(vm, "bytes", members);
}
#else

#include "../generate/be_const_bytes_def.h"

/* @const_object_info_begin
class be_class_bytes (scope: global, name: bytes) {
.p, var
.size, var
.len, var
.size, var
_buffer, func(m_buffer)
_change_buffer, func(m_change_buffer)
ismapped, func(m_is_mapped)
isreadonly, func(m_is_readonly)
init, func(m_init)
deinit, func(m_deinit)
tostring, func(m_tostring)
Expand Down
44 changes: 44 additions & 0 deletions lib/libesp32/berry/src/be_byteslib.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/********************************************************************
** Copyright (c) 2018-2020 Guan Wenliang - Stephan Hadinger
** This file is part of the Berry default interpreter.
** [email protected], https://github.com/Skiars/berry
** See Copyright Notice in the LICENSE file or at
** https://github.com/Skiars/berry/blob/master/LICENSE
********************************************************************/
#ifndef __BE_BYTESLIB_H
#define __BE_BYTESLIB_H

#include "be_object.h"

#define BYTES_DEFAULT_SIZE 28 /* default pre-reserved size for buffer (keep 4 bytes for len/size) */
#define BYTES_OVERHEAD 4 /* bytes overhead to be added when allocating (used to store len and size) */
#define BYTES_HEADROOM 8 /* keep a natural headroom of 8 bytes when resizing */

#define BYTES_SIZE_FIXED -1 /* if size is -1, then the bytes object cannot be reized */
#define BYTES_SIZE_MAPPED -2 /* if size is -2, then the bytes object is mapped to a fixed memory region, i.e. cannot be resized */
#define BYTES_SIZE_SOLIDIFIED -3 /* is size is -3, then the bytes object is solidified and cannot be resized nor modified */

#define BYTES_RESIZE_ERROR "attribute_error"
#define BYTES_RESIZE_MESSAGE "bytes object size if fixed and cannot be resized"
#define BYTES_READ_ONLY_MESSAGE "bytes object is read only"
/* be_raise(vm, BYTES_RESIZE_ERROR, BYTES_RESIZE_MESSAGE); */

typedef struct buf_impl {
int32_t size; // size in bytes of the buffer
int32_t len; // current size of the data in buffer. Invariant: len <= size
uint8_t *bufptr; // the actual data
int32_t prev_size; // previous value read from the instance
int32_t prev_len; // previous value read from the instance
uint8_t *prev_bufptr;
bbool fixed; // is size fixed? (actually encoded as negative size)
bbool mapped;
bbool solidified;
} buf_impl;

size_t be_bytes_tohex(char * out, size_t outsz, const uint8_t * in, size_t insz);

#if BE_USE_PRECOMPILED_OBJECT
#include "../generate/be_const_bytes.h"
#endif

#endif
10 changes: 10 additions & 0 deletions lib/libesp32/berry/src/be_class.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ struct binstance {
bvalue members[1]; /* members variable data field */
};

/* special structure accepting 3 instance variables used only for bytes() solidification */
struct binstance_arg3 {
bcommon_header;
struct binstance *super;
struct binstance *sub;
bclass *_class;
bgcobject *gray; /* for gc gray list */
bvalue members[3]; /* members variable data field */
};

bclass* be_newclass(bvm *vm, bstring *name, bclass *super);
void be_class_compress(bvm *vm, bclass *c);
int be_class_attribute(bvm *vm, bclass *c, bstring *attr);
Expand Down
Loading