Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
nox committed Jan 8, 2013
1 parent 6f1adbb commit bf3334c
Show file tree
Hide file tree
Showing 11 changed files with 164 additions and 55 deletions.
7 changes: 7 additions & 0 deletions erts/emulator/beam/atom.h
Expand Up @@ -73,6 +73,13 @@ ERTS_GLB_INLINE int erts_atom_name(Eterm term, size_t *len, byte **name)
*name = a->name;
}
return 1;
} else if (is_local_atom(term)) {
LocalAtom *a = local_atom_val(term);
*len = a->len;
if (name) {
*name = (byte *) a->name;
}
return 1;
} else {
return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion erts/emulator/beam/beam_emu.c
Expand Up @@ -670,7 +670,7 @@ extern int count_instructions;

#define IsNumber(X, Fail) if (is_not_integer(X) && is_not_float(X)) { Fail; }

#define IsAtom(Src, Fail) if (is_not_atom(Src)) { Fail; }
#define IsAtom(Src, Fail) if (is_not_any_atom(Src)) { Fail; }

#define IsIntegerAllocate(Src, Need, Alive, Fail) \
if (is_not_integer(Src)) { Fail; } \
Expand Down
89 changes: 63 additions & 26 deletions erts/emulator/beam/bif.c
Expand Up @@ -2621,50 +2621,87 @@ BIF_RETTYPE atom_to_list_1(BIF_ALIST_1)

/**********************************************************************/

/* convert a list of ascii integers to an atom */

BIF_RETTYPE list_to_atom_1(BIF_ALIST_1)
static Uint32 atom_hash(byte* p, size_t len)
{
Eterm res;
char *buf = (char *) erts_alloc(ERTS_ALC_T_TMP, MAX_ATOM_LENGTH);
int i = intlist_to_buf(BIF_ARG_1, buf, MAX_ATOM_LENGTH);
Uint32 h = 0, g;

if (i < 0) {
erts_free(ERTS_ALC_T_TMP, (void *) buf);
i = list_length(BIF_ARG_1);
if (i > MAX_ATOM_LENGTH) {
BIF_ERROR(BIF_P, SYSTEM_LIMIT);
while(len--) {
h = (h << 4) + *p++;
if ((g = h & 0xf0000000)) {
h ^= (g >> 24);
h ^= g;
}
BIF_ERROR(BIF_P, BADARG);
}
res = am_atom_put(buf, i);
erts_free(ERTS_ALC_T_TMP, (void *) buf);
BIF_RET(res);
return h;
}

/* conditionally convert a list of ascii integers to an atom */

BIF_RETTYPE list_to_existing_atom_1(BIF_ALIST_1)
Eterm erts_make_local_atom_in_buffer(Eterm *buffer, byte *name, size_t len)
{
LocalAtom* hp = (LocalAtom *) buffer;
Eterm atom = make_local_atom(hp);
hp->header = make_local_atom_header(len);
hp->equivrep = atom;
hp->hash = atom_hash(name, len);
hp->len = len;
memcpy(hp->name, name, len);
return atom;
}

Eterm erts_make_local_atom(Process *p, byte *name, size_t len)
{
Eterm* hp;
ASSERT(len <= 255);
hp = HAlloc(p, local_atom_size(len));
return erts_make_local_atom_in_buffer(hp, name, len);
}

static BIF_RETTYPE
list_to_atom(Process *p, Eterm list, int force, int must_exist)
{
Eterm res;
int i;
char *buf = (char *) erts_alloc(ERTS_ALC_T_TMP, MAX_ATOM_LENGTH);

if ((i = intlist_to_buf(BIF_ARG_1, buf, MAX_ATOM_LENGTH)) < 0) {
if ((i = intlist_to_buf(list, buf, MAX_ATOM_LENGTH)) < 0) {
error:
erts_free(ERTS_ALC_T_TMP, (void *) buf);
BIF_ERROR(BIF_P, BADARG);
BIF_ERROR(p, BADARG);
} else {
Eterm a;

if (erts_atom_get(buf, i, &a)) {
erts_free(ERTS_ALC_T_TMP, (void *) buf);
BIF_RET(a);
if (force) {
res = am_atom_put(buf, i);
} else {
goto error;
if (!erts_atom_get(buf, i, &res)) {
if (must_exist) {
goto error;
}
res = erts_make_local_atom(p, (byte *) buf, i);
}
}
}
erts_free(ERTS_ALC_T_TMP, (void *) buf);
BIF_RET(res);
}

/* convert a list of ascii integers to a global atom */

BIF_RETTYPE list_to_atom_1(BIF_ALIST_1)
{
return list_to_atom(BIF_P, BIF_ARG_1, 1, 1);
}

/* conditionally convert a list of ascii integers to a global atom */

BIF_RETTYPE list_to_existing_atom_1(BIF_ALIST_1)
{
return list_to_atom(BIF_P, BIF_ARG_1, 0, 1);
}

/* convert a list of ascii integers to a local atom */

BIF_RETTYPE list_to_local_atom_1(BIF_ALIST_1)
{
return list_to_atom(BIF_P, BIF_ARG_1, 0, 0);
}

/**********************************************************************/

Expand Down
2 changes: 2 additions & 0 deletions erts/emulator/beam/bif.tab
Expand Up @@ -823,6 +823,8 @@ bif erlang:prepare_loading/2
bif erlang:finish_loading/1
bif erlang:insert_element/3
bif erlang:delete_element/2
bif erlang:binary_to_local_atom/2
bif erlang:list_to_local_atom/1

#
# Obsolete
Expand Down
21 changes: 11 additions & 10 deletions erts/emulator/beam/erl_printf_term.c
Expand Up @@ -140,7 +140,7 @@ is_printable_string(Eterm list, Eterm* base)
/* print a atom doing what quoting is necessary */
static int print_atom_name(fmtfn_t fn, void* arg, Eterm atom, long *dcount)
{
int n, i;
size_t n;
int res;
int need_quote;
int pos;
Expand All @@ -149,19 +149,20 @@ static int print_atom_name(fmtfn_t fn, void* arg, Eterm atom, long *dcount)
int c;

res = 0;
i = atom_val(atom);
if (is_atom(atom)) {
int i = atom_val(atom);

if ((i < 0) || (i >= atom_table_size()) || (atom_tab(i) == NULL)) {
PRINT_STRING(res, fn, arg, "<bad atom index: ");
PRINT_SLONG(res, fn, arg, 'd', 0, 1, (signed long) i);
PRINT_CHAR(res, fn, arg, '>');
return res;
if ((i < 0) || (i >= atom_table_size()) || (atom_tab(i) == NULL)) {
PRINT_STRING(res, fn, arg, "<bad atom index: ");
PRINT_SLONG(res, fn, arg, 'd', 0, 1, (signed long) i);
PRINT_CHAR(res, fn, arg, '>');
return res;
}
}

s = atom_tab(i)->name;
n = atom_tab(i)->len;
erts_atom_name(atom, &n, &s);

*dcount -= atom_tab(i)->len;
*dcount -= n;

if (n == 0) {
PRINT_STRING(res, fn, arg, "''");
Expand Down
1 change: 1 addition & 0 deletions erts/emulator/beam/erl_term.c
Expand Up @@ -144,6 +144,7 @@ ET_DEFINE_CHECKED(Uint,bignum_header_arity,Eterm,_is_bignum_header);
ET_DEFINE_CHECKED(Eterm*,big_val,Wterm,is_big);
ET_DEFINE_CHECKED(Eterm*,float_val,Wterm,is_float);
ET_DEFINE_CHECKED(Eterm*,tuple_val,Wterm,is_tuple);
ET_DEFINE_CHECKED(LocalAtom*,local_atom_val,Wterm,is_local_atom);
ET_DEFINE_CHECKED(struct erl_node_*,internal_pid_node,Eterm,is_internal_pid);
ET_DEFINE_CHECKED(struct erl_node_*,internal_port_node,Eterm,is_internal_port);
ET_DEFINE_CHECKED(Eterm*,internal_ref_val,Wterm,is_internal_ref);
Expand Down
39 changes: 38 additions & 1 deletion erts/emulator/beam/erl_term.h
Expand Up @@ -112,7 +112,7 @@ struct erl_node_; /* Declared in erl_node_tables.h */
* 1000 REFC_BINARY | |
* 1001 HEAP_BINARY | BINARIES |
* 1010 SUB_BINARY | |
* 1011 Not used
* 1011 LOCAL_ATOM
* 1100 EXTERNAL_PID | |
* 1101 EXTERNAL_PORT | EXTERNAL THINGS |
* 1110 EXTERNAL_REF | |
Expand Down Expand Up @@ -140,6 +140,7 @@ struct erl_node_; /* Declared in erl_node_tables.h */
#define REFC_BINARY_SUBTAG (0x8 << _TAG_PRIMARY_SIZE) /* BINARY */
#define HEAP_BINARY_SUBTAG (0x9 << _TAG_PRIMARY_SIZE) /* BINARY */
#define SUB_BINARY_SUBTAG (0xA << _TAG_PRIMARY_SIZE) /* BINARY */
#define LOCAL_ATOM_SUBTAG (0xB << _TAG_PRIMARY_SIZE) /* LOCAL_ATOM */
#define EXTERNAL_PID_SUBTAG (0xC << _TAG_PRIMARY_SIZE) /* EXTERNAL_PID */
#define EXTERNAL_PORT_SUBTAG (0xD << _TAG_PRIMARY_SIZE) /* EXTERNAL_PORT */
#define EXTERNAL_REF_SUBTAG (0xE << _TAG_PRIMARY_SIZE) /* EXTERNAL_REF */
Expand All @@ -155,6 +156,7 @@ struct erl_node_; /* Declared in erl_node_tables.h */
#define _TAG_HEADER_REFC_BIN (TAG_PRIMARY_HEADER|REFC_BINARY_SUBTAG)
#define _TAG_HEADER_HEAP_BIN (TAG_PRIMARY_HEADER|HEAP_BINARY_SUBTAG)
#define _TAG_HEADER_SUB_BIN (TAG_PRIMARY_HEADER|SUB_BINARY_SUBTAG)
#define _TAG_HEADER_LOCAL_ATOM (TAG_PRIMARY_HEADER|LOCAL_ATOM_SUBTAG)
#define _TAG_HEADER_EXTERNAL_PID (TAG_PRIMARY_HEADER|EXTERNAL_PID_SUBTAG)
#define _TAG_HEADER_EXTERNAL_PORT (TAG_PRIMARY_HEADER|EXTERNAL_PORT_SUBTAG)
#define _TAG_HEADER_EXTERNAL_REF (TAG_PRIMARY_HEADER|EXTERNAL_REF_SUBTAG)
Expand All @@ -170,6 +172,7 @@ struct erl_node_; /* Declared in erl_node_tables.h */
#define header_is_arityval(x) (((x) & _HEADER_SUBTAG_MASK) == ARITYVAL_SUBTAG)
#define header_is_thing(x) (!header_is_transparent((x)))
#define header_is_bin_matchstate(x) ((((x) & (_HEADER_SUBTAG_MASK)) == BIN_MATCHSTATE_SUBTAG))
#define header_is_local_atom(x) ((((x) & (_HEADER_SUBTAG_MASK)) == LOCAL_ATOM_SUBTAG))

#define _CPMASK 0x3

Expand Down Expand Up @@ -284,6 +287,9 @@ _ET_DECLARE_CHECKED(Sint,signed_val,Eterm)

#define MAX_ATOM_INDEX (~(~((Uint) 0) << (sizeof(Uint)*8 - _TAG_IMMED2_SIZE)))

#define is_any_atom(x) (is_atom((x)) || is_local_atom((x)))
#define is_not_any_atom(x) (!is_any_atom((x)))

/* atom access methods */
#define make_atom(x) ((Eterm)(((x) << _TAG_IMMED2_SIZE) + _TAG_IMMED2_ATOM))
#define is_atom(x) (((x) & _TAG_IMMED2_MASK) == _TAG_IMMED2_ATOM)
Expand Down Expand Up @@ -550,6 +556,34 @@ _ET_DECLARE_CHECKED(Eterm*,tuple_val,Wterm)

#define _GETBITS(X,Pos,Size) (((X) >> (Pos)) & ~(~((Uint) 0) << (Size)))

/* Local atom */

typedef struct local_atom_ {
Eterm header;
Eterm equivrep;
Uint32 hash;
Uint32 len;
Eterm name[1];
} LocalAtom;

#define LOCAL_ATOM_HEAD_SIZE (sizeof(LocalAtom) / sizeof(Eterm) - 1)
#define local_atom_size(num_chars) \
(LOCAL_ATOM_HEAD_SIZE + ((num_chars) + sizeof(Eterm) - 1) / sizeof(Eterm))

#define make_local_atom(x) make_boxed((x))

#define _unchecked_local_atom_val(x) ((LocalAtom*) _unchecked_boxed_val((x)))
_ET_DECLARE_CHECKED(LocalAtom*, local_atom_val, Wterm)
#define local_atom_val(x) _ET_APPLY(local_atom_val, (x))

#define make_local_atom_header(num_chars) \
_make_header(local_atom_size((num_chars)) - 1, _TAG_HEADER_LOCAL_ATOM)
#define _is_local_atom_header(x) \
(((x) & _TAG_HEADER_MASK) == _TAG_HEADER_LOCAL_ATOM)
#define is_local_atom(x) \
(is_boxed((x)) && _is_local_atom_header(*boxed_val((x))))
#define is_not_local_atom(x) (!is_local_atom((x)))

/*
* Creation in node specific data (pids, ports, refs)
*/
Expand Down Expand Up @@ -1126,6 +1160,7 @@ extern unsigned tag_val_def(Wterm);
#define make_tuple_rel make_boxed_rel
#define make_external_rel make_boxed_rel
#define make_internal_ref_rel make_boxed_rel
#define make_local_atom_rel make_boxed_rel

#define binary_val_rel(RTERM, BASE) binary_val(rterm2wterm(RTERM, BASE))
#define list_val_rel(RTERM, BASE) list_val(rterm2wterm(RTERM, BASE))
Expand All @@ -1136,6 +1171,7 @@ extern unsigned tag_val_def(Wterm);
#define big_val_rel(RTERM,BASE) big_val(rterm2wterm(RTERM,BASE))
#define float_val_rel(RTERM,BASE) float_val(rterm2wterm(RTERM,BASE))
#define internal_ref_val_rel(RTERM,BASE) internal_ref_val(rterm2wterm(RTERM,BASE))
#define local_atom_val_rel(RTERM,BASE) local_atom_val(rterm2wterm(RTERM,BASE))

#define external_thing_ptr_rel(RTERM, BASE) external_thing_ptr(rterm2wterm(RTERM, BASE))
#define external_data_words_rel(RTERM,BASE) external_data_words(rterm2wterm(RTERM,BASE))
Expand All @@ -1161,6 +1197,7 @@ extern unsigned tag_val_def(Wterm);
#define is_external_rel(RTERM,BASE) is_external(rterm2wterm(RTERM,BASE))
#define is_external_port_rel(RTERM,BASE) is_external_port(rterm2wterm(RTERM,BASE))
#define is_external_ref_rel(RTERM,BASE) is_external_ref(rterm2wterm(RTERM,BASE))
#define is_local_atom_rel(RTERM,BASE) is_local_atom(rterm2wterm(RTERM,BASE))

#define external_node_rel(RTERM,BASE) external_node(rterm2wterm(RTERM,BASE))

Expand Down
40 changes: 25 additions & 15 deletions erts/emulator/beam/erl_unicode.c
Expand Up @@ -1843,7 +1843,7 @@ BIF_RETTYPE atom_to_binary_2(BIF_ALIST_2)
}

static BIF_RETTYPE
binary_to_atom(Process* p, Eterm bin, Eterm enc, int must_exist)
binary_to_atom(Process* p, Eterm bin, Eterm enc, int force, int must_exist)
{
byte* bytes;
byte *temp_alloc = NULL;
Expand All @@ -1860,15 +1860,19 @@ binary_to_atom(Process* p, Eterm bin, Eterm enc, int must_exist)
erts_free_aligned_binary_bytes(temp_alloc);
BIF_ERROR(p, SYSTEM_LIMIT);
}
if (!must_exist) {
if (force) {
a = am_atom_put((char *)bytes, bin_size);
erts_free_aligned_binary_bytes(temp_alloc);
BIF_RET(a);
} else if (erts_atom_get((char *)bytes, bin_size, &a)) {
} else {
if (!erts_atom_get((char *)bytes, bin_size, &a)) {
if (must_exist) {
goto badarg;
}
a = erts_make_local_atom(p, bytes, bin_size);
}
erts_free_aligned_binary_bytes(temp_alloc);
BIF_RET(a);
} else {
goto badarg;
}
} else if (enc == am_utf8 || enc == am_unicode) {
char *buf;
Expand Down Expand Up @@ -1936,20 +1940,21 @@ binary_to_atom(Process* p, Eterm bin, Eterm enc, int must_exist)
erts_free(ERTS_ALC_T_TMP, (void *) buf);
goto system_limit;
}
if (!must_exist) {
if (force) {
res = am_atom_put(buf, num_chars);
erts_free(ERTS_ALC_T_TMP, (void *) buf);
erts_free_aligned_binary_bytes(temp_alloc);
BIF_RET(res);
} else {
int exists = erts_atom_get(buf, num_chars, &res);
erts_free(ERTS_ALC_T_TMP, (void *) buf);
if (exists) {
erts_free_aligned_binary_bytes(temp_alloc);
BIF_RET(res);
} else {
goto badarg;
if (!erts_atom_get(buf, num_chars, &res)) {
if (must_exist) {
goto free_badarg;
}
res = erts_make_local_atom(p, (byte *) buf, num_chars);
}
erts_free(ERTS_ALC_T_TMP, (void *) buf);
erts_free_aligned_binary_bytes(temp_alloc);
BIF_RET(res);
}
} else {
badarg:
Expand All @@ -1960,12 +1965,17 @@ binary_to_atom(Process* p, Eterm bin, Eterm enc, int must_exist)

BIF_RETTYPE binary_to_atom_2(BIF_ALIST_2)
{
return binary_to_atom(BIF_P, BIF_ARG_1, BIF_ARG_2, 0);
return binary_to_atom(BIF_P, BIF_ARG_1, BIF_ARG_2, 1, 1);
}

BIF_RETTYPE binary_to_existing_atom_2(BIF_ALIST_2)
{
return binary_to_atom(BIF_P, BIF_ARG_1, BIF_ARG_2, 1);
return binary_to_atom(BIF_P, BIF_ARG_1, BIF_ARG_2, 0, 1);
}

BIF_RETTYPE binary_to_local_atom_2(BIF_ALIST_2)
{
return binary_to_atom(BIF_P, BIF_ARG_1, BIF_ARG_2, 0, 0);
}

/**********************************************************
Expand Down
2 changes: 2 additions & 0 deletions erts/emulator/beam/global.h
Expand Up @@ -503,6 +503,8 @@ erts_bld_port_info(Eterm **hpp,
void erts_bif_info_init(void);

/* bif.c */
Eterm erts_make_local_atom(Process *p, byte *name, size_t len);
Eterm erts_make_local_atom_in_buffer(Eterm *buffer, byte *name, size_t len);
Eterm erts_make_ref(Process *);
Eterm erts_make_ref_in_buffer(Eterm buffer[REF_THING_SIZE]);
void erts_make_ref_in_array(Uint32 ref[ERTS_MAX_REF_NUMBERS]);
Expand Down

0 comments on commit bf3334c

Please sign in to comment.