1 // -*- c-basic-offset: 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)
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.
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.
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.
25 #ifndef COMPILE_STATE_H
26 #define COMPILE_STATE_H
28 #include "ExecState.h" // For codetype... Kinda odd.
31 #include "bytecode/opargs.h"
33 #include <wtf/Assertions.h>
34 #include <wtf/HashSet.h>
35 #include <wtf/HashMap.h>
45 class FunctionBodyNode
;
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)
64 FunctionBodyNode
* functionBody() {
68 CodeType
codeType() const {
72 CodeBlock
& codeBlock();
74 CompileType
compileType() const {
81 // Returns true if the register is a formal temporary.
82 bool isTemporaryReg(Register regNum
) {
83 return regNum
>= initialMaxTemp
;
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
);
90 // This method is used to acquire a read value of a local...
91 OpValue
localReadVal(Register regNum
);
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
);
98 // This forces all live locals to temporaries.
99 void localFlushAll(CodeBlock
& block
);
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
;
109 OpValue
* localScope() {
110 return localScopeVal
;
113 OpValue
* thisValue() {
117 OpValue
* globalScope() {
118 return globalScopeVal
;
121 void setEvalResultRegister(OpValue
* val
) {
122 evalResRegister
= val
;
125 OpValue
* evalResultReg() {
126 return evalResRegister
;
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.
144 void pushNest(NestType type
, Node
* node
= 0);
152 bool inNestedScope() {
153 return scopeDepth
> 0;
156 bool inTryFinally() {
157 return finallyDepth
> 0;
160 const WTF::Vector
<NestInfo
>& nestStack() {
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
;
171 void setNeedsClosures() {
172 neededClosures
= true;
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
);
182 // Binds all the labels to the given node
183 void bindLabels(Node
* node
);
185 // Returns destination for the label (node will be 0 if not found)
186 Node
* resolveContinueLabel(Identifier label
);
187 Node
* resolveBreakLabel (Identifier label
);
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();
195 // Helpers for these and resolvePendingBreak
196 void enterLoop(Node
* node
) {
197 pushNest(ContBreakTarget
, node
);
198 pushDefaultBreak(node
);
199 pushDefaultContinue(node
);
202 void exitLoop(Node
* node
) {
205 popDefaultContinue();
206 resolvePendingBreaks(node
, CodeGen::nextPC(this));
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
);
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
);
219 OpValue
* localScopeVal
;
221 OpValue
* globalScopeVal
;
222 OpValue
* evalResRegister
;
225 CompileType compType
;
227 // Makes sure that any values of a local are
228 void flushLocal(CodeBlock
& block
, Register reg
);
230 friend class RegDescriptor
;
231 WTF::Vector
<RegDescriptor
*> locals
;
232 WTF::Vector
<RegDescriptor
*> freeMarkTemps
;
233 WTF::Vector
<RegDescriptor
*> freeNonMarkTemps
;
234 Register initialMaxTemp
;
237 FunctionBodyNode
* fbody
;
239 void reuse(RegDescriptor
* desc
, bool markable
) {
241 freeMarkTemps
.append(desc
);
243 freeNonMarkTemps
.append(desc
);
246 // Cached version of #of Scopes's from below.
249 // Cached version of #of Finally's from below...
252 WTF::Vector
<NestInfo
> nests
;
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.
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
264 // Targets for continue/break w/o destination.
265 WTF::Vector
<Node
*> defaultBreakTargets
;
266 WTF::Vector
<Node
*> defaultContinueTargets
;
268 // Named label targets
269 WTF::HashMap
<Identifier
, Node
*> labelTargets
;
271 WTF::HashMap
<Node
*, WTF::Vector
<Addr
>* > pendingBreaks
;
272 WTF::HashMap
<Node
*, WTF::Vector
<Addr
>* > pendingContinues
;
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...
281 RegDescriptor(CompileState
* owner
, Register reg
, bool markable
, bool temp
= true):
282 owner(owner
), regNo(reg
), temp(temp
), markable(markable
), killed(false), refCount(0)
285 Register
reg() const {
299 owner
->reuse(this, markable
);
307 void adopt(RegDescriptor
* other
) {
308 // Make this point to the same as an another descriptor, which is about to die..
310 markable
= other
->markable
;
311 regNo
= other
->regNo
;
313 // Mark the other descriptor as killed, as we took ownership of this.
314 other
->killed
= true;
325 inline OpValue
OpValue::immInt32(int32_t in
) {
327 initImm(&res
, OpType_int32
);
328 res
.value
.narrow
.int32Val
= in
;
332 inline OpValue
OpValue::immNumber(double in
) {
334 initImm(&res
, OpType_number
);
335 res
.value
.wide
.numberVal
= in
;
339 inline OpValue
OpValue::immValue(JSValue
* in
) {
341 initImm(&res
, OpType_value
);
342 res
.value
.wide
.valueVal
= in
;
346 inline OpValue
OpValue::immBool(bool in
) {
348 initImm(&res
, OpType_bool
);
349 res
.value
.narrow
.boolVal
= in
;
353 inline OpValue
OpValue::immString(UString
* in
) {
355 initImm(&res
, OpType_string
);
356 res
.value
.wide
.stringVal
= in
;
360 inline OpValue
OpValue::immIdent(Identifier
* in
) {
362 initImm(&res
, OpType_ident
);
363 res
.value
.wide
.identVal
= in
;
367 inline OpValue
OpValue::immNode(KJS::Node
* in
) {
369 initImm(&res
, OpType_node
);
370 res
.value
.wide
.nodeVal
= in
;
374 inline OpValue
OpValue::immCStr(const char* in
) {
376 initImm(&res
, OpType_cstr
);
377 res
.value
.wide
.cstrVal
= in
;
381 inline OpValue
OpValue::immAddr(Addr in
) {
383 initImm(&res
, OpType_addr
);
384 res
.value
.narrow
.addrVal
= in
;
388 inline OpValue::OpValue(): type(OpType_void
) {} // since should never occur as an argument..
393 // kate: indent-width 4; replace-tabs on; tab-width 4; space-indent on;