1 | // -*- c-basic-offset: 2 -*- |
2 | /* |
3 | * This file is part of the KDE libraries |
4 | * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) |
5 | * Copyright (C) 2001 Peter Kelly (pmk@post.com) |
6 | * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc. |
7 | * Copyright (C) 2007, 2008 Maksim Orlovich (maksim@kde.org) |
8 | * |
9 | * This library is free software; you can redistribute it and/or |
10 | * modify it under the terms of the GNU Library General Public |
11 | * License as published by the Free Software Foundation; either |
12 | * version 2 of the License, or (at your option) any later version. |
13 | * |
14 | * This library is distributed in the hope that it will be useful, |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
17 | * Library General Public License for more details. |
18 | * |
19 | * You should have received a copy of the GNU Library General Public License |
20 | * along with this library; see the file COPYING.LIB. If not, write to |
21 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
22 | * Boston, MA 02110-1301, USA. |
23 | * |
24 | */ |
25 | #ifndef COMPILE_STATE_H |
26 | #define COMPILE_STATE_H |
27 | |
28 | #include "ExecState.h" // For codetype... Kinda odd. |
29 | |
30 | #include "opcodes.h" |
31 | #include "bytecode/opargs.h" |
32 | |
33 | #include <wtf/Assertions.h> |
34 | #include <wtf/HashSet.h> |
35 | #include <wtf/HashMap.h> |
36 | |
37 | using WTF::HashSet; |
38 | using WTF::HashMap; |
39 | using WTF::Vector; |
40 | |
41 | |
42 | namespace KJS { |
43 | |
44 | class RegDescriptor; |
45 | class FunctionBodyNode; |
46 | |
47 | |
48 | enum CompileType |
49 | { |
50 | NotCompiled, |
51 | Release, |
52 | Debug |
53 | }; |
54 | |
55 | class CompileState |
56 | { |
57 | public: |
58 | CompileState(CodeType ctype, CompileType compType, FunctionBodyNode* fbody, Register initialMaxTemp): |
59 | localScopeVal(0), thisVal(0), globalScopeVal(0), evalResRegister(0), |
60 | ctype(ctype), compType(compType), locals(initialMaxTemp, 0), initialMaxTemp(initialMaxTemp), |
61 | maxTemp(initialMaxTemp), fbody(fbody), scopeDepth(0), finallyDepth(0), neededClosures(false) |
62 | { } |
63 | |
64 | FunctionBodyNode* functionBody() { |
65 | return fbody; |
66 | } |
67 | |
68 | CodeType codeType() const { |
69 | return ctype; |
70 | } |
71 | |
72 | CodeBlock& codeBlock(); |
73 | |
74 | CompileType compileType() const { |
75 | return compType; |
76 | } |
77 | |
78 | |
79 | ~CompileState(); |
80 | |
81 | // Returns true if the register is a formal temporary. |
82 | bool isTemporaryReg(Register regNum) { |
83 | return regNum >= initialMaxTemp; |
84 | } |
85 | |
86 | // We distinguish two kinds of temporaries --- markable and not. They'll get |
87 | // corresponding bits set in localStore when that's initialized. |
88 | void requestTemporary(OpType type, OpValue* value, OpValue* reference); |
89 | |
90 | // This method is used to acquire a read value of a local... |
91 | OpValue localReadVal(Register regNum); |
92 | |
93 | // And this one returns a reference, acquiring it for (immediate) write. |
94 | // If there are any active read copies, we will backup the old value to |
95 | // a temporary, and petchup their register descriptor to point to the backup. |
96 | OpValue localWriteRef(CodeBlock& block, Register regNum); |
97 | |
98 | // This forces all live locals to temporaries. |
99 | void localFlushAll(CodeBlock& block); |
100 | |
101 | // This sets the registers containing the local scope and |
102 | // 'this' values... It should be the rvalue, not the regnums |
103 | void setPreloadRegs(OpValue* localReg, OpValue* globalReg, OpValue* thisReg) { |
104 | localScopeVal = localReg; |
105 | globalScopeVal = globalReg; |
106 | thisVal = thisReg; |
107 | } |
108 | |
109 | OpValue* localScope() { |
110 | return localScopeVal; |
111 | } |
112 | |
113 | OpValue* thisValue() { |
114 | return thisVal; |
115 | } |
116 | |
117 | OpValue* globalScope() { |
118 | return globalScopeVal; |
119 | } |
120 | |
121 | void setEvalResultRegister(OpValue* val) { |
122 | evalResRegister = val; |
123 | } |
124 | |
125 | OpValue* evalResultReg() { |
126 | return evalResRegister; |
127 | } |
128 | |
129 | // To properly implement operations like continue and break, we need to keep track whether we |
130 | // are nested inside with, try-catch and try-finally operations. |
131 | // This serves two purposes: |
132 | // 1) if we're not jumping out of a try-finally, we have to unwind the cleanup stacks |
133 | // 2) if we're inside a try-finally, we have to jump to the finally and not |
134 | // do the normal operation (this applies to return as well) |
135 | // Also, if we're inside a 'with' or a catch we cannot optimize local variable access. |
136 | |
137 | enum NestType { |
138 | Scope, |
139 | OtherCleanup, |
140 | TryFinally, |
141 | ContBreakTarget |
142 | }; |
143 | |
144 | void pushNest(NestType type, Node* node = 0); |
145 | void popNest (); |
146 | |
147 | struct NestInfo { |
148 | NestType type; |
149 | Node* node; |
150 | }; |
151 | |
152 | bool inNestedScope() { |
153 | return scopeDepth > 0; |
154 | } |
155 | |
156 | bool inTryFinally() { |
157 | return finallyDepth > 0; |
158 | } |
159 | |
160 | const WTF::Vector<NestInfo>& nestStack() { |
161 | return nests; |
162 | } |
163 | |
164 | // Some constructs can be detected at compile time to involve |
165 | // taking of closures. We keep track of that and avoid stack-allocation |
166 | // if those are present. |
167 | bool needsClosures() { |
168 | return neededClosures; |
169 | } |
170 | |
171 | void setNeedsClosures() { |
172 | neededClosures = true; |
173 | } |
174 | |
175 | // Label stuff.... |
176 | |
177 | // Registers a pending label. Returns true if the label is OK, false if it's a duplicate. |
178 | // If it fails, the label stack isn't touched! |
179 | bool pushLabel(const Identifier& label); |
180 | void popLabel(); |
181 | |
182 | // Binds all the labels to the given node |
183 | void bindLabels(Node* node); |
184 | |
185 | // Returns destination for the label (node will be 0 if not found) |
186 | Node* resolveContinueLabel(Identifier label); |
187 | Node* resolveBreakLabel (Identifier label); |
188 | |
189 | // Sets the targets for break/continues w/o label name |
190 | void pushDefaultBreak (Node* node); |
191 | void pushDefaultContinue(Node* node); |
192 | void popDefaultBreak (); |
193 | void popDefaultContinue(); |
194 | |
195 | // Helpers for these and resolvePendingBreak |
196 | void enterLoop(Node* node) { |
197 | pushNest(ContBreakTarget, node); |
198 | pushDefaultBreak(node); |
199 | pushDefaultContinue(node); |
200 | } |
201 | |
202 | void exitLoop(Node* node) { |
203 | popNest(); |
204 | popDefaultBreak(); |
205 | popDefaultContinue(); |
206 | resolvePendingBreaks(node, CodeGen::nextPC(this)); |
207 | } |
208 | |
209 | // Adds break/continue as needing relevant target for given node |
210 | void addPendingBreak (Node* node, Addr addr); |
211 | void addPendingContinue(Node* node, Addr addr); |
212 | |
213 | // Patches up all pending break/continue statements to given destination. |
214 | // LabelNode takes care of the breaks itself, the loops need to deal |
215 | // with continue, though. |
216 | void resolvePendingBreaks (Node* node, Addr dest); |
217 | void resolvePendingContinues(Node* node, Addr dest); |
218 | private: |
219 | OpValue* localScopeVal; |
220 | OpValue* thisVal; |
221 | OpValue* globalScopeVal; |
222 | OpValue* evalResRegister; |
223 | |
224 | CodeType ctype; |
225 | CompileType compType; |
226 | |
227 | // Makes sure that any values of a local are |
228 | void flushLocal(CodeBlock& block, Register reg); |
229 | |
230 | friend class RegDescriptor; |
231 | WTF::Vector<RegDescriptor*> locals; |
232 | WTF::Vector<RegDescriptor*> freeMarkTemps; |
233 | WTF::Vector<RegDescriptor*> freeNonMarkTemps; |
234 | Register initialMaxTemp; |
235 | Register maxTemp; |
236 | |
237 | FunctionBodyNode* fbody; |
238 | |
239 | void reuse(RegDescriptor* desc, bool markable) { |
240 | if (markable) |
241 | freeMarkTemps.append(desc); |
242 | else |
243 | freeNonMarkTemps.append(desc); |
244 | } |
245 | |
246 | // Cached version of #of Scopes's from below. |
247 | int scopeDepth; |
248 | |
249 | // Cached version of #of Finally's from below... |
250 | int finallyDepth; |
251 | |
252 | WTF::Vector<NestInfo> nests; |
253 | |
254 | // This is true if we see code constructs that require taking a closure |
255 | // inside here, which means we should not stack-allocate activations. |
256 | bool neededClosures; |
257 | |
258 | // Label resolution.. |
259 | WTF::HashSet<Identifier> seenLabels; // all labels we're inside |
260 | WTF::Vector <Identifier> seenLabelsStack; |
261 | WTF::Vector <Identifier> pendingLabels; // labels tha that haven't been bound to |
262 | // a statement yet. |
263 | |
264 | // Targets for continue/break w/o destination. |
265 | WTF::Vector<Node*> defaultBreakTargets; |
266 | WTF::Vector<Node*> defaultContinueTargets; |
267 | |
268 | // Named label targets |
269 | WTF::HashMap<Identifier, Node*> labelTargets; |
270 | |
271 | WTF::HashMap<Node*, WTF::Vector<Addr>* > pendingBreaks; |
272 | WTF::HashMap<Node*, WTF::Vector<Addr>* > pendingContinues; |
273 | }; |
274 | |
275 | // We used register descriptors for two reasons: |
276 | // 1) For temporaries, we ref-counted them by OpValue in order to manage their lifetime |
277 | // 2) For locals, we use them to do COW of values... |
278 | class RegDescriptor |
279 | { |
280 | public: |
281 | RegDescriptor(CompileState* owner, Register reg, bool markable, bool temp = true): |
282 | owner(owner), regNo(reg), temp(temp), markable(markable), killed(false), refCount(0) |
283 | {} |
284 | |
285 | Register reg() const { |
286 | return regNo; |
287 | } |
288 | |
289 | void ref() { |
290 | ++refCount; |
291 | } |
292 | |
293 | void deref() { |
294 | --refCount; |
295 | if (refCount == 0) { |
296 | if (killed) |
297 | delete this; |
298 | else if (temp) |
299 | owner->reuse(this, markable); |
300 | } |
301 | } |
302 | |
303 | bool live() { |
304 | return refCount > 0; |
305 | } |
306 | |
307 | void adopt(RegDescriptor* other) { |
308 | // Make this point to the same as an another descriptor, which is about to die.. |
309 | temp = other->temp; |
310 | markable = other->markable; |
311 | regNo = other->regNo; |
312 | |
313 | // Mark the other descriptor as killed, as we took ownership of this. |
314 | other->killed = true; |
315 | } |
316 | private: |
317 | CompileState* owner; |
318 | Register regNo; |
319 | bool temp; |
320 | bool markable; |
321 | bool killed; |
322 | int refCount; |
323 | }; |
324 | |
325 | inline OpValue OpValue::immInt32(int32_t in) { |
326 | OpValue res; |
327 | initImm(&res, OpType_int32); |
328 | res.value.narrow.int32Val = in; |
329 | return res; |
330 | } |
331 | |
332 | inline OpValue OpValue::immNumber(double in) { |
333 | OpValue res; |
334 | initImm(&res, OpType_number); |
335 | res.value.wide.numberVal = in; |
336 | return res; |
337 | } |
338 | |
339 | inline OpValue OpValue::immValue(JSValue* in) { |
340 | assert(in); |
341 | OpValue res; |
342 | initImm(&res, OpType_value); |
343 | res.value.wide.valueVal = in; |
344 | return res; |
345 | } |
346 | |
347 | inline OpValue OpValue::immBool(bool in) { |
348 | OpValue res; |
349 | initImm(&res, OpType_bool); |
350 | res.value.narrow.boolVal = in; |
351 | return res; |
352 | } |
353 | |
354 | inline OpValue OpValue::immString(UString* in) { |
355 | OpValue res; |
356 | initImm(&res, OpType_string); |
357 | res.value.wide.stringVal = in; |
358 | return res; |
359 | } |
360 | |
361 | inline OpValue OpValue::immIdent(Identifier* in) { |
362 | OpValue res; |
363 | initImm(&res, OpType_ident); |
364 | res.value.wide.identVal = in; |
365 | return res; |
366 | } |
367 | |
368 | inline OpValue OpValue::immNode(KJS::Node* in) { |
369 | OpValue res; |
370 | initImm(&res, OpType_node); |
371 | res.value.wide.nodeVal = in; |
372 | return res; |
373 | } |
374 | |
375 | inline OpValue OpValue::immCStr(const char* in) { |
376 | OpValue res; |
377 | initImm(&res, OpType_cstr); |
378 | res.value.wide.cstrVal = in; |
379 | return res; |
380 | } |
381 | |
382 | inline OpValue OpValue::immAddr(Addr in) { |
383 | OpValue res; |
384 | initImm(&res, OpType_addr); |
385 | res.value.narrow.addrVal = in; |
386 | return res; |
387 | } |
388 | |
389 | inline OpValue::OpValue(): type(OpType_void) {} // since should never occur as an argument.. |
390 | |
391 | } |
392 | |
393 | #endif |
394 | // kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on; |
395 | |