Hotspot 方法调用之StubRoutines 源码解析

  目录

一、StubRoutines

1、定义

2、  initialize1和initialize2方法

二、ResourceMark

1、ResourceArea

2、构造和析构函数

三、BufferBlob

四、CodeBlob

1、定义

2、构造和flush方法 

五、CodeBuffer

1、定义

2、构造和析构方法

3、copy_code_and_locs_to方法

六、CodeSection

1、定义

 2、initialize


上篇博客《Hotspot 方法调用之JavaCalls 源码解析》分析了本地代码调用Java方法的核心入口JavaCalls相关类的实现,本篇博客继续深入分析StubRoutines相关类的实现。

一、StubRoutines

1、定义

    StubRoutines是一个包含一系列编译程序或者JVM运行时系统使用的关键函数的地址的Holder类,其定义在hotspot src/share/vm/runtime/stubRoutines.hpp中。可以通过StubRoutines获取这些函数的内存地址,然后通过指针的方式调用目标函数,如下图:

以JavaCalls::call_helper方法中调用的StubRoutines::call_stub()方法为例说明,该方法返回的其实就是一个函数的地址,如下图:

CallStub就是这个函数的别名,这个其实是解释器执行字节码的终极入口。CAST_TO_FN_PTR宏定义就是完成指针类型转换的,如下图:

 

2、  initialize1和initialize2方法

我们重点关注StubRoutines的两个静态初始化方法initialize1和initialize2方法的实现,以此为入口了解该类的用法。这两个方法的调用链如下:

 

    最终都是在init_globals一个方法中调用的,不过initialize1在前,在universe初始化前执行,initialize2在universe初始化完成后执行,init_globals的代码如下:

  两者的源码实现说明如下:

void stubRoutines_init1() { StubRoutines::initialize1(); }
void stubRoutines_init2() { StubRoutines::initialize2(); }

void StubRoutines::initialize1() {
  if (_code1 == NULL) {
    //ResourceMark的作用类似于HandleMark,两者mark的区域不同,一个是ResourceArea,一个是HandleArea
    ResourceMark rm;
    //跟踪启动时间
    TraceTime timer("StubRoutines generation 1", TraceStartupTime);
    //创建一个保存不会重定位的本地代码的Blob
    _code1 = BufferBlob::create("StubRoutines (1)", code_size1);
    if (_code1 == NULL) {
      //创建失败抛出OOM异常
      vm_exit_out_of_memory(code_size1, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (1)");
    }
    CodeBuffer buffer(_code1);
    //生成字节码解释模板
    StubGenerator_generate(&buffer, false);
  }
}


void StubRoutines::initialize2() {
  if (_code2 == NULL) {
    ResourceMark rm;
    TraceTime timer("StubRoutines generation 2", TraceStartupTime);
    _code2 = BufferBlob::create("StubRoutines (2)", code_size2);
    if (_code2 == NULL) {
      vm_exit_out_of_memory(code_size2, OOM_MALLOC_ERROR, "CodeCache: no room for StubRoutines (2)");
    }
    CodeBuffer buffer(_code2);
    //跟initialize1中不同的是,这里传入的true,其他的都一样
    StubGenerator_generate(&buffer, true);
  }


   public:
  StubGenerator(CodeBuffer* code, bool all) : StubCodeGenerator(code) {
    if (all) {
      generate_all();
    } else {
      //如果传入false执行的是initial相关的代码
      generate_initial();
    }
  }
}; // end class declaration

void StubGenerator_generate(CodeBuffer* code, bool all) {
  StubGenerator g(code, all);
}

   下面会逐一分析相关类的用法。

二、ResourceMark

      ResourceMark和HandleMark用法类似,通过构造方法来保存当前线程的ResourceArea的状态,当方法执行完毕后,通过析构函数及时释放方法执行过程中从ResourceArea中分配的内存,将当前线程的ResourceArea的状态恢复至方法执行前的状态。ResourceMark的定义位于hotspot src/share/vm/memory/resourceArea.hpp中,它定义了四个protected属性,如下:

  • _area:ResourceArea *,关联的ResourceArea实例
  • _chunk:Chunk *,_area当前使用的Chunk
  • _hwm,_max:char *,_area当前使用的Chunk的可分配内存的范围
  • _size_in_bytes:size_t,_area的总的内存大小

ResourceMark定义的核心方法就只有其构造和析构函数。可参考《Hotspot 方法调用之HandleMark 源码解析》中HandleMark和HandleArea的实现和使用方式

1、ResourceArea

    ResourceArea跟HandleArea一样继承Area,其核心就是一个方法allocate_bytes,用于分配指定大小的内存,其源码说明如下:

 ResourceArea(MEMFLAGS flags = mtThread) : Arena(flags) {
    debug_only(_nesting = 0;)
  }

  ResourceArea(size_t init_size, MEMFLAGS flags = mtThread) : Arena(flags, init_size) {
    debug_only(_nesting = 0;);
  }


char* allocate_bytes(size_t size, AllocFailType alloc_failmode = AllocFailStrategy::EXIT_OOM) {
    //调用Area的Amalloc方法分配内存
    return (char*)Amalloc(size, alloc_failmode);
  }

  allocate_bytes的调用链如下:

2、构造和析构函数

     构造和析构函数的源码说明如下:

ResourceMark()               { initialize(Thread::current()); }

  ResourceMark( ResourceArea *r ) :
    _area(r), _chunk(r->_chunk), _hwm(r->_hwm), _max(r->_max) {
    //保存ResourceArea的各属性
    _size_in_bytes = r->_size_in_bytes;
    debug_only(_area->_nesting++;)
    assert( _area->_nesting > 0, "must stack allocate RMs" );
  }

    void initialize(Thread *thread) {
    //保存线程thread的resource_area的各属性
    _area = thread->resource_area();
    _chunk = _area->_chunk;
    _hwm = _area->_hwm;
    _max= _area->_max;
    _size_in_bytes = _area->size_in_bytes();
    debug_only(_area->_nesting++;)
    assert( _area->_nesting > 0, "must stack allocate RMs" );
  }

   ~ResourceMark() {
    assert( _area->_nesting > 0, "must stack allocate RMs" );
    debug_only(_area->_nesting--;)
    //把_area重置到ResourceMark创建时的属性
    reset_to_mark();
  }

    void reset_to_mark() {
     //UseMallocOnly表示只使用默认的malloc/free分配内存
    if (UseMallocOnly) free_malloced_objects();

    //如果存在下一个Chunk,即创建了新的Chunk
    if( _chunk->next() ) {       // Delete later chunks
      //创建了新Chunk则size_in_bytes变大
      assert(_area->size_in_bytes() > size_in_bytes(), "Sanity check");
      //恢复成原来的大小
      _area->set_size_in_bytes(size_in_bytes());
      //释放当前Chunk以后的所有Chunk
      _chunk->next_chop();
    } else {
      //没有创建新的Chunk,则size_in_bytes不变
      assert(_area->size_in_bytes() == size_in_bytes(), "Sanity check");
    }
    //恢复_area的各种属性
    _area->_chunk = _chunk;     // Roll back arena to saved chunk
    _area->_hwm = _hwm;
    _area->_max = _max;

    // 将_hwm和_max之间的内存填充badResourceValue
    if (ZapResourceArea) memset(_hwm, badResourceValue, _max - _hwm);
  }

以get_canonical_path的使用为例说明,如下图:

从上述的实例可知ResourceMark是在使用ResourceArea分配内存时构建,当分配的内存不再使用了就销毁ResourceMark,跟HandleMark在Java方法调用前后创建销毁略有不同。

三、BufferBlob

       BufferBlob继承自CodeBlob,定义位于hotspot src/share/vm/code/codeBlob.hpp中,用来保存不需要重定向的机器码,如解释器或者stubroutines的机器码,其类继承关系如下图:

BufferBlob没有添加新的属性,主要添加了创建和释放的方法,其源码说明如下:

BufferBlob* BufferBlob::create(const char* name, int buffer_size) {
   //通过构造和析构函数实现线程的状态转换
   //执行构造函数时从_thread_in_native转换成_thread_in_vm,析构时转换回去
  ThreadInVMfromUnknown __tiv;  // get to VM state in case we block on CodeCache_lock

  BufferBlob* blob = NULL;
  unsigned int size = sizeof(BufferBlob);
  //计算待分配的内存大小
  size = align_code_offset(size);
  //round_to是对buffer_size取整,使其等于oopSize的整数倍
  size += round_to(buffer_size, oopSize);
  assert(name != NULL, "must provide a name");
  {
    //获取锁CodeCache_lock
    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
    //创建一个新的BufferBlob,这里是分两步操作,先调用new分配内存,对分配的内存调用BufferBlob构造方法
    blob = new (size) BufferBlob(name, size);
  }
  //CodeCache_lock释放后记录内存的使用
  MemoryService::track_code_cache_memory_usage();

  return blob;
}

void* BufferBlob::operator new(size_t s, unsigned size, bool is_critical) throw() {
  //从CodeCache中分配指定大小的内存
  void* p = CodeCache::allocate(size, is_critical);
  return p;
}

BufferBlob::BufferBlob(const char* name, int size)
: CodeBlob(name, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, /*locs_size:*/ 0)
{}


BufferBlob* BufferBlob::create(const char* name, CodeBuffer* cb) {
  ThreadInVMfromUnknown __tiv;  // get to VM state in case we block on CodeCache_lock

  BufferBlob* blob = NULL;
  //计算待分配的内存大小
  unsigned int size = allocation_size(cb, sizeof(BufferBlob));
  assert(name != NULL, "must provide a name");
  {
    //获取锁CodeCache_lock
    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
    blob = new (size) BufferBlob(name, size, cb);
  }
  // Track memory usage statistic after releasing CodeCache_lock
  MemoryService::track_code_cache_memory_usage();

  return blob;
}

unsigned int CodeBlob::allocation_size(CodeBuffer* cb, int header_size) {
  //将CodeBuffer的各部分的内存大小相加
  unsigned int size = header_size;
  size += round_to(cb->total_relocation_size(), oopSize);
  // align the size to CodeEntryAlignment
  size = align_code_offset(size);
  size += round_to(cb->total_content_size(), oopSize);
  size += round_to(cb->total_oop_size(), oopSize);
  size += round_to(cb->total_metadata_size(), oopSize);
  return size;
}

BufferBlob::BufferBlob(const char* name, int size, CodeBuffer* cb)
  : CodeBlob(name, cb, sizeof(BufferBlob), size, CodeOffsets::frame_never_safe, 0, NULL)
{}


void BufferBlob::free( BufferBlob *blob ) {
   //转换线程状态
  ThreadInVMfromUnknown __tiv; 
  // 清空blob的数据
  blob->flush();
  {
    //获取锁CodeCache_lock
    MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
    //释放blob
    CodeCache::free((CodeBlob*)blob);
  }
  // Track memory usage statistic after releasing CodeCache_lock
  MemoryService::track_code_cache_memory_usage();
}

四、CodeBlob

1、定义

     CodeBlob是保存在CodeCache中所有实例的基类,跟BufferCode一样位于codeBlob.hpp中,参考BufferBlob中的类继承关系,其中

  • nmethod:表示编译后的Java代码,包含调用本地代码的方法
  • RuntimeStub:JVM运行时的方法
  • DeoptimizationBlob:用于去优化
  • ExceptionBlob:用于调用栈回滚
  • SafepointBlob:用于处理非法使用指令导致的易擦航

     其定义的属性如下:

  • _name:char*, CodeBlob的名称
  • _size:int,CodeBlob总的内存大小
  • _header_size:int,CodeBlob中header区的大小
  • _relocation_size:int,CodeBlob中relocation区的大小
  • _content_offset:int,content区开始的偏移位置
  • _code_offset:int,指令区开始的偏移位置
  • _frame_complete_offset:int,_frame_complete指令的偏移位置
  • _data_offset:int,data区的偏移位置
  • _frame_size:int,栈帧的大小
  • _oop_maps:OopMapSet*,关联的OopMapSet
  • _strings: CodeStrings,关联的代码字符串

    CodeBlob整体上在内存中划分为几个区的,如下图,其中content部分包含常量,指令等

     CodeBlob定义的方法可以分为以下几种:

  • 获取当前CodeBlob的类型,如is_buffer_blob,is_nmethod,is_runtime_stub等,都是虚方法,默认返回false
  • 获取CodeBlob中各部分内存的边界,如header_begin,header_end,relocation_begin,relocation_end等
  • 获取CodeBlob中各部分内存的大小,如header_size,relocation_size,content_size等
  • 获取CodeBlob中各部分内存的起始偏移量,如relocation_offset,data_offset等
  • 判断某部分内存是否包含某个指针,如blob_contains,relocation_contains,code_contains等
  • 其他属性相关的方法,如oop_maps,oop_map_for_return_address,frame_size,name等

2、构造和flush方法 

    BufferBlob中用到CodeBlob的构造方法和flush方法的源码说明如下:

CodeBlob::CodeBlob(const char* name, int header_size, int size, int frame_complete, int locs_size) {

  //校验size等是经过round_to取整后的
  assert(size        == round_to(size,        oopSize), "unaligned size");
  assert(locs_size   == round_to(locs_size,   oopSize), "unaligned size");
  assert(header_size == round_to(header_size, oopSize), "unaligned size");
  assert(!UseRelocIndex, "no space allocated for reloc index yet");

  //设置各属性
  _name                  = name;
  _size                  = size;
  _frame_complete_offset = frame_complete;
  _header_size           = header_size;
  _relocation_size       = locs_size;
  _content_offset        = align_code_offset(header_size + _relocation_size);
  _code_offset           = _content_offset;
  _data_offset           = size;
  _frame_size            =  0;
  set_oop_maps(NULL);
}

CodeBlob::CodeBlob(
  const char* name,
  CodeBuffer* cb,
  int         header_size,
  int         size,
  int         frame_complete,
  int         frame_size,
  OopMapSet*  oop_maps
) {
 //校验size等是经过round_to取整后的
  assert(size        == round_to(size,        oopSize), "unaligned size");
  assert(header_size == round_to(header_size, oopSize), "unaligned size");

  _name                  = name;
  _size                  = size;
  _frame_complete_offset = frame_complete;
  _header_size           = header_size;
   //从CodeBuffer中取出相关属性,设置到CodeBlob
  _relocation_size       = round_to(cb->total_relocation_size(), oopSize);
  _content_offset        = align_code_offset(header_size + _relocation_size);
  _code_offset           = _content_offset + cb->total_offset_of(cb->insts());
  _data_offset           = _content_offset + round_to(cb->total_content_size(), oopSize);
  assert(_data_offset <= size, "codeBlob is too small");
  //从CodeBuffer拷贝内存数据到CodeBlob中
  cb->copy_code_and_locs_to(this);
  set_oop_maps(oop_maps);
  _frame_size = frame_size;

}

void CodeBlob::flush() {
  if (_oop_maps) {
    //释放堆内存
    FREE_C_HEAP_ARRAY(unsigned char, _oop_maps, mtCode);
    _oop_maps = NULL;
  }
  //释放CodeString
  _strings.free();
}

五、CodeBuffer

1、定义

       CodeBuffer类似于IO里面的BufferedReader等用来临时缓存生成的汇编代码,CodeBuffer用来缓存汇编代码的内存通常是BufferBlob中content部分的内存,也可以是其他的已分配的一片内存,可参考CodeBuffer的构造函数,其定义位于hotspot src/share/vm/asm/codeBuffer.hpp中。CodeBuffer有两种变种,一种是引用一片用来生成静态代码的内存,这种代码没有任何重定向信息;一种是引用CodeBuffer创建时创建的内存,用于nmethod生成汇编代码。CodeBuffer的内存可以被划分成几个部分,每个部分称之为section,每个section都是独立增加汇编代码的,可以不断增长的。

       CodeBuffer定义的私有属性如下:

  • _name: const char*,CodeBuffer的名称
  • _consts:CodeSection,常量,指令跳转部分
  • _insts:CodeSection,汇编指令部分
  • _stubs:CodeSection,异常处理的回调地址等
  • _before_expand:CodeBuffer*,扩展前的CodeBuffer
  • _blob:BufferBlob*,可选的用于缓存生成的代码
  • _total_start:address,缓存代码的内存的起始地址
  • _total_size:csize_t,缓存代码的内存的大小
  • _oop_recorder:OopRecorder*,用于记录和检索oop的
  • _code_strings:CodeStrings,汇编代码字符串
  • _default_oop_recorder:OopRecorder,覆盖初始的initialize_oop_recorder

       CodeBuffer定义了一个表示其内存布局的枚举,也可通过此枚举完成内存各部分的遍历,如下图:

 

      CodeBuffer定义的public方法主要有以下几类:

  • 用来查找操作section的,如code_section,code_section_name,section_index_of等
  • 返回私有属性相关的,如consts,name,before_expand,blob,set_blob,oop_recorder等
  • 获取表示汇编指令的_insts的属性相关的,如insts_begin,insts_limit,insts_mark,insts_size,insts_remaining,relocate等
  • 获取某部分的内存大小,如total_content_size,total_offset_of,total_relocation_size,total_oop_size等

2、构造和析构方法

      构造和析构方法的源码说明如下:

CodeBuffer(address code_start, csize_t code_size) {
    assert(code_start != NULL, "sanity");
    initialize_misc("static buffer");
    initialize(code_start, code_size);
    verify_section_allocation();
  }

   void initialize_misc(const char * name) {
    // 各属性初始化
    assert(name != NULL, "must have a name");
    _name            = name;
    _before_expand   = NULL;
    _blob            = NULL;
    _oop_recorder    = NULL;
    _decode_begin    = NULL;
    _overflow_arena  = NULL;
  }

  void initialize(address code_start, csize_t code_size) {
     //各section初始化
    _consts.initialize_outer(this,  SECT_CONSTS);
    _insts.initialize_outer(this,   SECT_INSTS);
    _stubs.initialize_outer(this,   SECT_STUBS);
    _total_start = code_start;
    _total_size  = code_size;
    // Initialize the main section:
    _insts.initialize(code_start, code_size);
    assert(!_stubs.is_allocated(),  "no garbage here");
    assert(!_consts.is_allocated(), "no garbage here");
    _oop_recorder = &_default_oop_recorder;
  }

void CodeBuffer::verify_section_allocation() {
  //tstart表示内存的起始地址,tend表示结束地址
  address tstart = _total_start;
  if (tstart == badAddress)  return;  // smashed by set_blob(NULL)
  address tend   = tstart + _total_size;
  if (_blob != NULL) {
    //确保blob的content部分的内存在CodeBuffer的内存范围内
    guarantee(tstart >= _blob->content_begin(), "sanity");
    guarantee(tend   <= _blob->content_end(),   "sanity");
  }
  // 逐一遍历各section
  for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) {
    CodeSection* sect = code_section(n);
    //section为空或者未分配表示未填充对应的数据
    if (!sect->is_allocated() || sect->is_empty())  continue;
    //section不为空,其起始地址是按照alignment取整的
    guarantee((intptr_t)sect->start() % sect->alignment() == 0
           || sect->is_empty() || _blob == NULL,
           "start is aligned");
    for (int m = (int) SECT_FIRST; m < (int) SECT_LIMIT; m++) {
      CodeSection* other = code_section(m);
      if (!other->is_allocated() || other == sect)  continue;
      //确保其他section与当前section的内存没有重叠的
      guarantee(!other->contains(sect->start()    ), "sanity");
      guarantee(!other->contains(sect->limit() - 1), "sanity");
    }
    //确保section的结束地址小于CodeBuffer的结束地址
    guarantee(sect->end() <= tend, "sanity");
    guarantee(sect->end() <= sect->limit(), "sanity");
  }
}

