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 "Opcode.h"
29#include <wtf/Ref.h>
30#include <wtf/RefCounted.h>
31
32namespace JSC {
33
34class MetadataTable;
35
36class UnlinkedMetadataTable : public RefCounted<UnlinkedMetadataTable> {
37 friend class LLIntOffsetsExtractor;
38 friend class MetadataTable;
39 friend class CachedMetadataTable;
40public:
41 static constexpr unsigned s_maxMetadataAlignment = 8;
42
43 struct LinkingData {
44 Ref<UnlinkedMetadataTable> unlinkedMetadata;
45 unsigned refCount;
46 };
47
48 ~UnlinkedMetadataTable();
49
50 unsigned addEntry(OpcodeID);
51
52 size_t sizeInBytes();
53
54 void finalize();
55
56 RefPtr<MetadataTable> link();
57
58 static Ref<UnlinkedMetadataTable> create()
59 {
60 return adoptRef(*new UnlinkedMetadataTable);
61 }
62
63private:
64 enum EmptyTag { Empty };
65
66 UnlinkedMetadataTable();
67 UnlinkedMetadataTable(bool is32Bit);
68 UnlinkedMetadataTable(EmptyTag);
69
70 static Ref<UnlinkedMetadataTable> create(bool is32Bit)
71 {
72 return adoptRef(*new UnlinkedMetadataTable(is32Bit));
73 }
74
75 static Ref<UnlinkedMetadataTable> empty()
76 {
77 return adoptRef(*new UnlinkedMetadataTable(Empty));
78 }
79
80 void unlink(MetadataTable&);
81
82 size_t sizeInBytes(MetadataTable&);
83
84 unsigned totalSize() const
85 {
86 ASSERT(m_isFinalized);
87 if (m_is32Bit)
88 return offsetTable32()[s_offsetTableEntries - 1];
89 return offsetTable16()[s_offsetTableEntries - 1];
90 }
91
92 unsigned offsetTableSize() const
93 {
94 ASSERT(m_isFinalized);
95 if (m_is32Bit)
96 return s_offset16TableSize + s_offset32TableSize;
97 return s_offset16TableSize;
98 }
99
100 using Offset32 = uint32_t;
101 using Offset16 = uint16_t;
102
103 static constexpr unsigned s_offsetTableEntries = NUMBER_OF_BYTECODE_WITH_METADATA + 1; // one extra entry for the "end" offset;
104
105 // Not to break alignment of 32bit offset table, we round up size with sizeof(Offset32).
106 static constexpr unsigned s_offset16TableSize = roundUpToMultipleOf<sizeof(Offset32)>(s_offsetTableEntries * sizeof(Offset16));
107 // Not to break alignment of the metadata calculated based on the alignment of s_offset16TableSize, s_offset32TableSize must be rounded by 8.
108 // Then, s_offset16TableSize and s_offset16TableSize + s_offset32TableSize offer the same alignment characteristics for subsequent Metadata.
109 static constexpr unsigned s_offset32TableSize = roundUpToMultipleOf<s_maxMetadataAlignment>(s_offsetTableEntries * sizeof(Offset32));
110
111 Offset32* preprocessBuffer() const { return bitwise_cast<Offset32*>(m_rawBuffer + sizeof(LinkingData)); }
112 void* buffer() const { return m_rawBuffer + sizeof(LinkingData); }
113
114 Offset16* offsetTable16() const
115 {
116 ASSERT(!m_is32Bit);
117 return bitwise_cast<Offset16*>(m_rawBuffer + sizeof(LinkingData));
118 }
119 Offset32* offsetTable32() const
120 {
121 ASSERT(m_is32Bit);
122 return bitwise_cast<Offset32*>(m_rawBuffer + sizeof(LinkingData) + s_offset16TableSize);
123 }
124
125 bool m_hasMetadata : 1;
126 bool m_isFinalized : 1;
127 bool m_isLinked : 1;
128 bool m_is32Bit : 1;
129 uint8_t* m_rawBuffer;
130};
131
132} // namespace JSC
133