⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 copy.c

📁 OTP是开放电信平台的简称
💻 C
📖 第 1 页 / 共 2 页
字号:
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. *  * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. *  * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' *  *     $Id$ */#ifdef HAVE_CONFIG_H#  include "config.h"#endif#include "sys.h"#include "erl_vm.h"#include "global.h"#include "erl_process.h"#include "ggc.h"#include "erl_nmgc.h"#include "big.h"#include "erl_binary.h"#ifdef HYBRIDMA_STACK_DECLARE(src);MA_STACK_DECLARE(dst);MA_STACK_DECLARE(offset);#endifvoidinit_copy(void){#ifdef HYBRID    MA_STACK_ALLOC(src);    MA_STACK_ALLOC(dst);    MA_STACK_ALLOC(offset);#endif}/* *  Copy object "obj" to process p. */Etermcopy_object(Eterm obj, Process* to){    Uint size = size_object(obj);    Eterm* hp = HAlloc(to, size);    Eterm res;    res = copy_struct(obj, size, &hp, &to->off_heap);#ifdef DEBUG    if (eq(obj, res) == 0) {	erl_exit(ERTS_ABORT_EXIT, "copy not equal to source\n");    }#endif    return res;}/* * Return the "flat" size of the object. */Uintsize_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 size_common;		    }		    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 size_common;		    }		    break;		case BIN_MATCHSTATE_SUBTAG:		    erl_exit(ERTS_ABORT_EXIT,			     "size_object: matchstate term not allowed");		default:		    sum += thing_arityval(hdr) + 1;		    /* Fall through */		size_common:		    if (ESTACK_ISEMPTY(s)) {			DESTROY_ESTACK(s);			return sum;		    }		    obj = ESTACK_POP(s);		    break;		}	    }	    break;	case TAG_PRIMARY_IMMED1:	    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);	}    }}/* *  Copy a structure to a heap. */Etermcopy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap){#define in_area(ptr,start,nbytes) \    ((unsigned long)((char*)(ptr) - (char*)(start)) < (nbytes))    char* hstart;    Uint hsize;    Eterm* htop;    Eterm* hbot;    Eterm* hp;    Eterm* objp;    Eterm* tp;    Eterm  res;    Eterm  elem;    Eterm* tailp;    Eterm* argp;    Eterm* const_tuple;    Eterm hdr;    int i;#ifdef DEBUG    Eterm org_obj = obj;    Uint org_sz = sz;#endif    if (IS_CONST(obj))	return obj;    hp = htop = *hpp;    hbot   = htop + sz;    hstart = (char *)htop;    hsize = (char*) hbot - hstart;    const_tuple = 0;    /* Copy the object onto the heap */    switch (primary_tag(obj)) {    case TAG_PRIMARY_LIST: argp = &res; goto L_copy_list;    case TAG_PRIMARY_BOXED: argp = &res; goto L_copy_boxed;    default:	erl_exit(ERTS_ABORT_EXIT,		 "%s, line %d: Internal error in copy_struct: 0x%08x\n",		 __FILE__, __LINE__,obj);    } L_copy:    while (hp != htop) {	obj = *hp;	switch (primary_tag(obj)) {	case TAG_PRIMARY_IMMED1:	    hp++;	    break;	case TAG_PRIMARY_LIST:	    objp = list_val(obj);	    if (in_area(objp,hstart,hsize)) {		hp++;		break;	    }	    argp = hp++;	    /* Fall through */	L_copy_list:	    tailp = argp;	    while (is_list(obj)) {		objp = list_val(obj);		tp = tailp;		elem = *objp;		if (IS_CONST(elem)) {		    *(hbot-2) = elem;		    tailp = hbot-1;		    hbot -= 2;		}		else {		    *htop = elem;		    tailp = htop+1;		    htop += 2;		}		*tp = make_list(tailp - 1);		obj = *(objp+1);	    }	    switch (primary_tag(obj)) {	    case TAG_PRIMARY_IMMED1: *tailp = obj; goto L_copy;	    case TAG_PRIMARY_BOXED: argp = tailp; goto L_copy_boxed;	    default:		erl_exit(ERTS_ABORT_EXIT,			 "%s, line %d: Internal error in copy_struct: 0x%08x\n",			 __FILE__, __LINE__,obj);	    }	    	case TAG_PRIMARY_BOXED:	    if (in_area(boxed_val(obj),hstart,hsize)) {		hp++;		break;	    }	    argp = hp++;	L_copy_boxed:	    objp = boxed_val(obj);	    hdr = *objp;	    switch (hdr & _TAG_HEADER_MASK) {	    case ARITYVAL_SUBTAG:		{		    int const_flag = 1; /* assume constant tuple */		    i = arityval(hdr);		    *argp = make_tuple(htop);		    tp = htop;	/* tp is pointer to new arity value */		    *htop++ = *objp++; /* copy arity value */		    while (i--) {			elem = *objp++;			if (!IS_CONST(elem)) {			    const_flag = 0;			}			*htop++ = elem;		    }		    if (const_flag) {			const_tuple = tp; /* this is the latest const_tuple */		    }		}		break;	    case REFC_BINARY_SUBTAG:		{		    ProcBin* pb;		    i = thing_arityval(*objp) + 1;		    hbot -= i;		    tp = hbot;		    while (i--)  {			*tp++ = *objp++;		    }		    *argp = make_binary(hbot);		    pb = (ProcBin*) hbot;		    erts_refc_inc(&pb->val->refc, 2);		    pb->next = off_heap->mso;		    off_heap->mso = pb;		    off_heap->overhead += pb->size /		      BINARY_OVERHEAD_FACTOR / sizeof(Eterm);		}		break;	    case SUB_BINARY_SUBTAG:		{		    ErlSubBin* sb = (ErlSubBin *) objp;		    Eterm real_bin = sb->orig;		    Uint bit_offset = sb->bitoffs;		    Uint bit_size = sb -> bitsize;		    Uint offset = sb->offs;		    size_t size = sb->size;		    Uint extra_bytes;		    Uint real_size;		    if ((bit_size + bit_offset) > 8) {			  extra_bytes = 2;			}  			else if ((bit_size + bit_offset) > 0) {			  extra_bytes = 1;			}			else {			  extra_bytes = 0;			} 		    real_size = size+extra_bytes;		    objp = binary_val(real_bin);		    if (thing_subtag(*objp) == HEAP_BINARY_SUBTAG) {			ErlHeapBin* from = (ErlHeapBin *) objp;			ErlHeapBin* to;			i = heap_bin_size(real_size);			hbot -= i;			to = (ErlHeapBin *) hbot;			to->thing_word = header_heap_bin(real_size);			to->size = real_size;			sys_memcpy(to->data, ((byte *)from->data)+offset, real_size);		    } else {			ProcBin* from = (ProcBin *) objp;			ProcBin* to;						ASSERT(thing_subtag(*objp) == REFC_BINARY_SUBTAG);			hbot -= PROC_BIN_SIZE;			to = (ProcBin *) hbot;			to->thing_word = HEADER_PROC_BIN;			to->size = real_size;			to->val = from->val;			erts_refc_inc(&to->val->refc, 2);			to->bytes = from->bytes + offset;			to->next = off_heap->mso;			off_heap->mso = to;			off_heap->overhead += to->size /			  BINARY_OVERHEAD_FACTOR / sizeof(Eterm);		    }		    *argp = make_binary(hbot);		    if (extra_bytes != 0) {		      ErlSubBin* res;		      hbot -= ERL_SUB_BIN_SIZE;		      res = (ErlSubBin *) hbot;		      res->thing_word = HEADER_SUB_BIN;		      res->size = size;		      res->bitsize = bit_size;		      res->bitoffs = bit_offset;		      res->offs = 0;		      res->orig = *argp;		      *argp = make_binary(hbot);		    }		    break;		}		break;	    case FUN_SUBTAG:		{		    ErlFunThing* funp = (ErlFunThing *) objp;		    i =  thing_arityval(hdr) + 2 + funp->num_free;		    tp = htop;		    while (i--)  {			*htop++ = *objp++;		    }#ifndef HYBRID /* FIND ME! */		    funp = (ErlFunThing *) tp;		    funp->next = off_heap->funs;		    off_heap->funs = funp;		    erts_refc_inc(&funp->fe->refc, 2);#endif		    *argp = make_fun(tp);		}		break;	    case EXTERNAL_PID_SUBTAG:	    case EXTERNAL_PORT_SUBTAG:	    case EXTERNAL_REF_SUBTAG:		{		  ExternalThing *etp = (ExternalThing *) htop;		  i =  thing_arityval(hdr) + 1;		  tp = htop;		  while (i--)  {		    *htop++ = *objp++;		  }		  etp->next = off_heap->externals;		  off_heap->externals = etp;		  erts_refc_inc(&etp->node->refc, 2);		  *argp = make_external(tp);		}		break;	    case BIN_MATCHSTATE_SUBTAG:		erl_exit(ERTS_ABORT_EXIT,			 "copy_struct: matchstate term not allowed");	    default:		i = thing_arityval(hdr)+1;		hbot -= i;		tp = hbot;		*argp = make_boxed(hbot);		while (i--) {		    *tp++ = *objp++;		}	    }	    break;	case TAG_PRIMARY_HEADER:	    if (header_is_thing(obj) || hp == const_tuple) {		hp += header_arity(obj) + 1;	    } else {		hp++;	    }	    break;	}    }#ifdef DEBUG    if (htop != hbot)	erl_exit(ERTS_ABORT_EXIT,		 "Internal error in copy_struct() when copying %T:"		 " htop=%p != hbot=%p (sz=%bpu)\n",		 org_obj, htop, hbot, org_sz); #else    if (htop > hbot) {	erl_exit(ERTS_ABORT_EXIT,		 "Internal error in copy_struct(): htop, hbot overrun\n");    }#endif    *hpp = (Eterm *) (hstart+hsize);    return res;#undef in_area}#ifdef HYBRID#ifdef BM_MESSAGE_SIZES#  define BM_ADD(var,val) (var) += (val);#else#  define BM_ADD(var,val)#endif#ifdef DEBUG#  define CLEARMEM(PTR,SIZE) memset(PTR,0,SIZE*sizeof(Eterm))#else#  define CLEARMEM(PTR,SIZE)#endif#ifdef INCREMENTAL#define GlobalAlloc(p, need, hp)                                        \do {                                                                    \    Uint n = (need);                                                    \    BM_ADD(words_copied,n);                                             \    BM_SWAP_TIMER(copy,system);                                         \    /* If a new collection cycle is started during copy, the message *  \     * will end up in the old generation and all allocations         *  \     * thereafter must go directly into the old generation.          */ \    if (alloc_old) {                                                    \        erts_incremental_gc((p),n,&dest,1);                             \

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -