changeset 30590 | 14f7f48c1377 |
parent 25715 | d5a8dbdc5150 |
child 30774 | 6745424a720f |
child 30764 | fec48bf5a827 |
30589:4722e25bfd6d | 30590:14f7f48c1377 |
---|---|
40 #include "opto/optoreg.hpp" |
40 #include "opto/optoreg.hpp" |
41 #endif |
41 #endif |
42 |
42 |
43 // OopMapStream |
43 // OopMapStream |
44 |
44 |
45 OopMapStream::OopMapStream(OopMap* oop_map) { |
45 OopMapStream::OopMapStream(OopMap* oop_map, int oop_types_mask) { |
46 if(oop_map->omv_data() == NULL) { |
46 _stream = new CompressedReadStream(oop_map->write_stream()->buffer()); |
47 _stream = new CompressedReadStream(oop_map->write_stream()->buffer()); |
47 _mask = oop_types_mask; |
48 } else { |
|
49 _stream = new CompressedReadStream(oop_map->omv_data()); |
|
50 } |
|
51 _mask = OopMapValue::type_mask_in_place; |
|
52 _size = oop_map->omv_count(); |
48 _size = oop_map->omv_count(); |
53 _position = 0; |
49 _position = 0; |
54 _valid_omv = false; |
50 _valid_omv = false; |
55 } |
51 } |
56 |
52 |
57 |
53 OopMapStream::OopMapStream(const ImmutableOopMap* oop_map, int oop_types_mask) { |
58 OopMapStream::OopMapStream(OopMap* oop_map, int oop_types_mask) { |
54 _stream = new CompressedReadStream(oop_map->data_addr()); |
59 if(oop_map->omv_data() == NULL) { |
|
60 _stream = new CompressedReadStream(oop_map->write_stream()->buffer()); |
|
61 } else { |
|
62 _stream = new CompressedReadStream(oop_map->omv_data()); |
|
63 } |
|
64 _mask = oop_types_mask; |
55 _mask = oop_types_mask; |
65 _size = oop_map->omv_count(); |
56 _size = oop_map->count(); |
66 _position = 0; |
57 _position = 0; |
67 _valid_omv = false; |
58 _valid_omv = false; |
68 } |
59 } |
69 |
60 |
70 |
61 |
85 // frame_size units are stack-slots (4 bytes) NOT intptr_t; we can name odd |
76 // frame_size units are stack-slots (4 bytes) NOT intptr_t; we can name odd |
86 // slots to hold 4-byte values like ints and floats in the LP64 build. |
77 // slots to hold 4-byte values like ints and floats in the LP64 build. |
87 OopMap::OopMap(int frame_size, int arg_count) { |
78 OopMap::OopMap(int frame_size, int arg_count) { |
88 // OopMaps are usually quite so small, so pick a small initial size |
79 // OopMaps are usually quite so small, so pick a small initial size |
89 set_write_stream(new CompressedWriteStream(32)); |
80 set_write_stream(new CompressedWriteStream(32)); |
90 set_omv_data(NULL); |
|
91 set_omv_count(0); |
81 set_omv_count(0); |
92 |
82 |
93 #ifdef ASSERT |
83 #ifdef ASSERT |
94 _locs_length = VMRegImpl::stack2reg(0)->value() + frame_size + arg_count; |
84 _locs_length = VMRegImpl::stack2reg(0)->value() + frame_size + arg_count; |
95 _locs_used = NEW_RESOURCE_ARRAY(OopMapValue::oop_types, _locs_length); |
85 _locs_used = NEW_RESOURCE_ARRAY(OopMapValue::oop_types, _locs_length); |
100 |
90 |
101 OopMap::OopMap(OopMap::DeepCopyToken, OopMap* source) { |
91 OopMap::OopMap(OopMap::DeepCopyToken, OopMap* source) { |
102 // This constructor does a deep copy |
92 // This constructor does a deep copy |
103 // of the source OopMap. |
93 // of the source OopMap. |
104 set_write_stream(new CompressedWriteStream(source->omv_count() * 2)); |
94 set_write_stream(new CompressedWriteStream(source->omv_count() * 2)); |
105 set_omv_data(NULL); |
|
106 set_omv_count(0); |
95 set_omv_count(0); |
107 set_offset(source->offset()); |
96 set_offset(source->offset()); |
108 |
97 |
109 #ifdef ASSERT |
98 #ifdef ASSERT |
110 _locs_length = source->_locs_length; |
99 _locs_length = source->_locs_length; |
123 |
112 |
124 OopMap* OopMap::deep_copy() { |
113 OopMap* OopMap::deep_copy() { |
125 return new OopMap(_deep_copy_token, this); |
114 return new OopMap(_deep_copy_token, this); |
126 } |
115 } |
127 |
116 |
128 |
117 void OopMap::copy_data_to(address addr) const { |
129 void OopMap::copy_to(address addr) { |
118 memcpy(addr, write_stream()->buffer(), write_stream()->position()); |
130 memcpy(addr,this,sizeof(OopMap)); |
119 } |
131 memcpy(addr + sizeof(OopMap),write_stream()->buffer(),write_stream()->position()); |
|
132 OopMap* new_oop = (OopMap*)addr; |
|
133 new_oop->set_omv_data_size(write_stream()->position()); |
|
134 new_oop->set_omv_data((unsigned char *)(addr + sizeof(OopMap))); |
|
135 new_oop->set_write_stream(NULL); |
|
136 } |
|
137 |
|
138 |
120 |
139 int OopMap::heap_size() const { |
121 int OopMap::heap_size() const { |
140 int size = sizeof(OopMap); |
122 int size = sizeof(OopMap); |
141 int align = sizeof(void *) - 1; |
123 int align = sizeof(void *) - 1; |
142 if(write_stream() != NULL) { |
124 size += write_stream()->position(); |
143 size += write_stream()->position(); |
|
144 } else { |
|
145 size += omv_data_size(); |
|
146 } |
|
147 // Align to a reasonable ending point |
125 // Align to a reasonable ending point |
148 size = ((size+align) & ~align); |
126 size = ((size+align) & ~align); |
149 return size; |
127 return size; |
150 } |
128 } |
151 |
129 |
217 int new_size = om_size() * 2; |
195 int new_size = om_size() * 2; |
218 OopMap** new_data = NEW_RESOURCE_ARRAY(OopMap*, new_size); |
196 OopMap** new_data = NEW_RESOURCE_ARRAY(OopMap*, new_size); |
219 memcpy(new_data,om_data(),om_size() * sizeof(OopMap*)); |
197 memcpy(new_data,om_data(),om_size() * sizeof(OopMap*)); |
220 set_om_size(new_size); |
198 set_om_size(new_size); |
221 set_om_data(new_data); |
199 set_om_data(new_data); |
222 } |
|
223 |
|
224 |
|
225 void OopMapSet::copy_to(address addr) { |
|
226 address temp = addr; |
|
227 int align = sizeof(void *) - 1; |
|
228 // Copy this |
|
229 memcpy(addr,this,sizeof(OopMapSet)); |
|
230 temp += sizeof(OopMapSet); |
|
231 temp = (address)((intptr_t)(temp + align) & ~align); |
|
232 // Do the needed fixups to the new OopMapSet |
|
233 OopMapSet* new_set = (OopMapSet*)addr; |
|
234 new_set->set_om_data((OopMap**)temp); |
|
235 // Allow enough space for the OopMap pointers |
|
236 temp += (om_count() * sizeof(OopMap*)); |
|
237 |
|
238 for(int i=0; i < om_count(); i++) { |
|
239 OopMap* map = at(i); |
|
240 map->copy_to((address)temp); |
|
241 new_set->set(i,(OopMap*)temp); |
|
242 temp += map->heap_size(); |
|
243 } |
|
244 // This "locks" the OopMapSet |
|
245 new_set->set_om_size(-1); |
|
246 } |
200 } |
247 |
201 |
248 |
202 |
249 void OopMapSet::add_gc_map(int pc_offset, OopMap *map ) { |
203 void OopMapSet::add_gc_map(int pc_offset, OopMap *map ) { |
250 assert(om_size() != -1,"Cannot grow a fixed OopMapSet"); |
204 assert(om_size() != -1,"Cannot grow a fixed OopMapSet"); |
332 #ifndef PRODUCT |
286 #ifndef PRODUCT |
333 static void trace_codeblob_maps(const frame *fr, const RegisterMap *reg_map) { |
287 static void trace_codeblob_maps(const frame *fr, const RegisterMap *reg_map) { |
334 // Print oopmap and regmap |
288 // Print oopmap and regmap |
335 tty->print_cr("------ "); |
289 tty->print_cr("------ "); |
336 CodeBlob* cb = fr->cb(); |
290 CodeBlob* cb = fr->cb(); |
337 OopMapSet* maps = cb->oop_maps(); |
291 ImmutableOopMapSet* maps = cb->oop_maps(); |
338 OopMap* map = cb->oop_map_for_return_address(fr->pc()); |
292 const ImmutableOopMap* map = cb->oop_map_for_return_address(fr->pc()); |
339 map->print(); |
293 map->print(); |
340 if( cb->is_nmethod() ) { |
294 if( cb->is_nmethod() ) { |
341 nmethod* nm = (nmethod*)cb; |
295 nmethod* nm = (nmethod*)cb; |
342 // native wrappers have no scope data, it is implied |
296 // native wrappers have no scope data, it is implied |
343 if (nm->is_native_method()) { |
297 if (nm->is_native_method()) { |
369 CodeBlob* cb = fr->cb(); |
323 CodeBlob* cb = fr->cb(); |
370 assert(cb != NULL, "no codeblob"); |
324 assert(cb != NULL, "no codeblob"); |
371 |
325 |
372 NOT_PRODUCT(if (TraceCodeBlobStacks) trace_codeblob_maps(fr, reg_map);) |
326 NOT_PRODUCT(if (TraceCodeBlobStacks) trace_codeblob_maps(fr, reg_map);) |
373 |
327 |
374 OopMapSet* maps = cb->oop_maps(); |
328 ImmutableOopMapSet* maps = cb->oop_maps(); |
375 OopMap* map = cb->oop_map_for_return_address(fr->pc()); |
329 const ImmutableOopMap* map = cb->oop_map_for_return_address(fr->pc()); |
376 assert(map != NULL, "no ptr map found"); |
330 assert(map != NULL, "no ptr map found"); |
377 |
331 |
378 // handle derived pointers first (otherwise base pointer may be |
332 // handle derived pointers first (otherwise base pointer may be |
379 // changed before derived pointer offset has been collected) |
333 // changed before derived pointer offset has been collected) |
380 OopMapValue omv; |
334 OopMapValue omv; |
481 |
435 |
482 // Scan through oopmap and find location of all callee-saved registers |
436 // Scan through oopmap and find location of all callee-saved registers |
483 // (we do not do update in place, since info could be overwritten) |
437 // (we do not do update in place, since info could be overwritten) |
484 |
438 |
485 address pc = fr->pc(); |
439 address pc = fr->pc(); |
486 OopMap* map = cb->oop_map_for_return_address(pc); |
440 const ImmutableOopMap* map = cb->oop_map_for_return_address(pc); |
487 assert(map != NULL, "no ptr map found"); |
441 assert(map != NULL, "no ptr map found"); |
488 DEBUG_ONLY(int nof_callee = 0;) |
442 DEBUG_ONLY(int nof_callee = 0;) |
489 |
443 |
490 for (OopMapStream oms(map, OopMapValue::callee_saved_value); !oms.is_done(); oms.next()) { |
444 for (OopMapStream oms(map, OopMapValue::callee_saved_value); !oms.is_done(); oms.next()) { |
491 OopMapValue omv = oms.current(); |
445 OopMapValue omv = oms.current(); |
506 //============================================================================= |
460 //============================================================================= |
507 // Non-Product code |
461 // Non-Product code |
508 |
462 |
509 #ifndef PRODUCT |
463 #ifndef PRODUCT |
510 |
464 |
511 bool OopMap::has_derived_pointer() const { |
465 bool ImmutableOopMap::has_derived_pointer() const { |
512 #ifndef TIERED |
466 #ifndef TIERED |
513 COMPILER1_PRESENT(return false); |
467 COMPILER1_PRESENT(return false); |
514 #endif // !TIERED |
468 #endif // !TIERED |
515 #ifdef COMPILER2 |
469 #ifdef COMPILER2 |
516 OopMapStream oms((OopMap*)this,OopMapValue::derived_oop_value); |
470 OopMapStream oms((OopMap*)this,OopMapValue::derived_oop_value); |
548 default: |
502 default: |
549 ShouldNotReachHere(); |
503 ShouldNotReachHere(); |
550 } |
504 } |
551 } |
505 } |
552 |
506 |
553 |
|
554 void OopMapValue::print_on(outputStream* st) const { |
507 void OopMapValue::print_on(outputStream* st) const { |
555 reg()->print_on(st); |
508 reg()->print_on(st); |
556 st->print("="); |
509 st->print("="); |
557 print_register_type(type(),content_reg(),st); |
510 print_register_type(type(),content_reg(),st); |
558 st->print(" "); |
511 st->print(" "); |
559 } |
512 } |
560 |
513 |
514 void ImmutableOopMap::print_on(outputStream* st) const { |
|
515 OopMapValue omv; |
|
516 st->print("ImmutableOopMap{"); |
|
517 for(OopMapStream oms(this); !oms.is_done(); oms.next()) { |
|
518 omv = oms.current(); |
|
519 omv.print_on(st); |
|
520 } |
|
521 st->print("}"); |
|
522 } |
|
561 |
523 |
562 void OopMap::print_on(outputStream* st) const { |
524 void OopMap::print_on(outputStream* st) const { |
563 OopMapValue omv; |
525 OopMapValue omv; |
564 st->print("OopMap{"); |
526 st->print("OopMap{"); |
565 for(OopMapStream oms((OopMap*)this); !oms.is_done(); oms.next()) { |
527 for(OopMapStream oms((OopMap*)this); !oms.is_done(); oms.next()) { |
567 omv.print_on(st); |
529 omv.print_on(st); |
568 } |
530 } |
569 st->print("off=%d}", (int) offset()); |
531 st->print("off=%d}", (int) offset()); |
570 } |
532 } |
571 |
533 |
534 void ImmutableOopMapSet::print_on(outputStream* st) const { |
|
535 const ImmutableOopMap* last = NULL; |
|
536 for (int i = 0; i < _count; ++i) { |
|
537 const ImmutableOopMapPair* pair = pair_at(i); |
|
538 const ImmutableOopMap* map = pair->get_from(this); |
|
539 if (map != last) { |
|
540 st->cr(); |
|
541 map->print_on(st); |
|
542 st->print("pc offsets: "); |
|
543 } |
|
544 last = map; |
|
545 st->print("%d ", pair->pc_offset()); |
|
546 } |
|
547 } |
|
572 |
548 |
573 void OopMapSet::print_on(outputStream* st) const { |
549 void OopMapSet::print_on(outputStream* st) const { |
574 int i, len = om_count(); |
550 int i, len = om_count(); |
575 |
551 |
576 st->print_cr("OopMapSet contains %d OopMaps\n",len); |
552 st->print_cr("OopMapSet contains %d OopMaps\n",len); |
581 m->print_on(st); |
557 m->print_on(st); |
582 st->cr(); |
558 st->cr(); |
583 } |
559 } |
584 } |
560 } |
585 |
561 |
562 bool OopMap::equals(const OopMap* other) const { |
|
563 if (other->_omv_count != _omv_count) { |
|
564 return false; |
|
565 } |
|
566 if (other->write_stream()->position() != write_stream()->position()) { |
|
567 return false; |
|
568 } |
|
569 if (memcmp(other->write_stream()->buffer(), write_stream()->buffer(), write_stream()->position()) != 0) { |
|
570 return false; |
|
571 } |
|
572 return true; |
|
573 } |
|
574 |
|
575 const ImmutableOopMap* ImmutableOopMapSet::find_map_at_offset(int pc_offset) const { |
|
576 ImmutableOopMapPair* pairs = get_pairs(); |
|
577 ImmutableOopMapPair* last = NULL; |
|
578 |
|
579 for (int i = 0; i < _count; ++i) { |
|
580 if (pairs[i].pc_offset() >= pc_offset) { |
|
581 last = &pairs[i]; |
|
582 break; |
|
583 } |
|
584 } |
|
585 |
|
586 assert(last->pc_offset() == pc_offset, "oopmap not found"); |
|
587 return last->get_from(this); |
|
588 } |
|
589 |
|
590 const ImmutableOopMap* ImmutableOopMapPair::get_from(const ImmutableOopMapSet* set) const { |
|
591 return set->oopmap_at_offset(_oopmap_offset); |
|
592 } |
|
593 |
|
594 ImmutableOopMap::ImmutableOopMap(const OopMap* oopmap) : _count(oopmap->count()) { |
|
595 address addr = data_addr(); |
|
596 oopmap->copy_data_to(addr); |
|
597 } |
|
598 |
|
599 class ImmutableOopMapBuilder { |
|
600 private: |
|
601 class Mapping; |
|
602 |
|
603 private: |
|
604 const OopMapSet* _set; |
|
605 const OopMap* _empty; |
|
606 const OopMap* _last; |
|
607 int _empty_offset; |
|
608 int _last_offset; |
|
609 int _offset; |
|
610 Mapping* _mapping; |
|
611 ImmutableOopMapSet* _new_set; |
|
612 |
|
613 /* Used for bookkeeping when building ImmutableOopMaps */ |
|
614 class Mapping : public ResourceObj { |
|
615 public: |
|
616 enum kind_t { OOPMAP_UNKNOWN = 0, OOPMAP_NEW = 1, OOPMAP_EMPTY = 2, OOPMAP_DUPLICATE = 3 }; |
|
617 |
|
618 kind_t _kind; |
|
619 int _offset; |
|
620 int _size; |
|
621 const OopMap* _map; |
|
622 const OopMap* _other; |
|
623 |
|
624 Mapping() : _kind(OOPMAP_UNKNOWN), _offset(-1), _size(-1), _map(NULL) {} |
|
625 |
|
626 void set(kind_t kind, int offset, int size, const OopMap* map = 0, const OopMap* other = 0) { |
|
627 _kind = kind; |
|
628 _offset = offset; |
|
629 _size = size; |
|
630 _map = map; |
|
631 _other = other; |
|
632 } |
|
633 }; |
|
634 |
|
635 public: |
|
636 ImmutableOopMapBuilder(const OopMapSet* set) : _set(set), _new_set(NULL), _empty(NULL), _last(NULL), _empty_offset(-1), _last_offset(-1), _offset(0) { |
|
637 _mapping = NEW_RESOURCE_ARRAY(Mapping, _set->size()); |
|
638 } |
|
639 |
|
640 int heap_size(); |
|
641 ImmutableOopMapSet* build(); |
|
642 private: |
|
643 bool is_empty(const OopMap* map) const { |
|
644 return map->count() == 0; |
|
645 } |
|
646 |
|
647 bool is_last_duplicate(const OopMap* map) { |
|
648 if (_last != NULL && _last->count() > 0 && _last->equals(map)) { |
|
649 return true; |
|
650 } |
|
651 return false; |
|
652 } |
|
653 |
|
654 #ifdef ASSERT |
|
655 void verify(address buffer, int size); |
|
656 #endif |
|
657 |
|
658 bool has_empty() const { |
|
659 return _empty_offset != -1; |
|
660 } |
|
661 |
|
662 int size_for(const OopMap* map) const; |
|
663 void fill_pair(ImmutableOopMapPair* pair, const OopMap* map, int offset); |
|
664 int fill_map(ImmutableOopMapPair* pair, const OopMap* map, int offset); |
|
665 void fill(ImmutableOopMapSet* set, int size); |
|
666 }; |
|
667 |
|
668 int ImmutableOopMapBuilder::size_for(const OopMap* map) const { |
|
669 return align_size_up(sizeof(ImmutableOopMap) + map->data_size(), 8); |
|
670 } |
|
671 |
|
672 int ImmutableOopMapBuilder::heap_size() { |
|
673 int base = sizeof(ImmutableOopMapSet); |
|
674 base = align_size_up(base, 8); |
|
675 |
|
676 // all of ours pc / offset pairs |
|
677 int pairs = _set->size() * sizeof(ImmutableOopMapPair); |
|
678 pairs = align_size_up(pairs, 8); |
|
679 |
|
680 for (int i = 0; i < _set->size(); ++i) { |
|
681 int size = 0; |
|
682 OopMap* map = _set->at(i); |
|
683 |
|
684 if (is_empty(map)) { |
|
685 /* only keep a single empty map in the set */ |
|
686 if (has_empty()) { |
|
687 _mapping[i].set(Mapping::OOPMAP_EMPTY, _empty_offset, 0, map, _empty); |
|
688 } else { |
|
689 _empty_offset = _offset; |
|
690 _empty = map; |
|
691 size = size_for(map); |
|
692 _mapping[i].set(Mapping::OOPMAP_NEW, _offset, size, map); |
|
693 } |
|
694 } else if (is_last_duplicate(map)) { |
|
695 /* if this entry is identical to the previous one, just point it there */ |
|
696 _mapping[i].set(Mapping::OOPMAP_DUPLICATE, _last_offset, 0, map, _last); |
|
697 } else { |
|
698 /* not empty, not an identical copy of the previous entry */ |
|
699 size = size_for(map); |
|
700 _mapping[i].set(Mapping::OOPMAP_NEW, _offset, size, map); |
|
701 _last_offset = _offset; |
|
702 _last = map; |
|
703 } |
|
704 |
|
705 assert(_mapping[i]._map == map, "check"); |
|
706 _offset += size; |
|
707 } |
|
708 |
|
709 int total = base + pairs + _offset; |
|
710 DEBUG_ONLY(total += 8); |
|
711 return total; |
|
712 } |
|
713 |
|
714 void ImmutableOopMapBuilder::fill_pair(ImmutableOopMapPair* pair, const OopMap* map, int offset) { |
|
715 new ((address) pair) ImmutableOopMapPair(map->offset(), offset); |
|
716 } |
|
717 |
|
718 int ImmutableOopMapBuilder::fill_map(ImmutableOopMapPair* pair, const OopMap* map, int offset) { |
|
719 fill_pair(pair, map, offset); |
|
720 address addr = (address) pair->get_from(_new_set); // location of the ImmutableOopMap |
|
721 |
|
722 new (addr) ImmutableOopMap(map); |
|
723 return align_size_up(sizeof(ImmutableOopMap) + map->data_size(), 8); |
|
724 } |
|
725 |
|
726 void ImmutableOopMapBuilder::fill(ImmutableOopMapSet* set, int sz) { |
|
727 ImmutableOopMapPair* pairs = set->get_pairs(); |
|
728 |
|
729 for (int i = 0; i < set->count(); ++i) { |
|
730 const OopMap* map = _mapping[i]._map; |
|
731 ImmutableOopMapPair* pair = NULL; |
|
732 int size = 0; |
|
733 |
|
734 if (_mapping[i]._kind == Mapping::OOPMAP_NEW) { |
|
735 size = fill_map(&pairs[i], map, _mapping[i]._offset); |
|
736 } else if (_mapping[i]._kind == Mapping::OOPMAP_DUPLICATE || _mapping[i]._kind == Mapping::OOPMAP_EMPTY) { |
|
737 fill_pair(&pairs[i], map, _mapping[i]._offset); |
|
738 } |
|
739 |
|
740 const ImmutableOopMap* nv = set->find_map_at_offset(map->offset()); |
|
741 assert(memcmp(map->data(), nv->data_addr(), map->data_size()) == 0, "check identity"); |
|
742 } |
|
743 } |
|
744 |
|
745 #ifdef ASSERT |
|
746 void ImmutableOopMapBuilder::verify(address buffer, int size) { |
|
747 for (int i = 0; i < 8; ++i) { |
|
748 assert(buffer[size - 8 + i] == (unsigned char) 0xff, "overwritten memory check"); |
|
749 } |
|
750 } |
|
751 #endif |
|
752 |
|
753 ImmutableOopMapSet* ImmutableOopMapBuilder::build() { |
|
754 int required = heap_size(); |
|
755 |
|
756 // We need to allocate a chunk big enough to hold the ImmutableOopMapSet and all of its ImmutableOopMaps |
|
757 address buffer = (address) NEW_C_HEAP_ARRAY(unsigned char, required, mtCode); |
|
758 DEBUG_ONLY(memset(&buffer[required-8], 0xff, 8)); |
|
759 |
|
760 _new_set = new (buffer) ImmutableOopMapSet(_set, required); |
|
761 fill(_new_set, required); |
|
762 |
|
763 DEBUG_ONLY(verify(buffer, required)); |
|
764 |
|
765 return _new_set; |
|
766 } |
|
767 |
|
768 ImmutableOopMapSet* ImmutableOopMapSet::build_from(const OopMapSet* oopmap_set) { |
|
769 ResourceMark mark; |
|
770 ImmutableOopMapBuilder builder(oopmap_set); |
|
771 return builder.build(); |
|
772 } |
|
586 |
773 |
587 |
774 |
588 //------------------------------DerivedPointerTable--------------------------- |
775 //------------------------------DerivedPointerTable--------------------------- |
589 |
776 |
590 #ifdef COMPILER2 |
777 #ifdef COMPILER2 |