2 * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
5 * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
6 * Copyright (C) 2007 Maks Orlovich
7 * Copyright (C) 2007 Eric Seidel <eric@webkit.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.
29 #include "ExecState.h"
30 #include "JSGlobalObject.h"
32 #include "PropertyNameArray.h"
33 #include "array_object.h"
35 #include "function_object.h"
37 #include "operations.h"
38 #include "regexp_object.h"
40 #include <wtf/Assertions.h>
41 #include <wtf/HashCountedSet.h>
42 #include <wtf/HashSet.h>
43 #include <wtf/MathExtras.h>
47 class FunctionBodyNodeWithDebuggerHooks
: public FunctionBodyNode
{
49 FunctionBodyNodeWithDebuggerHooks(SourceElements
*, VarStack
*, FunctionStack
*) KJS_FAST_CALL
;
50 virtual JSValue
* execute(ExecState
*) KJS_FAST_CALL
;
53 #define KJS_CHECKEXCEPTION \
54 if (exec->hadException()) \
55 return rethrowException(exec);
57 #define KJS_CHECKEXCEPTIONVALUE \
58 if (exec->hadException()) { \
59 handleException(exec); \
60 return jsUndefined(); \
63 #define KJS_CHECKEXCEPTIONNUMBER \
64 if (exec->hadException()) { \
65 handleException(exec); \
69 #define KJS_CHECKEXCEPTIONBOOLEAN \
70 if (exec->hadException()) { \
71 handleException(exec); \
75 #define KJS_CHECKEXCEPTIONVOID \
76 if (exec->hadException()) { \
77 handleException(exec); \
82 static inline bool canSkipLookup(ExecState
* exec
, const Identifier
& ident
)
84 // Static lookup in EvalCode is impossible because variables aren't DontDelete.
85 // Static lookup in GlobalCode may be possible, but we haven't implemented support for it yet.
86 if (exec
->codeType() != FunctionCode
)
89 // Static lookup is impossible when something dynamic has been added to the front of the scope chain.
90 if (exec
->variableObject() != exec
->scopeChain().top())
93 // Static lookup is impossible if the symbol isn't statically declared.
94 if (!exec
->variableObject()->symbolTable().contains(ident
.ustring().rep()))
101 static inline bool isConstant(const LocalStorage
& localStorage
, size_t index
)
103 ASSERT(index
< localStorage
.size());
104 return localStorage
[index
].attributes
& ReadOnly
;
107 // ------------------------------ Node -----------------------------------------
110 #ifndef LOG_CHANNEL_PREFIX
111 #define LOG_CHANNEL_PREFIX Log
113 static WTFLogChannel LogKJSNodeLeaks
= { 0x00000000, "", WTFLogChannelOn
};
115 struct ParserRefCountedCounter
{
116 static unsigned count
;
117 ParserRefCountedCounter()
120 LOG(KJSNodeLeaks
, "LEAK: %u KJS::Node\n", count
);
123 unsigned ParserRefCountedCounter::count
= 0;
124 static ParserRefCountedCounter parserRefCountedCounter
;
127 static HashSet
<ParserRefCounted
*>* newTrackedObjects
;
128 static HashCountedSet
<ParserRefCounted
*>* trackedObjectExtraRefCounts
;
130 ParserRefCounted::ParserRefCounted()
133 ++ParserRefCountedCounter::count
;
135 if (!newTrackedObjects
)
136 newTrackedObjects
= new HashSet
<ParserRefCounted
*>;
137 newTrackedObjects
->add(this);
138 ASSERT(newTrackedObjects
->contains(this));
141 ParserRefCounted::~ParserRefCounted()
144 --ParserRefCountedCounter::count
;
148 void ParserRefCounted::ref()
150 // bumping from 0 to 1 is just removing from the new nodes set
151 if (newTrackedObjects
) {
152 HashSet
<ParserRefCounted
*>::iterator it
= newTrackedObjects
->find(this);
153 if (it
!= newTrackedObjects
->end()) {
154 newTrackedObjects
->remove(it
);
155 ASSERT(!trackedObjectExtraRefCounts
|| !trackedObjectExtraRefCounts
->contains(this));
160 ASSERT(!newTrackedObjects
|| !newTrackedObjects
->contains(this));
162 if (!trackedObjectExtraRefCounts
)
163 trackedObjectExtraRefCounts
= new HashCountedSet
<ParserRefCounted
*>;
164 trackedObjectExtraRefCounts
->add(this);
167 void ParserRefCounted::deref()
169 ASSERT(!newTrackedObjects
|| !newTrackedObjects
->contains(this));
171 if (!trackedObjectExtraRefCounts
) {
176 HashCountedSet
<ParserRefCounted
*>::iterator it
= trackedObjectExtraRefCounts
->find(this);
177 if (it
== trackedObjectExtraRefCounts
->end())
180 trackedObjectExtraRefCounts
->remove(it
);
183 unsigned ParserRefCounted::refcount()
185 if (newTrackedObjects
&& newTrackedObjects
->contains(this)) {
186 ASSERT(!trackedObjectExtraRefCounts
|| !trackedObjectExtraRefCounts
->contains(this));
190 ASSERT(!newTrackedObjects
|| !newTrackedObjects
->contains(this));
192 if (!trackedObjectExtraRefCounts
)
195 return 1 + trackedObjectExtraRefCounts
->count(this);
198 void ParserRefCounted::deleteNewObjects()
200 if (!newTrackedObjects
)
204 HashSet
<ParserRefCounted
*>::iterator end
= newTrackedObjects
->end();
205 for (HashSet
<ParserRefCounted
*>::iterator it
= newTrackedObjects
->begin(); it
!= end
; ++it
)
206 ASSERT(!trackedObjectExtraRefCounts
|| !trackedObjectExtraRefCounts
->contains(*it
));
208 deleteAllValues(*newTrackedObjects
);
209 delete newTrackedObjects
;
210 newTrackedObjects
= 0;
214 : m_expectedReturnType(ObjectType
)
216 m_line
= lexer().lineNo();
219 Node::Node(JSType expectedReturn
)
220 : m_expectedReturnType(expectedReturn
)
222 m_line
= lexer().lineNo();
225 double ExpressionNode::evaluateToNumber(ExecState
* exec
)
227 JSValue
* value
= evaluate(exec
);
228 KJS_CHECKEXCEPTIONNUMBER
229 return value
->toNumber(exec
);
232 bool ExpressionNode::evaluateToBoolean(ExecState
* exec
)
234 JSValue
* value
= evaluate(exec
);
235 KJS_CHECKEXCEPTIONBOOLEAN
236 return value
->toBoolean(exec
);
239 int32_t ExpressionNode::evaluateToInt32(ExecState
* exec
)
241 JSValue
* value
= evaluate(exec
);
242 KJS_CHECKEXCEPTIONNUMBER
243 return value
->toInt32(exec
);
246 uint32_t ExpressionNode::evaluateToUInt32(ExecState
* exec
)
248 JSValue
* value
= evaluate(exec
);
249 KJS_CHECKEXCEPTIONNUMBER
250 return value
->toUInt32(exec
);
253 static void substitute(UString
& string
, const UString
& substring
) KJS_FAST_CALL
;
254 static void substitute(UString
& string
, const UString
& substring
)
256 int position
= string
.find("%s");
257 ASSERT(position
!= -1);
258 UString newString
= string
.substr(0, position
);
259 newString
.append(substring
);
260 newString
.append(string
.substr(position
+ 2));
264 static inline int currentSourceID(ExecState
* exec
) KJS_FAST_CALL
;
265 static inline int currentSourceID(ExecState
* exec
)
267 return exec
->scopeNode()->sourceID();
270 static inline const UString
& currentSourceURL(ExecState
* exec
) KJS_FAST_CALL
;
271 static inline const UString
& currentSourceURL(ExecState
* exec
)
273 return exec
->scopeNode()->sourceURL();
276 JSValue
* Node::setInterruptedCompletion(ExecState
* exec
)
278 return exec
->setInterruptedCompletion(Error::create(exec
, TimeoutError
, "JavaScript execution exceeded timeout.", lineNo(), currentSourceID(exec
), currentSourceURL(exec
)));
281 JSValue
* Node::setErrorCompletion(ExecState
* exec
, ErrorType e
, const char* msg
)
283 return exec
->setThrowCompletion(Error::create(exec
, e
, msg
, lineNo(), currentSourceID(exec
), currentSourceURL(exec
)));
286 JSValue
* Node::setErrorCompletion(ExecState
* exec
, ErrorType e
, const char* msg
, const Identifier
& ident
)
288 UString message
= msg
;
289 substitute(message
, ident
.ustring());
290 return exec
->setThrowCompletion(Error::create(exec
, e
, message
, lineNo(), currentSourceID(exec
), currentSourceURL(exec
)));
293 JSValue
* Node::throwError(ExecState
* exec
, ErrorType e
, const char* msg
)
295 return KJS::throwError(exec
, e
, msg
, lineNo(), currentSourceID(exec
), currentSourceURL(exec
));
298 JSValue
* Node::throwError(ExecState
* exec
, ErrorType e
, const char* msg
, const char* string
)
300 UString message
= msg
;
301 substitute(message
, string
);
302 return KJS::throwError(exec
, e
, message
, lineNo(), currentSourceID(exec
), currentSourceURL(exec
));
305 JSValue
* Node::throwError(ExecState
* exec
, ErrorType e
, const char* msg
, JSValue
* v
, Node
* expr
)
307 UString message
= msg
;
308 substitute(message
, v
->toString(exec
));
309 substitute(message
, expr
->toString());
310 return KJS::throwError(exec
, e
, message
, lineNo(), currentSourceID(exec
), currentSourceURL(exec
));
313 JSValue
* Node::throwError(ExecState
* exec
, ErrorType e
, const char* msg
, const Identifier
& label
)
315 UString message
= msg
;
316 substitute(message
, label
.ustring());
317 return KJS::throwError(exec
, e
, message
, lineNo(), currentSourceID(exec
), currentSourceURL(exec
));
320 JSValue
* Node::throwError(ExecState
* exec
, ErrorType e
, const char* msg
, JSValue
* v
, Node
* e1
, Node
* e2
)
322 UString message
= msg
;
323 substitute(message
, v
->toString(exec
));
324 substitute(message
, e1
->toString());
325 substitute(message
, e2
->toString());
326 return KJS::throwError(exec
, e
, message
, lineNo(), currentSourceID(exec
), currentSourceURL(exec
));
329 JSValue
* Node::throwError(ExecState
* exec
, ErrorType e
, const char* msg
, JSValue
* v
, Node
* expr
, const Identifier
& label
)
331 UString message
= msg
;
332 substitute(message
, v
->toString(exec
));
333 substitute(message
, expr
->toString());
334 substitute(message
, label
.ustring());
335 return KJS::throwError(exec
, e
, message
, lineNo(), currentSourceID(exec
), currentSourceURL(exec
));
338 JSValue
* Node::throwError(ExecState
* exec
, ErrorType e
, const char* msg
, JSValue
* v
, const Identifier
& label
)
340 UString message
= msg
;
341 substitute(message
, v
->toString(exec
));
342 substitute(message
, label
.ustring());
343 return KJS::throwError(exec
, e
, message
, lineNo(), currentSourceID(exec
), currentSourceURL(exec
));
346 JSValue
* Node::throwUndefinedVariableError(ExecState
* exec
, const Identifier
& ident
)
348 return throwError(exec
, ReferenceError
, "Can't find variable: %s", ident
);
351 void Node::handleException(ExecState
* exec
)
353 handleException(exec
, exec
->exception());
356 void Node::handleException(ExecState
* exec
, JSValue
* exceptionValue
)
358 if (exceptionValue
->isObject()) {
359 JSObject
* exception
= static_cast<JSObject
*>(exceptionValue
);
360 if (!exception
->hasProperty(exec
, "line") && !exception
->hasProperty(exec
, "sourceURL")) {
361 exception
->put(exec
, "line", jsNumber(m_line
));
362 exception
->put(exec
, "sourceURL", jsString(currentSourceURL(exec
)));
365 Debugger
* dbg
= exec
->dynamicGlobalObject()->debugger();
366 if (dbg
&& !dbg
->hasHandledException(exec
, exceptionValue
)) {
367 bool cont
= dbg
->exception(exec
, currentSourceID(exec
), m_line
, exceptionValue
);
373 NEVER_INLINE JSValue
* Node::rethrowException(ExecState
* exec
)
375 JSValue
* exception
= exec
->exception();
376 exec
->clearException();
377 handleException(exec
, exception
);
378 return exec
->setThrowCompletion(exception
);
381 // ------------------------------ StatementNode --------------------------------
383 StatementNode::StatementNode()
389 void StatementNode::setLoc(int firstLine
, int lastLine
)
392 m_lastLine
= lastLine
;
395 // ------------------------------ SourceElements --------------------------------
397 void SourceElements::append(PassRefPtr
<StatementNode
> statement
)
399 if (statement
->isEmptyStatement())
402 if (Debugger::debuggersPresent
)
403 m_statements
.append(new BreakpointCheckStatement(statement
));
405 m_statements
.append(statement
);
408 // ------------------------------ BreakpointCheckStatement --------------------------------
410 BreakpointCheckStatement::BreakpointCheckStatement(PassRefPtr
<StatementNode
> statement
)
411 : m_statement(statement
)
416 JSValue
* BreakpointCheckStatement::execute(ExecState
* exec
)
418 if (Debugger
* debugger
= exec
->dynamicGlobalObject()->debugger())
419 if (!debugger
->atStatement(exec
, currentSourceID(exec
), m_statement
->firstLine(), m_statement
->lastLine()))
420 return exec
->setNormalCompletion();
421 return m_statement
->execute(exec
);
424 void BreakpointCheckStatement::streamTo(SourceStream
& stream
)
426 m_statement
->streamTo(stream
);
429 void BreakpointCheckStatement::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
431 nodeStack
.append(m_statement
.get());
434 // ------------------------------ NullNode -------------------------------------
436 JSValue
* NullNode::evaluate(ExecState
* )
441 // ------------------------------ FalseNode ----------------------------------
443 JSValue
* FalseNode::evaluate(ExecState
*)
445 return jsBoolean(false);
448 // ------------------------------ TrueNode ----------------------------------
450 JSValue
* TrueNode::evaluate(ExecState
*)
452 return jsBoolean(true);
455 // ------------------------------ NumberNode -----------------------------------
457 JSValue
* NumberNode::evaluate(ExecState
*)
459 // Number nodes are only created when the number can't fit in a JSImmediate, so no need to check again.
460 return jsNumberCell(m_double
);
463 double NumberNode::evaluateToNumber(ExecState
*)
468 bool NumberNode::evaluateToBoolean(ExecState
*)
470 return m_double
< 0.0 || m_double
> 0.0; // false for NaN as well as 0
473 int32_t NumberNode::evaluateToInt32(ExecState
*)
475 return JSValue::toInt32(m_double
);
478 uint32_t NumberNode::evaluateToUInt32(ExecState
*)
480 return JSValue::toUInt32(m_double
);
483 // ------------------------------ ImmediateNumberNode -----------------------------------
485 JSValue
* ImmediateNumberNode::evaluate(ExecState
*)
490 int32_t ImmediateNumberNode::evaluateToInt32(ExecState
*)
492 return JSImmediate::getTruncatedInt32(m_value
);
495 uint32_t ImmediateNumberNode::evaluateToUInt32(ExecState
*)
498 if (JSImmediate::getTruncatedUInt32(m_value
, i
))
501 return JSValue::toUInt32SlowCase(m_double
, ok
);
504 // ------------------------------ StringNode -----------------------------------
506 JSValue
* StringNode::evaluate(ExecState
*)
508 return jsOwnedString(m_value
);
511 double StringNode::evaluateToNumber(ExecState
*)
513 return m_value
.toDouble();
516 bool StringNode::evaluateToBoolean(ExecState
*)
518 return !m_value
.isEmpty();
521 // ------------------------------ RegExpNode -----------------------------------
523 JSValue
* RegExpNode::evaluate(ExecState
* exec
)
525 return exec
->lexicalGlobalObject()->regExpConstructor()->createRegExpImp(exec
, m_regExp
);
528 // ------------------------------ ThisNode -------------------------------------
531 JSValue
* ThisNode::evaluate(ExecState
* exec
)
533 return exec
->thisValue();
536 // ------------------------------ ResolveNode ----------------------------------
538 // ECMA 11.1.2 & 10.1.4
539 JSValue
* ResolveNode::inlineEvaluate(ExecState
* exec
)
541 // Check for missed optimization opportunity.
542 ASSERT(!canSkipLookup(exec
, m_ident
));
544 const ScopeChain
& chain
= exec
->scopeChain();
545 ScopeChainIterator iter
= chain
.begin();
546 ScopeChainIterator end
= chain
.end();
548 // we must always have something in the scope chain
555 if (o
->getPropertySlot(exec
, m_ident
, slot
))
556 return slot
.getValue(exec
, o
, m_ident
);
559 } while (iter
!= end
);
561 return throwUndefinedVariableError(exec
, m_ident
);
564 JSValue
* ResolveNode::evaluate(ExecState
* exec
)
566 return inlineEvaluate(exec
);
569 double ResolveNode::evaluateToNumber(ExecState
* exec
)
571 JSValue
* v
= inlineEvaluate(exec
);
572 KJS_CHECKEXCEPTIONNUMBER
573 return v
->toNumber(exec
);
576 bool ResolveNode::evaluateToBoolean(ExecState
* exec
)
578 JSValue
* v
= inlineEvaluate(exec
);
579 KJS_CHECKEXCEPTIONBOOLEAN
580 return v
->toBoolean(exec
);
583 int32_t ResolveNode::evaluateToInt32(ExecState
* exec
)
585 JSValue
* v
= inlineEvaluate(exec
);
586 KJS_CHECKEXCEPTIONNUMBER
587 return v
->toInt32(exec
);
590 uint32_t ResolveNode::evaluateToUInt32(ExecState
* exec
)
592 JSValue
* v
= inlineEvaluate(exec
);
593 KJS_CHECKEXCEPTIONNUMBER
594 return v
->toUInt32(exec
);
597 void ResolveNode::optimizeVariableAccess(const SymbolTable
& symbolTable
, const LocalStorage
&, NodeStack
&)
599 size_t index
= symbolTable
.get(m_ident
.ustring().rep());
600 if (index
!= missingSymbolMarker())
601 new (this) LocalVarAccessNode(index
);
604 JSValue
* LocalVarAccessNode::inlineEvaluate(ExecState
* exec
)
606 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
607 return exec
->localStorage()[m_index
].value
;
610 JSValue
* LocalVarAccessNode::evaluate(ExecState
* exec
)
612 return inlineEvaluate(exec
);
615 double LocalVarAccessNode::evaluateToNumber(ExecState
* exec
)
617 return inlineEvaluate(exec
)->toNumber(exec
);
620 bool LocalVarAccessNode::evaluateToBoolean(ExecState
* exec
)
622 return inlineEvaluate(exec
)->toBoolean(exec
);
625 int32_t LocalVarAccessNode::evaluateToInt32(ExecState
* exec
)
627 return inlineEvaluate(exec
)->toInt32(exec
);
630 uint32_t LocalVarAccessNode::evaluateToUInt32(ExecState
* exec
)
632 return inlineEvaluate(exec
)->toUInt32(exec
);
635 // ------------------------------ ElementNode ----------------------------------
637 void ElementNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
640 nodeStack
.append(m_next
.get());
642 nodeStack
.append(m_node
.get());
646 JSValue
* ElementNode::evaluate(ExecState
* exec
)
648 JSObject
* array
= exec
->lexicalGlobalObject()->arrayConstructor()->construct(exec
, exec
->emptyList());
650 for (ElementNode
* n
= this; n
; n
= n
->m_next
.get()) {
651 JSValue
* val
= n
->m_node
->evaluate(exec
);
652 KJS_CHECKEXCEPTIONVALUE
653 length
+= n
->m_elision
;
654 array
->put(exec
, length
++, val
);
659 // ------------------------------ ArrayNode ------------------------------------
661 void ArrayNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
664 nodeStack
.append(m_element
.get());
668 JSValue
* ArrayNode::evaluate(ExecState
* exec
)
674 array
= static_cast<JSObject
*>(m_element
->evaluate(exec
));
675 KJS_CHECKEXCEPTIONVALUE
676 length
= m_optional
? array
->get(exec
, exec
->propertyNames().length
)->toInt32(exec
) : 0;
678 JSValue
* newArr
= exec
->lexicalGlobalObject()->arrayConstructor()->construct(exec
, exec
->emptyList());
679 array
= static_cast<JSObject
*>(newArr
);
684 array
->put(exec
, exec
->propertyNames().length
, jsNumber(m_elision
+ length
));
689 // ------------------------------ ObjectLiteralNode ----------------------------
691 void ObjectLiteralNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
694 nodeStack
.append(m_list
.get());
698 JSValue
* ObjectLiteralNode::evaluate(ExecState
* exec
)
701 return m_list
->evaluate(exec
);
703 return exec
->lexicalGlobalObject()->objectConstructor()->construct(exec
, exec
->emptyList());
706 // ------------------------------ PropertyListNode -----------------------------
708 void PropertyListNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
711 nodeStack
.append(m_next
.get());
712 nodeStack
.append(m_node
.get());
716 JSValue
* PropertyListNode::evaluate(ExecState
* exec
)
718 JSObject
* obj
= exec
->lexicalGlobalObject()->objectConstructor()->construct(exec
, exec
->emptyList());
720 for (PropertyListNode
* p
= this; p
; p
= p
->m_next
.get()) {
721 JSValue
* v
= p
->m_node
->m_assign
->evaluate(exec
);
722 KJS_CHECKEXCEPTIONVALUE
724 switch (p
->m_node
->m_type
) {
725 case PropertyNode::Getter
:
726 ASSERT(v
->isObject());
727 obj
->defineGetter(exec
, p
->m_node
->name(), static_cast<JSObject
* >(v
));
729 case PropertyNode::Setter
:
730 ASSERT(v
->isObject());
731 obj
->defineSetter(exec
, p
->m_node
->name(), static_cast<JSObject
* >(v
));
733 case PropertyNode::Constant
:
734 obj
->put(exec
, p
->m_node
->name(), v
);
742 // ------------------------------ PropertyNode -----------------------------
744 void PropertyNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
746 nodeStack
.append(m_assign
.get());
750 JSValue
* PropertyNode::evaluate(ExecState
*)
756 // ------------------------------ BracketAccessorNode --------------------------------
758 void BracketAccessorNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
760 nodeStack
.append(m_subscript
.get());
761 nodeStack
.append(m_base
.get());
765 JSValue
* BracketAccessorNode::inlineEvaluate(ExecState
* exec
)
767 JSValue
* v1
= m_base
->evaluate(exec
);
768 KJS_CHECKEXCEPTIONVALUE
769 JSValue
* v2
= m_subscript
->evaluate(exec
);
770 KJS_CHECKEXCEPTIONVALUE
771 JSObject
* o
= v1
->toObject(exec
);
773 if (v2
->getUInt32(i
))
774 return o
->get(exec
, i
);
775 return o
->get(exec
, Identifier(v2
->toString(exec
)));
778 JSValue
* BracketAccessorNode::evaluate(ExecState
* exec
)
780 return inlineEvaluate(exec
);
783 double BracketAccessorNode::evaluateToNumber(ExecState
* exec
)
785 JSValue
* v
= inlineEvaluate(exec
);
786 KJS_CHECKEXCEPTIONNUMBER
787 return v
->toNumber(exec
);
790 bool BracketAccessorNode::evaluateToBoolean(ExecState
* exec
)
792 JSValue
* v
= inlineEvaluate(exec
);
793 KJS_CHECKEXCEPTIONBOOLEAN
794 return v
->toBoolean(exec
);
797 int32_t BracketAccessorNode::evaluateToInt32(ExecState
* exec
)
799 JSValue
* v
= inlineEvaluate(exec
);
800 KJS_CHECKEXCEPTIONNUMBER
801 return v
->toInt32(exec
);
804 uint32_t BracketAccessorNode::evaluateToUInt32(ExecState
* exec
)
806 JSValue
* v
= inlineEvaluate(exec
);
807 KJS_CHECKEXCEPTIONNUMBER
808 return v
->toUInt32(exec
);
811 // ------------------------------ DotAccessorNode --------------------------------
813 void DotAccessorNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
815 nodeStack
.append(m_base
.get());
819 JSValue
* DotAccessorNode::inlineEvaluate(ExecState
* exec
)
821 JSValue
* v
= m_base
->evaluate(exec
);
822 KJS_CHECKEXCEPTIONVALUE
823 return v
->toObject(exec
)->get(exec
, m_ident
);
826 JSValue
* DotAccessorNode::evaluate(ExecState
* exec
)
828 return inlineEvaluate(exec
);
831 double DotAccessorNode::evaluateToNumber(ExecState
* exec
)
833 JSValue
* v
= inlineEvaluate(exec
);
834 KJS_CHECKEXCEPTIONNUMBER
835 return v
->toNumber(exec
);
838 bool DotAccessorNode::evaluateToBoolean(ExecState
* exec
)
840 JSValue
* v
= inlineEvaluate(exec
);
841 KJS_CHECKEXCEPTIONBOOLEAN
842 return v
->toBoolean(exec
);
845 int32_t DotAccessorNode::evaluateToInt32(ExecState
* exec
)
847 JSValue
* v
= inlineEvaluate(exec
);
848 KJS_CHECKEXCEPTIONNUMBER
849 return v
->toInt32(exec
);
852 uint32_t DotAccessorNode::evaluateToUInt32(ExecState
* exec
)
854 JSValue
* v
= inlineEvaluate(exec
);
855 KJS_CHECKEXCEPTIONNUMBER
856 return v
->toUInt32(exec
);
859 // ------------------------------ ArgumentListNode -----------------------------
861 void ArgumentListNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
864 nodeStack
.append(m_next
.get());
866 nodeStack
.append(m_expr
.get());
870 void ArgumentListNode::evaluateList(ExecState
* exec
, List
& list
)
872 for (ArgumentListNode
* n
= this; n
; n
= n
->m_next
.get()) {
873 JSValue
* v
= n
->m_expr
->evaluate(exec
);
874 KJS_CHECKEXCEPTIONVOID
879 // ------------------------------ ArgumentsNode --------------------------------
881 void ArgumentsNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
884 nodeStack
.append(m_listNode
.get());
887 // ------------------------------ NewExprNode ----------------------------------
889 void NewExprNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
892 nodeStack
.append(m_args
.get());
893 nodeStack
.append(m_expr
.get());
898 JSValue
* NewExprNode::inlineEvaluate(ExecState
* exec
)
900 JSValue
* v
= m_expr
->evaluate(exec
);
901 KJS_CHECKEXCEPTIONVALUE
905 m_args
->evaluateList(exec
, argList
);
906 KJS_CHECKEXCEPTIONVALUE
910 return throwError(exec
, TypeError
, "Value %s (result of expression %s) is not an object. Cannot be used with new.", v
, m_expr
.get());
912 JSObject
* constr
= static_cast<JSObject
*>(v
);
913 if (!constr
->implementsConstruct())
914 return throwError(exec
, TypeError
, "Value %s (result of expression %s) is not a constructor. Cannot be used with new.", v
, m_expr
.get());
916 return constr
->construct(exec
, argList
);
919 JSValue
* NewExprNode::evaluate(ExecState
* exec
)
921 return inlineEvaluate(exec
);
924 double NewExprNode::evaluateToNumber(ExecState
* exec
)
926 JSValue
* v
= inlineEvaluate(exec
);
927 KJS_CHECKEXCEPTIONNUMBER
928 return v
->toNumber(exec
);
931 bool NewExprNode::evaluateToBoolean(ExecState
* exec
)
933 JSValue
* v
= inlineEvaluate(exec
);
934 KJS_CHECKEXCEPTIONBOOLEAN
935 return v
->toBoolean(exec
);
938 int32_t NewExprNode::evaluateToInt32(ExecState
* exec
)
940 JSValue
* v
= inlineEvaluate(exec
);
941 KJS_CHECKEXCEPTIONNUMBER
942 return v
->toInt32(exec
);
945 uint32_t NewExprNode::evaluateToUInt32(ExecState
* exec
)
947 JSValue
* v
= inlineEvaluate(exec
);
948 KJS_CHECKEXCEPTIONNUMBER
949 return v
->toUInt32(exec
);
952 void FunctionCallValueNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
954 nodeStack
.append(m_args
.get());
955 nodeStack
.append(m_expr
.get());
959 JSValue
* FunctionCallValueNode::evaluate(ExecState
* exec
)
961 JSValue
* v
= m_expr
->evaluate(exec
);
962 KJS_CHECKEXCEPTIONVALUE
964 if (!v
->isObject()) {
965 return throwError(exec
, TypeError
, "Value %s (result of expression %s) is not object.", v
, m_expr
.get());
968 JSObject
* func
= static_cast<JSObject
*>(v
);
970 if (!func
->implementsCall()) {
971 return throwError(exec
, TypeError
, "Object %s (result of expression %s) does not allow calls.", v
, m_expr
.get());
975 m_args
->evaluateList(exec
, argList
);
976 KJS_CHECKEXCEPTIONVALUE
978 JSObject
* thisObj
= exec
->dynamicGlobalObject();
980 return func
->call(exec
, thisObj
, argList
);
983 void FunctionCallResolveNode::optimizeVariableAccess(const SymbolTable
& symbolTable
, const LocalStorage
&, NodeStack
& nodeStack
)
985 nodeStack
.append(m_args
.get());
987 size_t index
= symbolTable
.get(m_ident
.ustring().rep());
988 if (index
!= missingSymbolMarker())
989 new (this) LocalVarFunctionCallNode(index
);
993 JSValue
* FunctionCallResolveNode::inlineEvaluate(ExecState
* exec
)
995 // Check for missed optimization opportunity.
996 ASSERT(!canSkipLookup(exec
, m_ident
));
998 const ScopeChain
& chain
= exec
->scopeChain();
999 ScopeChainIterator iter
= chain
.begin();
1000 ScopeChainIterator end
= chain
.end();
1002 // we must always have something in the scope chain
1003 ASSERT(iter
!= end
);
1009 if (base
->getPropertySlot(exec
, m_ident
, slot
)) {
1010 JSValue
* v
= slot
.getValue(exec
, base
, m_ident
);
1011 KJS_CHECKEXCEPTIONVALUE
1014 return throwError(exec
, TypeError
, "Value %s (result of expression %s) is not object.", v
, m_ident
);
1016 JSObject
* func
= static_cast<JSObject
*>(v
);
1018 if (!func
->implementsCall())
1019 return throwError(exec
, TypeError
, "Object %s (result of expression %s) does not allow calls.", v
, m_ident
);
1022 m_args
->evaluateList(exec
, argList
);
1023 KJS_CHECKEXCEPTIONVALUE
1025 JSObject
* thisObj
= base
;
1026 // ECMA 11.2.3 says that in this situation the this value should be null.
1027 // However, section 10.2.3 says that in the case where the value provided
1028 // by the caller is null, the global object should be used. It also says
1029 // that the section does not apply to internal functions, but for simplicity
1030 // of implementation we use the global object anyway here. This guarantees
1031 // that in host objects you always get a valid object for this.
1032 if (thisObj
->isActivationObject())
1033 thisObj
= exec
->dynamicGlobalObject();
1035 return func
->call(exec
, thisObj
, argList
);
1038 } while (iter
!= end
);
1040 return throwUndefinedVariableError(exec
, m_ident
);
1043 JSValue
* FunctionCallResolveNode::evaluate(ExecState
* exec
)
1045 return inlineEvaluate(exec
);
1048 double FunctionCallResolveNode::evaluateToNumber(ExecState
* exec
)
1050 JSValue
* v
= inlineEvaluate(exec
);
1051 KJS_CHECKEXCEPTIONNUMBER
1052 return v
->toNumber(exec
);
1055 bool FunctionCallResolveNode::evaluateToBoolean(ExecState
* exec
)
1057 JSValue
* v
= inlineEvaluate(exec
);
1058 KJS_CHECKEXCEPTIONBOOLEAN
1059 return v
->toBoolean(exec
);
1062 int32_t FunctionCallResolveNode::evaluateToInt32(ExecState
* exec
)
1064 JSValue
* v
= inlineEvaluate(exec
);
1065 KJS_CHECKEXCEPTIONNUMBER
1066 return v
->toInt32(exec
);
1069 uint32_t FunctionCallResolveNode::evaluateToUInt32(ExecState
* exec
)
1071 JSValue
* v
= inlineEvaluate(exec
);
1072 KJS_CHECKEXCEPTIONNUMBER
1073 return v
->toUInt32(exec
);
1076 JSValue
* LocalVarFunctionCallNode::inlineEvaluate(ExecState
* exec
)
1078 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
1080 JSValue
* v
= exec
->localStorage()[m_index
].value
;
1083 return throwError(exec
, TypeError
, "Value %s (result of expression %s) is not object.", v
, m_ident
);
1085 JSObject
* func
= static_cast<JSObject
*>(v
);
1086 if (!func
->implementsCall())
1087 return throwError(exec
, TypeError
, "Object %s (result of expression %s) does not allow calls.", v
, m_ident
);
1090 m_args
->evaluateList(exec
, argList
);
1091 KJS_CHECKEXCEPTIONVALUE
1093 return func
->call(exec
, exec
->dynamicGlobalObject(), argList
);
1096 JSValue
* LocalVarFunctionCallNode::evaluate(ExecState
* exec
)
1098 return inlineEvaluate(exec
);
1101 double LocalVarFunctionCallNode::evaluateToNumber(ExecState
* exec
)
1103 JSValue
* v
= inlineEvaluate(exec
);
1104 KJS_CHECKEXCEPTIONNUMBER
1105 return v
->toNumber(exec
);
1108 bool LocalVarFunctionCallNode::evaluateToBoolean(ExecState
* exec
)
1110 JSValue
* v
= inlineEvaluate(exec
);
1111 KJS_CHECKEXCEPTIONBOOLEAN
1112 return v
->toBoolean(exec
);
1115 int32_t LocalVarFunctionCallNode::evaluateToInt32(ExecState
* exec
)
1117 JSValue
* v
= inlineEvaluate(exec
);
1118 KJS_CHECKEXCEPTIONNUMBER
1119 return v
->toInt32(exec
);
1122 uint32_t LocalVarFunctionCallNode::evaluateToUInt32(ExecState
* exec
)
1124 JSValue
* v
= inlineEvaluate(exec
);
1125 KJS_CHECKEXCEPTIONNUMBER
1126 return v
->toUInt32(exec
);
1129 void FunctionCallBracketNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
1131 nodeStack
.append(m_args
.get());
1132 nodeStack
.append(m_subscript
.get());
1133 nodeStack
.append(m_base
.get());
1137 JSValue
* FunctionCallBracketNode::evaluate(ExecState
* exec
)
1139 JSValue
* baseVal
= m_base
->evaluate(exec
);
1140 KJS_CHECKEXCEPTIONVALUE
1142 JSValue
* subscriptVal
= m_subscript
->evaluate(exec
);
1144 JSObject
* baseObj
= baseVal
->toObject(exec
);
1149 if (subscriptVal
->getUInt32(i
)) {
1150 if (baseObj
->getPropertySlot(exec
, i
, slot
))
1151 funcVal
= slot
.getValue(exec
, baseObj
, i
);
1153 funcVal
= jsUndefined();
1155 Identifier
ident(subscriptVal
->toString(exec
));
1156 if (baseObj
->getPropertySlot(exec
, ident
, slot
))
1157 funcVal
= baseObj
->get(exec
, ident
);
1159 funcVal
= jsUndefined();
1162 KJS_CHECKEXCEPTIONVALUE
1164 if (!funcVal
->isObject())
1165 return throwError(exec
, TypeError
, "Value %s (result of expression %s[%s]) is not object.", funcVal
, m_base
.get(), m_subscript
.get());
1167 JSObject
* func
= static_cast<JSObject
*>(funcVal
);
1169 if (!func
->implementsCall())
1170 return throwError(exec
, TypeError
, "Object %s (result of expression %s[%s]) does not allow calls.", funcVal
, m_base
.get(), m_subscript
.get());
1173 m_args
->evaluateList(exec
, argList
);
1174 KJS_CHECKEXCEPTIONVALUE
1176 JSObject
* thisObj
= baseObj
;
1178 ASSERT(thisObj
->isObject());
1179 ASSERT(!thisObj
->isActivationObject());
1181 return func
->call(exec
, thisObj
, argList
);
1184 static const char* dotExprNotAnObjectString() KJS_FAST_CALL
;
1185 static const char* dotExprNotAnObjectString()
1187 return "Value %s (result of expression %s.%s) is not object.";
1190 static const char* dotExprDoesNotAllowCallsString() KJS_FAST_CALL
;
1191 static const char* dotExprDoesNotAllowCallsString()
1193 return "Object %s (result of expression %s.%s) does not allow calls.";
1196 void FunctionCallDotNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
1198 nodeStack
.append(m_args
.get());
1199 nodeStack
.append(m_base
.get());
1203 JSValue
* FunctionCallDotNode::inlineEvaluate(ExecState
* exec
)
1205 JSValue
* baseVal
= m_base
->evaluate(exec
);
1206 KJS_CHECKEXCEPTIONVALUE
1208 JSObject
* baseObj
= baseVal
->toObject(exec
);
1210 JSValue
* funcVal
= baseObj
->getPropertySlot(exec
, m_ident
, slot
) ? slot
.getValue(exec
, baseObj
, m_ident
) : jsUndefined();
1211 KJS_CHECKEXCEPTIONVALUE
1213 if (!funcVal
->isObject())
1214 return throwError(exec
, TypeError
, dotExprNotAnObjectString(), funcVal
, m_base
.get(), m_ident
);
1216 JSObject
* func
= static_cast<JSObject
*>(funcVal
);
1218 if (!func
->implementsCall())
1219 return throwError(exec
, TypeError
, dotExprDoesNotAllowCallsString(), funcVal
, m_base
.get(), m_ident
);
1222 m_args
->evaluateList(exec
, argList
);
1223 KJS_CHECKEXCEPTIONVALUE
1225 JSObject
* thisObj
= baseObj
;
1227 ASSERT(thisObj
->isObject());
1228 ASSERT(!thisObj
->isActivationObject());
1230 return func
->call(exec
, thisObj
, argList
);
1233 JSValue
* FunctionCallDotNode::evaluate(ExecState
* exec
)
1235 return inlineEvaluate(exec
);
1238 double FunctionCallDotNode::evaluateToNumber(ExecState
* exec
)
1240 JSValue
* v
= inlineEvaluate(exec
);
1241 KJS_CHECKEXCEPTIONNUMBER
1242 return v
->toNumber(exec
);
1245 bool FunctionCallDotNode::evaluateToBoolean(ExecState
* exec
)
1247 JSValue
* v
= inlineEvaluate(exec
);
1248 KJS_CHECKEXCEPTIONBOOLEAN
1249 return v
->toBoolean(exec
);
1252 int32_t FunctionCallDotNode::evaluateToInt32(ExecState
* exec
)
1254 JSValue
* v
= inlineEvaluate(exec
);
1255 KJS_CHECKEXCEPTIONNUMBER
1256 return v
->toInt32(exec
);
1259 uint32_t FunctionCallDotNode::evaluateToUInt32(ExecState
* exec
)
1261 JSValue
* v
= inlineEvaluate(exec
);
1262 KJS_CHECKEXCEPTIONNUMBER
1263 return v
->toUInt32(exec
);
1268 // ------------------------------ PostfixResolveNode ----------------------------------
1271 void PostIncResolveNode::optimizeVariableAccess(const SymbolTable
& symbolTable
, const LocalStorage
& localStorage
, NodeStack
&)
1273 size_t index
= symbolTable
.get(m_ident
.ustring().rep());
1274 if (index
!= missingSymbolMarker()) {
1275 if (isConstant(localStorage
, index
))
1276 new (this) PostIncConstNode(index
);
1278 new (this) PostIncLocalVarNode(index
);
1282 JSValue
* PostIncResolveNode::evaluate(ExecState
* exec
)
1284 // Check for missed optimization opportunity.
1285 ASSERT(!canSkipLookup(exec
, m_ident
));
1287 const ScopeChain
& chain
= exec
->scopeChain();
1288 ScopeChainIterator iter
= chain
.begin();
1289 ScopeChainIterator end
= chain
.end();
1291 // we must always have something in the scope chain
1292 ASSERT(iter
!= end
);
1296 if ((*iter
)->getPropertySlot(exec
, m_ident
, slot
)) {
1297 // If m_ident is 'arguments', the base->getPropertySlot() may cause
1298 // base (which must be an ActivationImp in such this case) to be torn
1299 // off from the activation stack, in which case we need to get it again
1300 // from the ScopeChainIterator.
1302 JSObject
* base
= *iter
;
1303 JSValue
* v
= slot
.getValue(exec
, base
, m_ident
)->toJSNumber(exec
);
1304 base
->put(exec
, m_ident
, jsNumber(v
->toNumber(exec
) + 1));
1309 } while (iter
!= end
);
1311 return throwUndefinedVariableError(exec
, m_ident
);
1314 void PostIncResolveNode::optimizeForUnnecessaryResult()
1316 new (this) PreIncResolveNode(PlacementNewAdopt
);
1319 JSValue
* PostIncLocalVarNode::evaluate(ExecState
* exec
)
1321 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
1323 JSValue
** slot
= &exec
->localStorage()[m_index
].value
;
1324 JSValue
* v
= (*slot
)->toJSNumber(exec
);
1325 *slot
= jsNumber(v
->toNumber(exec
) + 1);
1329 void PostIncLocalVarNode::optimizeForUnnecessaryResult()
1331 new (this) PreIncLocalVarNode(m_index
);
1335 void PostDecResolveNode::optimizeVariableAccess(const SymbolTable
& symbolTable
, const LocalStorage
& localStorage
, NodeStack
&)
1337 size_t index
= symbolTable
.get(m_ident
.ustring().rep());
1338 if (index
!= missingSymbolMarker()) {
1339 if (isConstant(localStorage
, index
))
1340 new (this) PostDecConstNode(index
);
1342 new (this) PostDecLocalVarNode(index
);
1346 JSValue
* PostDecResolveNode::evaluate(ExecState
* exec
)
1348 // Check for missed optimization opportunity.
1349 ASSERT(!canSkipLookup(exec
, m_ident
));
1351 const ScopeChain
& chain
= exec
->scopeChain();
1352 ScopeChainIterator iter
= chain
.begin();
1353 ScopeChainIterator end
= chain
.end();
1355 // we must always have something in the scope chain
1356 ASSERT(iter
!= end
);
1360 if ((*iter
)->getPropertySlot(exec
, m_ident
, slot
)) {
1361 // See the comment in PostIncResolveNode::evaluate().
1363 JSObject
* base
= *iter
;
1364 JSValue
* v
= slot
.getValue(exec
, base
, m_ident
)->toJSNumber(exec
);
1365 base
->put(exec
, m_ident
, jsNumber(v
->toNumber(exec
) - 1));
1370 } while (iter
!= end
);
1372 return throwUndefinedVariableError(exec
, m_ident
);
1375 void PostDecResolveNode::optimizeForUnnecessaryResult()
1377 new (this) PreDecResolveNode(PlacementNewAdopt
);
1380 JSValue
* PostDecLocalVarNode::evaluate(ExecState
* exec
)
1382 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
1384 JSValue
** slot
= &exec
->localStorage()[m_index
].value
;
1385 JSValue
* v
= (*slot
)->toJSNumber(exec
);
1386 *slot
= jsNumber(v
->toNumber(exec
) - 1);
1390 double PostDecLocalVarNode::inlineEvaluateToNumber(ExecState
* exec
)
1392 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
1394 JSValue
** slot
= &exec
->localStorage()[m_index
].value
;
1395 double n
= (*slot
)->toNumber(exec
);
1396 *slot
= jsNumber(n
- 1);
1400 double PostDecLocalVarNode::evaluateToNumber(ExecState
* exec
)
1402 return inlineEvaluateToNumber(exec
);
1405 bool PostDecLocalVarNode::evaluateToBoolean(ExecState
* exec
)
1407 double result
= inlineEvaluateToNumber(exec
);
1408 return result
> 0.0 || 0.0 > result
; // NaN produces false as well
1411 int32_t PostDecLocalVarNode::evaluateToInt32(ExecState
* exec
)
1413 return JSValue::toInt32(inlineEvaluateToNumber(exec
));
1416 uint32_t PostDecLocalVarNode::evaluateToUInt32(ExecState
* exec
)
1418 return JSValue::toUInt32(inlineEvaluateToNumber(exec
));
1421 void PostDecLocalVarNode::optimizeForUnnecessaryResult()
1423 new (this) PreDecLocalVarNode(m_index
);
1426 // ------------------------------ PostfixBracketNode ----------------------------------
1428 void PostfixBracketNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
1430 nodeStack
.append(m_subscript
.get());
1431 nodeStack
.append(m_base
.get());
1434 JSValue
* PostIncBracketNode::evaluate(ExecState
* exec
)
1436 JSValue
* baseValue
= m_base
->evaluate(exec
);
1437 KJS_CHECKEXCEPTIONVALUE
1438 JSValue
* subscript
= m_subscript
->evaluate(exec
);
1439 KJS_CHECKEXCEPTIONVALUE
1441 JSObject
* base
= baseValue
->toObject(exec
);
1443 uint32_t propertyIndex
;
1444 if (subscript
->getUInt32(propertyIndex
)) {
1446 JSValue
* v
= base
->getPropertySlot(exec
, propertyIndex
, slot
) ? slot
.getValue(exec
, base
, propertyIndex
) : jsUndefined();
1447 KJS_CHECKEXCEPTIONVALUE
1449 JSValue
* v2
= v
->toJSNumber(exec
);
1450 base
->put(exec
, propertyIndex
, jsNumber(v2
->toNumber(exec
) + 1));
1455 Identifier
propertyName(subscript
->toString(exec
));
1457 JSValue
* v
= base
->getPropertySlot(exec
, propertyName
, slot
) ? slot
.getValue(exec
, base
, propertyName
) : jsUndefined();
1458 KJS_CHECKEXCEPTIONVALUE
1460 JSValue
* v2
= v
->toJSNumber(exec
);
1461 base
->put(exec
, propertyName
, jsNumber(v2
->toNumber(exec
) + 1));
1465 JSValue
* PostDecBracketNode::evaluate(ExecState
* exec
)
1467 JSValue
* baseValue
= m_base
->evaluate(exec
);
1468 KJS_CHECKEXCEPTIONVALUE
1469 JSValue
* subscript
= m_subscript
->evaluate(exec
);
1470 KJS_CHECKEXCEPTIONVALUE
1472 JSObject
* base
= baseValue
->toObject(exec
);
1474 uint32_t propertyIndex
;
1475 if (subscript
->getUInt32(propertyIndex
)) {
1477 JSValue
* v
= base
->getPropertySlot(exec
, propertyIndex
, slot
) ? slot
.getValue(exec
, base
, propertyIndex
) : jsUndefined();
1478 KJS_CHECKEXCEPTIONVALUE
1480 JSValue
* v2
= v
->toJSNumber(exec
);
1481 base
->put(exec
, propertyIndex
, jsNumber(v2
->toNumber(exec
) - 1));
1485 Identifier
propertyName(subscript
->toString(exec
));
1487 JSValue
* v
= base
->getPropertySlot(exec
, propertyName
, slot
) ? slot
.getValue(exec
, base
, propertyName
) : jsUndefined();
1488 KJS_CHECKEXCEPTIONVALUE
1490 JSValue
* v2
= v
->toJSNumber(exec
);
1491 base
->put(exec
, propertyName
, jsNumber(v2
->toNumber(exec
) - 1));
1495 // ------------------------------ PostfixDotNode ----------------------------------
1497 void PostfixDotNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
1499 nodeStack
.append(m_base
.get());
1502 JSValue
* PostIncDotNode::evaluate(ExecState
* exec
)
1504 JSValue
* baseValue
= m_base
->evaluate(exec
);
1505 KJS_CHECKEXCEPTIONVALUE
1506 JSObject
* base
= baseValue
->toObject(exec
);
1509 JSValue
* v
= base
->getPropertySlot(exec
, m_ident
, slot
) ? slot
.getValue(exec
, base
, m_ident
) : jsUndefined();
1510 KJS_CHECKEXCEPTIONVALUE
1512 JSValue
* v2
= v
->toJSNumber(exec
);
1513 base
->put(exec
, m_ident
, jsNumber(v2
->toNumber(exec
) + 1));
1517 JSValue
* PostDecDotNode::evaluate(ExecState
* exec
)
1519 JSValue
* baseValue
= m_base
->evaluate(exec
);
1520 KJS_CHECKEXCEPTIONVALUE
1521 JSObject
* base
= baseValue
->toObject(exec
);
1524 JSValue
* v
= base
->getPropertySlot(exec
, m_ident
, slot
) ? slot
.getValue(exec
, base
, m_ident
) : jsUndefined();
1525 KJS_CHECKEXCEPTIONVALUE
1527 JSValue
* v2
= v
->toJSNumber(exec
);
1528 base
->put(exec
, m_ident
, jsNumber(v2
->toNumber(exec
) - 1));
1532 // ------------------------------ PostfixErrorNode -----------------------------------
1534 JSValue
* PostfixErrorNode::evaluate(ExecState
* exec
)
1536 throwError(exec
, ReferenceError
, "Postfix %s operator applied to value that is not a reference.",
1537 m_operator
== OpPlusPlus
? "++" : "--");
1538 handleException(exec
);
1539 return jsUndefined();
1542 // ------------------------------ DeleteResolveNode -----------------------------------
1544 void DeleteResolveNode::optimizeVariableAccess(const SymbolTable
& symbolTable
, const LocalStorage
&, NodeStack
&)
1546 size_t index
= symbolTable
.get(m_ident
.ustring().rep());
1547 if (index
!= missingSymbolMarker())
1548 new (this) LocalVarDeleteNode();
1553 JSValue
* DeleteResolveNode::evaluate(ExecState
* exec
)
1555 // Check for missed optimization opportunity.
1556 ASSERT(!canSkipLookup(exec
, m_ident
));
1558 const ScopeChain
& chain
= exec
->scopeChain();
1559 ScopeChainIterator iter
= chain
.begin();
1560 ScopeChainIterator end
= chain
.end();
1562 // We must always have something in the scope chain
1563 ASSERT(iter
!= end
);
1569 if (base
->getPropertySlot(exec
, m_ident
, slot
))
1570 return jsBoolean(base
->deleteProperty(exec
, m_ident
));
1573 } while (iter
!= end
);
1575 return jsBoolean(true);
1578 JSValue
* LocalVarDeleteNode::evaluate(ExecState
*)
1580 return jsBoolean(false);
1583 // ------------------------------ DeleteBracketNode -----------------------------------
1585 void DeleteBracketNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
1587 nodeStack
.append(m_subscript
.get());
1588 nodeStack
.append(m_base
.get());
1591 JSValue
* DeleteBracketNode::evaluate(ExecState
* exec
)
1593 JSValue
* baseValue
= m_base
->evaluate(exec
);
1594 KJS_CHECKEXCEPTIONVALUE
1595 JSValue
* subscript
= m_subscript
->evaluate(exec
);
1596 KJS_CHECKEXCEPTIONVALUE
1598 JSObject
* base
= baseValue
->toObject(exec
);
1600 uint32_t propertyIndex
;
1601 if (subscript
->getUInt32(propertyIndex
))
1602 return jsBoolean(base
->deleteProperty(exec
, propertyIndex
));
1604 Identifier
propertyName(subscript
->toString(exec
));
1605 return jsBoolean(base
->deleteProperty(exec
, propertyName
));
1608 // ------------------------------ DeleteDotNode -----------------------------------
1610 void DeleteDotNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
1612 nodeStack
.append(m_base
.get());
1615 JSValue
* DeleteDotNode::evaluate(ExecState
* exec
)
1617 JSValue
* baseValue
= m_base
->evaluate(exec
);
1618 JSObject
* base
= baseValue
->toObject(exec
);
1619 KJS_CHECKEXCEPTIONVALUE
1621 return jsBoolean(base
->deleteProperty(exec
, m_ident
));
1624 // ------------------------------ DeleteValueNode -----------------------------------
1626 void DeleteValueNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
1628 nodeStack
.append(m_expr
.get());
1631 JSValue
* DeleteValueNode::evaluate(ExecState
* exec
)
1633 m_expr
->evaluate(exec
);
1634 KJS_CHECKEXCEPTIONVALUE
1636 // delete on a non-location expression ignores the value and returns true
1637 return jsBoolean(true);
1640 // ------------------------------ VoidNode -------------------------------------
1642 void VoidNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
1644 nodeStack
.append(m_expr
.get());
1648 JSValue
* VoidNode::evaluate(ExecState
* exec
)
1650 m_expr
->evaluate(exec
);
1651 KJS_CHECKEXCEPTIONVALUE
1653 return jsUndefined();
1658 // ------------------------------ TypeOfValueNode -----------------------------------
1660 void TypeOfValueNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
1662 nodeStack
.append(m_expr
.get());
1665 static JSValue
* typeStringForValue(JSValue
* v
) KJS_FAST_CALL
;
1666 static JSValue
* typeStringForValue(JSValue
* v
)
1668 switch (v
->type()) {
1670 return jsString("undefined");
1672 return jsString("object");
1674 return jsString("boolean");
1676 return jsString("number");
1678 return jsString("string");
1680 if (v
->isObject()) {
1681 // Return "undefined" for objects that should be treated
1682 // as null when doing comparisons.
1683 if (static_cast<JSObject
*>(v
)->masqueradeAsUndefined())
1684 return jsString("undefined");
1685 else if (static_cast<JSObject
*>(v
)->implementsCall())
1686 return jsString("function");
1689 return jsString("object");
1693 void TypeOfResolveNode::optimizeVariableAccess(const SymbolTable
& symbolTable
, const LocalStorage
&, NodeStack
&)
1695 size_t index
= symbolTable
.get(m_ident
.ustring().rep());
1696 if (index
!= missingSymbolMarker())
1697 new (this) LocalVarTypeOfNode(index
);
1700 JSValue
* LocalVarTypeOfNode::evaluate(ExecState
* exec
)
1702 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
1704 return typeStringForValue(exec
->localStorage()[m_index
].value
);
1707 JSValue
* TypeOfResolveNode::evaluate(ExecState
* exec
)
1709 const ScopeChain
& chain
= exec
->scopeChain();
1710 ScopeChainIterator iter
= chain
.begin();
1711 ScopeChainIterator end
= chain
.end();
1713 // We must always have something in the scope chain
1714 ASSERT(iter
!= end
);
1720 if (base
->getPropertySlot(exec
, m_ident
, slot
)) {
1721 JSValue
* v
= slot
.getValue(exec
, base
, m_ident
);
1722 return typeStringForValue(v
);
1726 } while (iter
!= end
);
1728 return jsString("undefined");
1731 // ------------------------------ TypeOfValueNode -----------------------------------
1733 JSValue
* TypeOfValueNode::evaluate(ExecState
* exec
)
1735 JSValue
* v
= m_expr
->evaluate(exec
);
1736 KJS_CHECKEXCEPTIONVALUE
1738 return typeStringForValue(v
);
1741 // ECMA 11.4.4 and 11.4.5
1743 // ------------------------------ PrefixResolveNode ----------------------------------
1745 void PreIncResolveNode::optimizeVariableAccess(const SymbolTable
& symbolTable
, const LocalStorage
& localStorage
, NodeStack
&)
1747 size_t index
= symbolTable
.get(m_ident
.ustring().rep());
1748 if (index
!= missingSymbolMarker()) {
1749 if (isConstant(localStorage
, index
))
1750 new (this) PreIncConstNode(index
);
1752 new (this) PreIncLocalVarNode(index
);
1756 JSValue
* PreIncLocalVarNode::evaluate(ExecState
* exec
)
1758 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
1759 JSValue
** slot
= &exec
->localStorage()[m_index
].value
;
1761 double n
= (*slot
)->toNumber(exec
);
1762 JSValue
* n2
= jsNumber(n
+ 1);
1767 JSValue
* PreIncResolveNode::evaluate(ExecState
* exec
)
1769 const ScopeChain
& chain
= exec
->scopeChain();
1770 ScopeChainIterator iter
= chain
.begin();
1771 ScopeChainIterator end
= chain
.end();
1773 // we must always have something in the scope chain
1774 ASSERT(iter
!= end
);
1778 if ((*iter
)->getPropertySlot(exec
, m_ident
, slot
)) {
1779 // See the comment in PostIncResolveNode::evaluate().
1781 JSObject
* base
= *iter
;
1782 JSValue
* v
= slot
.getValue(exec
, base
, m_ident
);
1784 double n
= v
->toNumber(exec
);
1785 JSValue
* n2
= jsNumber(n
+ 1);
1786 base
->put(exec
, m_ident
, n2
);
1792 } while (iter
!= end
);
1794 return throwUndefinedVariableError(exec
, m_ident
);
1797 void PreDecResolveNode::optimizeVariableAccess(const SymbolTable
& symbolTable
, const LocalStorage
& localStorage
, NodeStack
&)
1799 size_t index
= symbolTable
.get(m_ident
.ustring().rep());
1800 if (index
!= missingSymbolMarker()) {
1801 if (isConstant(localStorage
, index
))
1802 new (this) PreDecConstNode(index
);
1804 new (this) PreDecLocalVarNode(index
);
1808 JSValue
* PreDecLocalVarNode::evaluate(ExecState
* exec
)
1810 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
1811 JSValue
** slot
= &exec
->localStorage()[m_index
].value
;
1813 double n
= (*slot
)->toNumber(exec
);
1814 JSValue
* n2
= jsNumber(n
- 1);
1819 JSValue
* PreDecResolveNode::evaluate(ExecState
* exec
)
1821 const ScopeChain
& chain
= exec
->scopeChain();
1822 ScopeChainIterator iter
= chain
.begin();
1823 ScopeChainIterator end
= chain
.end();
1825 // we must always have something in the scope chain
1826 ASSERT(iter
!= end
);
1830 if ((*iter
)->getPropertySlot(exec
, m_ident
, slot
)) {
1831 // See the comment in PostIncResolveNode::evaluate().
1833 JSObject
* base
= *iter
;
1834 JSValue
* v
= slot
.getValue(exec
, base
, m_ident
);
1836 double n
= v
->toNumber(exec
);
1837 JSValue
* n2
= jsNumber(n
- 1);
1838 base
->put(exec
, m_ident
, n2
);
1844 } while (iter
!= end
);
1846 return throwUndefinedVariableError(exec
, m_ident
);
1849 // ------------------------------ PreIncConstNode ----------------------------------
1851 JSValue
* PreIncConstNode::evaluate(ExecState
* exec
)
1853 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
1854 return jsNumber(exec
->localStorage()[m_index
].value
->toNumber(exec
) + 1);
1857 // ------------------------------ PreDecConstNode ----------------------------------
1859 JSValue
* PreDecConstNode::evaluate(ExecState
* exec
)
1861 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
1862 return jsNumber(exec
->localStorage()[m_index
].value
->toNumber(exec
) - 1);
1865 // ------------------------------ PostIncConstNode ----------------------------------
1867 JSValue
* PostIncConstNode::evaluate(ExecState
* exec
)
1869 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
1870 return jsNumber(exec
->localStorage()[m_index
].value
->toNumber(exec
));
1873 // ------------------------------ PostDecConstNode ----------------------------------
1875 JSValue
* PostDecConstNode::evaluate(ExecState
* exec
)
1877 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
1878 return jsNumber(exec
->localStorage()[m_index
].value
->toNumber(exec
));
1881 // ------------------------------ PrefixBracketNode ----------------------------------
1883 void PrefixBracketNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
1885 nodeStack
.append(m_subscript
.get());
1886 nodeStack
.append(m_base
.get());
1889 JSValue
* PreIncBracketNode::evaluate(ExecState
* exec
)
1891 JSValue
* baseValue
= m_base
->evaluate(exec
);
1892 KJS_CHECKEXCEPTIONVALUE
1893 JSValue
* subscript
= m_subscript
->evaluate(exec
);
1894 KJS_CHECKEXCEPTIONVALUE
1896 JSObject
* base
= baseValue
->toObject(exec
);
1898 uint32_t propertyIndex
;
1899 if (subscript
->getUInt32(propertyIndex
)) {
1901 JSValue
* v
= base
->getPropertySlot(exec
, propertyIndex
, slot
) ? slot
.getValue(exec
, base
, propertyIndex
) : jsUndefined();
1902 KJS_CHECKEXCEPTIONVALUE
1904 JSValue
* n2
= jsNumber(v
->toNumber(exec
) + 1);
1905 base
->put(exec
, propertyIndex
, n2
);
1910 Identifier
propertyName(subscript
->toString(exec
));
1912 JSValue
* v
= base
->getPropertySlot(exec
, propertyName
, slot
) ? slot
.getValue(exec
, base
, propertyName
) : jsUndefined();
1913 KJS_CHECKEXCEPTIONVALUE
1915 JSValue
* n2
= jsNumber(v
->toNumber(exec
) + 1);
1916 base
->put(exec
, propertyName
, n2
);
1921 JSValue
* PreDecBracketNode::evaluate(ExecState
* exec
)
1923 JSValue
* baseValue
= m_base
->evaluate(exec
);
1924 KJS_CHECKEXCEPTIONVALUE
1925 JSValue
* subscript
= m_subscript
->evaluate(exec
);
1926 KJS_CHECKEXCEPTIONVALUE
1928 JSObject
* base
= baseValue
->toObject(exec
);
1930 uint32_t propertyIndex
;
1931 if (subscript
->getUInt32(propertyIndex
)) {
1933 JSValue
* v
= base
->getPropertySlot(exec
, propertyIndex
, slot
) ? slot
.getValue(exec
, base
, propertyIndex
) : jsUndefined();
1934 KJS_CHECKEXCEPTIONVALUE
1936 JSValue
* n2
= jsNumber(v
->toNumber(exec
) - 1);
1937 base
->put(exec
, propertyIndex
, n2
);
1942 Identifier
propertyName(subscript
->toString(exec
));
1944 JSValue
* v
= base
->getPropertySlot(exec
, propertyName
, slot
) ? slot
.getValue(exec
, base
, propertyName
) : jsUndefined();
1945 KJS_CHECKEXCEPTIONVALUE
1947 JSValue
* n2
= jsNumber(v
->toNumber(exec
) - 1);
1948 base
->put(exec
, propertyName
, n2
);
1953 // ------------------------------ PrefixDotNode ----------------------------------
1955 void PrefixDotNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
1957 nodeStack
.append(m_base
.get());
1960 JSValue
* PreIncDotNode::evaluate(ExecState
* exec
)
1962 JSValue
* baseValue
= m_base
->evaluate(exec
);
1963 KJS_CHECKEXCEPTIONVALUE
1964 JSObject
* base
= baseValue
->toObject(exec
);
1967 JSValue
* v
= base
->getPropertySlot(exec
, m_ident
, slot
) ? slot
.getValue(exec
, base
, m_ident
) : jsUndefined();
1968 KJS_CHECKEXCEPTIONVALUE
1970 double n
= v
->toNumber(exec
);
1971 JSValue
* n2
= jsNumber(n
+ 1);
1972 base
->put(exec
, m_ident
, n2
);
1977 JSValue
* PreDecDotNode::evaluate(ExecState
* exec
)
1979 JSValue
* baseValue
= m_base
->evaluate(exec
);
1980 KJS_CHECKEXCEPTIONVALUE
1981 JSObject
* base
= baseValue
->toObject(exec
);
1984 JSValue
* v
= base
->getPropertySlot(exec
, m_ident
, slot
) ? slot
.getValue(exec
, base
, m_ident
) : jsUndefined();
1985 KJS_CHECKEXCEPTIONVALUE
1987 double n
= v
->toNumber(exec
);
1988 JSValue
* n2
= jsNumber(n
- 1);
1989 base
->put(exec
, m_ident
, n2
);
1994 // ------------------------------ PrefixErrorNode -----------------------------------
1996 JSValue
* PrefixErrorNode::evaluate(ExecState
* exec
)
1998 throwError(exec
, ReferenceError
, "Prefix %s operator applied to value that is not a reference.",
1999 m_operator
== OpPlusPlus
? "++" : "--");
2000 handleException(exec
);
2001 return jsUndefined();
2004 // ------------------------------ UnaryPlusNode --------------------------------
2006 void UnaryPlusNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2008 nodeStack
.append(m_expr
.get());
2012 JSValue
* UnaryPlusNode::evaluate(ExecState
* exec
)
2014 JSValue
* v
= m_expr
->evaluate(exec
);
2015 KJS_CHECKEXCEPTIONVALUE
2016 return v
->toJSNumber(exec
);
2019 bool UnaryPlusNode::evaluateToBoolean(ExecState
* exec
)
2021 return m_expr
->evaluateToBoolean(exec
);
2024 double UnaryPlusNode::evaluateToNumber(ExecState
* exec
)
2026 return m_expr
->evaluateToNumber(exec
);
2029 int32_t UnaryPlusNode::evaluateToInt32(ExecState
* exec
)
2031 return m_expr
->evaluateToInt32(exec
);
2034 uint32_t UnaryPlusNode::evaluateToUInt32(ExecState
* exec
)
2036 return m_expr
->evaluateToInt32(exec
);
2039 // ------------------------------ NegateNode -----------------------------------
2041 void NegateNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2043 nodeStack
.append(m_expr
.get());
2047 JSValue
* NegateNode::evaluate(ExecState
* exec
)
2049 // No need to check exception, caller will do so right after evaluate()
2050 return jsNumber(-m_expr
->evaluateToNumber(exec
));
2053 double NegateNode::evaluateToNumber(ExecState
* exec
)
2055 // No need to check exception, caller will do so right after evaluateToNumber()
2056 return -m_expr
->evaluateToNumber(exec
);
2059 // ------------------------------ BitwiseNotNode -------------------------------
2061 void BitwiseNotNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2063 nodeStack
.append(m_expr
.get());
2067 int32_t BitwiseNotNode::inlineEvaluateToInt32(ExecState
* exec
)
2069 return ~m_expr
->evaluateToInt32(exec
);
2072 JSValue
* BitwiseNotNode::evaluate(ExecState
* exec
)
2074 return jsNumber(inlineEvaluateToInt32(exec
));
2077 double BitwiseNotNode::evaluateToNumber(ExecState
* exec
)
2079 return inlineEvaluateToInt32(exec
);
2082 bool BitwiseNotNode::evaluateToBoolean(ExecState
* exec
)
2084 return inlineEvaluateToInt32(exec
);
2087 int32_t BitwiseNotNode::evaluateToInt32(ExecState
* exec
)
2089 return inlineEvaluateToInt32(exec
);
2092 uint32_t BitwiseNotNode::evaluateToUInt32(ExecState
* exec
)
2094 return inlineEvaluateToInt32(exec
);
2097 // ------------------------------ LogicalNotNode -------------------------------
2099 void LogicalNotNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2101 nodeStack
.append(m_expr
.get());
2105 JSValue
* LogicalNotNode::evaluate(ExecState
* exec
)
2107 return jsBoolean(!m_expr
->evaluateToBoolean(exec
));
2110 bool LogicalNotNode::evaluateToBoolean(ExecState
* exec
)
2112 return !m_expr
->evaluateToBoolean(exec
);
2115 // ------------------------------ Multiplicative Nodes -----------------------------------
2117 void MultNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2119 nodeStack
.append(m_term1
.get());
2120 nodeStack
.append(m_term2
.get());
2124 double MultNode::inlineEvaluateToNumber(ExecState
* exec
)
2126 double n1
= m_term1
->evaluateToNumber(exec
);
2127 KJS_CHECKEXCEPTIONNUMBER
2128 double n2
= m_term2
->evaluateToNumber(exec
);
2132 JSValue
* MultNode::evaluate(ExecState
* exec
)
2134 return jsNumber(inlineEvaluateToNumber(exec
));
2137 double MultNode::evaluateToNumber(ExecState
* exec
)
2139 return inlineEvaluateToNumber(exec
);
2142 bool MultNode::evaluateToBoolean(ExecState
* exec
)
2144 double result
= inlineEvaluateToNumber(exec
);
2145 return result
> 0.0 || 0.0 > result
; // NaN produces false as well
2148 int32_t MultNode::evaluateToInt32(ExecState
* exec
)
2150 return JSValue::toInt32(inlineEvaluateToNumber(exec
));
2153 uint32_t MultNode::evaluateToUInt32(ExecState
* exec
)
2155 return JSValue::toUInt32(inlineEvaluateToNumber(exec
));
2158 void DivNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2160 nodeStack
.append(m_term1
.get());
2161 nodeStack
.append(m_term2
.get());
2165 double DivNode::inlineEvaluateToNumber(ExecState
* exec
)
2167 double n1
= m_term1
->evaluateToNumber(exec
);
2168 KJS_CHECKEXCEPTIONNUMBER
2169 double n2
= m_term2
->evaluateToNumber(exec
);
2173 JSValue
* DivNode::evaluate(ExecState
* exec
)
2175 return jsNumber(inlineEvaluateToNumber(exec
));
2178 double DivNode::evaluateToNumber(ExecState
* exec
)
2180 return inlineEvaluateToNumber(exec
);
2183 int32_t DivNode::evaluateToInt32(ExecState
* exec
)
2185 return JSValue::toInt32(inlineEvaluateToNumber(exec
));
2188 uint32_t DivNode::evaluateToUInt32(ExecState
* exec
)
2190 return JSValue::toUInt32(inlineEvaluateToNumber(exec
));
2193 void ModNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2195 nodeStack
.append(m_term1
.get());
2196 nodeStack
.append(m_term2
.get());
2200 double ModNode::inlineEvaluateToNumber(ExecState
* exec
)
2202 double n1
= m_term1
->evaluateToNumber(exec
);
2203 KJS_CHECKEXCEPTIONNUMBER
2204 double n2
= m_term2
->evaluateToNumber(exec
);
2205 return fmod(n1
, n2
);
2208 JSValue
* ModNode::evaluate(ExecState
* exec
)
2210 return jsNumber(inlineEvaluateToNumber(exec
));
2213 double ModNode::evaluateToNumber(ExecState
* exec
)
2215 return inlineEvaluateToNumber(exec
);
2218 bool ModNode::evaluateToBoolean(ExecState
* exec
)
2220 double result
= inlineEvaluateToNumber(exec
);
2221 return result
> 0.0 || 0.0 > result
; // NaN produces false as well
2224 int32_t ModNode::evaluateToInt32(ExecState
* exec
)
2226 return JSValue::toInt32(inlineEvaluateToNumber(exec
));
2229 uint32_t ModNode::evaluateToUInt32(ExecState
* exec
)
2231 return JSValue::toUInt32(inlineEvaluateToNumber(exec
));
2234 // ------------------------------ Additive Nodes --------------------------------------
2236 static JSValue
* throwOutOfMemoryError(ExecState
* exec
)
2238 JSObject
* error
= Error::create(exec
, GeneralError
, "Out of memory");
2239 exec
->setException(error
);
2243 static double throwOutOfMemoryErrorToNumber(ExecState
* exec
)
2245 JSObject
* error
= Error::create(exec
, GeneralError
, "Out of memory");
2246 exec
->setException(error
);
2251 static JSValue
* addSlowCase(ExecState
* exec
, JSValue
* v1
, JSValue
* v2
)
2253 // exception for the Date exception in defaultValue()
2254 JSValue
* p1
= v1
->toPrimitive(exec
, UnspecifiedType
);
2255 JSValue
* p2
= v2
->toPrimitive(exec
, UnspecifiedType
);
2257 if (p1
->isString() || p2
->isString()) {
2258 UString value
= p1
->toString(exec
) + p2
->toString(exec
);
2260 return throwOutOfMemoryError(exec
);
2261 return jsString(value
);
2264 return jsNumber(p1
->toNumber(exec
) + p2
->toNumber(exec
));
2267 static double addSlowCaseToNumber(ExecState
* exec
, JSValue
* v1
, JSValue
* v2
)
2269 // exception for the Date exception in defaultValue()
2270 JSValue
* p1
= v1
->toPrimitive(exec
, UnspecifiedType
);
2271 JSValue
* p2
= v2
->toPrimitive(exec
, UnspecifiedType
);
2273 if (p1
->isString() || p2
->isString()) {
2274 UString value
= p1
->toString(exec
) + p2
->toString(exec
);
2276 return throwOutOfMemoryErrorToNumber(exec
);
2277 return value
.toDouble();
2280 return p1
->toNumber(exec
) + p2
->toNumber(exec
);
2283 // Fast-path choices here are based on frequency data from SunSpider:
2284 // <times> Add case: <t1> <t2>
2285 // ---------------------------
2286 // 5627160 Add case: 1 1
2287 // 247427 Add case: 5 5
2288 // 20901 Add case: 5 6
2289 // 13978 Add case: 5 1
2290 // 4000 Add case: 1 5
2293 static inline JSValue
* add(ExecState
* exec
, JSValue
* v1
, JSValue
* v2
)
2295 JSType t1
= v1
->type();
2296 JSType t2
= v2
->type();
2297 const unsigned bothTypes
= (t1
<< 3) | t2
;
2299 if (bothTypes
== ((NumberType
<< 3) | NumberType
))
2300 return jsNumber(v1
->toNumber(exec
) + v2
->toNumber(exec
));
2301 if (bothTypes
== ((StringType
<< 3) | StringType
)) {
2302 UString value
= static_cast<StringImp
*>(v1
)->value() + static_cast<StringImp
*>(v2
)->value();
2304 return throwOutOfMemoryError(exec
);
2305 return jsString(value
);
2308 // All other cases are pretty uncommon
2309 return addSlowCase(exec
, v1
, v2
);
2312 static inline double addToNumber(ExecState
* exec
, JSValue
* v1
, JSValue
* v2
)
2314 JSType t1
= v1
->type();
2315 JSType t2
= v2
->type();
2316 const unsigned bothTypes
= (t1
<< 3) | t2
;
2318 if (bothTypes
== ((NumberType
<< 3) | NumberType
))
2319 return v1
->toNumber(exec
) + v2
->toNumber(exec
);
2320 if (bothTypes
== ((StringType
<< 3) | StringType
)) {
2321 UString value
= static_cast<StringImp
*>(v1
)->value() + static_cast<StringImp
*>(v2
)->value();
2323 return throwOutOfMemoryErrorToNumber(exec
);
2324 return value
.toDouble();
2327 // All other cases are pretty uncommon
2328 return addSlowCaseToNumber(exec
, v1
, v2
);
2331 void AddNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2333 nodeStack
.append(m_term1
.get());
2334 nodeStack
.append(m_term2
.get());
2338 JSValue
* AddNode::evaluate(ExecState
* exec
)
2340 JSValue
* v1
= m_term1
->evaluate(exec
);
2341 KJS_CHECKEXCEPTIONVALUE
2343 JSValue
* v2
= m_term2
->evaluate(exec
);
2344 KJS_CHECKEXCEPTIONVALUE
2346 return add(exec
, v1
, v2
);
2349 double AddNode::inlineEvaluateToNumber(ExecState
* exec
)
2351 JSValue
* v1
= m_term1
->evaluate(exec
);
2352 KJS_CHECKEXCEPTIONNUMBER
2354 JSValue
* v2
= m_term2
->evaluate(exec
);
2355 KJS_CHECKEXCEPTIONNUMBER
2357 return addToNumber(exec
, v1
, v2
);
2360 double AddNode::evaluateToNumber(ExecState
* exec
)
2362 return inlineEvaluateToNumber(exec
);
2365 int32_t AddNode::evaluateToInt32(ExecState
* exec
)
2367 return JSValue::toInt32(inlineEvaluateToNumber(exec
));
2370 uint32_t AddNode::evaluateToUInt32(ExecState
* exec
)
2372 return JSValue::toUInt32(inlineEvaluateToNumber(exec
));
2375 double AddNumbersNode::inlineEvaluateToNumber(ExecState
* exec
)
2377 double n1
= m_term1
->evaluateToNumber(exec
);
2378 KJS_CHECKEXCEPTIONNUMBER
2379 double n2
= m_term2
->evaluateToNumber(exec
);
2383 JSValue
* AddNumbersNode::evaluate(ExecState
* exec
)
2385 return jsNumber(inlineEvaluateToNumber(exec
));
2388 double AddNumbersNode::evaluateToNumber(ExecState
* exec
)
2390 return inlineEvaluateToNumber(exec
);
2393 int32_t AddNumbersNode::evaluateToInt32(ExecState
* exec
)
2395 return JSValue::toInt32(inlineEvaluateToNumber(exec
));
2398 uint32_t AddNumbersNode::evaluateToUInt32(ExecState
* exec
)
2400 return JSValue::toUInt32(inlineEvaluateToNumber(exec
));
2403 JSValue
* AddStringsNode::evaluate(ExecState
* exec
)
2405 JSValue
* v1
= m_term1
->evaluate(exec
);
2406 KJS_CHECKEXCEPTIONVALUE
2408 JSValue
* v2
= m_term2
->evaluate(exec
);
2409 KJS_CHECKEXCEPTIONVALUE
2411 return jsString(static_cast<StringImp
*>(v1
)->value() + static_cast<StringImp
*>(v2
)->value());
2414 JSValue
* AddStringLeftNode::evaluate(ExecState
* exec
)
2416 JSValue
* v1
= m_term1
->evaluate(exec
);
2417 KJS_CHECKEXCEPTIONVALUE
2419 JSValue
* v2
= m_term2
->evaluate(exec
);
2420 KJS_CHECKEXCEPTIONVALUE
2422 JSValue
* p2
= v2
->toPrimitive(exec
, UnspecifiedType
);
2423 return jsString(static_cast<StringImp
*>(v1
)->value() + p2
->toString(exec
));
2426 JSValue
* AddStringRightNode::evaluate(ExecState
* exec
)
2428 JSValue
* v1
= m_term1
->evaluate(exec
);
2429 KJS_CHECKEXCEPTIONVALUE
2431 JSValue
* v2
= m_term2
->evaluate(exec
);
2432 KJS_CHECKEXCEPTIONVALUE
2434 JSValue
* p1
= v1
->toPrimitive(exec
, UnspecifiedType
);
2435 return jsString(p1
->toString(exec
) + static_cast<StringImp
*>(v2
)->value());
2438 void SubNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2440 nodeStack
.append(m_term1
.get());
2441 nodeStack
.append(m_term2
.get());
2445 double SubNode::inlineEvaluateToNumber(ExecState
* exec
)
2447 double n1
= m_term1
->evaluateToNumber(exec
);
2448 KJS_CHECKEXCEPTIONNUMBER
2449 double n2
= m_term2
->evaluateToNumber(exec
);
2453 JSValue
* SubNode::evaluate(ExecState
* exec
)
2455 return jsNumber(inlineEvaluateToNumber(exec
));
2458 double SubNode::evaluateToNumber(ExecState
* exec
)
2460 return inlineEvaluateToNumber(exec
);
2463 int32_t SubNode::evaluateToInt32(ExecState
* exec
)
2465 return JSValue::toInt32(inlineEvaluateToNumber(exec
));
2468 uint32_t SubNode::evaluateToUInt32(ExecState
* exec
)
2470 return JSValue::toUInt32(inlineEvaluateToNumber(exec
));
2473 // ------------------------------ Shift Nodes ------------------------------------
2475 void LeftShiftNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2477 nodeStack
.append(m_term1
.get());
2478 nodeStack
.append(m_term2
.get());
2482 int32_t LeftShiftNode::inlineEvaluateToInt32(ExecState
* exec
)
2484 int i1
= m_term1
->evaluateToInt32(exec
);
2485 KJS_CHECKEXCEPTIONNUMBER
2486 unsigned int i2
= m_term2
->evaluateToUInt32(exec
) & 0x1f;
2490 JSValue
* LeftShiftNode::evaluate(ExecState
* exec
)
2492 return jsNumber(inlineEvaluateToInt32(exec
));
2495 double LeftShiftNode::evaluateToNumber(ExecState
* exec
)
2497 return inlineEvaluateToInt32(exec
);
2500 int32_t LeftShiftNode::evaluateToInt32(ExecState
* exec
)
2502 return inlineEvaluateToInt32(exec
);
2505 uint32_t LeftShiftNode::evaluateToUInt32(ExecState
* exec
)
2507 return inlineEvaluateToInt32(exec
);
2510 void RightShiftNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2512 nodeStack
.append(m_term1
.get());
2513 nodeStack
.append(m_term2
.get());
2517 int32_t RightShiftNode::inlineEvaluateToInt32(ExecState
* exec
)
2519 int i1
= m_term1
->evaluateToInt32(exec
);
2520 KJS_CHECKEXCEPTIONNUMBER
2521 unsigned int i2
= m_term2
->evaluateToUInt32(exec
) & 0x1f;
2525 JSValue
* RightShiftNode::evaluate(ExecState
* exec
)
2527 return jsNumber(inlineEvaluateToInt32(exec
));
2530 double RightShiftNode::evaluateToNumber(ExecState
* exec
)
2532 return inlineEvaluateToInt32(exec
);
2535 int32_t RightShiftNode::evaluateToInt32(ExecState
* exec
)
2537 return inlineEvaluateToInt32(exec
);
2540 uint32_t RightShiftNode::evaluateToUInt32(ExecState
* exec
)
2542 return inlineEvaluateToInt32(exec
);
2545 void UnsignedRightShiftNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2547 nodeStack
.append(m_term1
.get());
2548 nodeStack
.append(m_term2
.get());
2552 uint32_t UnsignedRightShiftNode::inlineEvaluateToUInt32(ExecState
* exec
)
2554 unsigned int i1
= m_term1
->evaluateToUInt32(exec
);
2555 KJS_CHECKEXCEPTIONNUMBER
2556 unsigned int i2
= m_term2
->evaluateToUInt32(exec
) & 0x1f;
2560 JSValue
* UnsignedRightShiftNode::evaluate(ExecState
* exec
)
2562 return jsNumber(inlineEvaluateToUInt32(exec
));
2565 double UnsignedRightShiftNode::evaluateToNumber(ExecState
* exec
)
2567 return inlineEvaluateToUInt32(exec
);
2570 int32_t UnsignedRightShiftNode::evaluateToInt32(ExecState
* exec
)
2572 return inlineEvaluateToUInt32(exec
);
2575 uint32_t UnsignedRightShiftNode::evaluateToUInt32(ExecState
* exec
)
2577 return inlineEvaluateToUInt32(exec
);
2580 // ------------------------------ Relational Nodes -------------------------------
2582 static inline bool lessThan(ExecState
* exec
, JSValue
* v1
, JSValue
* v2
)
2588 bool wasNotString1
= v1
->getPrimitiveNumber(exec
, n1
, p1
);
2589 bool wasNotString2
= v2
->getPrimitiveNumber(exec
, n2
, p2
);
2591 if (wasNotString1
| wasNotString2
)
2594 return static_cast<const StringImp
*>(p1
)->value() < static_cast<const StringImp
*>(p2
)->value();
2597 static inline bool lessThanEq(ExecState
* exec
, JSValue
* v1
, JSValue
* v2
)
2603 bool wasNotString1
= v1
->getPrimitiveNumber(exec
, n1
, p1
);
2604 bool wasNotString2
= v2
->getPrimitiveNumber(exec
, n2
, p2
);
2606 if (wasNotString1
| wasNotString2
)
2609 return !(static_cast<const StringImp
*>(p2
)->value() < static_cast<const StringImp
*>(p1
)->value());
2612 void LessNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2614 nodeStack
.append(m_expr2
.get());
2615 nodeStack
.append(m_expr1
.get());
2619 bool LessNode::inlineEvaluateToBoolean(ExecState
* exec
)
2621 JSValue
* v1
= m_expr1
->evaluate(exec
);
2622 KJS_CHECKEXCEPTIONBOOLEAN
2623 JSValue
* v2
= m_expr2
->evaluate(exec
);
2624 KJS_CHECKEXCEPTIONBOOLEAN
2625 return lessThan(exec
, v1
, v2
);
2628 JSValue
* LessNode::evaluate(ExecState
* exec
)
2630 return jsBoolean(inlineEvaluateToBoolean(exec
));
2633 bool LessNode::evaluateToBoolean(ExecState
* exec
)
2635 return inlineEvaluateToBoolean(exec
);
2638 bool LessNumbersNode::inlineEvaluateToBoolean(ExecState
* exec
)
2640 double n1
= m_expr1
->evaluateToNumber(exec
);
2641 KJS_CHECKEXCEPTIONVALUE
2642 double n2
= m_expr2
->evaluateToNumber(exec
);
2646 JSValue
* LessNumbersNode::evaluate(ExecState
* exec
)
2648 return jsBoolean(inlineEvaluateToBoolean(exec
));
2651 bool LessNumbersNode::evaluateToBoolean(ExecState
* exec
)
2653 return inlineEvaluateToBoolean(exec
);
2656 bool LessStringsNode::inlineEvaluateToBoolean(ExecState
* exec
)
2658 JSValue
* v1
= m_expr1
->evaluate(exec
);
2659 KJS_CHECKEXCEPTIONVALUE
2660 JSValue
* v2
= m_expr2
->evaluate(exec
);
2661 return static_cast<StringImp
*>(v1
)->value() < static_cast<StringImp
*>(v2
)->value();
2664 JSValue
* LessStringsNode::evaluate(ExecState
* exec
)
2666 return jsBoolean(inlineEvaluateToBoolean(exec
));
2669 bool LessStringsNode::evaluateToBoolean(ExecState
* exec
)
2671 return inlineEvaluateToBoolean(exec
);
2674 void GreaterNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2676 nodeStack
.append(m_expr2
.get());
2677 nodeStack
.append(m_expr1
.get());
2681 bool GreaterNode::inlineEvaluateToBoolean(ExecState
* exec
)
2683 JSValue
* v1
= m_expr1
->evaluate(exec
);
2684 KJS_CHECKEXCEPTIONBOOLEAN
2685 JSValue
* v2
= m_expr2
->evaluate(exec
);
2686 KJS_CHECKEXCEPTIONBOOLEAN
2687 return lessThan(exec
, v2
, v1
);
2690 JSValue
* GreaterNode::evaluate(ExecState
* exec
)
2692 return jsBoolean(inlineEvaluateToBoolean(exec
));
2695 bool GreaterNode::evaluateToBoolean(ExecState
* exec
)
2697 return inlineEvaluateToBoolean(exec
);
2700 void LessEqNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2702 nodeStack
.append(m_expr2
.get());
2703 nodeStack
.append(m_expr1
.get());
2707 bool LessEqNode::inlineEvaluateToBoolean(ExecState
* exec
)
2709 JSValue
* v1
= m_expr1
->evaluate(exec
);
2710 KJS_CHECKEXCEPTIONBOOLEAN
2711 JSValue
* v2
= m_expr2
->evaluate(exec
);
2712 KJS_CHECKEXCEPTIONBOOLEAN
2713 return lessThanEq(exec
, v1
, v2
);
2716 JSValue
* LessEqNode::evaluate(ExecState
* exec
)
2718 return jsBoolean(inlineEvaluateToBoolean(exec
));
2721 bool LessEqNode::evaluateToBoolean(ExecState
* exec
)
2723 return inlineEvaluateToBoolean(exec
);
2726 void GreaterEqNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2728 nodeStack
.append(m_expr2
.get());
2729 nodeStack
.append(m_expr1
.get());
2733 bool GreaterEqNode::inlineEvaluateToBoolean(ExecState
* exec
)
2735 JSValue
* v1
= m_expr1
->evaluate(exec
);
2736 KJS_CHECKEXCEPTIONBOOLEAN
2737 JSValue
* v2
= m_expr2
->evaluate(exec
);
2738 KJS_CHECKEXCEPTIONBOOLEAN
2739 return lessThanEq(exec
, v2
, v1
);
2742 JSValue
* GreaterEqNode::evaluate(ExecState
* exec
)
2744 return jsBoolean(inlineEvaluateToBoolean(exec
));
2747 bool GreaterEqNode::evaluateToBoolean(ExecState
* exec
)
2749 return inlineEvaluateToBoolean(exec
);
2752 void InstanceOfNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2754 nodeStack
.append(m_expr2
.get());
2755 nodeStack
.append(m_expr1
.get());
2759 JSValue
* InstanceOfNode::evaluate(ExecState
* exec
)
2761 JSValue
* v1
= m_expr1
->evaluate(exec
);
2762 KJS_CHECKEXCEPTIONVALUE
2763 JSValue
* v2
= m_expr2
->evaluate(exec
);
2764 KJS_CHECKEXCEPTIONVALUE
2766 if (!v2
->isObject())
2767 return throwError(exec
, TypeError
, "Value %s (result of expression %s) is not an object. Cannot be used with instanceof operator.", v2
, m_expr2
.get());
2769 JSObject
* o2
= static_cast<JSObject
*>(v2
);
2771 // According to the spec, only some types of objects "implement" the [[HasInstance]] property.
2772 // But we are supposed to throw an exception where the object does not "have" the [[HasInstance]]
2773 // property. It seems that all objects have the property, but not all implement it, so in this
2774 // case we return false (consistent with Mozilla).
2775 if (!o2
->implementsHasInstance())
2776 return jsBoolean(false);
2778 return jsBoolean(o2
->hasInstance(exec
, v1
));
2781 bool InstanceOfNode::evaluateToBoolean(ExecState
* exec
)
2783 JSValue
* v1
= m_expr1
->evaluate(exec
);
2784 KJS_CHECKEXCEPTIONBOOLEAN
2785 JSValue
* v2
= m_expr2
->evaluate(exec
);
2786 KJS_CHECKEXCEPTIONBOOLEAN
2788 if (!v2
->isObject()) {
2789 throwError(exec
, TypeError
, "Value %s (result of expression %s) is not an object. Cannot be used with 'instanceof' operator.", v2
, m_expr2
.get());
2793 JSObject
* o2
= static_cast<JSObject
*>(v2
);
2795 // According to the spec, only some types of objects "implement" the [[HasInstance]] property.
2796 // But we are supposed to throw an exception where the object does not "have" the [[HasInstance]]
2797 // property. It seems that all objects have the property, but not all implement it, so in this
2798 // case we return false (consistent with Mozilla).
2799 if (!o2
->implementsHasInstance())
2802 return o2
->hasInstance(exec
, v1
);
2805 void InNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2807 nodeStack
.append(m_expr2
.get());
2808 nodeStack
.append(m_expr1
.get());
2812 JSValue
* InNode::evaluate(ExecState
* exec
)
2814 JSValue
* v1
= m_expr1
->evaluate(exec
);
2815 KJS_CHECKEXCEPTIONVALUE
2816 JSValue
* v2
= m_expr2
->evaluate(exec
);
2817 KJS_CHECKEXCEPTIONVALUE
2819 if (!v2
->isObject())
2820 return throwError(exec
, TypeError
, "Value %s (result of expression %s) is not an object. Cannot be used with 'in' operator.", v2
, m_expr2
.get());
2822 return jsBoolean(static_cast<JSObject
*>(v2
)->hasProperty(exec
, Identifier(v1
->toString(exec
))));
2825 bool InNode::evaluateToBoolean(ExecState
* exec
)
2827 JSValue
* v1
= m_expr1
->evaluate(exec
);
2828 KJS_CHECKEXCEPTIONBOOLEAN
2829 JSValue
* v2
= m_expr2
->evaluate(exec
);
2830 KJS_CHECKEXCEPTIONBOOLEAN
2832 if (!v2
->isObject()) {
2833 throwError(exec
, TypeError
, "Value %s (result of expression %s) is not an object. Cannot be used with 'in' operator.", v2
, m_expr2
.get());
2837 return static_cast<JSObject
*>(v2
)->hasProperty(exec
, Identifier(v1
->toString(exec
)));
2840 // ------------------------------ Equality Nodes ------------------------------------
2842 void EqualNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2844 nodeStack
.append(m_expr2
.get());
2845 nodeStack
.append(m_expr1
.get());
2849 bool EqualNode::inlineEvaluateToBoolean(ExecState
* exec
)
2851 JSValue
* v1
= m_expr1
->evaluate(exec
);
2852 KJS_CHECKEXCEPTIONBOOLEAN
2853 JSValue
* v2
= m_expr2
->evaluate(exec
);
2854 KJS_CHECKEXCEPTIONBOOLEAN
2856 return equal(exec
, v1
, v2
);
2859 JSValue
* EqualNode::evaluate(ExecState
* exec
)
2861 return jsBoolean(inlineEvaluateToBoolean(exec
));
2864 bool EqualNode::evaluateToBoolean(ExecState
* exec
)
2866 return inlineEvaluateToBoolean(exec
);
2869 void NotEqualNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2871 nodeStack
.append(m_expr2
.get());
2872 nodeStack
.append(m_expr1
.get());
2876 bool NotEqualNode::inlineEvaluateToBoolean(ExecState
* exec
)
2878 JSValue
* v1
= m_expr1
->evaluate(exec
);
2879 KJS_CHECKEXCEPTIONBOOLEAN
2880 JSValue
* v2
= m_expr2
->evaluate(exec
);
2881 KJS_CHECKEXCEPTIONBOOLEAN
2883 return !equal(exec
,v1
, v2
);
2886 JSValue
* NotEqualNode::evaluate(ExecState
* exec
)
2888 return jsBoolean(inlineEvaluateToBoolean(exec
));
2891 bool NotEqualNode::evaluateToBoolean(ExecState
* exec
)
2893 return inlineEvaluateToBoolean(exec
);
2896 void StrictEqualNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2898 nodeStack
.append(m_expr2
.get());
2899 nodeStack
.append(m_expr1
.get());
2903 bool StrictEqualNode::inlineEvaluateToBoolean(ExecState
* exec
)
2905 JSValue
* v1
= m_expr1
->evaluate(exec
);
2906 KJS_CHECKEXCEPTIONBOOLEAN
2907 JSValue
* v2
= m_expr2
->evaluate(exec
);
2908 KJS_CHECKEXCEPTIONBOOLEAN
2910 return strictEqual(exec
,v1
, v2
);
2913 JSValue
* StrictEqualNode::evaluate(ExecState
* exec
)
2915 return jsBoolean(inlineEvaluateToBoolean(exec
));
2918 bool StrictEqualNode::evaluateToBoolean(ExecState
* exec
)
2920 return inlineEvaluateToBoolean(exec
);
2923 void NotStrictEqualNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2925 nodeStack
.append(m_expr2
.get());
2926 nodeStack
.append(m_expr1
.get());
2930 bool NotStrictEqualNode::inlineEvaluateToBoolean(ExecState
* exec
)
2932 JSValue
* v1
= m_expr1
->evaluate(exec
);
2933 KJS_CHECKEXCEPTIONBOOLEAN
2934 JSValue
* v2
= m_expr2
->evaluate(exec
);
2935 KJS_CHECKEXCEPTIONBOOLEAN
2937 return !strictEqual(exec
,v1
, v2
);
2940 JSValue
* NotStrictEqualNode::evaluate(ExecState
* exec
)
2942 return jsBoolean(inlineEvaluateToBoolean(exec
));
2945 bool NotStrictEqualNode::evaluateToBoolean(ExecState
* exec
)
2947 return inlineEvaluateToBoolean(exec
);
2950 // ------------------------------ Bit Operation Nodes ----------------------------------
2952 void BitAndNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2954 nodeStack
.append(m_expr2
.get());
2955 nodeStack
.append(m_expr1
.get());
2959 JSValue
* BitAndNode::evaluate(ExecState
* exec
)
2961 JSValue
* v1
= m_expr1
->evaluate(exec
);
2962 KJS_CHECKEXCEPTIONVALUE
2963 JSValue
* v2
= m_expr2
->evaluate(exec
);
2964 KJS_CHECKEXCEPTIONVALUE
2966 return jsNumberFromAnd(exec
, v1
, v2
);
2969 int32_t BitAndNode::inlineEvaluateToInt32(ExecState
* exec
)
2971 int32_t i1
= m_expr1
->evaluateToInt32(exec
);
2972 KJS_CHECKEXCEPTIONNUMBER
2973 int32_t i2
= m_expr2
->evaluateToInt32(exec
);
2977 double BitAndNode::evaluateToNumber(ExecState
* exec
)
2979 return inlineEvaluateToInt32(exec
);
2982 bool BitAndNode::evaluateToBoolean(ExecState
* exec
)
2984 return inlineEvaluateToInt32(exec
);
2987 int32_t BitAndNode::evaluateToInt32(ExecState
* exec
)
2989 return inlineEvaluateToInt32(exec
);
2992 uint32_t BitAndNode::evaluateToUInt32(ExecState
* exec
)
2994 return inlineEvaluateToInt32(exec
);
2997 void BitXOrNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
2999 nodeStack
.append(m_expr2
.get());
3000 nodeStack
.append(m_expr1
.get());
3003 int32_t BitXOrNode::inlineEvaluateToInt32(ExecState
* exec
)
3005 int i1
= m_expr1
->evaluateToInt32(exec
);
3006 KJS_CHECKEXCEPTIONNUMBER
3007 int i2
= m_expr2
->evaluateToInt32(exec
);
3011 JSValue
* BitXOrNode::evaluate(ExecState
* exec
)
3013 return jsNumber(inlineEvaluateToInt32(exec
));
3016 double BitXOrNode::evaluateToNumber(ExecState
* exec
)
3018 return inlineEvaluateToInt32(exec
);
3021 bool BitXOrNode::evaluateToBoolean(ExecState
* exec
)
3023 return inlineEvaluateToInt32(exec
);
3026 int32_t BitXOrNode::evaluateToInt32(ExecState
* exec
)
3028 return inlineEvaluateToInt32(exec
);
3031 uint32_t BitXOrNode::evaluateToUInt32(ExecState
* exec
)
3033 return inlineEvaluateToInt32(exec
);
3036 void BitOrNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3038 nodeStack
.append(m_expr2
.get());
3039 nodeStack
.append(m_expr1
.get());
3042 int32_t BitOrNode::inlineEvaluateToInt32(ExecState
* exec
)
3044 int i1
= m_expr1
->evaluateToInt32(exec
);
3045 KJS_CHECKEXCEPTIONNUMBER
3046 int i2
= m_expr2
->evaluateToInt32(exec
);
3050 JSValue
* BitOrNode::evaluate(ExecState
* exec
)
3052 return jsNumber(inlineEvaluateToInt32(exec
));
3055 double BitOrNode::evaluateToNumber(ExecState
* exec
)
3057 return inlineEvaluateToInt32(exec
);
3060 bool BitOrNode::evaluateToBoolean(ExecState
* exec
)
3062 return inlineEvaluateToInt32(exec
);
3065 int32_t BitOrNode::evaluateToInt32(ExecState
* exec
)
3067 return inlineEvaluateToInt32(exec
);
3070 uint32_t BitOrNode::evaluateToUInt32(ExecState
* exec
)
3072 return inlineEvaluateToInt32(exec
);
3075 // ------------------------------ Binary Logical Nodes ----------------------------
3077 void LogicalAndNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3079 nodeStack
.append(m_expr2
.get());
3080 nodeStack
.append(m_expr1
.get());
3084 JSValue
* LogicalAndNode::evaluate(ExecState
* exec
)
3086 JSValue
* v1
= m_expr1
->evaluate(exec
);
3087 KJS_CHECKEXCEPTIONVALUE
3088 bool b1
= v1
->toBoolean(exec
);
3089 KJS_CHECKEXCEPTIONVALUE
3092 JSValue
* v2
= m_expr2
->evaluate(exec
);
3093 KJS_CHECKEXCEPTIONVALUE
3097 bool LogicalAndNode::evaluateToBoolean(ExecState
* exec
)
3099 bool b
= m_expr1
->evaluateToBoolean(exec
);
3100 KJS_CHECKEXCEPTIONBOOLEAN
3101 return b
&& m_expr2
->evaluateToBoolean(exec
);
3104 void LogicalOrNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3106 nodeStack
.append(m_expr2
.get());
3107 nodeStack
.append(m_expr1
.get());
3110 JSValue
* LogicalOrNode::evaluate(ExecState
* exec
)
3112 JSValue
* v1
= m_expr1
->evaluate(exec
);
3113 KJS_CHECKEXCEPTIONVALUE
3114 if (v1
->toBoolean(exec
))
3116 return m_expr2
->evaluate(exec
);
3119 bool LogicalOrNode::evaluateToBoolean(ExecState
* exec
)
3121 bool b
= m_expr1
->evaluateToBoolean(exec
);
3122 KJS_CHECKEXCEPTIONBOOLEAN
3123 return b
|| m_expr2
->evaluateToBoolean(exec
);
3126 // ------------------------------ ConditionalNode ------------------------------
3128 void ConditionalNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3130 nodeStack
.append(m_expr2
.get());
3131 nodeStack
.append(m_expr1
.get());
3132 nodeStack
.append(m_logical
.get());
3136 JSValue
* ConditionalNode::evaluate(ExecState
* exec
)
3138 bool b
= m_logical
->evaluateToBoolean(exec
);
3139 KJS_CHECKEXCEPTIONVALUE
3140 return b
? m_expr1
->evaluate(exec
) : m_expr2
->evaluate(exec
);
3143 bool ConditionalNode::evaluateToBoolean(ExecState
* exec
)
3145 bool b
= m_logical
->evaluateToBoolean(exec
);
3146 KJS_CHECKEXCEPTIONBOOLEAN
3147 return b
? m_expr1
->evaluateToBoolean(exec
) : m_expr2
->evaluateToBoolean(exec
);
3150 double ConditionalNode::evaluateToNumber(ExecState
* exec
)
3152 bool b
= m_logical
->evaluateToBoolean(exec
);
3153 KJS_CHECKEXCEPTIONNUMBER
3154 return b
? m_expr1
->evaluateToNumber(exec
) : m_expr2
->evaluateToNumber(exec
);
3157 int32_t ConditionalNode::evaluateToInt32(ExecState
* exec
)
3159 bool b
= m_logical
->evaluateToBoolean(exec
);
3160 KJS_CHECKEXCEPTIONNUMBER
3161 return b
? m_expr1
->evaluateToInt32(exec
) : m_expr2
->evaluateToInt32(exec
);
3164 uint32_t ConditionalNode::evaluateToUInt32(ExecState
* exec
)
3166 bool b
= m_logical
->evaluateToBoolean(exec
);
3167 KJS_CHECKEXCEPTIONNUMBER
3168 return b
? m_expr1
->evaluateToUInt32(exec
) : m_expr2
->evaluateToUInt32(exec
);
3173 static ALWAYS_INLINE JSValue
* valueForReadModifyAssignment(ExecState
* exec
, JSValue
* current
, ExpressionNode
* right
, Operator oper
) KJS_FAST_CALL
;
3174 static ALWAYS_INLINE JSValue
* valueForReadModifyAssignment(ExecState
* exec
, JSValue
* current
, ExpressionNode
* right
, Operator oper
)
3182 v
= jsNumber(current
->toNumber(exec
) * right
->evaluateToNumber(exec
));
3185 v
= jsNumber(current
->toNumber(exec
) / right
->evaluateToNumber(exec
));
3188 v
= add(exec
, current
, right
->evaluate(exec
));
3191 v
= jsNumber(current
->toNumber(exec
) - right
->evaluateToNumber(exec
));
3194 i1
= current
->toInt32(exec
);
3195 i2
= right
->evaluateToInt32(exec
);
3196 v
= jsNumber(i1
<< i2
);
3199 i1
= current
->toInt32(exec
);
3200 i2
= right
->evaluateToInt32(exec
);
3201 v
= jsNumber(i1
>> i2
);
3204 ui
= current
->toUInt32(exec
);
3205 i2
= right
->evaluateToInt32(exec
);
3206 v
= jsNumber(ui
>> i2
);
3209 i1
= current
->toInt32(exec
);
3210 i2
= right
->evaluateToInt32(exec
);
3211 v
= jsNumber(i1
& i2
);
3214 i1
= current
->toInt32(exec
);
3215 i2
= right
->evaluateToInt32(exec
);
3216 v
= jsNumber(i1
^ i2
);
3219 i1
= current
->toInt32(exec
);
3220 i2
= right
->evaluateToInt32(exec
);
3221 v
= jsNumber(i1
| i2
);
3224 double d1
= current
->toNumber(exec
);
3225 double d2
= right
->evaluateToNumber(exec
);
3226 v
= jsNumber(fmod(d1
, d2
));
3230 ASSERT_NOT_REACHED();
3237 // ------------------------------ ReadModifyResolveNode -----------------------------------
3239 void ReadModifyResolveNode::optimizeVariableAccess(const SymbolTable
& symbolTable
, const LocalStorage
& localStorage
, NodeStack
& nodeStack
)
3241 nodeStack
.append(m_right
.get());
3242 size_t index
= symbolTable
.get(m_ident
.ustring().rep());
3243 if (index
!= missingSymbolMarker()) {
3244 if (isConstant(localStorage
, index
))
3245 new (this) ReadModifyConstNode(index
);
3247 new (this) ReadModifyLocalVarNode(index
);
3251 // ------------------------------ AssignResolveNode -----------------------------------
3253 void AssignResolveNode::optimizeVariableAccess(const SymbolTable
& symbolTable
, const LocalStorage
& localStorage
, NodeStack
& nodeStack
)
3255 nodeStack
.append(m_right
.get());
3256 size_t index
= symbolTable
.get(m_ident
.ustring().rep());
3257 if (index
!= missingSymbolMarker()) {
3258 if (isConstant(localStorage
, index
))
3259 new (this) AssignConstNode
;
3261 new (this) AssignLocalVarNode(index
);
3265 // ------------------------------ ReadModifyLocalVarNode -----------------------------------
3267 JSValue
* ReadModifyLocalVarNode::evaluate(ExecState
* exec
)
3269 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
3271 ASSERT(m_operator
!= OpEqual
);
3272 JSValue
* v
= valueForReadModifyAssignment(exec
, exec
->localStorage()[m_index
].value
, m_right
.get(), m_operator
);
3274 KJS_CHECKEXCEPTIONVALUE
3276 // We can't store a pointer into localStorage() and use it throughout the function
3277 // body, because valueForReadModifyAssignment() might cause an ActivationImp tear-off,
3278 // changing the value of localStorage().
3280 exec
->localStorage()[m_index
].value
= v
;
3284 // ------------------------------ AssignLocalVarNode -----------------------------------
3286 JSValue
* AssignLocalVarNode::evaluate(ExecState
* exec
)
3288 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
3289 JSValue
* v
= m_right
->evaluate(exec
);
3291 KJS_CHECKEXCEPTIONVALUE
3293 exec
->localStorage()[m_index
].value
= v
;
3298 // ------------------------------ ReadModifyConstNode -----------------------------------
3300 JSValue
* ReadModifyConstNode::evaluate(ExecState
* exec
)
3302 ASSERT(exec
->variableObject() == exec
->scopeChain().top());
3303 JSValue
* left
= exec
->localStorage()[m_index
].value
;
3304 ASSERT(m_operator
!= OpEqual
);
3305 JSValue
* result
= valueForReadModifyAssignment(exec
, left
, m_right
.get(), m_operator
);
3306 KJS_CHECKEXCEPTIONVALUE
3310 // ------------------------------ AssignConstNode -----------------------------------
3312 JSValue
* AssignConstNode::evaluate(ExecState
* exec
)
3314 return m_right
->evaluate(exec
);
3317 JSValue
* ReadModifyResolveNode::evaluate(ExecState
* exec
)
3319 const ScopeChain
& chain
= exec
->scopeChain();
3320 ScopeChainIterator iter
= chain
.begin();
3321 ScopeChainIterator end
= chain
.end();
3323 // We must always have something in the scope chain
3324 ASSERT(iter
!= end
);
3330 if (base
->getPropertySlot(exec
, m_ident
, slot
)) {
3331 // See the comment in PostIncResolveNode::evaluate().
3338 } while (iter
!= end
);
3340 ASSERT(m_operator
!= OpEqual
);
3341 return throwUndefinedVariableError(exec
, m_ident
);
3346 ASSERT(m_operator
!= OpEqual
);
3347 JSValue
* v1
= slot
.getValue(exec
, base
, m_ident
);
3348 KJS_CHECKEXCEPTIONVALUE
3349 v
= valueForReadModifyAssignment(exec
, v1
, m_right
.get(), m_operator
);
3351 KJS_CHECKEXCEPTIONVALUE
3353 // Since valueForReadModifyAssignment() might cause an ActivationImp tear-off,
3354 // we need to get the base from the ScopeChainIterator again.
3356 (*iter
)->put(exec
, m_ident
, v
);
3360 JSValue
* AssignResolveNode::evaluate(ExecState
* exec
)
3362 const ScopeChain
& chain
= exec
->scopeChain();
3363 ScopeChainIterator iter
= chain
.begin();
3364 ScopeChainIterator end
= chain
.end();
3366 // we must always have something in the scope chain
3367 ASSERT(iter
!= end
);
3373 if (base
->getPropertySlot(exec
, m_ident
, slot
)) {
3374 // See the comment in PostIncResolveNode::evaluate().
3381 } while (iter
!= end
);
3384 JSValue
* v
= m_right
->evaluate(exec
);
3386 KJS_CHECKEXCEPTIONVALUE
3388 base
->put(exec
, m_ident
, v
);
3392 // ------------------------------ ReadModifyDotNode -----------------------------------
3394 void AssignDotNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3396 nodeStack
.append(m_right
.get());
3397 nodeStack
.append(m_base
.get());
3400 JSValue
* AssignDotNode::evaluate(ExecState
* exec
)
3402 JSValue
* baseValue
= m_base
->evaluate(exec
);
3403 KJS_CHECKEXCEPTIONVALUE
3404 JSObject
* base
= baseValue
->toObject(exec
);
3406 JSValue
* v
= m_right
->evaluate(exec
);
3408 KJS_CHECKEXCEPTIONVALUE
3410 base
->put(exec
, m_ident
, v
);
3414 void ReadModifyDotNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3416 nodeStack
.append(m_right
.get());
3417 nodeStack
.append(m_base
.get());
3420 JSValue
* ReadModifyDotNode::evaluate(ExecState
* exec
)
3422 JSValue
* baseValue
= m_base
->evaluate(exec
);
3423 KJS_CHECKEXCEPTIONVALUE
3424 JSObject
* base
= baseValue
->toObject(exec
);
3428 ASSERT(m_operator
!= OpEqual
);
3430 JSValue
* v1
= base
->getPropertySlot(exec
, m_ident
, slot
) ? slot
.getValue(exec
, base
, m_ident
) : jsUndefined();
3431 KJS_CHECKEXCEPTIONVALUE
3432 v
= valueForReadModifyAssignment(exec
, v1
, m_right
.get(), m_operator
);
3434 KJS_CHECKEXCEPTIONVALUE
3436 base
->put(exec
, m_ident
, v
);
3440 // ------------------------------ AssignErrorNode -----------------------------------
3442 JSValue
* AssignErrorNode::evaluate(ExecState
* exec
)
3444 throwError(exec
, ReferenceError
, "Left side of assignment is not a reference.");
3445 handleException(exec
);
3446 return jsUndefined();
3449 // ------------------------------ AssignBracketNode -----------------------------------
3451 void AssignBracketNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3453 nodeStack
.append(m_right
.get());
3454 nodeStack
.append(m_subscript
.get());
3455 nodeStack
.append(m_base
.get());
3458 JSValue
* AssignBracketNode::evaluate(ExecState
* exec
)
3460 JSValue
* baseValue
= m_base
->evaluate(exec
);
3461 KJS_CHECKEXCEPTIONVALUE
3462 JSValue
* subscript
= m_subscript
->evaluate(exec
);
3463 KJS_CHECKEXCEPTIONVALUE
3465 JSObject
* base
= baseValue
->toObject(exec
);
3467 uint32_t propertyIndex
;
3468 if (subscript
->getUInt32(propertyIndex
)) {
3469 JSValue
* v
= m_right
->evaluate(exec
);
3470 KJS_CHECKEXCEPTIONVALUE
3472 base
->put(exec
, propertyIndex
, v
);
3476 Identifier
propertyName(subscript
->toString(exec
));
3477 JSValue
* v
= m_right
->evaluate(exec
);
3478 KJS_CHECKEXCEPTIONVALUE
3480 base
->put(exec
, propertyName
, v
);
3483 void ReadModifyBracketNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3485 nodeStack
.append(m_right
.get());
3486 nodeStack
.append(m_subscript
.get());
3487 nodeStack
.append(m_base
.get());
3490 JSValue
* ReadModifyBracketNode::evaluate(ExecState
* exec
)
3492 JSValue
* baseValue
= m_base
->evaluate(exec
);
3493 KJS_CHECKEXCEPTIONVALUE
3494 JSValue
* subscript
= m_subscript
->evaluate(exec
);
3495 KJS_CHECKEXCEPTIONVALUE
3497 JSObject
* base
= baseValue
->toObject(exec
);
3499 uint32_t propertyIndex
;
3500 if (subscript
->getUInt32(propertyIndex
)) {
3502 ASSERT(m_operator
!= OpEqual
);
3504 JSValue
* v1
= base
->getPropertySlot(exec
, propertyIndex
, slot
) ? slot
.getValue(exec
, base
, propertyIndex
) : jsUndefined();
3505 KJS_CHECKEXCEPTIONVALUE
3506 v
= valueForReadModifyAssignment(exec
, v1
, m_right
.get(), m_operator
);
3508 KJS_CHECKEXCEPTIONVALUE
3510 base
->put(exec
, propertyIndex
, v
);
3514 Identifier
propertyName(subscript
->toString(exec
));
3517 ASSERT(m_operator
!= OpEqual
);
3519 JSValue
* v1
= base
->getPropertySlot(exec
, propertyName
, slot
) ? slot
.getValue(exec
, base
, propertyName
) : jsUndefined();
3520 KJS_CHECKEXCEPTIONVALUE
3521 v
= valueForReadModifyAssignment(exec
, v1
, m_right
.get(), m_operator
);
3523 KJS_CHECKEXCEPTIONVALUE
3525 base
->put(exec
, propertyName
, v
);
3529 // ------------------------------ CommaNode ------------------------------------
3531 void CommaNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3533 nodeStack
.append(m_expr2
.get());
3534 nodeStack
.append(m_expr1
.get());
3538 JSValue
* CommaNode::evaluate(ExecState
* exec
)
3540 m_expr1
->evaluate(exec
);
3541 KJS_CHECKEXCEPTIONVALUE
3542 return m_expr2
->evaluate(exec
);
3545 // ------------------------------ ConstDeclNode ----------------------------------
3547 ConstDeclNode::ConstDeclNode(const Identifier
& ident
, ExpressionNode
* init
)
3553 void ConstDeclNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3556 nodeStack
.append(m_next
.get());
3558 nodeStack
.append(m_init
.get());
3561 void ConstDeclNode::handleSlowCase(ExecState
* exec
, const ScopeChain
& chain
, JSValue
* val
)
3563 ScopeChainIterator iter
= chain
.begin();
3564 ScopeChainIterator end
= chain
.end();
3566 // We must always have something in the scope chain
3567 ASSERT(iter
!= end
);
3574 if (base
->getPropertySlot(exec
, m_ident
, slot
))
3578 } while (iter
!= end
);
3581 base
->getPropertyAttributes(m_ident
, flags
);
3584 base
->put(exec
, m_ident
, val
, flags
);
3588 inline void ConstDeclNode::evaluateSingle(ExecState
* exec
)
3590 ASSERT(exec
->variableObject()->hasOwnProperty(exec
, m_ident
) || exec
->codeType() == EvalCode
); // Guaranteed by processDeclarations.
3591 const ScopeChain
& chain
= exec
->scopeChain();
3592 JSObject
* variableObject
= exec
->variableObject();
3594 ASSERT(!chain
.isEmpty());
3596 bool inGlobalScope
= ++chain
.begin() == chain
.end();
3599 if (inGlobalScope
) {
3600 JSValue
* val
= m_init
->evaluate(exec
);
3601 int flags
= Internal
;
3602 if (exec
->codeType() != EvalCode
)
3603 flags
|= DontDelete
;
3605 variableObject
->put(exec
, m_ident
, val
, flags
);
3607 JSValue
* val
= m_init
->evaluate(exec
);
3608 KJS_CHECKEXCEPTIONVOID
3610 // if the variable object is the top of the scope chain, then that must
3611 // be where this variable is declared, processVarDecls would have put
3612 // it there. Don't search the scope chain, to optimize this very common case.
3613 if (chain
.top() != variableObject
)
3614 return handleSlowCase(exec
, chain
, val
);
3617 variableObject
->getPropertyAttributes(m_ident
, flags
);
3620 variableObject
->put(exec
, m_ident
, val
, flags
);
3625 JSValue
* ConstDeclNode::evaluate(ExecState
* exec
)
3627 evaluateSingle(exec
);
3629 if (ConstDeclNode
* n
= m_next
.get()) {
3631 n
->evaluateSingle(exec
);
3632 KJS_CHECKEXCEPTIONVALUE
3633 n
= n
->m_next
.get();
3636 return jsUndefined();
3639 // ------------------------------ ConstStatementNode -----------------------------
3641 void ConstStatementNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3644 nodeStack
.append(m_next
.get());
3648 JSValue
* ConstStatementNode::execute(ExecState
* exec
)
3650 m_next
->evaluate(exec
);
3653 return exec
->setNormalCompletion();
3656 // ------------------------------ Helper functions for handling Vectors of StatementNode -------------------------------
3658 static inline void statementListPushFIFO(StatementVector
& statements
, DeclarationStacks::NodeStack
& stack
)
3660 StatementVector::iterator it
= statements
.end();
3661 StatementVector::iterator begin
= statements
.begin();
3662 while (it
!= begin
) {
3664 stack
.append((*it
).get());
3668 static inline Node
* statementListInitializeVariableAccessStack(StatementVector
& statements
, DeclarationStacks::NodeStack
& stack
)
3670 if (statements
.isEmpty())
3673 StatementVector::iterator it
= statements
.end();
3674 StatementVector::iterator begin
= statements
.begin();
3675 StatementVector::iterator beginPlusOne
= begin
+ 1;
3677 while (it
!= beginPlusOne
) {
3679 stack
.append((*it
).get());
3682 return (*begin
).get();
3685 static inline JSValue
* statementListExecute(StatementVector
& statements
, ExecState
* exec
)
3688 size_t size
= statements
.size();
3689 for (size_t i
= 0; i
!= size
; ++i
) {
3690 JSValue
* statementValue
= statements
[i
]->execute(exec
);
3692 value
= statementValue
;
3693 if (exec
->completionType() != Normal
)
3696 return exec
->setNormalCompletion(value
);
3699 // ------------------------------ BlockNode ------------------------------------
3701 BlockNode::BlockNode()
3705 BlockNode::BlockNode(SourceElements
* children
)
3708 children
->releaseContentsIntoVector(m_children
);
3711 void BlockNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3713 statementListPushFIFO(m_children
, nodeStack
);
3717 JSValue
* BlockNode::execute(ExecState
* exec
)
3719 return statementListExecute(m_children
, exec
);
3722 // ------------------------------ EmptyStatementNode ---------------------------
3725 JSValue
* EmptyStatementNode::execute(ExecState
* exec
)
3727 return exec
->setNormalCompletion();
3730 // ------------------------------ ExprStatementNode ----------------------------
3732 void ExprStatementNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3735 nodeStack
.append(m_expr
.get());
3739 JSValue
* ExprStatementNode::execute(ExecState
* exec
)
3741 JSValue
* value
= m_expr
->evaluate(exec
);
3744 return exec
->setNormalCompletion(value
);
3747 // ------------------------------ VarStatementNode ----------------------------
3749 void VarStatementNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3752 nodeStack
.append(m_expr
.get());
3755 JSValue
* VarStatementNode::execute(ExecState
* exec
)
3757 m_expr
->evaluate(exec
);
3760 return exec
->setNormalCompletion();
3763 // ------------------------------ IfNode ---------------------------------------
3765 void IfNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3767 nodeStack
.append(m_ifBlock
.get());
3768 nodeStack
.append(m_condition
.get());
3772 JSValue
* IfNode::execute(ExecState
* exec
)
3774 bool b
= m_condition
->evaluateToBoolean(exec
);
3778 return m_ifBlock
->execute(exec
);
3779 return exec
->setNormalCompletion();
3782 void IfElseNode::optimizeVariableAccess(const SymbolTable
& symbolTable
, const LocalStorage
& localStorage
, NodeStack
& nodeStack
)
3784 nodeStack
.append(m_elseBlock
.get());
3785 IfNode::optimizeVariableAccess(symbolTable
, localStorage
, nodeStack
);
3789 JSValue
* IfElseNode::execute(ExecState
* exec
)
3791 bool b
= m_condition
->evaluateToBoolean(exec
);
3795 return m_ifBlock
->execute(exec
);
3796 return m_elseBlock
->execute(exec
);
3799 // ------------------------------ DoWhileNode ----------------------------------
3801 void DoWhileNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3803 nodeStack
.append(m_statement
.get());
3804 nodeStack
.append(m_expr
.get());
3808 JSValue
* DoWhileNode::execute(ExecState
* exec
)
3813 exec
->pushIteration();
3814 JSValue
* statementValue
= m_statement
->execute(exec
);
3815 exec
->popIteration();
3817 if (exec
->dynamicGlobalObject()->timedOut())
3818 return setInterruptedCompletion(exec
);
3821 value
= statementValue
;
3823 if (exec
->completionType() != Normal
) {
3824 if (exec
->completionType() == Continue
&& m_labelStack
.contains(exec
->breakOrContinueTarget()))
3825 goto continueDoWhileLoop
;
3826 if (exec
->completionType() == Break
&& m_labelStack
.contains(exec
->breakOrContinueTarget()))
3828 return statementValue
;
3831 continueDoWhileLoop
:
3832 bool b
= m_expr
->evaluateToBoolean(exec
);
3838 return exec
->setNormalCompletion(value
);
3841 // ------------------------------ WhileNode ------------------------------------
3843 void WhileNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3845 nodeStack
.append(m_statement
.get());
3846 nodeStack
.append(m_expr
.get());
3850 JSValue
* WhileNode::execute(ExecState
* exec
)
3855 bool b
= m_expr
->evaluateToBoolean(exec
);
3860 exec
->pushIteration();
3861 JSValue
* statementValue
= m_statement
->execute(exec
);
3862 exec
->popIteration();
3864 if (exec
->dynamicGlobalObject()->timedOut())
3865 return setInterruptedCompletion(exec
);
3868 value
= statementValue
;
3870 if (exec
->completionType() != Normal
) {
3871 if (exec
->completionType() == Continue
&& m_labelStack
.contains(exec
->breakOrContinueTarget()))
3873 if (exec
->completionType() == Break
&& m_labelStack
.contains(exec
->breakOrContinueTarget()))
3875 return statementValue
;
3879 return exec
->setNormalCompletion(value
);
3882 // ------------------------------ ForNode --------------------------------------
3884 void ForNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3886 nodeStack
.append(m_statement
.get());
3887 nodeStack
.append(m_expr3
.get());
3888 nodeStack
.append(m_expr2
.get());
3889 nodeStack
.append(m_expr1
.get());
3893 JSValue
* ForNode::execute(ExecState
* exec
)
3897 m_expr1
->evaluate(exec
);
3901 bool b
= m_expr2
->evaluateToBoolean(exec
);
3906 exec
->pushIteration();
3907 JSValue
* statementValue
= m_statement
->execute(exec
);
3908 exec
->popIteration();
3910 value
= statementValue
;
3912 if (exec
->dynamicGlobalObject()->timedOut())
3913 return setInterruptedCompletion(exec
);
3915 if (exec
->completionType() != Normal
) {
3916 if (exec
->completionType() == Continue
&& m_labelStack
.contains(exec
->breakOrContinueTarget()))
3917 goto continueForLoop
;
3918 if (exec
->completionType() == Break
&& m_labelStack
.contains(exec
->breakOrContinueTarget()))
3920 return statementValue
;
3924 m_expr3
->evaluate(exec
);
3928 return exec
->setNormalCompletion(value
);
3931 // ------------------------------ ForInNode ------------------------------------
3933 ForInNode::ForInNode(ExpressionNode
* l
, ExpressionNode
* expr
, StatementNode
* statement
)
3937 , m_statement(statement
)
3938 , m_identIsVarDecl(false)
3942 ForInNode::ForInNode(const Identifier
& ident
, ExpressionNode
* in
, ExpressionNode
* expr
, StatementNode
* statement
)
3944 , m_lexpr(new ResolveNode(ident
))
3946 , m_statement(statement
)
3947 , m_identIsVarDecl(true)
3950 m_init
= new AssignResolveNode(ident
, in
);
3951 // for( var foo = bar in baz )
3954 void ForInNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
3956 nodeStack
.append(m_statement
.get());
3957 nodeStack
.append(m_expr
.get());
3958 nodeStack
.append(m_lexpr
.get());
3960 nodeStack
.append(m_init
.get());
3964 JSValue
* ForInNode::execute(ExecState
* exec
)
3969 m_init
->evaluate(exec
);
3973 JSValue
* e
= m_expr
->evaluate(exec
);
3976 // For Null and Undefined, we want to make sure not to go through
3977 // the loop at all, because toObject will throw an exception.
3978 if (e
->isUndefinedOrNull())
3979 return exec
->setNormalCompletion();
3981 JSObject
* v
= e
->toObject(exec
);
3982 PropertyNameArray propertyNames
;
3983 v
->getPropertyNames(exec
, propertyNames
);
3985 PropertyNameArray::const_iterator end
= propertyNames
.end();
3986 for (PropertyNameArray::const_iterator it
= propertyNames
.begin(); it
!= end
; ++it
) {
3987 const Identifier
& name
= *it
;
3988 if (!v
->hasProperty(exec
, name
))
3991 JSValue
* str
= jsOwnedString(name
.ustring());
3993 if (m_lexpr
->isResolveNode()) {
3994 const Identifier
& ident
= static_cast<ResolveNode
*>(m_lexpr
.get())->identifier();
3996 const ScopeChain
& chain
= exec
->scopeChain();
3997 ScopeChainIterator iter
= chain
.begin();
3998 ScopeChainIterator end
= chain
.end();
4000 // we must always have something in the scope chain
4001 ASSERT(iter
!= end
);
4007 if (o
->getPropertySlot(exec
, ident
, slot
)) {
4008 o
->put(exec
, ident
, str
);
4012 } while (iter
!= end
);
4015 o
->put(exec
, ident
, str
);
4016 } else if (m_lexpr
->isDotAccessorNode()) {
4017 const Identifier
& ident
= static_cast<DotAccessorNode
*>(m_lexpr
.get())->identifier();
4018 JSValue
* v
= static_cast<DotAccessorNode
*>(m_lexpr
.get())->base()->evaluate(exec
);
4020 JSObject
* o
= v
->toObject(exec
);
4022 o
->put(exec
, ident
, str
);
4024 ASSERT(m_lexpr
->isBracketAccessorNode());
4025 JSValue
* v
= static_cast<BracketAccessorNode
*>(m_lexpr
.get())->base()->evaluate(exec
);
4027 JSValue
* v2
= static_cast<BracketAccessorNode
*>(m_lexpr
.get())->subscript()->evaluate(exec
);
4029 JSObject
* o
= v
->toObject(exec
);
4032 if (v2
->getUInt32(i
))
4033 o
->put(exec
, i
, str
);
4034 o
->put(exec
, Identifier(v2
->toString(exec
)), str
);
4039 exec
->pushIteration();
4040 JSValue
* statementValue
= m_statement
->execute(exec
);
4041 exec
->popIteration();
4043 value
= statementValue
;
4045 if (exec
->completionType() != Normal
) {
4046 if (exec
->completionType() == Continue
&& m_labelStack
.contains(exec
->breakOrContinueTarget()))
4048 if (exec
->completionType() == Break
&& m_labelStack
.contains(exec
->breakOrContinueTarget()))
4050 return statementValue
;
4054 return exec
->setNormalCompletion(value
);
4057 // ------------------------------ ContinueNode ---------------------------------
4060 JSValue
* ContinueNode::execute(ExecState
* exec
)
4062 if (m_ident
.isEmpty() && !exec
->inIteration())
4063 return setErrorCompletion(exec
, SyntaxError
, "Invalid continue statement.");
4064 if (!m_ident
.isEmpty() && !exec
->seenLabels().contains(m_ident
))
4065 return setErrorCompletion(exec
, SyntaxError
, "Label %s not found.", m_ident
);
4066 return exec
->setContinueCompletion(&m_ident
);
4069 // ------------------------------ BreakNode ------------------------------------
4072 JSValue
* BreakNode::execute(ExecState
* exec
)
4074 if (m_ident
.isEmpty() && !exec
->inIteration() && !exec
->inSwitch())
4075 return setErrorCompletion(exec
, SyntaxError
, "Invalid break statement.");
4076 if (!m_ident
.isEmpty() && !exec
->seenLabels().contains(m_ident
))
4077 return setErrorCompletion(exec
, SyntaxError
, "Label %s not found.");
4078 return exec
->setBreakCompletion(&m_ident
);
4081 // ------------------------------ ReturnNode -----------------------------------
4083 void ReturnNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
4086 nodeStack
.append(m_value
.get());
4090 JSValue
* ReturnNode::execute(ExecState
* exec
)
4092 CodeType codeType
= exec
->codeType();
4093 if (codeType
!= FunctionCode
)
4094 return setErrorCompletion(exec
, SyntaxError
, "Invalid return statement.");
4097 return exec
->setReturnValueCompletion(jsUndefined());
4099 JSValue
* v
= m_value
->evaluate(exec
);
4102 return exec
->setReturnValueCompletion(v
);
4105 // ------------------------------ WithNode -------------------------------------
4107 void WithNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
4109 // Can't optimize within statement because "with" introduces a dynamic scope.
4110 nodeStack
.append(m_expr
.get());
4114 JSValue
* WithNode::execute(ExecState
* exec
)
4116 JSValue
* v
= m_expr
->evaluate(exec
);
4118 JSObject
* o
= v
->toObject(exec
);
4120 exec
->dynamicGlobalObject()->tearOffActivation(exec
);
4122 JSValue
* value
= m_statement
->execute(exec
);
4128 // ------------------------------ CaseClauseNode -------------------------------
4130 void CaseClauseNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
4133 nodeStack
.append(m_expr
.get());
4134 statementListPushFIFO(m_children
, nodeStack
);
4138 JSValue
* CaseClauseNode::evaluate(ExecState
* exec
)
4140 JSValue
* v
= m_expr
->evaluate(exec
);
4141 KJS_CHECKEXCEPTIONVALUE
4147 JSValue
* CaseClauseNode::executeStatements(ExecState
* exec
)
4149 return statementListExecute(m_children
, exec
);
4152 // ------------------------------ ClauseListNode -------------------------------
4154 void ClauseListNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
4157 nodeStack
.append(m_next
.get());
4158 nodeStack
.append(m_clause
.get());
4161 // ------------------------------ CaseBlockNode --------------------------------
4163 CaseBlockNode::CaseBlockNode(ClauseListNode
* list1
, CaseClauseNode
* defaultClause
, ClauseListNode
* list2
)
4165 , m_defaultClause(defaultClause
)
4170 void CaseBlockNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
4173 nodeStack
.append(m_list2
.get());
4174 if (m_defaultClause
)
4175 nodeStack
.append(m_defaultClause
.get());
4177 nodeStack
.append(m_list1
.get());
4181 JSValue
* CaseBlockNode::executeBlock(ExecState
* exec
, JSValue
* input
)
4183 ClauseListNode
* a
= m_list1
.get();
4185 CaseClauseNode
* clause
= a
->getClause();
4187 JSValue
* v
= clause
->evaluate(exec
);
4189 if (strictEqual(exec
, input
, v
)) {
4190 JSValue
* res
= clause
->executeStatements(exec
);
4191 if (exec
->completionType() != Normal
)
4193 for (; a
; a
= a
->getNext()) {
4194 JSValue
* res
= a
->getClause()->executeStatements(exec
);
4195 if (exec
->completionType() != Normal
)
4202 ClauseListNode
* b
= m_list2
.get();
4204 CaseClauseNode
* clause
= b
->getClause();
4206 JSValue
* v
= clause
->evaluate(exec
);
4208 if (strictEqual(exec
, input
, v
)) {
4209 JSValue
* res
= clause
->executeStatements(exec
);
4210 if (exec
->completionType() != Normal
)
4217 if (m_defaultClause
) {
4218 JSValue
* res
= m_defaultClause
->executeStatements(exec
);
4219 if (exec
->completionType() != Normal
)
4225 CaseClauseNode
* clause
= b
->getClause();
4226 JSValue
* res
= clause
->executeStatements(exec
);
4227 if (exec
->completionType() != Normal
)
4232 // bail out on error
4235 return exec
->setNormalCompletion();
4238 // ------------------------------ SwitchNode -----------------------------------
4240 void SwitchNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
4242 nodeStack
.append(m_block
.get());
4243 nodeStack
.append(m_expr
.get());
4247 JSValue
* SwitchNode::execute(ExecState
* exec
)
4249 JSValue
* v
= m_expr
->evaluate(exec
);
4253 JSValue
* result
= m_block
->executeBlock(exec
, v
);
4256 if (exec
->completionType() == Break
&& m_labelStack
.contains(exec
->breakOrContinueTarget()))
4257 exec
->setCompletionType(Normal
);
4261 // ------------------------------ LabelNode ------------------------------------
4263 void LabelNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
4265 nodeStack
.append(m_statement
.get());
4269 JSValue
* LabelNode::execute(ExecState
* exec
)
4271 if (!exec
->seenLabels().push(m_label
))
4272 return setErrorCompletion(exec
, SyntaxError
, "Duplicated label %s found.", m_label
);
4273 JSValue
* result
= m_statement
->execute(exec
);
4274 exec
->seenLabels().pop();
4276 if (exec
->completionType() == Break
&& exec
->breakOrContinueTarget() == m_label
)
4277 exec
->setCompletionType(Normal
);
4281 // ------------------------------ ThrowNode ------------------------------------
4283 void ThrowNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
4285 nodeStack
.append(m_expr
.get());
4289 JSValue
* ThrowNode::execute(ExecState
* exec
)
4291 JSValue
* v
= m_expr
->evaluate(exec
);
4294 handleException(exec
, v
);
4295 return exec
->setThrowCompletion(v
);
4298 // ------------------------------ TryNode --------------------------------------
4300 void TryNode::optimizeVariableAccess(const SymbolTable
&, const LocalStorage
&, NodeStack
& nodeStack
)
4302 // Can't optimize within catchBlock because "catch" introduces a dynamic scope.
4304 nodeStack
.append(m_finallyBlock
.get());
4305 nodeStack
.append(m_tryBlock
.get());
4309 JSValue
* TryNode::execute(ExecState
* exec
)
4311 JSValue
* result
= m_tryBlock
->execute(exec
);
4313 if (m_catchBlock
&& exec
->completionType() == Throw
) {
4314 JSObject
* obj
= new JSObject
;
4315 obj
->put(exec
, m_exceptionIdent
, result
, DontDelete
);
4316 exec
->dynamicGlobalObject()->tearOffActivation(exec
);
4317 exec
->pushScope(obj
);
4318 result
= m_catchBlock
->execute(exec
);
4322 if (m_finallyBlock
) {
4323 ComplType savedCompletionType
= exec
->completionType();
4324 JSValue
* finallyResult
= m_finallyBlock
->execute(exec
);
4325 if (exec
->completionType() != Normal
)
4326 result
= finallyResult
;
4328 exec
->setCompletionType(savedCompletionType
);
4334 // ------------------------------ FunctionBodyNode -----------------------------
4336 ScopeNode::ScopeNode()
4341 ScopeNode::ScopeNode(const SourceCode
& source
, SourceElements
* children
, VarStack
* varStack
, FunctionStack
* funcStack
)
4342 : BlockNode(children
)
4346 m_varStack
= *varStack
;
4348 m_functionStack
= *funcStack
;
4351 void ScopeNode::setData(SourceElements
* children
, VarStack
* varStack
, FunctionStack
* funcStack
)
4354 children
->releaseContentsIntoVector(m_children
);
4356 m_varStack
= *varStack
;
4358 m_functionStack
= *funcStack
;
4361 // ------------------------------ ProgramNode -----------------------------
4363 ProgramNode::ProgramNode(const SourceCode
& source
, SourceElements
* children
, VarStack
* varStack
, FunctionStack
* funcStack
)
4364 : ScopeNode(source
, children
, varStack
, funcStack
)
4368 ProgramNode
* ProgramNode::create(const SourceCode
& source
, SourceElements
* children
, VarStack
* varStack
, FunctionStack
* funcStack
)
4370 return new ProgramNode(source
, children
, varStack
, funcStack
);
4373 // ------------------------------ EvalNode -----------------------------
4375 EvalNode::EvalNode(const SourceCode
& source
, SourceElements
* children
, VarStack
* varStack
, FunctionStack
* funcStack
)
4376 : ScopeNode(source
, children
, varStack
, funcStack
)
4380 EvalNode
* EvalNode::create(const SourceCode
& source
, SourceElements
* children
, VarStack
* varStack
, FunctionStack
* funcStack
)
4382 return new EvalNode(source
, children
, varStack
, funcStack
);
4385 // ------------------------------ FunctionBodyNode -----------------------------
4387 FunctionBodyNode::FunctionBodyNode()
4389 , m_initialized(false)
4393 FunctionBodyNode::FunctionBodyNode(const SourceCode
& source
, SourceElements
* children
, VarStack
* varStack
, FunctionStack
* funcStack
)
4394 : ScopeNode(source
, children
, varStack
, funcStack
)
4395 , m_initialized(false)
4399 FunctionBodyNode
* FunctionBodyNode::create()
4401 return new FunctionBodyNode();
4404 FunctionBodyNode
* FunctionBodyNode::create(SourceElements
* children
, VarStack
* varStack
, FunctionStack
* funcStack
)
4406 // debugger code removed
4407 return new FunctionBodyNode(SourceCode(), children
, varStack
, funcStack
);
4410 FunctionBodyNode
* FunctionBodyNode::create(const SourceCode
& source
, SourceElements
* children
, VarStack
* varStack
, FunctionStack
* funcStack
)
4412 // debugger code removed
4413 return new FunctionBodyNode(source
, children
, varStack
, funcStack
);
4416 void FunctionBodyNode::initializeSymbolTable(ExecState
* exec
)
4418 SymbolTable
& symbolTable
= exec
->variableObject()->symbolTable();
4419 ASSERT(symbolTable
.isEmpty());
4421 size_t localStorageIndex
= 0;
4423 // Order must match the order in processDeclarations.
4425 for (size_t i
= 0, size
= m_parameters
.size(); i
< size
; ++i
, ++localStorageIndex
) {
4426 UString::Rep
* rep
= m_parameters
[i
].ustring().rep();
4427 symbolTable
.set(rep
, localStorageIndex
);
4430 for (size_t i
= 0, size
= m_functionStack
.size(); i
< size
; ++i
, ++localStorageIndex
) {
4431 UString::Rep
* rep
= m_functionStack
[i
]->m_ident
.ustring().rep();
4432 symbolTable
.set(rep
, localStorageIndex
);
4435 for (size_t i
= 0, size
= m_varStack
.size(); i
< size
; ++i
, ++localStorageIndex
) {
4436 Identifier
& ident
= m_varStack
[i
].first
;
4437 if (ident
== exec
->propertyNames().arguments
)
4439 symbolTable
.add(ident
.ustring().rep(), localStorageIndex
);
4443 void ProgramNode::initializeSymbolTable(ExecState
* exec
)
4445 // If a previous script defined a symbol with the same name as one of our
4446 // symbols, to avoid breaking previously optimized nodes, we need to reuse
4447 // the symbol's existing storage index. So, we can't be as efficient as
4448 // FunctionBodyNode::initializeSymbolTable, which knows that no bindings
4449 // have yet been made.
4451 JSVariableObject
* variableObject
= exec
->variableObject();
4452 SymbolTable
& symbolTable
= variableObject
->symbolTable();
4454 size_t localStorageIndex
= symbolTable
.size();
4457 // Order must match the order in processDeclarations.
4459 size
= m_functionStack
.size();
4460 m_functionIndexes
.resize(size
);
4461 for (size_t i
= 0; i
< size
; ++i
) {
4462 UString::Rep
* rep
= m_functionStack
[i
]->m_ident
.ustring().rep();
4463 pair
<SymbolTable::iterator
, bool> result
= symbolTable
.add(rep
, localStorageIndex
);
4464 m_functionIndexes
[i
] = result
.first
->second
;
4466 ++localStorageIndex
;
4469 size
= m_varStack
.size();
4470 m_varIndexes
.resize(size
);
4471 for (size_t i
= 0; i
< size
; ++i
) {
4472 const Identifier
& ident
= m_varStack
[i
].first
;
4473 if (variableObject
->hasProperty(exec
, ident
)) {
4474 m_varIndexes
[i
] = missingSymbolMarker(); // Signal not to initialize this declaration.
4478 UString::Rep
* rep
= ident
.ustring().rep();
4479 pair
<SymbolTable::iterator
, bool> result
= symbolTable
.add(rep
, localStorageIndex
);
4480 if (!result
.second
) {
4481 m_varIndexes
[i
] = missingSymbolMarker(); // Signal not to initialize this declaration.
4485 m_varIndexes
[i
] = result
.first
->second
;
4486 ++localStorageIndex
;
4490 void ScopeNode::optimizeVariableAccess(ExecState
* exec
)
4492 NodeStack nodeStack
;
4493 Node
* node
= statementListInitializeVariableAccessStack(m_children
, nodeStack
);
4497 const SymbolTable
& symbolTable
= exec
->variableObject()->symbolTable();
4498 const LocalStorage
& localStorage
= exec
->variableObject()->localStorage();
4500 node
->optimizeVariableAccess(symbolTable
, localStorage
, nodeStack
);
4502 size_t size
= nodeStack
.size();
4506 node
= nodeStack
[size
];
4507 nodeStack
.shrink(size
);
4511 void FunctionBodyNode::processDeclarations(ExecState
* exec
)
4514 initializeSymbolTable(exec
);
4516 if (!m_functionStack
.isEmpty())
4517 exec
->dynamicGlobalObject()->tearOffActivation(exec
);
4519 LocalStorage
& localStorage
= exec
->variableObject()->localStorage();
4521 // We can't just resize localStorage here because that would temporarily
4522 // leave uninitialized entries, which would crash GC during the mark phase.
4523 size_t totalSize
= m_varStack
.size() + m_parameters
.size() + m_functionStack
.size();
4524 if (totalSize
> localStorage
.capacity()) // Doing this check inline avoids function call overhead.
4525 localStorage
.reserveCapacity(totalSize
);
4527 int minAttributes
= Internal
| DontDelete
;
4529 // In order for our localStorage indexes to be correct, we must match the
4530 // order of addition in initializeSymbolTable().
4532 const List
& args
= *exec
->arguments();
4533 for (size_t i
= 0, size
= m_parameters
.size(); i
< size
; ++i
)
4534 localStorage
.uncheckedAppend(LocalStorageEntry(args
[i
], DontDelete
));
4536 for (size_t i
= 0, size
= m_functionStack
.size(); i
< size
; ++i
) {
4537 FuncDeclNode
* node
= m_functionStack
[i
];
4538 localStorage
.uncheckedAppend(LocalStorageEntry(node
->makeFunction(exec
), minAttributes
));
4541 for (size_t i
= 0, size
= m_varStack
.size(); i
< size
; ++i
) {
4542 int attributes
= minAttributes
;
4543 if (m_varStack
[i
].second
& DeclarationStacks::IsConstant
)
4544 attributes
|= ReadOnly
;
4545 localStorage
.uncheckedAppend(LocalStorageEntry(jsUndefined(), attributes
));
4548 if (!m_initialized
) {
4549 optimizeVariableAccess(exec
);
4550 m_initialized
= true;
4554 static void gccIsCrazy() KJS_FAST_CALL
;
4555 static void gccIsCrazy()
4559 void ProgramNode::processDeclarations(ExecState
* exec
)
4561 // If you remove this call, some SunSpider tests, including
4562 // bitops-nsieve-bits.js, will regress substantially on Mac, due to a ~40%
4563 // increase in L2 cache misses. FIXME: <rdar://problem/5657439> WTF?
4566 initializeSymbolTable(exec
);
4568 LocalStorage
& localStorage
= exec
->variableObject()->localStorage();
4570 // We can't just resize localStorage here because that would temporarily
4571 // leave uninitialized entries, which would crash GC during the mark phase.
4572 localStorage
.reserveCapacity(localStorage
.size() + m_varStack
.size() + m_functionStack
.size());
4574 int minAttributes
= Internal
| DontDelete
;
4576 // In order for our localStorage indexes to be correct, we must match the
4577 // order of addition in initializeSymbolTable().
4579 for (size_t i
= 0, size
= m_functionStack
.size(); i
< size
; ++i
) {
4580 FuncDeclNode
* node
= m_functionStack
[i
];
4581 LocalStorageEntry entry
= LocalStorageEntry(node
->makeFunction(exec
), minAttributes
);
4582 size_t index
= m_functionIndexes
[i
];
4584 if (index
== localStorage
.size())
4585 localStorage
.uncheckedAppend(entry
);
4587 ASSERT(index
< localStorage
.size());
4588 localStorage
[index
] = entry
;
4592 for (size_t i
= 0, size
= m_varStack
.size(); i
< size
; ++i
) {
4593 size_t index
= m_varIndexes
[i
];
4594 if (index
== missingSymbolMarker())
4597 int attributes
= minAttributes
;
4598 if (m_varStack
[i
].second
& DeclarationStacks::IsConstant
)
4599 attributes
|= ReadOnly
;
4600 LocalStorageEntry entry
= LocalStorageEntry(jsUndefined(), attributes
);
4602 ASSERT(index
== localStorage
.size());
4603 localStorage
.uncheckedAppend(entry
);
4606 optimizeVariableAccess(exec
);
4609 void EvalNode::processDeclarations(ExecState
* exec
)
4611 // We could optimize access to pre-existing symbols here, but SunSpider
4612 // reports that to be a net loss.
4617 JSVariableObject
* variableObject
= exec
->variableObject();
4619 int minAttributes
= Internal
;
4621 for (i
= 0, size
= m_varStack
.size(); i
< size
; ++i
) {
4622 Identifier
& ident
= m_varStack
[i
].first
;
4623 if (variableObject
->hasProperty(exec
, ident
))
4625 int attributes
= minAttributes
;
4626 if (m_varStack
[i
].second
& DeclarationStacks::IsConstant
)
4627 attributes
|= ReadOnly
;
4628 variableObject
->put(exec
, ident
, jsUndefined(), attributes
);
4631 for (i
= 0, size
= m_functionStack
.size(); i
< size
; ++i
) {
4632 FuncDeclNode
* node
= m_functionStack
[i
];
4633 variableObject
->put(exec
, node
->m_ident
, node
->makeFunction(exec
), minAttributes
);
4637 UString
FunctionBodyNode::paramString() const
4640 size_t count
= m_parameters
.size();
4641 for (size_t pos
= 0; pos
< count
; ++pos
) {
4644 s
+= m_parameters
[pos
].ustring();
4650 JSValue
* ProgramNode::execute(ExecState
* exec
)
4652 processDeclarations(exec
);
4653 return ScopeNode::execute(exec
);
4656 JSValue
* EvalNode::execute(ExecState
* exec
)
4658 processDeclarations(exec
);
4659 return ScopeNode::execute(exec
);
4662 JSValue
* FunctionBodyNode::execute(ExecState
* exec
)
4664 if (m_children
.isEmpty())
4665 parser().reparse(this);
4666 processDeclarations(exec
);
4667 return ScopeNode::execute(exec
);
4670 // ------------------------------ FunctionBodyNodeWithDebuggerHooks ---------------------------------
4672 FunctionBodyNodeWithDebuggerHooks::FunctionBodyNodeWithDebuggerHooks(SourceElements
* children
, DeclarationStacks::VarStack
* varStack
, DeclarationStacks::FunctionStack
* funcStack
)
4673 : FunctionBodyNode(SourceCode(), children
, varStack
, funcStack
)
4677 JSValue
* FunctionBodyNodeWithDebuggerHooks::execute(ExecState
* exec
)
4679 if (Debugger
* dbg
= exec
->dynamicGlobalObject()->debugger()) {
4680 if (!dbg
->callEvent(exec
, sourceID(), lineNo(), exec
->function(), *exec
->arguments())) {
4681 dbg
->imp()->abort();
4682 return exec
->setInterruptedCompletion();
4686 JSValue
* result
= FunctionBodyNode::execute(exec
);
4688 if (Debugger
* dbg
= exec
->dynamicGlobalObject()->debugger()) {
4689 if (exec
->completionType() == Throw
)
4690 exec
->setException(result
);
4691 if (!dbg
->returnEvent(exec
, sourceID(), lineNo(), exec
->function())) {
4692 dbg
->imp()->abort();
4693 return exec
->setInterruptedCompletion();
4700 // ------------------------------ FuncDeclNode ---------------------------------
4702 void FuncDeclNode::addParams()
4704 for (ParameterNode
* p
= m_parameter
.get(); p
; p
= p
->nextParam())
4705 m_body
->parameters().append(p
->ident());
4708 FunctionImp
* FuncDeclNode::makeFunction(ExecState
* exec
)
4710 FunctionImp
* func
= new FunctionImp(exec
, m_ident
, m_body
.get(), exec
->scopeChain());
4712 JSObject
* proto
= exec
->lexicalGlobalObject()->objectConstructor()->construct(exec
, exec
->emptyList());
4713 proto
->putDirect(exec
->propertyNames().constructor
, func
, ReadOnly
| DontDelete
| DontEnum
);
4714 func
->putDirect(exec
->propertyNames().prototype
, proto
, Internal
| DontDelete
);
4715 func
->putDirect(exec
->propertyNames().length
, jsNumber(m_body
->parameters().size()), ReadOnly
| DontDelete
| DontEnum
);
4719 JSValue
* FuncDeclNode::execute(ExecState
* exec
)
4721 return exec
->setNormalCompletion();
4724 // ------------------------------ FuncExprNode ---------------------------------
4727 void FuncExprNode::addParams()
4729 for (ParameterNode
* p
= m_parameter
.get(); p
; p
= p
->nextParam())
4730 m_body
->parameters().append(p
->ident());
4733 JSValue
* FuncExprNode::evaluate(ExecState
* exec
)
4735 exec
->dynamicGlobalObject()->tearOffActivation(exec
);
4737 bool named
= !m_ident
.isNull();
4738 JSObject
* functionScopeObject
= 0;
4741 // named FunctionExpressions can recursively call themselves,
4742 // but they won't register with the current scope chain and should
4743 // be contained as single property in an anonymous object.
4744 functionScopeObject
= new JSObject
;
4745 exec
->pushScope(functionScopeObject
);
4748 FunctionImp
* func
= new FunctionImp(exec
, m_ident
, m_body
.get(), exec
->scopeChain());
4749 JSObject
* proto
= exec
->lexicalGlobalObject()->objectConstructor()->construct(exec
, exec
->emptyList());
4750 proto
->putDirect(exec
->propertyNames().constructor
, func
, ReadOnly
| DontDelete
| DontEnum
);
4751 func
->putDirect(exec
->propertyNames().prototype
, proto
, Internal
| DontDelete
);
4754 functionScopeObject
->putDirect(m_ident
, func
, Internal
| ReadOnly
| (exec
->codeType() == EvalCode
? 0 : DontDelete
));