CodeBuffer::CodeBuffer(CodeBlob* blob) {
  initialize_misc("static buffer");
  //利用目标blob的content的起始地址和大小完成CodeBuffer的section初始化
  initialize(blob->content_begin(), blob->content_size());
  verify_section_allocation();
}

//惰性初始化版本
 CodeBuffer(const char* name) {
    initialize_misc(name);
  }

    CodeBuffer(const char* name, csize_t code_size, csize_t locs_size) {
    initialize_misc(name);
    initialize(code_size, locs_size);
  }

void CodeBuffer::initialize(csize_t code_size, csize_t locs_size) {
  // Compute maximal alignment.
  int align = _insts.alignment();
  //slop表示每个section的间隔
  int slop = (int) CodeSection::end_slop();

  assert(blob() == NULL, "only once");
  //注意这里用了乘法,即为每个section都分配了内存
  set_blob(BufferBlob::create(_name, code_size + (align+slop) * (SECT_LIMIT+1)));
  //blob分配失败,抛出异常
  if (blob() == NULL) {
    // The assembler constructor will throw a fatal on an empty CodeBuffer.
    return;  // caller must test this
  }

  //section初始化
  initialize(_total_start, _total_size);

  assert((uintptr_t)insts_begin() % CodeEntryAlignment == 0, "instruction start not code entry aligned");

  pd_initialize();

  if (locs_size != 0) {
    //初始化locs
    _insts.initialize_locs(locs_size / sizeof(relocInfo));
  }

  verify_section_allocation();
}

  CodeBuffer::~CodeBuffer() {
  verify_section_allocation();

  //往前遍历找到扩展前的CodeBuffer
  for (CodeBuffer* cb = this; cb != NULL; cb = cb->before_expand()) {
    //释放CodeBuffer对应的blob
    cb->free_blob();
  }

  //释放_overflow_arena对应的内存
  delete _overflow_arena;

  //释放_code_strings
  free_strings();

}

