BIF_RETTYPE prepare_loading_2(BIF_ALIST_2) { byte* temp_alloc = NULL; byte* code; Uint sz; Binary* magic; Eterm reason; Eterm* hp; Eterm res; if (is_not_atom(BIF_ARG_1)) { error: erts_free_aligned_binary_bytes(temp_alloc); BIF_ERROR(BIF_P, BADARG); } if ((code = erts_get_aligned_binary_bytes(BIF_ARG_2, &temp_alloc)) == NULL) { goto error; } magic = erts_alloc_loader_state(); sz = binary_size(BIF_ARG_2); reason = erts_prepare_loading(magic, BIF_P, BIF_P->group_leader, &BIF_ARG_1, code, sz); erts_free_aligned_binary_bytes(temp_alloc); if (reason != NIL) { hp = HAlloc(BIF_P, 3); res = TUPLE2(hp, am_error, reason); BIF_RET(res); } hp = HAlloc(BIF_P, PROC_BIN_SIZE); res = erts_mk_magic_binary_term(&hp, &MSO(BIF_P), magic); erts_refc_dec(&magic->refc, 1); BIF_RET(res); }
Eterm enif_make_sub_binary(ErlNifEnv* env, ERL_NIF_TERM bin_term, size_t pos, size_t size) { ErlSubBin* sb; Eterm orig; Uint offset, bit_offset, bit_size; #ifdef DEBUG unsigned src_size; ASSERT(is_binary(bin_term)); src_size = binary_size(bin_term); ASSERT(pos <= src_size); ASSERT(size <= src_size); ASSERT(pos + size <= src_size); #endif sb = (ErlSubBin*) alloc_heap(env, ERL_SUB_BIN_SIZE); ERTS_GET_REAL_BIN(bin_term, orig, offset, bit_offset, bit_size); sb->thing_word = HEADER_SUB_BIN; sb->size = size; sb->offs = offset + pos; sb->orig = orig; sb->bitoffs = bit_offset; sb->bitsize = 0; sb->is_writable = 0; return make_binary(sb); }
BIF_RETTYPE bit_size_1(BIF_ALIST_1) { Uint low_bits; Uint bytesize; Uint high_bits; if (is_binary(BIF_ARG_1)) { bytesize = binary_size(BIF_ARG_1); high_bits = bytesize >> ((sizeof(Uint) * 8)-3); low_bits = (bytesize << 3) + binary_bitsize(BIF_ARG_1); if (high_bits == 0) { if (IS_USMALL(0,low_bits)) { BIF_RET(make_small(low_bits)); } else { Eterm* hp = HAlloc(BIF_P, BIG_UINT_HEAP_SIZE); BIF_RET(uint_to_big(low_bits, hp)); } } else { Uint sz = BIG_UINT_HEAP_SIZE+1; Eterm* hp = HAlloc(BIF_P, sz); hp[0] = make_pos_bignum_header(sz-1); BIG_DIGIT(hp,0) = low_bits; BIG_DIGIT(hp,1) = high_bits; BIF_RET(make_big(hp)); } } else {
int enif_inspect_binary(ErlNifEnv* env, Eterm bin_term, ErlNifBinary* bin) { ErtsAlcType_t allocator = is_proc_bound(env) ? ERTS_ALC_T_TMP : ERTS_ALC_T_NIF; union { struct enif_tmp_obj_t* tmp; byte* raw_ptr; }u; u.tmp = NULL; bin->data = erts_get_aligned_binary_bytes_extra(bin_term, &u.raw_ptr, allocator, sizeof(struct enif_tmp_obj_t)); if (bin->data == NULL) { return 0; } if (u.tmp != NULL) { u.tmp->allocator = allocator; u.tmp->next = env->tmp_obj_list; u.tmp->dtor = &aligned_binary_dtor; env->tmp_obj_list = u.tmp; } bin->bin_term = bin_term; bin->size = binary_size(bin_term); bin->ref_bin = NULL; ADD_READONLY_CHECK(env, bin->data, bin->size); return 1; }
BIF_RETTYPE iolist_to_iovec_1(BIF_ALIST_1) { BIF_RETTYPE result; if (is_nil(BIF_ARG_1)) { BIF_RET(NIL); } else if (is_binary(BIF_ARG_1)) { if (binary_bitsize(BIF_ARG_1) != 0) { ASSERT(!(BIF_P->flags & F_DISABLE_GC)); BIF_ERROR(BIF_P, BADARG); } else if (binary_size(BIF_ARG_1) != 0) { Eterm *hp = HAlloc(BIF_P, 2); BIF_RET(CONS(hp, BIF_ARG_1, NIL)); } else { BIF_RET(NIL); } } else if (is_internal_magic_ref(BIF_ARG_1)) { iol2v_state_t *state; Binary *magic; magic = erts_magic_ref2bin(BIF_ARG_1); if (ERTS_MAGIC_BIN_DESTRUCTOR(magic) != &iol2v_state_destructor) { ASSERT(!(BIF_P->flags & F_DISABLE_GC)); BIF_ERROR(BIF_P, BADARG); } ASSERT(BIF_P->flags & F_DISABLE_GC); state = ERTS_MAGIC_BIN_UNALIGNED_DATA(magic); result = iol2v_continue(state); } else if (!is_list(BIF_ARG_1)) { ASSERT(!(BIF_P->flags & F_DISABLE_GC)); BIF_ERROR(BIF_P, BADARG); } else { iol2v_state_t state; iol2v_init(&state, BIF_P, BIF_ARG_1); erts_set_gc_state(BIF_P, 0); result = iol2v_continue(&state); } if (result != THE_NON_VALUE || BIF_P->freason != TRAP) { erts_set_gc_state(BIF_P, 1); } BIF_RET(result); }
static ERTS_INLINE int io_list_vec_count(Eterm obj, Uint *v_size, Uint *c_size, Uint *b_size, Uint *in_clist, Uint *p_v_size, Uint *p_c_size, Uint *p_in_clist, Uint blimit) { Uint size = binary_size(obj); Eterm real; ERTS_DECLARE_DUMMY(Uint offset); int bitoffs; int bitsize; ERTS_GET_REAL_BIN(obj, real, offset, bitoffs, bitsize); if (bitsize != 0) return 1; if (thing_subtag(*binary_val(real)) == REFC_BINARY_SUBTAG && bitoffs == 0) { *b_size += size; if (*b_size < size) return 2; *in_clist = 0; ++*v_size; /* If iov_len is smaller then Uint we split the binary into*/ /* multiple smaller (2GB) elements in the iolist.*/ *v_size += size / MAX_SYSIOVEC_IOVLEN; if (size >= blimit) { *p_in_clist = 0; ++*p_v_size; } else { *p_c_size += size; if (!*p_in_clist) { *p_in_clist = 1; ++*p_v_size; } } } else { *c_size += size; if (*c_size < size) return 2; if (!*in_clist) { *in_clist = 1; ++*v_size; } *p_c_size += size; if (!*p_in_clist) { *p_in_clist = 1; ++*p_v_size; } } return 0; }
BIF_RETTYPE size_1(BIF_ALIST_1) { if (is_tuple(BIF_ARG_1)) { Eterm* tupleptr = tuple_val(BIF_ARG_1); BIF_RET(make_small(arityval(*tupleptr))); } else if (is_binary(BIF_ARG_1)) { Uint sz = binary_size(BIF_ARG_1); if (IS_USMALL(0, sz)) { return make_small(sz); } else { Eterm* hp = HAlloc(BIF_P, BIG_UINT_HEAP_SIZE); BIF_RET(uint_to_big(sz, hp)); } } BIF_ERROR(BIF_P, BADARG); }
static Eterm do_chksum(ChksumFun sumfun, Process *p, Eterm ioterm, int left, void *sum, int *res, int *err) { Eterm *objp; Eterm obj; int c; DECLARE_ESTACK(stack); unsigned char *bytes = NULL; int numbytes = 0; *err = 0; if (left <= 0 || is_nil(ioterm)) { DESTROY_ESTACK(stack); *res = 0; return ioterm; } if(is_binary(ioterm)) { Uint bitoffs; Uint bitsize; Uint size; Eterm res_term = NIL; unsigned char *bytes; byte *temp_alloc = NULL; ERTS_GET_BINARY_BYTES(ioterm, bytes, bitoffs, bitsize); if (bitsize != 0) { *res = 0; *err = 1; DESTROY_ESTACK(stack); return NIL; } if (bitoffs != 0) { bytes = erts_get_aligned_binary_bytes(ioterm, &temp_alloc); /* The call to erts_get_aligned_binary_bytes cannot fail as we'we already checked bitsize and that this is a binary */ } size = binary_size(ioterm); if (size > left) { Eterm *hp; ErlSubBin *sb; Eterm orig; Uint offset; /* Split the binary in two parts, of which we only process the first */ hp = HAlloc(p, ERL_SUB_BIN_SIZE); sb = (ErlSubBin *) hp; ERTS_GET_REAL_BIN(ioterm, orig, offset, bitoffs, bitsize); sb->thing_word = HEADER_SUB_BIN; sb->size = size - left; sb->offs = offset + left; sb->orig = orig; sb->bitoffs = bitoffs; sb->bitsize = bitsize; sb->is_writable = 0; res_term = make_binary(sb); size = left; } (*sumfun)(sum, bytes, size); *res = size; DESTROY_ESTACK(stack); erts_free_aligned_binary_bytes(temp_alloc); return res_term; } if (!is_list(ioterm)) { *res = 0; *err = 1; DESTROY_ESTACK(stack); return NIL; } /* OK a list, needs to be processed in order, handling each flat list-level as they occur, just like io_list_to_binary would */ *res = 0; ESTACK_PUSH(stack,ioterm); while (!ESTACK_ISEMPTY(stack) && left) { ioterm = ESTACK_POP(stack); if (is_nil(ioterm)) { /* ignore empty lists */ continue; } if(is_list(ioterm)) { L_Again: /* Restart with sublist, old listend was pushed on stack */ objp = list_val(ioterm); obj = CAR(objp); for(;;) { /* loop over one flat list of bytes and binaries until sublist or list end is encountered */ if (is_byte(obj)) { int bsize = 0; for(;;) { if (bsize >= numbytes) { if (!bytes) { bytes = erts_alloc(ERTS_ALC_T_TMP, numbytes = 500); } else { if (numbytes > left) { numbytes += left; } else { numbytes *= 2; } bytes = erts_realloc(ERTS_ALC_T_TMP, bytes, numbytes); } } bytes[bsize++] = (unsigned char) unsigned_val(obj); --left; ioterm = CDR(objp); if (!is_list(ioterm)) { break; } objp = list_val(ioterm); obj = CAR(objp); if (!is_byte(obj)) break; if (!left) { break; } } (*sumfun)(sum, bytes, bsize); *res += bsize; } else if (is_nil(obj)) { ioterm = CDR(objp); if (!is_list(ioterm)) { break; } objp = list_val(ioterm); obj = CAR(objp); } else if (is_list(obj)) { /* push rest of list for later processing, start again with sublist */ ESTACK_PUSH(stack,CDR(objp)); ioterm = obj; goto L_Again; } else if (is_binary(obj)) { int sres, serr; Eterm rest_term; rest_term = do_chksum(sumfun, p, obj, left, sum, &sres, &serr); *res += sres; if (serr != 0) { *err = 1; DESTROY_ESTACK(stack); if (bytes != NULL) erts_free(ERTS_ALC_T_TMP, bytes); return NIL; } left -= sres; if (rest_term != NIL) { Eterm *hp; hp = HAlloc(p, 2); obj = CDR(objp); ioterm = CONS(hp, rest_term, obj); left = 0; break; } ioterm = CDR(objp); if (is_list(ioterm)) { /* objp and obj need to be updated if loop is to continue */ objp = list_val(ioterm); obj = CAR(objp); } } else { *err = 1; DESTROY_ESTACK(stack); if (bytes != NULL) erts_free(ERTS_ALC_T_TMP, bytes); return NIL; } if (!left || is_nil(ioterm) || !is_list(ioterm)) { break; } } /* for(;;) */ } /* is_list(ioterm) */ if (!left) { #ifdef ALLOW_BYTE_TAIL if (is_byte(ioterm)) { /* inproper list with byte tail*/ Eterm *hp; hp = HAlloc(p, 2); ioterm = CONS(hp, ioterm, NIL); } #else ; #endif } else if (!is_list(ioterm) && !is_nil(ioterm)) { /* inproper list end */ #ifdef ALLOW_BYTE_TAIL if (is_byte(ioterm)) { unsigned char b[1]; b[0] = (unsigned char) unsigned_val(ioterm); (*sumfun)(sum, b, 1); ++(*res); --left; ioterm = NIL; } else #endif if is_binary(ioterm) { int sres, serr; ioterm = do_chksum(sumfun, p, ioterm, left, sum, &sres, &serr); *res +=sres; if (serr != 0) { *err = 1; DESTROY_ESTACK(stack); if (bytes != NULL) erts_free(ERTS_ALC_T_TMP, bytes); return NIL; } left -= sres; } else { *err = 1; DESTROY_ESTACK(stack); if (bytes != NULL) erts_free(ERTS_ALC_T_TMP, bytes); return NIL; } } } /* while left and not estack empty */
Uint size_object(Eterm obj) { Uint sum = 0; Eterm* ptr; int arity; DECLARE_ESTACK(s); for (;;) { switch (primary_tag(obj)) { case TAG_PRIMARY_LIST: sum += 2; ptr = list_val(obj); obj = *ptr++; if (!IS_CONST(obj)) { ESTACK_PUSH(s, obj); } obj = *ptr; break; case TAG_PRIMARY_BOXED: { Eterm hdr = *boxed_val(obj); ASSERT(is_header(hdr)); switch (hdr & _TAG_HEADER_MASK) { case ARITYVAL_SUBTAG: ptr = tuple_val(obj); arity = header_arity(hdr); sum += arity + 1; if (arity == 0) { /* Empty tuple -- unusual. */ goto pop_next; } while (arity-- > 1) { obj = *++ptr; if (!IS_CONST(obj)) { ESTACK_PUSH(s, obj); } } obj = *++ptr; break; case FUN_SUBTAG: { Eterm* bptr = fun_val(obj); ErlFunThing* funp = (ErlFunThing *) bptr; unsigned eterms = 1 /* creator */ + funp->num_free; unsigned sz = thing_arityval(hdr); sum += 1 /* header */ + sz + eterms; bptr += 1 /* header */ + sz; while (eterms-- > 1) { obj = *bptr++; if (!IS_CONST(obj)) { ESTACK_PUSH(s, obj); } } obj = *bptr; break; } case SUB_BINARY_SUBTAG: { Eterm real_bin; Uint offset; /* Not used. */ Uint bitsize; Uint bitoffs; Uint extra_bytes; Eterm hdr; ERTS_GET_REAL_BIN(obj, real_bin, offset, bitoffs, bitsize); if ((bitsize + bitoffs) > 8) { sum += ERL_SUB_BIN_SIZE; extra_bytes = 2; } else if ((bitsize + bitoffs) > 0) { sum += ERL_SUB_BIN_SIZE; extra_bytes = 1; } else { extra_bytes = 0; } hdr = *binary_val(real_bin); if (thing_subtag(hdr) == REFC_BINARY_SUBTAG) { sum += PROC_BIN_SIZE; } else { sum += heap_bin_size(binary_size(obj)+extra_bytes); } goto pop_next; } break; case BIN_MATCHSTATE_SUBTAG: erl_exit(ERTS_ABORT_EXIT, "size_object: matchstate term not allowed"); default: sum += thing_arityval(hdr) + 1; goto pop_next; } } break; case TAG_PRIMARY_IMMED1: pop_next: if (ESTACK_ISEMPTY(s)) { DESTROY_ESTACK(s); return sum; } obj = ESTACK_POP(s); break; default: erl_exit(ERTS_ABORT_EXIT, "size_object: bad tag for %#x\n", obj); } } }
Eterm load_module_2(BIF_ALIST_2) { Eterm reason; Eterm* hp; int i; int sz; byte* code; int trace_pattern_is_on; Binary *match_spec; Binary *meta_match_spec; struct trace_pattern_flags trace_pattern_flags; Eterm meta_tracer_pid; Eterm res; byte* temp_alloc = NULL; if (is_not_atom(BIF_ARG_1)) { error: erts_free_aligned_binary_bytes(temp_alloc); BIF_ERROR(BIF_P, BADARG); } if ((code = erts_get_aligned_binary_bytes(BIF_ARG_2, &temp_alloc)) == NULL) { goto error; } erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_block_system(0); erts_export_consolidate(); hp = HAlloc(BIF_P, 3); sz = binary_size(BIF_ARG_2); if ((i = erts_load_module(BIF_P, 0, BIF_P->group_leader, &BIF_ARG_1, code, sz)) < 0) { switch (i) { case -1: reason = am_badfile; break; case -2: reason = am_nofile; break; case -3: reason = am_not_purged; break; case -4: reason = am_atom_put("native_code", sizeof("native_code")-1); break; default: reason = am_badfile; break; } res = TUPLE2(hp, am_error, reason); goto done; } erts_get_default_trace_pattern(&trace_pattern_is_on, &match_spec, &meta_match_spec, &trace_pattern_flags, &meta_tracer_pid); if (trace_pattern_is_on) { Eterm mfa[1]; mfa[0] = BIF_ARG_1; (void) erts_set_trace_pattern(mfa, 1, match_spec, meta_match_spec, 1, trace_pattern_flags, meta_tracer_pid); } res = TUPLE2(hp, am_module, BIF_ARG_1); done: erts_free_aligned_binary_bytes(temp_alloc); erts_smp_release_system(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); BIF_RET(res); }
/* decode_packet(Type,Bin,Options) Returns: {ok, PacketBodyBin, RestBin} {more, PacketSz | undefined} {error, invalid} */ BIF_RETTYPE decode_packet_3(BIF_ALIST_3) { unsigned max_plen = 0; /* Packet max length, 0=no limit */ unsigned trunc_len = 0; /* Truncate lines if longer, 0=no limit */ int http_state = 0; /* 0=request/response 1=header */ int packet_sz; /*-------Binaries involved: ------------------*/ byte* bin_ptr; /*| orig: original binary */ byte bin_bitsz; /*| bin: BIF_ARG_2, may be sub-binary of orig */ /*| packet: prefix of bin */ char* body_ptr; /*| body: part of packet to return */ int body_sz; /*| rest: bin without packet */ struct packet_callback_args pca; enum PacketParseType type; Eterm* hp; Eterm* hend; ErlSubBin* rest; Eterm res; Eterm options; int code; char delimiter = '\n'; if (!is_binary(BIF_ARG_2) || (!is_list(BIF_ARG_3) && !is_nil(BIF_ARG_3))) { BIF_ERROR(BIF_P, BADARG); } switch (BIF_ARG_1) { case make_small(0): case am_raw: type = TCP_PB_RAW; break; case make_small(1): type = TCP_PB_1; break; case make_small(2): type = TCP_PB_2; break; case make_small(4): type = TCP_PB_4; break; case am_asn1: type = TCP_PB_ASN1; break; case am_sunrm: type = TCP_PB_RM; break; case am_cdr: type = TCP_PB_CDR; break; case am_fcgi: type = TCP_PB_FCGI; break; case am_line: type = TCP_PB_LINE_LF; break; case am_tpkt: type = TCP_PB_TPKT; break; case am_http: type = TCP_PB_HTTP; break; case am_httph: type = TCP_PB_HTTPH; break; case am_http_bin: type = TCP_PB_HTTP_BIN; break; case am_httph_bin: type = TCP_PB_HTTPH_BIN; break; case am_ssl_tls: type = TCP_PB_SSL_TLS; break; default: BIF_ERROR(BIF_P, BADARG); } options = BIF_ARG_3; while (!is_nil(options)) { Eterm* cons = list_val(options); if (is_tuple(CAR(cons))) { Eterm* tpl = tuple_val(CAR(cons)); Uint val; if (tpl[0] == make_arityval(2) && term_to_Uint(tpl[2],&val) && val <= UINT_MAX) { switch (tpl[1]) { case am_packet_size: max_plen = val; goto next_option; case am_line_length: trunc_len = val; goto next_option; case am_line_delimiter: if (type == TCP_PB_LINE_LF && val <= 255) { delimiter = (char)val; goto next_option; } } } } BIF_ERROR(BIF_P, BADARG); next_option: options = CDR(cons); } pca.bin_sz = binary_size(BIF_ARG_2); ERTS_GET_BINARY_BYTES(BIF_ARG_2, bin_ptr, pca.bin_bitoffs, bin_bitsz); if (pca.bin_bitoffs != 0) { pca.aligned_ptr = erts_alloc(ERTS_ALC_T_TMP, pca.bin_sz); erts_copy_bits(bin_ptr, pca.bin_bitoffs, 1, pca.aligned_ptr, 0, 1, pca.bin_sz*8); } else { pca.aligned_ptr = bin_ptr; } packet_sz = packet_get_length(type, (char*)pca.aligned_ptr, pca.bin_sz, max_plen, trunc_len, delimiter, &http_state); if (!(packet_sz > 0 && packet_sz <= pca.bin_sz)) { if (packet_sz < 0) { goto error; } else { /* not enough data */ Eterm plen = (packet_sz==0) ? am_undefined : erts_make_integer(packet_sz, BIF_P); Eterm* hp = HAlloc(BIF_P,3); res = TUPLE2(hp, am_more, plen); goto done; } } /* We got a whole packet */ body_ptr = (char*) pca.aligned_ptr; body_sz = packet_sz; packet_get_body(type, (const char**) &body_ptr, &body_sz); ERTS_GET_REAL_BIN(BIF_ARG_2, pca.orig, pca.bin_offs, pca.bin_bitoffs, bin_bitsz); pca.p = BIF_P; pca.res = THE_NON_VALUE; pca.string_as_bin = (type == TCP_PB_HTTP_BIN || type == TCP_PB_HTTPH_BIN); code = packet_parse(type, (char*)pca.aligned_ptr, packet_sz, &http_state, &packet_callbacks_erl, &pca); if (code == 0) { /* no special packet parsing, make plain binary */ ErlSubBin* body; Uint hsz = 2*ERL_SUB_BIN_SIZE + 4; hp = HAlloc(BIF_P, hsz); hend = hp + hsz; body = (ErlSubBin *) hp; body->thing_word = HEADER_SUB_BIN; body->size = body_sz; body->offs = pca.bin_offs + (body_ptr - (char*)pca.aligned_ptr); body->orig = pca.orig; body->bitoffs = pca.bin_bitoffs; body->bitsize = 0; body->is_writable = 0; hp += ERL_SUB_BIN_SIZE; pca.res = make_binary(body); } else if (code > 0) { Uint hsz = ERL_SUB_BIN_SIZE + 4; ASSERT(pca.res != THE_NON_VALUE); hp = HAlloc(BIF_P, hsz); hend = hp + hsz; } else { error: hp = HAlloc(BIF_P,3); res = TUPLE2(hp, am_error, am_invalid); goto done; } rest = (ErlSubBin *) hp; rest->thing_word = HEADER_SUB_BIN; rest->size = pca.bin_sz - packet_sz; rest->offs = pca.bin_offs + packet_sz; rest->orig = pca.orig; rest->bitoffs = pca.bin_bitoffs; rest->bitsize = bin_bitsz; /* The extra bits go into the rest. */ rest->is_writable = 0; hp += ERL_SUB_BIN_SIZE; res = TUPLE3(hp, am_ok, pca.res, make_binary(rest)); hp += 4; ASSERT(hp==hend); (void)hend; done: if (pca.aligned_ptr != bin_ptr) { erts_free(ERTS_ALC_T_TMP, pca.aligned_ptr); } BIF_RET(res); }
Eterm load_module_2(BIF_ALIST_2) { Eterm reason; Eterm* hp; int i; int sz; byte* code; Eterm res; byte* temp_alloc = NULL; if (is_not_atom(BIF_ARG_1)) { error: erts_free_aligned_binary_bytes(temp_alloc); BIF_ERROR(BIF_P, BADARG); } if ((code = erts_get_aligned_binary_bytes(BIF_ARG_2, &temp_alloc)) == NULL) { goto error; } erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); erts_smp_thr_progress_block(); hp = HAlloc(BIF_P, 3); sz = binary_size(BIF_ARG_2); if ((i = erts_load_module(BIF_P, 0, BIF_P->group_leader, &BIF_ARG_1, code, sz)) < 0) { switch (i) { case -1: reason = am_badfile; break; case -2: reason = am_nofile; break; case -3: reason = am_not_purged; break; case -4: reason = am_atom_put("native_code", sizeof("native_code")-1); break; case -5: { /* * The module contains an on_load function. The loader * has loaded the module as usual, except that the * export entries does not point into the module, so it * is not possible to call any code in the module. */ ERTS_DECL_AM(on_load); reason = AM_on_load; break; } default: reason = am_badfile; break; } res = TUPLE2(hp, am_error, reason); goto done; } set_default_trace_pattern(BIF_ARG_1); res = TUPLE2(hp, am_module, BIF_ARG_1); done: erts_free_aligned_binary_bytes(temp_alloc); erts_smp_thr_progress_unblock(); erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN); BIF_RET(res); }
static int iol2v_append_binary(iol2v_state_t *state, Eterm bin_term) { int is_acc_small, is_bin_small; UWord combined_size; UWord binary_size; Uint byte_offset, bit_offset, bit_size; byte *binary_data; Eterm *parent_header; Eterm parent_binary; ASSERT(state->bytereds_available > state->bytereds_spent); ERTS_GET_REAL_BIN(bin_term, parent_binary, byte_offset, bit_offset, bit_size); parent_header = binary_val(parent_binary); binary_size = binary_size(bin_term); if (bit_size != 0) { return 0; } else if (binary_size == 0) { state->bytereds_spent += 1; return 1; } is_acc_small = state->acc_size < IOL2V_SMALL_BIN_LIMIT; is_bin_small = binary_size < IOL2V_SMALL_BIN_LIMIT; combined_size = binary_size + state->acc_size; if (thing_subtag(*parent_header) == REFC_BINARY_SUBTAG) { ProcBin *pb = (ProcBin*)parent_header; if (pb->flags) { erts_emasculate_writable_binary(pb); } binary_data = &((byte*)pb->bytes)[byte_offset]; } else { ErlHeapBin *hb = (ErlHeapBin*)parent_header; ASSERT(thing_subtag(*parent_header) == HEAP_BINARY_SUBTAG); ASSERT(is_bin_small); binary_data = &((byte*)&hb->data)[byte_offset]; } if (!is_bin_small && (state->acc_size == 0 || !is_acc_small)) { /* Avoid combining if we encounter an acceptably large binary while the * accumulator is either empty or large enough to be returned on its * own. */ if (state->acc_size != 0) { iol2v_enqueue_result(state, iol2v_promote_acc(state)); } iol2v_enqueue_result(state, bin_term); } else if (is_bin_small || combined_size < (IOL2V_SMALL_BIN_LIMIT * 2)) { /* If the candidate is small or we can't split the combination in two, * then just copy it into the accumulator. */ iol2v_expand_acc(state, binary_size); if (ERTS_LIKELY(bit_offset == 0)) { sys_memcpy(&(state->acc)->orig_bytes[state->acc_size], binary_data, binary_size); } else { ASSERT(binary_size <= ERTS_UWORD_MAX / 8); erts_copy_bits(binary_data, bit_offset, 1, (byte*)&(state->acc)->orig_bytes[state->acc_size], 0, 1, binary_size * 8); } state->acc_size += binary_size; } else { /* Otherwise, append enough data for the accumulator to be valid, and * then return the rest as a sub-binary. */ UWord spill = IOL2V_SMALL_BIN_LIMIT - state->acc_size; Eterm binary_tail; iol2v_expand_acc(state, spill); if (ERTS_LIKELY(bit_offset == 0)) { sys_memcpy(&(state->acc)->orig_bytes[state->acc_size], binary_data, spill); } else { ASSERT(binary_size <= ERTS_UWORD_MAX / 8); erts_copy_bits(binary_data, bit_offset, 1, (byte*)&(state->acc)->orig_bytes[state->acc_size], 0, 1, spill * 8); } state->acc_size += spill; binary_tail = iol2v_make_sub_bin(state, bin_term, spill, binary_size - spill); iol2v_enqueue_result(state, iol2v_promote_acc(state)); iol2v_enqueue_result(state, binary_tail); } return 1; }
int erts_ioq_iolist_to_vec(Eterm obj, /* io-list */ SysIOVec* iov, /* io vector */ ErtsIOQBinary** binv, /* binary reference vector */ ErtsIOQBinary* cbin, /* binary to store characters */ Uint bin_limit, /* small binaries limit */ int driver) { DECLARE_ESTACK(s); Eterm* objp; byte *buf = NULL; Uint len = 0; Uint csize = 0; int vlen = 0; byte* cptr; if (cbin) { if (driver) { buf = (byte*)cbin->driver.orig_bytes; len = cbin->driver.orig_size; } else { buf = (byte*)cbin->nif.orig_bytes; len = cbin->nif.orig_size; } } cptr = buf; goto L_jump_start; /* avoid push */ while (!ESTACK_ISEMPTY(s)) { obj = ESTACK_POP(s); L_jump_start: if (is_list(obj)) { L_iter_list: objp = list_val(obj); obj = CAR(objp); if (is_byte(obj)) { if (len == 0) goto L_overflow; *buf++ = unsigned_val(obj); csize++; len--; } else if (is_binary(obj)) { ESTACK_PUSH(s, CDR(objp)); goto handle_binary; } else if (is_list(obj)) { ESTACK_PUSH(s, CDR(objp)); goto L_iter_list; /* on head */ } else if (!is_nil(obj)) { goto L_type_error; } obj = CDR(objp); if (is_list(obj)) goto L_iter_list; /* on tail */ else if (is_binary(obj)) { goto handle_binary; } else if (!is_nil(obj)) { goto L_type_error; } } else if (is_binary(obj)) { Eterm real_bin; Uint offset; Eterm* bptr; Uint size; int bitoffs; int bitsize; handle_binary: size = binary_size(obj); ERTS_GET_REAL_BIN(obj, real_bin, offset, bitoffs, bitsize); ASSERT(bitsize == 0); bptr = binary_val(real_bin); if (*bptr == HEADER_PROC_BIN) { ProcBin* pb = (ProcBin *) bptr; if (bitoffs != 0) { if (len < size) { goto L_overflow; } erts_copy_bits(pb->bytes+offset, bitoffs, 1, (byte *) buf, 0, 1, size*8); csize += size; buf += size; len -= size; } else if (bin_limit && size < bin_limit) { if (len < size) { goto L_overflow; } sys_memcpy(buf, pb->bytes+offset, size); csize += size; buf += size; len -= size; } else { ErtsIOQBinary *qbin; if (csize != 0) { io_list_to_vec_set_vec(&iov, &binv, cbin, cptr, csize, &vlen); cptr = buf; csize = 0; } if (pb->flags) { erts_emasculate_writable_binary(pb); } if (driver) qbin = (ErtsIOQBinary*)Binary2ErlDrvBinary(pb->val); else qbin = (ErtsIOQBinary*)pb->val; io_list_to_vec_set_vec( &iov, &binv, qbin, pb->bytes+offset, size, &vlen); } } else { ErlHeapBin* hb = (ErlHeapBin *) bptr; if (len < size) { goto L_overflow; } copy_binary_to_buffer(buf, 0, ((byte *) hb->data)+offset, bitoffs, 8*size); csize += size; buf += size; len -= size; } } else if (!is_nil(obj)) { goto L_type_error; } } if (csize != 0) { io_list_to_vec_set_vec(&iov, &binv, cbin, cptr, csize, &vlen); } DESTROY_ESTACK(s); return vlen; L_type_error: DESTROY_ESTACK(s); return -2; L_overflow: DESTROY_ESTACK(s); return -1; }