1 | /*
|
---|
2 | * Copyright (C) 2008 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 | *
|
---|
8 | * 1. Redistributions of source code must retain the above copyright
|
---|
9 | * notice, this list of conditions and the following disclaimer.
|
---|
10 | * 2. Redistributions in binary form must reproduce the above copyright
|
---|
11 | * notice, this list of conditions and the following disclaimer in the
|
---|
12 | * documentation and/or other materials provided with the distribution.
|
---|
13 | * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
|
---|
14 | * its contributors may be used to endorse or promote products derived
|
---|
15 | * from this software without specific prior written permission.
|
---|
16 | *
|
---|
17 | * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
|
---|
18 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
---|
19 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
---|
20 | * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
|
---|
21 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
---|
22 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
---|
23 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
---|
24 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
---|
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
---|
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
---|
27 | */
|
---|
28 |
|
---|
29 | #ifndef RegisterFile_h
|
---|
30 | #define RegisterFile_h
|
---|
31 |
|
---|
32 | #include "Register.h"
|
---|
33 | #include "collector.h"
|
---|
34 | #include <wtf/Noncopyable.h>
|
---|
35 |
|
---|
36 | namespace KJS {
|
---|
37 |
|
---|
38 | /*
|
---|
39 | A register file is a stack of register frames. We represent a register
|
---|
40 | frame by its offset from "base", the logical first entry in the register
|
---|
41 | file. The bottom-most register frame's offset from base is 0.
|
---|
42 |
|
---|
43 | In a program where function "a" calls function "b" (global code -> a -> b),
|
---|
44 | the register file might look like this:
|
---|
45 |
|
---|
46 | | global frame | call frame | call frame | spare capacity |
|
---|
47 | -----------------------------------------------------------------------------------------------------
|
---|
48 | | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | | | | | | <-- index in buffer
|
---|
49 | -----------------------------------------------------------------------------------------------------
|
---|
50 | | -3 | -2 | -1 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | | | | | | <-- index relative to base
|
---|
51 | -----------------------------------------------------------------------------------------------------
|
---|
52 | | <-globals | temps-> | <-vars | temps-> | <-vars |
|
---|
53 | ^ ^ ^ ^
|
---|
54 | | | | |
|
---|
55 | buffer base (frame 0) frame 1 frame 2
|
---|
56 |
|
---|
57 | Since all variables, including globals, are accessed by negative offsets
|
---|
58 | from their register frame pointers, to keep old global offsets correct, new
|
---|
59 | globals must appear at the beginning of the register file, shifting base
|
---|
60 | to the right.
|
---|
61 |
|
---|
62 | If we added one global variable to the register file depicted above, it
|
---|
63 | would look like this:
|
---|
64 |
|
---|
65 | | global frame |< >
|
---|
66 | -------------------------------> <
|
---|
67 | | 0 | 1 | 2 | 3 | 4 | 5 |< >snip< > <-- index in buffer
|
---|
68 | -------------------------------> <
|
---|
69 | | -4 | -3 | -2 | -1 | 0 | 1 |< > <-- index relative to base
|
---|
70 | -------------------------------> <
|
---|
71 | | <-globals | temps-> |
|
---|
72 | ^ ^
|
---|
73 | | |
|
---|
74 | buffer base (frame 0)
|
---|
75 |
|
---|
76 | As you can see, global offsets relative to base have stayed constant,
|
---|
77 | but base itself has moved. To keep up with possible changes to base,
|
---|
78 | clients keep an indirect pointer, so their calculations update
|
---|
79 | automatically when base changes.
|
---|
80 |
|
---|
81 | For client simplicity, the RegisterFile measures size and capacity from
|
---|
82 | "base", not "buffer".
|
---|
83 | */
|
---|
84 |
|
---|
85 | class RegisterFileStack;
|
---|
86 |
|
---|
87 | class RegisterFile : Noncopyable {
|
---|
88 | public:
|
---|
89 | enum { DefaultRegisterFileSize = 2 * 1024 * 1024 };
|
---|
90 |
|
---|
91 | RegisterFile(size_t maxSize, RegisterFileStack* m_baseObserver)
|
---|
92 | : m_safeForReentry(true)
|
---|
93 | , m_size(0)
|
---|
94 | , m_capacity(0)
|
---|
95 | , m_maxSize(maxSize)
|
---|
96 | , m_base(0)
|
---|
97 | , m_buffer(0)
|
---|
98 | , m_baseObserver(m_baseObserver)
|
---|
99 | {
|
---|
100 | }
|
---|
101 |
|
---|
102 | ~RegisterFile()
|
---|
103 | {
|
---|
104 | setBuffer(0);
|
---|
105 | }
|
---|
106 |
|
---|
107 | // Pointer to a value that holds the base of this register file.
|
---|
108 | Register** basePointer() { return &m_base; }
|
---|
109 |
|
---|
110 | void shrink(size_t size)
|
---|
111 | {
|
---|
112 | if (size < m_size)
|
---|
113 | m_size = size;
|
---|
114 | }
|
---|
115 |
|
---|
116 | bool grow(size_t size)
|
---|
117 | {
|
---|
118 | if (size > m_size) {
|
---|
119 | if (size > m_capacity) {
|
---|
120 | if (size > m_maxSize)
|
---|
121 | return false;
|
---|
122 | growBuffer(size, m_maxSize);
|
---|
123 | }
|
---|
124 | m_size = size;
|
---|
125 | }
|
---|
126 | return true;
|
---|
127 | }
|
---|
128 |
|
---|
129 | size_t size() { return m_size; }
|
---|
130 | size_t maxSize() { return m_maxSize; }
|
---|
131 |
|
---|
132 | void clear();
|
---|
133 |
|
---|
134 | void addGlobalSlots(size_t count);
|
---|
135 | int numGlobalSlots() { return static_cast<int>(m_base - m_buffer); }
|
---|
136 |
|
---|
137 | void copyGlobals(RegisterFile* src);
|
---|
138 |
|
---|
139 | void mark()
|
---|
140 | {
|
---|
141 | Collector::markStackObjectsConservatively(m_buffer, m_base + m_size);
|
---|
142 | }
|
---|
143 |
|
---|
144 | bool isGlobal() { return !!m_baseObserver; }
|
---|
145 |
|
---|
146 | bool safeForReentry() { return m_safeForReentry; }
|
---|
147 | void setSafeForReentry(bool safeForReentry) { m_safeForReentry = safeForReentry; }
|
---|
148 |
|
---|
149 | private:
|
---|
150 | size_t newBuffer(size_t size, size_t capacity, size_t minCapacity, size_t maxSize, size_t offset);
|
---|
151 | bool growBuffer(size_t minCapacity, size_t maxSize);
|
---|
152 | void setBuffer(Register* buffer)
|
---|
153 | {
|
---|
154 | if (m_buffer)
|
---|
155 | fastFree(m_buffer);
|
---|
156 |
|
---|
157 | m_buffer = buffer;
|
---|
158 | }
|
---|
159 |
|
---|
160 | void setBase(Register*);
|
---|
161 |
|
---|
162 | bool m_safeForReentry;
|
---|
163 | size_t m_size;
|
---|
164 | size_t m_capacity;
|
---|
165 | size_t m_maxSize;
|
---|
166 | Register* m_base;
|
---|
167 | Register* m_buffer;
|
---|
168 | RegisterFileStack* m_baseObserver;
|
---|
169 | };
|
---|
170 |
|
---|
171 | } // namespace KJS
|
---|
172 |
|
---|
173 | #endif // RegisterFile_h
|
---|