📄 serialize.cc.svn-base
字号:
// Copyright 2006-2008 the V8 project authors. All rights reserved.// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following// disclaimer in the documentation and/or other materials provided// with the distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived// from this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#include "v8.h"#include "accessors.h"#include "api.h"#include "execution.h"#include "global-handles.h"#include "ic-inl.h"#include "natives.h"#include "platform.h"#include "runtime.h"#include "serialize.h"#include "stub-cache.h"#include "v8threads.h"namespace v8 { namespace internal {// Encoding: a RelativeAddress must be able to fit in a pointer:// it is encoded as an Address with (from MS to LS bits):// 27 bits identifying a word in the space, in one of three formats:// - MAP and OLD spaces: 16 bits of page number, 11 bits of word offset in page// - NEW space: 27 bits of word offset// - LO space: 27 bits of page number// 3 bits to encode the AllocationSpace (special values for code in LO space)// 2 bits identifying this as a HeapObjectconst int kSpaceShift = kHeapObjectTagSize;const int kSpaceBits = kSpaceTagSize;const int kSpaceMask = kSpaceTagMask;// These value are used instead of space numbers when serializing/// deserializing. They indicate an object that is in large object space, but// should be treated specially.// Make the pages executable on platforms that support it:const int kLOSpaceExecutable = LAST_SPACE + 1;// Reserve space for write barrier bits (for objects that can contain// references to new space):const int kLOSpacePointer = LAST_SPACE + 2;const int kOffsetShift = kSpaceShift + kSpaceBits;const int kOffsetBits = 11;const int kOffsetMask = (1 << kOffsetBits) - 1;const int kPageBits = 32 - (kOffsetBits + kSpaceBits + kHeapObjectTagSize);const int kPageShift = kOffsetShift + kOffsetBits;const int kPageMask = (1 << kPageBits) - 1;const int kPageAndOffsetShift = kOffsetShift;const int kPageAndOffsetBits = kPageBits + kOffsetBits;const int kPageAndOffsetMask = (1 << kPageAndOffsetBits) - 1;static inline AllocationSpace GetSpace(Address addr) { const int encoded = reinterpret_cast<int>(addr); int space_number = ((encoded >> kSpaceShift) & kSpaceMask); if (space_number == kLOSpaceExecutable) space_number = LO_SPACE; else if (space_number == kLOSpacePointer) space_number = LO_SPACE; return static_cast<AllocationSpace>(space_number);}static inline bool IsLargeExecutableObject(Address addr) { const int encoded = reinterpret_cast<int>(addr); const int space_number = ((encoded >> kSpaceShift) & kSpaceMask); if (space_number == kLOSpaceExecutable) return true; return false;}static inline bool IsLargeFixedArray(Address addr) { const int encoded = reinterpret_cast<int>(addr); const int space_number = ((encoded >> kSpaceShift) & kSpaceMask); if (space_number == kLOSpacePointer) return true; return false;}static inline int PageIndex(Address addr) { const int encoded = reinterpret_cast<int>(addr); return (encoded >> kPageShift) & kPageMask;}static inline int PageOffset(Address addr) { const int encoded = reinterpret_cast<int>(addr); return ((encoded >> kOffsetShift) & kOffsetMask) << kObjectAlignmentBits;}static inline int NewSpaceOffset(Address addr) { const int encoded = reinterpret_cast<int>(addr); return ((encoded >> kPageAndOffsetShift) & kPageAndOffsetMask) << kObjectAlignmentBits;}static inline int LargeObjectIndex(Address addr) { const int encoded = reinterpret_cast<int>(addr); return (encoded >> kPageAndOffsetShift) & kPageAndOffsetMask;}// A RelativeAddress encodes a heap address that is independent of// the actual memory addresses in real heap. The general case (for the// OLD, CODE and MAP spaces) is as a (space id, page number, page offset)// triple. The NEW space has page number == 0, because there are no// pages. The LARGE_OBJECT space has page offset = 0, since there is// exactly one object per page. RelativeAddresses are encodable as// Addresses, so that they can replace the map() pointers of// HeapObjects. The encoded Addresses are also encoded as HeapObjects// and allow for marking (is_marked() see mark(), clear_mark()...) as// used by the Mark-Compact collector.class RelativeAddress { public: RelativeAddress(AllocationSpace space, int page_index, int page_offset) : space_(space), page_index_(page_index), page_offset_(page_offset) { ASSERT(space <= LAST_SPACE && space >= 0); } // Return the encoding of 'this' as an Address. Decode with constructor. Address Encode() const; AllocationSpace space() const { if (space_ == kLOSpaceExecutable) return LO_SPACE; if (space_ == kLOSpacePointer) return LO_SPACE; return static_cast<AllocationSpace>(space_); } int page_index() const { return page_index_; } int page_offset() const { return page_offset_; } bool in_paged_space() const { return space_ == CODE_SPACE || space_ == OLD_POINTER_SPACE || space_ == OLD_DATA_SPACE || space_ == MAP_SPACE; } void next_address(int offset) { page_offset_ += offset; } void next_page(int init_offset = 0) { page_index_++; page_offset_ = init_offset; }#ifdef DEBUG void Verify();#endif void set_to_large_code_object() { ASSERT(space_ == LO_SPACE); space_ = kLOSpaceExecutable; } void set_to_large_fixed_array() { ASSERT(space_ == LO_SPACE); space_ = kLOSpacePointer; } private: int space_; int page_index_; int page_offset_;};Address RelativeAddress::Encode() const { ASSERT(page_index_ >= 0); int word_offset = 0; int result = 0; switch (space_) { case MAP_SPACE: case OLD_POINTER_SPACE: case OLD_DATA_SPACE: case CODE_SPACE: ASSERT_EQ(0, page_index_ & ~kPageMask); word_offset = page_offset_ >> kObjectAlignmentBits; ASSERT_EQ(0, word_offset & ~kOffsetMask); result = (page_index_ << kPageShift) | (word_offset << kOffsetShift); break; case NEW_SPACE: ASSERT_EQ(0, page_index_); word_offset = page_offset_ >> kObjectAlignmentBits; ASSERT_EQ(0, word_offset & ~kPageAndOffsetMask); result = word_offset << kPageAndOffsetShift; break; case LO_SPACE: case kLOSpaceExecutable: case kLOSpacePointer: ASSERT_EQ(0, page_offset_); ASSERT_EQ(0, page_index_ & ~kPageAndOffsetMask); result = page_index_ << kPageAndOffsetShift; break; } // OR in AllocationSpace and kHeapObjectTag ASSERT_EQ(0, space_ & ~kSpaceMask); result |= (space_ << kSpaceShift) | kHeapObjectTag; return reinterpret_cast<Address>(result);}#ifdef DEBUGvoid RelativeAddress::Verify() { ASSERT(page_offset_ >= 0 && page_index_ >= 0); switch (space_) { case MAP_SPACE: case OLD_POINTER_SPACE: case OLD_DATA_SPACE: case CODE_SPACE: ASSERT(Page::kObjectStartOffset <= page_offset_ && page_offset_ <= Page::kPageSize); break; case NEW_SPACE: ASSERT(page_index_ == 0); break; case LO_SPACE: case kLOSpaceExecutable: case kLOSpacePointer: ASSERT(page_offset_ == 0); break; }}#endifenum GCTreatment { DataObject, // Object that cannot contain a reference to new space. PointerObject, // Object that can contain a reference to new space. CodeObject // Object that contains executable code.};// A SimulatedHeapSpace simulates the allocation of objects in a page in// the heap. It uses linear allocation - that is, it doesn't simulate the// use of a free list. This simulated// allocation must exactly match that done by Heap.class SimulatedHeapSpace { public: // The default constructor initializes to an invalid state. SimulatedHeapSpace(): current_(LAST_SPACE, -1, -1) {} // Sets 'this' to the first address in 'space' that would be // returned by allocation in an empty heap. void InitEmptyHeap(AllocationSpace space); // Sets 'this' to the next address in 'space' that would be returned // by allocation in the current heap. Intended only for testing // serialization and deserialization in the current address space. void InitCurrentHeap(AllocationSpace space); // Returns the RelativeAddress where the next // object of 'size' bytes will be allocated, and updates 'this' to // point to the next free address beyond that object. RelativeAddress Allocate(int size, GCTreatment special_gc_treatment); private: RelativeAddress current_;};void SimulatedHeapSpace::InitEmptyHeap(AllocationSpace space) { switch (space) { case MAP_SPACE: case OLD_POINTER_SPACE: case OLD_DATA_SPACE: case CODE_SPACE: current_ = RelativeAddress(space, 0, Page::kObjectStartOffset); break; case NEW_SPACE: case LO_SPACE: current_ = RelativeAddress(space, 0, 0); break; }}void SimulatedHeapSpace::InitCurrentHeap(AllocationSpace space) { switch (space) { case MAP_SPACE: case OLD_POINTER_SPACE: case OLD_DATA_SPACE: case CODE_SPACE: { PagedSpace* ps; if (space == MAP_SPACE) { ps = Heap::map_space(); } else if (space == OLD_POINTER_SPACE) { ps = Heap::old_pointer_space(); } else if (space == OLD_DATA_SPACE) { ps = Heap::old_data_space(); } else { ASSERT(space == CODE_SPACE); ps = Heap::code_space(); } Address top = ps->top(); Page* top_page = Page::FromAllocationTop(top); int page_index = 0; PageIterator it(ps, PageIterator::PAGES_IN_USE); while (it.has_next()) { if (it.next() == top_page) break; page_index++; } current_ = RelativeAddress(space, page_index, top_page->Offset(top)); break; } case NEW_SPACE: current_ = RelativeAddress(space, 0, Heap::NewSpaceTop() - Heap::NewSpaceStart()); break; case LO_SPACE: int page_index = 0; for (LargeObjectIterator it(Heap::lo_space()); it.has_next(); it.next()) { page_index++; } current_ = RelativeAddress(space, page_index, 0); break; }}RelativeAddress SimulatedHeapSpace::Allocate(int size, GCTreatment special_gc_treatment) {#ifdef DEBUG current_.Verify();#endif int alloc_size = OBJECT_SIZE_ALIGN(size); if (current_.in_paged_space() && current_.page_offset() + alloc_size > Page::kPageSize) { ASSERT(alloc_size <= Page::kMaxHeapObjectSize); current_.next_page(Page::kObjectStartOffset); } RelativeAddress result = current_; if (current_.space() == LO_SPACE) { current_.next_page(); if (special_gc_treatment == CodeObject) { result.set_to_large_code_object(); } else if (special_gc_treatment == PointerObject) { result.set_to_large_fixed_array(); } } else { current_.next_address(alloc_size); }#ifdef DEBUG current_.Verify(); result.Verify();#endif return result;}// -----------------------------------------------------------------------------// Coding of external references.// The encoding of an external reference. The type is in the high word.// The id is in the low word.static uint32_t EncodeExternal(TypeCode type, uint16_t id) { return static_cast<uint32_t>(type) << 16 | id;}static int* GetInternalPointer(StatsCounter* counter) { // All counters refer to dummy_counter, if deserializing happens without // setting up counters. static int dummy_counter = 0; return counter->Enabled() ? counter->GetInternalPointer() : &dummy_counter;}// ExternalReferenceTable is a helper class that defines the relationship// between external references and their encodings. It is used to build// hashmaps in ExternalReferenceEncoder and ExternalReferenceDecoder.class ExternalReferenceTable { public: static ExternalReferenceTable* instance() { if (!instance_) instance_ = new ExternalReferenceTable(); return instance_; } int size() const { return refs_.length(); } Address address(int i) { return refs_[i].address; } uint32_t code(int i) { return refs_[i].code; } const char* name(int i) { return refs_[i].name; } int max_id(int code) { return max_id_[code]; } private: static ExternalReferenceTable* instance_; ExternalReferenceTable(); struct ExternalReferenceEntry { Address address; uint32_t code; const char* name; }; void Add(Address address, TypeCode type, uint16_t id, const char* name) { CHECK_NE(NULL, address); ExternalReferenceEntry entry; entry.address = address; entry.code = EncodeExternal(type, id); entry.name = name; CHECK_NE(0, entry.code); refs_.Add(entry); if (id > max_id_[type]) max_id_[type] = id; } List<ExternalReferenceEntry> refs_; int max_id_[kTypeCodeCount];};ExternalReferenceTable* ExternalReferenceTable::instance_ = NULL;ExternalReferenceTable::ExternalReferenceTable() : refs_(64) { for (int type_code = 0; type_code < kTypeCodeCount; type_code++) { max_id_[type_code] = 0; } // Define all entries in the table. // Builtins#define DEF_ENTRY_C(name) \ Add(Builtins::c_function_address(Builtins::c_##name), \ C_BUILTIN, \ Builtins::c_##name, \ "Builtins::" #name); BUILTIN_LIST_C(DEF_ENTRY_C)#undef DEF_ENTRY_C#define DEF_ENTRY_C(name) \ Add(Builtins::builtin_address(Builtins::name), \ BUILTIN, \ Builtins::name, \ "Builtins::" #name);#define DEF_ENTRY_A(name, kind, state) DEF_ENTRY_C(name) BUILTIN_LIST_C(DEF_ENTRY_C) BUILTIN_LIST_A(DEF_ENTRY_A)#undef DEF_ENTRY_C#undef DEF_ENTRY_A // Runtime functions#define RUNTIME_ENTRY(name, nargs) \ Add(Runtime::FunctionForId(Runtime::k##name)->entry, \ RUNTIME_FUNCTION, \ Runtime::k##name, \ "Runtime::" #name); RUNTIME_FUNCTION_LIST(RUNTIME_ENTRY)#undef RUNTIME_ENTRY // IC utilities#define IC_ENTRY(name) \ Add(IC::AddressFromUtilityId(IC::k##name), \ IC_UTILITY, \ IC::k##name, \ "IC::" #name); IC_UTIL_LIST(IC_ENTRY)#undef IC_ENTRY // Debug addresses Add(Debug_Address(Debug::k_after_break_target_address).address(), DEBUG_ADDRESS, Debug::k_after_break_target_address << kDebugIdShift, "Debug::after_break_target_address()"); Add(Debug_Address(Debug::k_debug_break_return_address).address(), DEBUG_ADDRESS, Debug::k_debug_break_return_address << kDebugIdShift, "Debug::debug_break_return_address()"); const char* debug_register_format = "Debug::register_address(%i)"; size_t dr_format_length = strlen(debug_register_format); for (int i = 0; i < kNumJSCallerSaved; ++i) { Vector<char> name = Vector<char>::New(dr_format_length + 1); OS::SNPrintF(name, debug_register_format, i); Add(Debug_Address(Debug::k_register_address, i).address(), DEBUG_ADDRESS, Debug::k_register_address << kDebugIdShift | i, name.start()); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -