/ bytecode / UnlinkedMetadataTableInlines.h
UnlinkedMetadataTableInlines.h
  1  /*
  2   * Copyright (C) 2018 Apple Inc. All rights reserved.
  3   *
  4   * Redistribution and use in source and binary forms, with or without
  5   * modification, are permitted provided that the following conditions
  6   * are met:
  7   * 1. Redistributions of source code must retain the above copyright
  8   *    notice, this list of conditions and the following disclaimer.
  9   * 2. Redistributions in binary form must reproduce the above copyright
 10   *    notice, this list of conditions and the following disclaimer in the
 11   *    documentation and/or other materials provided with the distribution.
 12   *
 13   * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14   * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
 17   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18   * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19   * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20   * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21   * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24   */
 25  
 26  #pragma once
 27  
 28  #include "MetadataTable.h"
 29  #include "UnlinkedMetadataTable.h"
 30  #include <wtf/FastMalloc.h>
 31  
 32  namespace JSC {
 33  
 34  
 35  ALWAYS_INLINE UnlinkedMetadataTable::UnlinkedMetadataTable()
 36      : m_hasMetadata(false)
 37      , m_isFinalized(false)
 38      , m_isLinked(false)
 39      , m_is32Bit(false)
 40      , m_rawBuffer(static_cast<uint8_t*>(MetadataTableMalloc::zeroedMalloc(sizeof(LinkingData) + s_offset32TableSize)))
 41  {
 42  }
 43  
 44  ALWAYS_INLINE UnlinkedMetadataTable::UnlinkedMetadataTable(bool is32Bit)
 45      : m_hasMetadata(false)
 46      , m_isFinalized(false)
 47      , m_isLinked(false)
 48      , m_is32Bit(is32Bit)
 49      , m_rawBuffer(static_cast<uint8_t*>(MetadataTableMalloc::zeroedMalloc(sizeof(LinkingData) + (is32Bit ? s_offset16TableSize + s_offset32TableSize : s_offset16TableSize))))
 50  {
 51  }
 52  
 53  ALWAYS_INLINE UnlinkedMetadataTable::UnlinkedMetadataTable(EmptyTag)
 54      : m_hasMetadata(false)
 55      , m_isFinalized(true)
 56      , m_isLinked(false)
 57      , m_is32Bit(false)
 58      , m_rawBuffer(nullptr)
 59  {
 60  }
 61  
 62  ALWAYS_INLINE UnlinkedMetadataTable::~UnlinkedMetadataTable()
 63  {
 64      ASSERT(!m_isLinked);
 65      if (m_hasMetadata || !m_isFinalized)
 66          MetadataTableMalloc::free(m_rawBuffer);
 67  }
 68  
 69  ALWAYS_INLINE unsigned UnlinkedMetadataTable::addEntry(OpcodeID opcodeID)
 70  {
 71      ASSERT(!m_isFinalized && opcodeID < s_offsetTableEntries - 1);
 72      m_hasMetadata = true;
 73      return preprocessBuffer()[opcodeID]++;
 74  }
 75  
 76  ALWAYS_INLINE size_t UnlinkedMetadataTable::sizeInBytes()
 77  {
 78      if (m_isFinalized && !m_hasMetadata)
 79          return 0;
 80  
 81      if (m_is32Bit)
 82          return s_offset16TableSize + s_offset32TableSize;
 83      return s_offset16TableSize;
 84  }
 85  
 86  ALWAYS_INLINE size_t UnlinkedMetadataTable::sizeInBytes(MetadataTable& metadataTable)
 87  {
 88      ASSERT(m_isFinalized);
 89  
 90      // In this case, we return the size of the table minus the offset table,
 91      // which was already accounted for in the UnlinkedCodeBlock.
 92  
 93      // Be careful not to touch m_rawBuffer if this metadataTable is not owning it.
 94      // It is possible that, m_rawBuffer is realloced in the other thread while we are accessing here.
 95      size_t result = metadataTable.totalSize();
 96      if (metadataTable.buffer() == buffer()) {
 97          ASSERT(m_isLinked);
 98          if (m_is32Bit)
 99              return result - (s_offset16TableSize + s_offset32TableSize);
100          return result - s_offset16TableSize;
101      }
102      return result;
103  }
104  
105  ALWAYS_INLINE RefPtr<MetadataTable> UnlinkedMetadataTable::link()
106  {
107      ASSERT(m_isFinalized);
108  
109      if (!m_hasMetadata)
110          return nullptr;
111  
112      unsigned totalSize = this->totalSize();
113      unsigned offsetTableSize = this->offsetTableSize();
114      uint8_t* buffer;
115      if (!m_isLinked) {
116          m_isLinked = true;
117          m_rawBuffer = buffer = reinterpret_cast<uint8_t*>(MetadataTableMalloc::realloc(m_rawBuffer, sizeof(LinkingData) + totalSize));
118      } else {
119          buffer = reinterpret_cast<uint8_t*>(MetadataTableMalloc::malloc(sizeof(LinkingData) + totalSize));
120          memcpy(buffer, m_rawBuffer, sizeof(LinkingData) + offsetTableSize);
121      }
122      memset(buffer + sizeof(LinkingData) + offsetTableSize, 0, totalSize - offsetTableSize);
123      return adoptRef(*new (buffer + sizeof(LinkingData)) MetadataTable(*this));
124  }
125  
126  ALWAYS_INLINE void UnlinkedMetadataTable::unlink(MetadataTable& metadataTable)
127  {
128      ASSERT(m_isFinalized);
129      if (!m_hasMetadata)
130          return;
131  
132      if (metadataTable.buffer() == buffer()) {
133          ASSERT(m_isLinked);
134          m_isLinked = false;
135          m_rawBuffer = static_cast<uint8_t*>(MetadataTableMalloc::realloc(m_rawBuffer, sizeof(LinkingData) + offsetTableSize()));
136          return;
137      }
138      MetadataTableMalloc::free(&metadataTable.linkingData());
139  }
140  
141  } // namespace JSC