void CodeBuffer::set_blob(BufferBlob* blob) {
  _blob = blob;
  if (blob != NULL) {
    address start = blob->content_begin();
    address end   = blob->content_end();
    //对起始地址取整,这个是根据blob的content的begin和end计算CodeBuffer的start和size
    int align = _insts.alignment();
    start += (-(intptr_t)start) & (align-1);
    _total_start = start;
    _total_size  = end - start;
  } else {

}

void CodeBuffer::free_blob() {
  if (_blob != NULL) {
    BufferBlob::free(_blob);
    set_blob(NULL);
  }
}

void free_strings() {
    if (!_code_strings.is_null()) {
      _code_strings.free(); // sets _strings Null as a side-effect.
    }
  }

3、copy_code_and_locs_to方法

     copy_code_and_locs_to方法用于将CodeBuffe中的汇编代码和重定向数据拷贝到一个新的Blob中,其源码说明如下:

void copy_code_and_locs_to(CodeBlob* blob) {
    assert(blob != NULL, "sane");
    //拷贝重定向section
    copy_relocations_to(blob);
    //拷贝inst汇编指令section
    copy_code_to(blob);
  }

  void CodeBuffer::copy_code_to(CodeBlob* dest_blob) {
  //利用目标dest_blob构造一个新的CodeBuffer
  CodeBuffer dest(dest_blob);
  //校验CodeBlob的content部分的大小大于CodeBuffer的大小
  assert(dest_blob->content_size() >= total_content_size(), "good sizing");
   //根据当前CodeBuffer的各section的属性初始化dest中各section的属性
  this->compute_final_layout(&dest);
  //拷贝代码
  relocate_code_to(&dest);

  //设置codeString
  dest_blob->set_strings(_code_strings);

  //检验dest代码拷贝的结果是否正确
  assert(round_to(dest.total_content_size(), oopSize) == dest_blob->content_size(), "sanity");

  //刷新指令缓存
  ICache::invalidate_range(dest_blob->code_begin(), dest_blob->code_size());
}


void CodeBuffer::compute_final_layout(CodeBuffer* dest) const {
  address buf = dest->_total_start;
  csize_t buf_offset = 0;
  //校验目标CodeBuffer的空间足够大
  assert(dest->_total_size >= total_content_size(), "must be big enough");

  {
    // not sure why this is here, but why not...
    int alignSize = MAX2((intx) sizeof(jdouble), CodeEntryAlignment);
    assert( (dest->_total_start - _insts.start()) % alignSize == 0, "copy must preserve alignment");
  }

  const CodeSection* prev_cs      = NULL;
  CodeSection*       prev_dest_cs = NULL;

  //逐一处理原CodeBuffer和新CodeBuffer的各section
  for (int n = (int) SECT_FIRST; n < (int) SECT_LIMIT; n++) {
    //cs表示原CodeBuffer的section
    const CodeSection* cs = code_section(n);
    csize_t csize = cs->size();
    //dest_cs表示新CodeBuffer的section
    CodeSection* dest_cs = dest->code_section(n);
    //如果cs不为空
    if (!cs->is_empty()) {
      // Compute initial padding; assign it to the previous non-empty guy.
      // Cf. figure_expanded_capacities.
      csize_t padding = cs->align_at_start(buf_offset) - buf_offset;
      if (padding != 0) {
        buf_offset += padding;
        assert(prev_dest_cs != NULL, "sanity");
        prev_dest_cs->_limit += padding;
      }
      prev_dest_cs = dest_cs;
      prev_cs      = cs;
    }

    debug_only(dest_cs->_start = NULL);  
    //dest_cs的初始化
    dest_cs->initialize(buf+buf_offset, csize);
    dest_cs->set_end(buf+buf_offset+csize);
    assert(dest_cs->is_allocated(), "must always be allocated");
    assert(cs->is_empty() == dest_cs->is_empty(), "sanity");

    buf_offset += csize;
  }

  // Done calculating sections; did it come out to the right end?
  assert(buf_offset == total_content_size(), "sanity");
  dest->verify_section_allocation();
}

六、CodeSection

1、定义

      CodeSection表示一个用来保存汇编代码和其关联的重定向表的内存区,CodeBuffer中有几个CodeSection,他们可以被并发的填充且尾部是连起来的。CodeSection同样定义在codeBuffer.hpp中,其包含私有属性如下:

  • _start:address,汇编指令的开始地址
  • _mark:address,用户打标的一个地址
  • _end:address,汇编指令的结束地址
  • _limit:address,允许填充汇编指令的地址下限
  • _locs_start: relocInfo* ,重定向信息的起始地址
  • _locs_end: relocInfo* ,重定向信息的结束地址
  • _locs_limit: relocInfo* ,保存重定向信息的内存的下限
  • _locs_point: address,上一次重定向的地址
  • _locs_own:bool,是否自己分配一个locs
  • _frozen:bool,是否冻结了
  • _index:int,标识所属的section的类型
  • _outer:CodeBuffer*,关联的外层的CodeBuffer

其描述的内存结构如下图所示:

 

CodeSection定义的方法可以分为以下几种:

  读写属性相关的,如start,end,set_end,locs_start,locs_end,index,has_locs等

  初始化相关的,如initialize_outer,initialize,initialize_locs,initialize_locs_from,initialize_shared_locs等

 Code emission时用来改写_end的方法,如emit_int8,emit_int16,emit_float,emit_address等

 2、initialize

      重点关注initialize相关方法的实现,其源码说明如下:

 
  //初始化_consts section调用
  void initialize_outer(CodeBuffer* outer, int index) {
    _outer = outer;
    _index = index;
  }
  
  //初始化_insts section调用
  void initialize(address start, csize_t size = 0) {
    assert(_start == NULL, "only one init step, please");
    _start         = start;
    _mark          = NULL;
    _end           = start;

    _limit         = start + size;
    _locs_point    = start;
  }

 //CodeBuffer::initialize(csize_t code_size, csize_t locs_size) 时调用
  void CodeSection::initialize_locs(int locs_capacity) {
  assert(_locs_start == NULL, "only one locs init step, please");
 
  csize_t min_locs = MAX2(size() / 16, (csize_t)4);
  //不能低于最低值
  if (locs_capacity < min_locs)  locs_capacity = min_locs;
  //NEW_RESOURCE_ARRAY是一个宏定义,从ResourceArea中分配内存
  relocInfo* locs_start = NEW_RESOURCE_ARRAY(relocInfo, locs_capacity);
  _locs_start    = locs_start;
  _locs_end      = locs_start;
  _locs_limit    = locs_start + locs_capacity;
  _locs_own      = true;
}


#define NEW_RESOURCE_ARRAY(type, size)\
  (type*) resource_allocate_bytes((size) * sizeof(type))

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值