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
37using WTF::HashSet;
38using WTF::HashMap;
39using WTF::Vector;
40
41
42namespace KJS {
43
44class RegDescriptor;
45class FunctionBodyNode;
46
47
48enum CompileType
49{
50 NotCompiled,
51 Release,
52 Debug
53};
54
55class CompileState
56{
57public:
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);
218private:
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...
278class RegDescriptor
279{
280public:
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 }
316private:
317 CompileState* owner;
318 Register regNo;
319 bool temp;
320 bool markable;
321 bool killed;
322 int refCount;
323};
324
325inline 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
332inline OpValue OpValue::immNumber(double in) {
333 OpValue res;
334 initImm(&res, OpType_number);
335 res.value.wide.numberVal = in;
336 return res;
337}
338
339inline 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
347inline OpValue OpValue::immBool(bool in) {
348 OpValue res;
349 initImm(&res, OpType_bool);
350 res.value.narrow.boolVal = in;
351 return res;
352}
353
354inline OpValue OpValue::immString(UString* in) {
355 OpValue res;
356 initImm(&res, OpType_string);
357 res.value.wide.stringVal = in;
358 return res;
359}
360
361inline OpValue OpValue::immIdent(Identifier* in) {
362 OpValue res;
363 initImm(&res, OpType_ident);
364 res.value.wide.identVal = in;
365 return res;
366}
367
368inline 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
375inline 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
382inline OpValue OpValue::immAddr(Addr in) {
383 OpValue res;
384 initImm(&res, OpType_addr);
385 res.value.narrow.addrVal = in;
386 return res;
387}
388
389inline 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