]> git.saurik.com Git - apple/javascriptcore.git/blame - kjs/nodes.cpp
JavaScriptCore-461.tar.gz
[apple/javascriptcore.git] / kjs / nodes.cpp
CommitLineData
b37bf2e1
A
1/*
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>
8*
9* This library is free software; you can redistribute it and/or
10* modify it under the terms of the GNU Library General Public
11* License as published by the Free Software Foundation; either
12* version 2 of the License, or (at your option) any later version.
13*
14* This library is distributed in the hope that it will be useful,
15* but WITHOUT ANY WARRANTY; without even the implied warranty of
16* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17* Library General Public License for more details.
18*
19* You should have received a copy of the GNU Library General Public License
20* along with this library; see the file COPYING.LIB. If not, write to
21* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22* Boston, MA 02110-1301, USA.
23*
24*/
25
26#include "config.h"
27#include "nodes.h"
28
29#include "ExecState.h"
30#include "JSGlobalObject.h"
31#include "Parser.h"
32#include "PropertyNameArray.h"
33#include "array_object.h"
34#include "debugger.h"
35#include "function_object.h"
36#include "lexer.h"
37#include "operations.h"
38#include "regexp_object.h"
39#include <math.h>
40#include <wtf/Assertions.h>
41#include <wtf/HashCountedSet.h>
42#include <wtf/HashSet.h>
43#include <wtf/MathExtras.h>
44
45namespace KJS {
46
47class FunctionBodyNodeWithDebuggerHooks : public FunctionBodyNode {
48public:
49 FunctionBodyNodeWithDebuggerHooks(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
50 virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
51};
52
53#define KJS_CHECKEXCEPTION \
54if (exec->hadException()) \
55 return rethrowException(exec);
56
57#define KJS_CHECKEXCEPTIONVALUE \
58if (exec->hadException()) { \
59 handleException(exec); \
60 return jsUndefined(); \
61}
62
63#define KJS_CHECKEXCEPTIONNUMBER \
64if (exec->hadException()) { \
65 handleException(exec); \
66 return 0; \
67}
68
69#define KJS_CHECKEXCEPTIONBOOLEAN \
70if (exec->hadException()) { \
71 handleException(exec); \
72 return false; \
73}
74
75#define KJS_CHECKEXCEPTIONVOID \
76if (exec->hadException()) { \
77 handleException(exec); \
78 return; \
79}
80
81#if !ASSERT_DISABLED
82static inline bool canSkipLookup(ExecState* exec, const Identifier& ident)
83{
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)
87 return false;
88
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())
91 return false;
92
93 // Static lookup is impossible if the symbol isn't statically declared.
94 if (!exec->variableObject()->symbolTable().contains(ident.ustring().rep()))
95 return false;
96
97 return true;
98}
99#endif
100
101static inline bool isConstant(const LocalStorage& localStorage, size_t index)
102{
103 ASSERT(index < localStorage.size());
104 return localStorage[index].attributes & ReadOnly;
105}
106
107// ------------------------------ Node -----------------------------------------
108
109#ifndef NDEBUG
110#ifndef LOG_CHANNEL_PREFIX
111#define LOG_CHANNEL_PREFIX Log
112#endif
113static WTFLogChannel LogKJSNodeLeaks = { 0x00000000, "", WTFLogChannelOn };
114
115struct ParserRefCountedCounter {
116 static unsigned count;
117 ParserRefCountedCounter()
118 {
119 if (count)
120 LOG(KJSNodeLeaks, "LEAK: %u KJS::Node\n", count);
121 }
122};
123unsigned ParserRefCountedCounter::count = 0;
124static ParserRefCountedCounter parserRefCountedCounter;
125#endif
126
127static HashSet<ParserRefCounted*>* newTrackedObjects;
128static HashCountedSet<ParserRefCounted*>* trackedObjectExtraRefCounts;
129
130ParserRefCounted::ParserRefCounted()
131{
132#ifndef NDEBUG
133 ++ParserRefCountedCounter::count;
134#endif
135 if (!newTrackedObjects)
136 newTrackedObjects = new HashSet<ParserRefCounted*>;
137 newTrackedObjects->add(this);
138 ASSERT(newTrackedObjects->contains(this));
139}
140
141ParserRefCounted::~ParserRefCounted()
142{
143#ifndef NDEBUG
144 --ParserRefCountedCounter::count;
145#endif
146}
147
148void ParserRefCounted::ref()
149{
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));
156 return;
157 }
158 }
159
160 ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
161
162 if (!trackedObjectExtraRefCounts)
163 trackedObjectExtraRefCounts = new HashCountedSet<ParserRefCounted*>;
164 trackedObjectExtraRefCounts->add(this);
165}
166
167void ParserRefCounted::deref()
168{
169 ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
170
171 if (!trackedObjectExtraRefCounts) {
172 delete this;
173 return;
174 }
175
176 HashCountedSet<ParserRefCounted*>::iterator it = trackedObjectExtraRefCounts->find(this);
177 if (it == trackedObjectExtraRefCounts->end())
178 delete this;
179 else
180 trackedObjectExtraRefCounts->remove(it);
181}
182
183unsigned ParserRefCounted::refcount()
184{
185 if (newTrackedObjects && newTrackedObjects->contains(this)) {
186 ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(this));
187 return 0;
188 }
189
190 ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
191
192 if (!trackedObjectExtraRefCounts)
193 return 1;
194
195 return 1 + trackedObjectExtraRefCounts->count(this);
196}
197
198void ParserRefCounted::deleteNewObjects()
199{
200 if (!newTrackedObjects)
201 return;
202
203#ifndef NDEBUG
204 HashSet<ParserRefCounted*>::iterator end = newTrackedObjects->end();
205 for (HashSet<ParserRefCounted*>::iterator it = newTrackedObjects->begin(); it != end; ++it)
206 ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(*it));
207#endif
208 deleteAllValues(*newTrackedObjects);
209 delete newTrackedObjects;
210 newTrackedObjects = 0;
211}
212
213Node::Node()
214 : m_expectedReturnType(ObjectType)
215{
216 m_line = lexer().lineNo();
217}
218
219Node::Node(JSType expectedReturn)
220 : m_expectedReturnType(expectedReturn)
221{
222 m_line = lexer().lineNo();
223}
224
225double ExpressionNode::evaluateToNumber(ExecState* exec)
226{
227 JSValue* value = evaluate(exec);
228 KJS_CHECKEXCEPTIONNUMBER
229 return value->toNumber(exec);
230}
231
232bool ExpressionNode::evaluateToBoolean(ExecState* exec)
233{
234 JSValue* value = evaluate(exec);
235 KJS_CHECKEXCEPTIONBOOLEAN
236 return value->toBoolean(exec);
237}
238
239int32_t ExpressionNode::evaluateToInt32(ExecState* exec)
240{
241 JSValue* value = evaluate(exec);
242 KJS_CHECKEXCEPTIONNUMBER
243 return value->toInt32(exec);
244}
245
246uint32_t ExpressionNode::evaluateToUInt32(ExecState* exec)
247{
248 JSValue* value = evaluate(exec);
249 KJS_CHECKEXCEPTIONNUMBER
250 return value->toUInt32(exec);
251}
252
253static void substitute(UString& string, const UString& substring) KJS_FAST_CALL;
254static void substitute(UString& string, const UString& substring)
255{
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));
261 string = newString;
262}
263
264static inline int currentSourceId(ExecState* exec) KJS_FAST_CALL;
265static inline int currentSourceId(ExecState* exec)
266{
267 return exec->scopeNode()->sourceId();
268}
269
270static inline const UString& currentSourceURL(ExecState* exec) KJS_FAST_CALL;
271static inline const UString& currentSourceURL(ExecState* exec)
272{
273 return exec->scopeNode()->sourceURL();
274}
275
276JSValue* Node::setInterruptedCompletion(ExecState* exec)
277{
278 return exec->setInterruptedCompletion(Error::create(exec, TimeoutError, "JavaScript execution exceeded timeout.", lineNo(), currentSourceId(exec), currentSourceURL(exec)));
279}
280
281JSValue* Node::setErrorCompletion(ExecState* exec, ErrorType e, const char* msg)
282{
283 return exec->setThrowCompletion(Error::create(exec, e, msg, lineNo(), currentSourceId(exec), currentSourceURL(exec)));
284}
285
286JSValue* Node::setErrorCompletion(ExecState* exec, ErrorType e, const char* msg, const Identifier& ident)
287{
288 UString message = msg;
289 substitute(message, ident.ustring());
290 return exec->setThrowCompletion(Error::create(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec)));
291}
292
293JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg)
294{
295 return KJS::throwError(exec, e, msg, lineNo(), currentSourceId(exec), currentSourceURL(exec));
296}
297
298JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg, const char* string)
299{
300 UString message = msg;
301 substitute(message, string);
302 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
303}
304
305JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg, JSValue* v, Node* expr)
306{
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));
311}
312
313JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg, const Identifier& label)
314{
315 UString message = msg;
316 substitute(message, label.ustring());
317 return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
318}
319
320JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg, JSValue* v, Node* e1, Node* e2)
321{
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));
327}
328
329JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg, JSValue* v, Node* expr, const Identifier& label)
330{
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));
336}
337
338JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg, JSValue* v, const Identifier& label)
339{
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));
344}
345
346JSValue* Node::throwUndefinedVariableError(ExecState* exec, const Identifier& ident)
347{
348 return throwError(exec, ReferenceError, "Can't find variable: %s", ident);
349}
350
351void Node::handleException(ExecState* exec)
352{
353 handleException(exec, exec->exception());
354}
355
356void Node::handleException(ExecState* exec, JSValue* exceptionValue)
357{
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)));
363 }
364 }
365 Debugger* dbg = exec->dynamicGlobalObject()->debugger();
366 if (dbg && !dbg->hasHandledException(exec, exceptionValue)) {
367 bool cont = dbg->exception(exec, currentSourceId(exec), m_line, exceptionValue);
368 if (!cont)
369 dbg->imp()->abort();
370 }
371}
372
373NEVER_INLINE JSValue* Node::rethrowException(ExecState* exec)
374{
375 JSValue* exception = exec->exception();
376 exec->clearException();
377 handleException(exec, exception);
378 return exec->setThrowCompletion(exception);
379}
380
381// ------------------------------ StatementNode --------------------------------
382
383StatementNode::StatementNode()
384 : m_lastLine(-1)
385{
386 m_line = -1;
387}
388
389void StatementNode::setLoc(int firstLine, int lastLine)
390{
391 m_line = firstLine;
392 m_lastLine = lastLine;
393}
394
395// ------------------------------ SourceElements --------------------------------
396
397void SourceElements::append(PassRefPtr<StatementNode> statement)
398{
399 if (statement->isEmptyStatement())
400 return;
401
402 if (Debugger::debuggersPresent)
403 m_statements.append(new BreakpointCheckStatement(statement));
404 else
405 m_statements.append(statement);
406}
407
408// ------------------------------ BreakpointCheckStatement --------------------------------
409
410BreakpointCheckStatement::BreakpointCheckStatement(PassRefPtr<StatementNode> statement)
411 : m_statement(statement)
412{
413 ASSERT(m_statement);
414}
415
416JSValue* BreakpointCheckStatement::execute(ExecState* exec)
417{
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);
422}
423
424void BreakpointCheckStatement::streamTo(SourceStream& stream) const
425{
426 m_statement->streamTo(stream);
427}
428
429void BreakpointCheckStatement::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
430{
431 nodeStack.append(m_statement.get());
432}
433
434// ------------------------------ NullNode -------------------------------------
435
436JSValue* NullNode::evaluate(ExecState* )
437{
438 return jsNull();
439}
440
441// ------------------------------ FalseNode ----------------------------------
442
443JSValue* FalseNode::evaluate(ExecState*)
444{
445 return jsBoolean(false);
446}
447
448// ------------------------------ TrueNode ----------------------------------
449
450JSValue* TrueNode::evaluate(ExecState*)
451{
452 return jsBoolean(true);
453}
454
455// ------------------------------ NumberNode -----------------------------------
456
457JSValue* NumberNode::evaluate(ExecState*)
458{
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);
461}
462
463double NumberNode::evaluateToNumber(ExecState*)
464{
465 return m_double;
466}
467
468bool NumberNode::evaluateToBoolean(ExecState*)
469{
470 return m_double < 0.0 || m_double > 0.0; // false for NaN as well as 0
471}
472
473int32_t NumberNode::evaluateToInt32(ExecState*)
474{
475 return JSValue::toInt32(m_double);
476}
477
478uint32_t NumberNode::evaluateToUInt32(ExecState*)
479{
480 return JSValue::toUInt32(m_double);
481}
482
483// ------------------------------ ImmediateNumberNode -----------------------------------
484
485JSValue* ImmediateNumberNode::evaluate(ExecState*)
486{
487 return m_value;
488}
489
490int32_t ImmediateNumberNode::evaluateToInt32(ExecState*)
491{
492 return JSImmediate::getTruncatedInt32(m_value);
493}
494
495uint32_t ImmediateNumberNode::evaluateToUInt32(ExecState*)
496{
497 uint32_t i;
498 if (JSImmediate::getTruncatedUInt32(m_value, i))
499 return i;
500 bool ok;
501 return JSValue::toUInt32SlowCase(m_double, ok);
502}
503
504// ------------------------------ StringNode -----------------------------------
505
506JSValue* StringNode::evaluate(ExecState*)
507{
508 return jsOwnedString(m_value);
509}
510
511double StringNode::evaluateToNumber(ExecState*)
512{
513 return m_value.toDouble();
514}
515
516bool StringNode::evaluateToBoolean(ExecState*)
517{
518 return !m_value.isEmpty();
519}
520
521// ------------------------------ RegExpNode -----------------------------------
522
523JSValue* RegExpNode::evaluate(ExecState* exec)
524{
525 return exec->lexicalGlobalObject()->regExpConstructor()->createRegExpImp(exec, m_regExp);
526}
527
528// ------------------------------ ThisNode -------------------------------------
529
530// ECMA 11.1.1
531JSValue* ThisNode::evaluate(ExecState* exec)
532{
533 return exec->thisValue();
534}
535
536// ------------------------------ ResolveNode ----------------------------------
537
538// ECMA 11.1.2 & 10.1.4
539JSValue* ResolveNode::inlineEvaluate(ExecState* exec)
540{
541 // Check for missed optimization opportunity.
542 ASSERT(!canSkipLookup(exec, m_ident));
543
544 const ScopeChain& chain = exec->scopeChain();
545 ScopeChainIterator iter = chain.begin();
546 ScopeChainIterator end = chain.end();
547
548 // we must always have something in the scope chain
549 ASSERT(iter != end);
550
551 PropertySlot slot;
552 do {
553 JSObject* o = *iter;
554
555 if (o->getPropertySlot(exec, m_ident, slot))
556 return slot.getValue(exec, o, m_ident);
557
558 ++iter;
559 } while (iter != end);
560
561 return throwUndefinedVariableError(exec, m_ident);
562}
563
564JSValue* ResolveNode::evaluate(ExecState* exec)
565{
566 return inlineEvaluate(exec);
567}
568
569double ResolveNode::evaluateToNumber(ExecState* exec)
570{
571 JSValue* v = inlineEvaluate(exec);
572 KJS_CHECKEXCEPTIONNUMBER
573 return v->toNumber(exec);
574}
575
576bool ResolveNode::evaluateToBoolean(ExecState* exec)
577{
578 JSValue* v = inlineEvaluate(exec);
579 KJS_CHECKEXCEPTIONBOOLEAN
580 return v->toBoolean(exec);
581}
582
583int32_t ResolveNode::evaluateToInt32(ExecState* exec)
584{
585 JSValue* v = inlineEvaluate(exec);
586 KJS_CHECKEXCEPTIONNUMBER
587 return v->toInt32(exec);
588}
589
590uint32_t ResolveNode::evaluateToUInt32(ExecState* exec)
591{
592 JSValue* v = inlineEvaluate(exec);
593 KJS_CHECKEXCEPTIONNUMBER
594 return v->toUInt32(exec);
595}
596
597void ResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
598{
599 size_t index = symbolTable.get(m_ident.ustring().rep());
600 if (index != missingSymbolMarker())
601 new (this) LocalVarAccessNode(index);
602}
603
604JSValue* LocalVarAccessNode::inlineEvaluate(ExecState* exec)
605{
606 ASSERT(exec->variableObject() == exec->scopeChain().top());
607 return exec->localStorage()[m_index].value;
608}
609
610JSValue* LocalVarAccessNode::evaluate(ExecState* exec)
611{
612 return inlineEvaluate(exec);
613}
614
615double LocalVarAccessNode::evaluateToNumber(ExecState* exec)
616{
617 return inlineEvaluate(exec)->toNumber(exec);
618}
619
620bool LocalVarAccessNode::evaluateToBoolean(ExecState* exec)
621{
622 return inlineEvaluate(exec)->toBoolean(exec);
623}
624
625int32_t LocalVarAccessNode::evaluateToInt32(ExecState* exec)
626{
627 return inlineEvaluate(exec)->toInt32(exec);
628}
629
630uint32_t LocalVarAccessNode::evaluateToUInt32(ExecState* exec)
631{
632 return inlineEvaluate(exec)->toUInt32(exec);
633}
634
635// ------------------------------ ElementNode ----------------------------------
636
637void ElementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
638{
639 if (m_next)
640 nodeStack.append(m_next.get());
641 ASSERT(m_node);
642 nodeStack.append(m_node.get());
643}
644
645// ECMA 11.1.4
646JSValue* ElementNode::evaluate(ExecState* exec)
647{
648 JSObject* array = exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList());
649 int length = 0;
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);
655 }
656 return array;
657}
658
659// ------------------------------ ArrayNode ------------------------------------
660
661void ArrayNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
662{
663 if (m_element)
664 nodeStack.append(m_element.get());
665}
666
667// ECMA 11.1.4
668JSValue* ArrayNode::evaluate(ExecState* exec)
669{
670 JSObject* array;
671 int length;
672
673 if (m_element) {
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;
677 } else {
678 JSValue* newArr = exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList());
679 array = static_cast<JSObject*>(newArr);
680 length = 0;
681 }
682
683 if (m_optional)
684 array->put(exec, exec->propertyNames().length, jsNumber(m_elision + length));
685
686 return array;
687}
688
689// ------------------------------ ObjectLiteralNode ----------------------------
690
691void ObjectLiteralNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
692{
693 if (m_list)
694 nodeStack.append(m_list.get());
695}
696
697// ECMA 11.1.5
698JSValue* ObjectLiteralNode::evaluate(ExecState* exec)
699{
700 if (m_list)
701 return m_list->evaluate(exec);
702
703 return exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
704}
705
706// ------------------------------ PropertyListNode -----------------------------
707
708void PropertyListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
709{
710 if (m_next)
711 nodeStack.append(m_next.get());
712 nodeStack.append(m_node.get());
713}
714
715// ECMA 11.1.5
716JSValue* PropertyListNode::evaluate(ExecState* exec)
717{
718 JSObject* obj = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
719
720 for (PropertyListNode* p = this; p; p = p->m_next.get()) {
721 JSValue* v = p->m_node->m_assign->evaluate(exec);
722 KJS_CHECKEXCEPTIONVALUE
723
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));
728 break;
729 case PropertyNode::Setter:
730 ASSERT(v->isObject());
731 obj->defineSetter(exec, p->m_node->name(), static_cast<JSObject* >(v));
732 break;
733 case PropertyNode::Constant:
734 obj->put(exec, p->m_node->name(), v);
735 break;
736 }
737 }
738
739 return obj;
740}
741
742// ------------------------------ PropertyNode -----------------------------
743
744void PropertyNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
745{
746 nodeStack.append(m_assign.get());
747}
748
749// ECMA 11.1.5
750JSValue* PropertyNode::evaluate(ExecState*)
751{
752 ASSERT(false);
753 return jsNull();
754}
755
756// ------------------------------ BracketAccessorNode --------------------------------
757
758void BracketAccessorNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
759{
760 nodeStack.append(m_subscript.get());
761 nodeStack.append(m_base.get());
762}
763
764// ECMA 11.2.1a
765JSValue* BracketAccessorNode::inlineEvaluate(ExecState* exec)
766{
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);
772 uint32_t i;
773 if (v2->getUInt32(i))
774 return o->get(exec, i);
775 return o->get(exec, Identifier(v2->toString(exec)));
776}
777
778JSValue* BracketAccessorNode::evaluate(ExecState* exec)
779{
780 return inlineEvaluate(exec);
781}
782
783double BracketAccessorNode::evaluateToNumber(ExecState* exec)
784{
785 JSValue* v = inlineEvaluate(exec);
786 KJS_CHECKEXCEPTIONNUMBER
787 return v->toNumber(exec);
788}
789
790bool BracketAccessorNode::evaluateToBoolean(ExecState* exec)
791{
792 JSValue* v = inlineEvaluate(exec);
793 KJS_CHECKEXCEPTIONBOOLEAN
794 return v->toBoolean(exec);
795}
796
797int32_t BracketAccessorNode::evaluateToInt32(ExecState* exec)
798{
799 JSValue* v = inlineEvaluate(exec);
800 KJS_CHECKEXCEPTIONNUMBER
801 return v->toInt32(exec);
802}
803
804uint32_t BracketAccessorNode::evaluateToUInt32(ExecState* exec)
805{
806 JSValue* v = inlineEvaluate(exec);
807 KJS_CHECKEXCEPTIONNUMBER
808 return v->toUInt32(exec);
809}
810
811// ------------------------------ DotAccessorNode --------------------------------
812
813void DotAccessorNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
814{
815 nodeStack.append(m_base.get());
816}
817
818// ECMA 11.2.1b
819JSValue* DotAccessorNode::inlineEvaluate(ExecState* exec)
820{
821 JSValue* v = m_base->evaluate(exec);
822 KJS_CHECKEXCEPTIONVALUE
823 return v->toObject(exec)->get(exec, m_ident);
824}
825
826JSValue* DotAccessorNode::evaluate(ExecState* exec)
827{
828 return inlineEvaluate(exec);
829}
830
831double DotAccessorNode::evaluateToNumber(ExecState* exec)
832{
833 JSValue* v = inlineEvaluate(exec);
834 KJS_CHECKEXCEPTIONNUMBER
835 return v->toNumber(exec);
836}
837
838bool DotAccessorNode::evaluateToBoolean(ExecState* exec)
839{
840 JSValue* v = inlineEvaluate(exec);
841 KJS_CHECKEXCEPTIONBOOLEAN
842 return v->toBoolean(exec);
843}
844
845int32_t DotAccessorNode::evaluateToInt32(ExecState* exec)
846{
847 JSValue* v = inlineEvaluate(exec);
848 KJS_CHECKEXCEPTIONNUMBER
849 return v->toInt32(exec);
850}
851
852uint32_t DotAccessorNode::evaluateToUInt32(ExecState* exec)
853{
854 JSValue* v = inlineEvaluate(exec);
855 KJS_CHECKEXCEPTIONNUMBER
856 return v->toUInt32(exec);
857}
858
859// ------------------------------ ArgumentListNode -----------------------------
860
861void ArgumentListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
862{
863 if (m_next)
864 nodeStack.append(m_next.get());
865 ASSERT(m_expr);
866 nodeStack.append(m_expr.get());
867}
868
869// ECMA 11.2.4
870void ArgumentListNode::evaluateList(ExecState* exec, List& list)
871{
872 for (ArgumentListNode* n = this; n; n = n->m_next.get()) {
873 JSValue* v = n->m_expr->evaluate(exec);
874 KJS_CHECKEXCEPTIONVOID
875 list.append(v);
876 }
877}
878
879// ------------------------------ ArgumentsNode --------------------------------
880
881void ArgumentsNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
882{
883 if (m_listNode)
884 nodeStack.append(m_listNode.get());
885}
886
887// ------------------------------ NewExprNode ----------------------------------
888
889void NewExprNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
890{
891 if (m_args)
892 nodeStack.append(m_args.get());
893 nodeStack.append(m_expr.get());
894}
895
896// ECMA 11.2.2
897
898JSValue* NewExprNode::inlineEvaluate(ExecState* exec)
899{
900 JSValue* v = m_expr->evaluate(exec);
901 KJS_CHECKEXCEPTIONVALUE
902
903 List argList;
904 if (m_args) {
905 m_args->evaluateList(exec, argList);
906 KJS_CHECKEXCEPTIONVALUE
907 }
908
909 if (!v->isObject())
910 return throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with new.", v, m_expr.get());
911
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());
915
916 return constr->construct(exec, argList);
917}
918
919JSValue* NewExprNode::evaluate(ExecState* exec)
920{
921 return inlineEvaluate(exec);
922}
923
924double NewExprNode::evaluateToNumber(ExecState* exec)
925{
926 JSValue* v = inlineEvaluate(exec);
927 KJS_CHECKEXCEPTIONNUMBER
928 return v->toNumber(exec);
929}
930
931bool NewExprNode::evaluateToBoolean(ExecState* exec)
932{
933 JSValue* v = inlineEvaluate(exec);
934 KJS_CHECKEXCEPTIONBOOLEAN
935 return v->toBoolean(exec);
936}
937
938int32_t NewExprNode::evaluateToInt32(ExecState* exec)
939{
940 JSValue* v = inlineEvaluate(exec);
941 KJS_CHECKEXCEPTIONNUMBER
942 return v->toInt32(exec);
943}
944
945uint32_t NewExprNode::evaluateToUInt32(ExecState* exec)
946{
947 JSValue* v = inlineEvaluate(exec);
948 KJS_CHECKEXCEPTIONNUMBER
949 return v->toUInt32(exec);
950}
951
952void FunctionCallValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
953{
954 nodeStack.append(m_args.get());
955 nodeStack.append(m_expr.get());
956}
957
958// ECMA 11.2.3
959JSValue* FunctionCallValueNode::evaluate(ExecState* exec)
960{
961 JSValue* v = m_expr->evaluate(exec);
962 KJS_CHECKEXCEPTIONVALUE
963
964 if (!v->isObject()) {
965 return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, m_expr.get());
966 }
967
968 JSObject* func = static_cast<JSObject*>(v);
969
970 if (!func->implementsCall()) {
971 return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, m_expr.get());
972 }
973
974 List argList;
975 m_args->evaluateList(exec, argList);
976 KJS_CHECKEXCEPTIONVALUE
977
978 JSObject* thisObj = exec->dynamicGlobalObject();
979
980 return func->call(exec, thisObj, argList);
981}
982
983void FunctionCallResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack& nodeStack)
984{
985 nodeStack.append(m_args.get());
986
987 size_t index = symbolTable.get(m_ident.ustring().rep());
988 if (index != missingSymbolMarker())
989 new (this) LocalVarFunctionCallNode(index);
990}
991
992// ECMA 11.2.3
993JSValue* FunctionCallResolveNode::inlineEvaluate(ExecState* exec)
994{
995 // Check for missed optimization opportunity.
996 ASSERT(!canSkipLookup(exec, m_ident));
997
998 const ScopeChain& chain = exec->scopeChain();
999 ScopeChainIterator iter = chain.begin();
1000 ScopeChainIterator end = chain.end();
1001
1002 // we must always have something in the scope chain
1003 ASSERT(iter != end);
1004
1005 PropertySlot slot;
1006 JSObject* base;
1007 do {
1008 base = *iter;
1009 if (base->getPropertySlot(exec, m_ident, slot)) {
1010 JSValue* v = slot.getValue(exec, base, m_ident);
1011 KJS_CHECKEXCEPTIONVALUE
1012
1013 if (!v->isObject())
1014 return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, m_ident);
1015
1016 JSObject* func = static_cast<JSObject*>(v);
1017
1018 if (!func->implementsCall())
1019 return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, m_ident);
1020
1021 List argList;
1022 m_args->evaluateList(exec, argList);
1023 KJS_CHECKEXCEPTIONVALUE
1024
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();
1034
1035 return func->call(exec, thisObj, argList);
1036 }
1037 ++iter;
1038 } while (iter != end);
1039
1040 return throwUndefinedVariableError(exec, m_ident);
1041}
1042
1043JSValue* FunctionCallResolveNode::evaluate(ExecState* exec)
1044{
1045 return inlineEvaluate(exec);
1046}
1047
1048double FunctionCallResolveNode::evaluateToNumber(ExecState* exec)
1049{
1050 JSValue* v = inlineEvaluate(exec);
1051 KJS_CHECKEXCEPTIONNUMBER
1052 return v->toNumber(exec);
1053}
1054
1055bool FunctionCallResolveNode::evaluateToBoolean(ExecState* exec)
1056{
1057 JSValue* v = inlineEvaluate(exec);
1058 KJS_CHECKEXCEPTIONBOOLEAN
1059 return v->toBoolean(exec);
1060}
1061
1062int32_t FunctionCallResolveNode::evaluateToInt32(ExecState* exec)
1063{
1064 JSValue* v = inlineEvaluate(exec);
1065 KJS_CHECKEXCEPTIONNUMBER
1066 return v->toInt32(exec);
1067}
1068
1069uint32_t FunctionCallResolveNode::evaluateToUInt32(ExecState* exec)
1070{
1071 JSValue* v = inlineEvaluate(exec);
1072 KJS_CHECKEXCEPTIONNUMBER
1073 return v->toUInt32(exec);
1074}
1075
1076JSValue* LocalVarFunctionCallNode::inlineEvaluate(ExecState* exec)
1077{
1078 ASSERT(exec->variableObject() == exec->scopeChain().top());
1079
1080 JSValue* v = exec->localStorage()[m_index].value;
1081
1082 if (!v->isObject())
1083 return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, m_ident);
1084
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);
1088
1089 List argList;
1090 m_args->evaluateList(exec, argList);
1091 KJS_CHECKEXCEPTIONVALUE
1092
1093 return func->call(exec, exec->dynamicGlobalObject(), argList);
1094}
1095
1096JSValue* LocalVarFunctionCallNode::evaluate(ExecState* exec)
1097{
1098 return inlineEvaluate(exec);
1099}
1100
1101double LocalVarFunctionCallNode::evaluateToNumber(ExecState* exec)
1102{
1103 JSValue* v = inlineEvaluate(exec);
1104 KJS_CHECKEXCEPTIONNUMBER
1105 return v->toNumber(exec);
1106}
1107
1108bool LocalVarFunctionCallNode::evaluateToBoolean(ExecState* exec)
1109{
1110 JSValue* v = inlineEvaluate(exec);
1111 KJS_CHECKEXCEPTIONBOOLEAN
1112 return v->toBoolean(exec);
1113}
1114
1115int32_t LocalVarFunctionCallNode::evaluateToInt32(ExecState* exec)
1116{
1117 JSValue* v = inlineEvaluate(exec);
1118 KJS_CHECKEXCEPTIONNUMBER
1119 return v->toInt32(exec);
1120}
1121
1122uint32_t LocalVarFunctionCallNode::evaluateToUInt32(ExecState* exec)
1123{
1124 JSValue* v = inlineEvaluate(exec);
1125 KJS_CHECKEXCEPTIONNUMBER
1126 return v->toUInt32(exec);
1127}
1128
1129void FunctionCallBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1130{
1131 nodeStack.append(m_args.get());
1132 nodeStack.append(m_subscript.get());
1133 nodeStack.append(m_base.get());
1134}
1135
1136// ECMA 11.2.3
1137JSValue* FunctionCallBracketNode::evaluate(ExecState* exec)
1138{
1139 JSValue* baseVal = m_base->evaluate(exec);
1140 KJS_CHECKEXCEPTIONVALUE
1141
1142 JSValue* subscriptVal = m_subscript->evaluate(exec);
1143
1144 JSObject* baseObj = baseVal->toObject(exec);
1145 uint32_t i;
1146 PropertySlot slot;
1147
1148 JSValue* funcVal;
1149 if (subscriptVal->getUInt32(i)) {
1150 if (baseObj->getPropertySlot(exec, i, slot))
1151 funcVal = slot.getValue(exec, baseObj, i);
1152 else
1153 funcVal = jsUndefined();
1154 } else {
1155 Identifier ident(subscriptVal->toString(exec));
1156 if (baseObj->getPropertySlot(exec, ident, slot))
1157 funcVal = baseObj->get(exec, ident);
1158 else
1159 funcVal = jsUndefined();
1160 }
1161
1162 KJS_CHECKEXCEPTIONVALUE
1163
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());
1166
1167 JSObject* func = static_cast<JSObject*>(funcVal);
1168
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());
1171
1172 List argList;
1173 m_args->evaluateList(exec, argList);
1174 KJS_CHECKEXCEPTIONVALUE
1175
1176 JSObject* thisObj = baseObj;
1177 ASSERT(thisObj);
1178 ASSERT(thisObj->isObject());
1179 ASSERT(!thisObj->isActivationObject());
1180
1181 return func->call(exec, thisObj, argList);
1182}
1183
1184static const char* dotExprNotAnObjectString() KJS_FAST_CALL;
1185static const char* dotExprNotAnObjectString()
1186{
1187 return "Value %s (result of expression %s.%s) is not object.";
1188}
1189
1190static const char* dotExprDoesNotAllowCallsString() KJS_FAST_CALL;
1191static const char* dotExprDoesNotAllowCallsString()
1192{
1193 return "Object %s (result of expression %s.%s) does not allow calls.";
1194}
1195
1196void FunctionCallDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1197{
1198 nodeStack.append(m_args.get());
1199 nodeStack.append(m_base.get());
1200}
1201
1202// ECMA 11.2.3
1203JSValue* FunctionCallDotNode::inlineEvaluate(ExecState* exec)
1204{
1205 JSValue* baseVal = m_base->evaluate(exec);
1206 KJS_CHECKEXCEPTIONVALUE
1207
1208 JSObject* baseObj = baseVal->toObject(exec);
1209 PropertySlot slot;
1210 JSValue* funcVal = baseObj->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, baseObj, m_ident) : jsUndefined();
1211 KJS_CHECKEXCEPTIONVALUE
1212
1213 if (!funcVal->isObject())
1214 return throwError(exec, TypeError, dotExprNotAnObjectString(), funcVal, m_base.get(), m_ident);
1215
1216 JSObject* func = static_cast<JSObject*>(funcVal);
1217
1218 if (!func->implementsCall())
1219 return throwError(exec, TypeError, dotExprDoesNotAllowCallsString(), funcVal, m_base.get(), m_ident);
1220
1221 List argList;
1222 m_args->evaluateList(exec, argList);
1223 KJS_CHECKEXCEPTIONVALUE
1224
1225 JSObject* thisObj = baseObj;
1226 ASSERT(thisObj);
1227 ASSERT(thisObj->isObject());
1228 ASSERT(!thisObj->isActivationObject());
1229
1230 return func->call(exec, thisObj, argList);
1231}
1232
1233JSValue* FunctionCallDotNode::evaluate(ExecState* exec)
1234{
1235 return inlineEvaluate(exec);
1236}
1237
1238double FunctionCallDotNode::evaluateToNumber(ExecState* exec)
1239{
1240 JSValue* v = inlineEvaluate(exec);
1241 KJS_CHECKEXCEPTIONNUMBER
1242 return v->toNumber(exec);
1243}
1244
1245bool FunctionCallDotNode::evaluateToBoolean(ExecState* exec)
1246{
1247 JSValue* v = inlineEvaluate(exec);
1248 KJS_CHECKEXCEPTIONBOOLEAN
1249 return v->toBoolean(exec);
1250}
1251
1252int32_t FunctionCallDotNode::evaluateToInt32(ExecState* exec)
1253{
1254 JSValue* v = inlineEvaluate(exec);
1255 KJS_CHECKEXCEPTIONNUMBER
1256 return v->toInt32(exec);
1257}
1258
1259uint32_t FunctionCallDotNode::evaluateToUInt32(ExecState* exec)
1260{
1261 JSValue* v = inlineEvaluate(exec);
1262 KJS_CHECKEXCEPTIONNUMBER
1263 return v->toUInt32(exec);
1264}
1265
1266// ECMA 11.3
1267
1268// ------------------------------ PostfixResolveNode ----------------------------------
1269
1270// Increment
1271void PostIncResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
1272{
1273 size_t index = symbolTable.get(m_ident.ustring().rep());
1274 if (index != missingSymbolMarker()) {
1275 if (isConstant(localStorage, index))
1276 new (this) PostIncConstNode(index);
1277 else
1278 new (this) PostIncLocalVarNode(index);
1279 }
1280}
1281
1282JSValue* PostIncResolveNode::evaluate(ExecState* exec)
1283{
1284 // Check for missed optimization opportunity.
1285 ASSERT(!canSkipLookup(exec, m_ident));
1286
1287 const ScopeChain& chain = exec->scopeChain();
1288 ScopeChainIterator iter = chain.begin();
1289 ScopeChainIterator end = chain.end();
1290
1291 // we must always have something in the scope chain
1292 ASSERT(iter != end);
1293
1294 PropertySlot slot;
1295 do {
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.
1301
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));
1305 return v;
1306 }
1307
1308 ++iter;
1309 } while (iter != end);
1310
1311 return throwUndefinedVariableError(exec, m_ident);
1312}
1313
1314void PostIncResolveNode::optimizeForUnnecessaryResult()
1315{
1316 new (this) PreIncResolveNode(PlacementNewAdopt);
1317}
1318
1319JSValue* PostIncLocalVarNode::evaluate(ExecState* exec)
1320{
1321 ASSERT(exec->variableObject() == exec->scopeChain().top());
1322
1323 JSValue** slot = &exec->localStorage()[m_index].value;
1324 JSValue* v = (*slot)->toJSNumber(exec);
1325 *slot = jsNumber(v->toNumber(exec) + 1);
1326 return v;
1327}
1328
1329void PostIncLocalVarNode::optimizeForUnnecessaryResult()
1330{
1331 new (this) PreIncLocalVarNode(m_index);
1332}
1333
1334// Decrement
1335void PostDecResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
1336{
1337 size_t index = symbolTable.get(m_ident.ustring().rep());
1338 if (index != missingSymbolMarker()) {
1339 if (isConstant(localStorage, index))
1340 new (this) PostDecConstNode(index);
1341 else
1342 new (this) PostDecLocalVarNode(index);
1343 }
1344}
1345
1346JSValue* PostDecResolveNode::evaluate(ExecState* exec)
1347{
1348 // Check for missed optimization opportunity.
1349 ASSERT(!canSkipLookup(exec, m_ident));
1350
1351 const ScopeChain& chain = exec->scopeChain();
1352 ScopeChainIterator iter = chain.begin();
1353 ScopeChainIterator end = chain.end();
1354
1355 // we must always have something in the scope chain
1356 ASSERT(iter != end);
1357
1358 PropertySlot slot;
1359 do {
1360 if ((*iter)->getPropertySlot(exec, m_ident, slot)) {
1361 // See the comment in PostIncResolveNode::evaluate().
1362
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));
1366 return v;
1367 }
1368
1369 ++iter;
1370 } while (iter != end);
1371
1372 return throwUndefinedVariableError(exec, m_ident);
1373}
1374
1375void PostDecResolveNode::optimizeForUnnecessaryResult()
1376{
1377 new (this) PreDecResolveNode(PlacementNewAdopt);
1378}
1379
1380JSValue* PostDecLocalVarNode::evaluate(ExecState* exec)
1381{
1382 ASSERT(exec->variableObject() == exec->scopeChain().top());
1383
1384 JSValue** slot = &exec->localStorage()[m_index].value;
1385 JSValue* v = (*slot)->toJSNumber(exec);
1386 *slot = jsNumber(v->toNumber(exec) - 1);
1387 return v;
1388}
1389
1390double PostDecLocalVarNode::inlineEvaluateToNumber(ExecState* exec)
1391{
1392 ASSERT(exec->variableObject() == exec->scopeChain().top());
1393
1394 JSValue** slot = &exec->localStorage()[m_index].value;
1395 double n = (*slot)->toNumber(exec);
1396 *slot = jsNumber(n - 1);
1397 return n;
1398}
1399
1400double PostDecLocalVarNode::evaluateToNumber(ExecState* exec)
1401{
1402 return inlineEvaluateToNumber(exec);
1403}
1404
1405bool PostDecLocalVarNode::evaluateToBoolean(ExecState* exec)
1406{
1407 double result = inlineEvaluateToNumber(exec);
1408 return result > 0.0 || 0.0 > result; // NaN produces false as well
1409}
1410
1411int32_t PostDecLocalVarNode::evaluateToInt32(ExecState* exec)
1412{
1413 return JSValue::toInt32(inlineEvaluateToNumber(exec));
1414}
1415
1416uint32_t PostDecLocalVarNode::evaluateToUInt32(ExecState* exec)
1417{
1418 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
1419}
1420
1421void PostDecLocalVarNode::optimizeForUnnecessaryResult()
1422{
1423 new (this) PreDecLocalVarNode(m_index);
1424}
1425
1426// ------------------------------ PostfixBracketNode ----------------------------------
1427
1428void PostfixBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1429{
1430 nodeStack.append(m_subscript.get());
1431 nodeStack.append(m_base.get());
1432}
1433
1434JSValue* PostIncBracketNode::evaluate(ExecState* exec)
1435{
1436 JSValue* baseValue = m_base->evaluate(exec);
1437 KJS_CHECKEXCEPTIONVALUE
1438 JSValue* subscript = m_subscript->evaluate(exec);
1439 KJS_CHECKEXCEPTIONVALUE
1440
1441 JSObject* base = baseValue->toObject(exec);
1442
1443 uint32_t propertyIndex;
1444 if (subscript->getUInt32(propertyIndex)) {
1445 PropertySlot slot;
1446 JSValue* v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1447 KJS_CHECKEXCEPTIONVALUE
1448
1449 JSValue* v2 = v->toJSNumber(exec);
1450 base->put(exec, propertyIndex, jsNumber(v2->toNumber(exec) + 1));
1451
1452 return v2;
1453 }
1454
1455 Identifier propertyName(subscript->toString(exec));
1456 PropertySlot slot;
1457 JSValue* v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1458 KJS_CHECKEXCEPTIONVALUE
1459
1460 JSValue* v2 = v->toJSNumber(exec);
1461 base->put(exec, propertyName, jsNumber(v2->toNumber(exec) + 1));
1462 return v2;
1463}
1464
1465JSValue* PostDecBracketNode::evaluate(ExecState* exec)
1466{
1467 JSValue* baseValue = m_base->evaluate(exec);
1468 KJS_CHECKEXCEPTIONVALUE
1469 JSValue* subscript = m_subscript->evaluate(exec);
1470 KJS_CHECKEXCEPTIONVALUE
1471
1472 JSObject* base = baseValue->toObject(exec);
1473
1474 uint32_t propertyIndex;
1475 if (subscript->getUInt32(propertyIndex)) {
1476 PropertySlot slot;
1477 JSValue* v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1478 KJS_CHECKEXCEPTIONVALUE
1479
1480 JSValue* v2 = v->toJSNumber(exec);
1481 base->put(exec, propertyIndex, jsNumber(v2->toNumber(exec) - 1));
1482 return v2;
1483 }
1484
1485 Identifier propertyName(subscript->toString(exec));
1486 PropertySlot slot;
1487 JSValue* v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1488 KJS_CHECKEXCEPTIONVALUE
1489
1490 JSValue* v2 = v->toJSNumber(exec);
1491 base->put(exec, propertyName, jsNumber(v2->toNumber(exec) - 1));
1492 return v2;
1493}
1494
1495// ------------------------------ PostfixDotNode ----------------------------------
1496
1497void PostfixDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1498{
1499 nodeStack.append(m_base.get());
1500}
1501
1502JSValue* PostIncDotNode::evaluate(ExecState* exec)
1503{
1504 JSValue* baseValue = m_base->evaluate(exec);
1505 KJS_CHECKEXCEPTIONVALUE
1506 JSObject* base = baseValue->toObject(exec);
1507
1508 PropertySlot slot;
1509 JSValue* v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1510 KJS_CHECKEXCEPTIONVALUE
1511
1512 JSValue* v2 = v->toJSNumber(exec);
1513 base->put(exec, m_ident, jsNumber(v2->toNumber(exec) + 1));
1514 return v2;
1515}
1516
1517JSValue* PostDecDotNode::evaluate(ExecState* exec)
1518{
1519 JSValue* baseValue = m_base->evaluate(exec);
1520 KJS_CHECKEXCEPTIONVALUE
1521 JSObject* base = baseValue->toObject(exec);
1522
1523 PropertySlot slot;
1524 JSValue* v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1525 KJS_CHECKEXCEPTIONVALUE
1526
1527 JSValue* v2 = v->toJSNumber(exec);
1528 base->put(exec, m_ident, jsNumber(v2->toNumber(exec) - 1));
1529 return v2;
1530}
1531
1532// ------------------------------ PostfixErrorNode -----------------------------------
1533
1534JSValue* PostfixErrorNode::evaluate(ExecState* exec)
1535{
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();
1540}
1541
1542// ------------------------------ DeleteResolveNode -----------------------------------
1543
1544void DeleteResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
1545{
1546 size_t index = symbolTable.get(m_ident.ustring().rep());
1547 if (index != missingSymbolMarker())
1548 new (this) LocalVarDeleteNode();
1549}
1550
1551// ECMA 11.4.1
1552
1553JSValue* DeleteResolveNode::evaluate(ExecState* exec)
1554{
1555 // Check for missed optimization opportunity.
1556 ASSERT(!canSkipLookup(exec, m_ident));
1557
1558 const ScopeChain& chain = exec->scopeChain();
1559 ScopeChainIterator iter = chain.begin();
1560 ScopeChainIterator end = chain.end();
1561
1562 // We must always have something in the scope chain
1563 ASSERT(iter != end);
1564
1565 PropertySlot slot;
1566 JSObject* base;
1567 do {
1568 base = *iter;
1569 if (base->getPropertySlot(exec, m_ident, slot))
1570 return jsBoolean(base->deleteProperty(exec, m_ident));
1571
1572 ++iter;
1573 } while (iter != end);
1574
1575 return jsBoolean(true);
1576}
1577
1578JSValue* LocalVarDeleteNode::evaluate(ExecState*)
1579{
1580 return jsBoolean(false);
1581}
1582
1583// ------------------------------ DeleteBracketNode -----------------------------------
1584
1585void DeleteBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1586{
1587 nodeStack.append(m_subscript.get());
1588 nodeStack.append(m_base.get());
1589}
1590
1591JSValue* DeleteBracketNode::evaluate(ExecState* exec)
1592{
1593 JSValue* baseValue = m_base->evaluate(exec);
1594 KJS_CHECKEXCEPTIONVALUE
1595 JSValue* subscript = m_subscript->evaluate(exec);
1596 KJS_CHECKEXCEPTIONVALUE
1597
1598 JSObject* base = baseValue->toObject(exec);
1599
1600 uint32_t propertyIndex;
1601 if (subscript->getUInt32(propertyIndex))
1602 return jsBoolean(base->deleteProperty(exec, propertyIndex));
1603
1604 Identifier propertyName(subscript->toString(exec));
1605 return jsBoolean(base->deleteProperty(exec, propertyName));
1606}
1607
1608// ------------------------------ DeleteDotNode -----------------------------------
1609
1610void DeleteDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1611{
1612 nodeStack.append(m_base.get());
1613}
1614
1615JSValue* DeleteDotNode::evaluate(ExecState* exec)
1616{
1617 JSValue* baseValue = m_base->evaluate(exec);
1618 JSObject* base = baseValue->toObject(exec);
1619 KJS_CHECKEXCEPTIONVALUE
1620
1621 return jsBoolean(base->deleteProperty(exec, m_ident));
1622}
1623
1624// ------------------------------ DeleteValueNode -----------------------------------
1625
1626void DeleteValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1627{
1628 nodeStack.append(m_expr.get());
1629}
1630
1631JSValue* DeleteValueNode::evaluate(ExecState* exec)
1632{
1633 m_expr->evaluate(exec);
1634 KJS_CHECKEXCEPTIONVALUE
1635
1636 // delete on a non-location expression ignores the value and returns true
1637 return jsBoolean(true);
1638}
1639
1640// ------------------------------ VoidNode -------------------------------------
1641
1642void VoidNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1643{
1644 nodeStack.append(m_expr.get());
1645}
1646
1647// ECMA 11.4.2
1648JSValue* VoidNode::evaluate(ExecState* exec)
1649{
1650 m_expr->evaluate(exec);
1651 KJS_CHECKEXCEPTIONVALUE
1652
1653 return jsUndefined();
1654}
1655
1656// ECMA 11.4.3
1657
1658// ------------------------------ TypeOfValueNode -----------------------------------
1659
1660void TypeOfValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1661{
1662 nodeStack.append(m_expr.get());
1663}
1664
1665static JSValue* typeStringForValue(JSValue* v) KJS_FAST_CALL;
1666static JSValue* typeStringForValue(JSValue* v)
1667{
1668 switch (v->type()) {
1669 case UndefinedType:
1670 return jsString("undefined");
1671 case NullType:
1672 return jsString("object");
1673 case BooleanType:
1674 return jsString("boolean");
1675 case NumberType:
1676 return jsString("number");
1677 case StringType:
1678 return jsString("string");
1679 default:
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");
1687 }
1688
1689 return jsString("object");
1690 }
1691}
1692
1693void TypeOfResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
1694{
1695 size_t index = symbolTable.get(m_ident.ustring().rep());
1696 if (index != missingSymbolMarker())
1697 new (this) LocalVarTypeOfNode(index);
1698}
1699
1700JSValue* LocalVarTypeOfNode::evaluate(ExecState* exec)
1701{
1702 ASSERT(exec->variableObject() == exec->scopeChain().top());
1703
1704 return typeStringForValue(exec->localStorage()[m_index].value);
1705}
1706
1707JSValue* TypeOfResolveNode::evaluate(ExecState* exec)
1708{
1709 const ScopeChain& chain = exec->scopeChain();
1710 ScopeChainIterator iter = chain.begin();
1711 ScopeChainIterator end = chain.end();
1712
1713 // We must always have something in the scope chain
1714 ASSERT(iter != end);
1715
1716 PropertySlot slot;
1717 JSObject* base;
1718 do {
1719 base = *iter;
1720 if (base->getPropertySlot(exec, m_ident, slot)) {
1721 JSValue* v = slot.getValue(exec, base, m_ident);
1722 return typeStringForValue(v);
1723 }
1724
1725 ++iter;
1726 } while (iter != end);
1727
1728 return jsString("undefined");
1729}
1730
1731// ------------------------------ TypeOfValueNode -----------------------------------
1732
1733JSValue* TypeOfValueNode::evaluate(ExecState* exec)
1734{
1735 JSValue* v = m_expr->evaluate(exec);
1736 KJS_CHECKEXCEPTIONVALUE
1737
1738 return typeStringForValue(v);
1739}
1740
1741// ECMA 11.4.4 and 11.4.5
1742
1743// ------------------------------ PrefixResolveNode ----------------------------------
1744
1745void PreIncResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
1746{
1747 size_t index = symbolTable.get(m_ident.ustring().rep());
1748 if (index != missingSymbolMarker()) {
1749 if (isConstant(localStorage, index))
1750 new (this) PreIncConstNode(index);
1751 else
1752 new (this) PreIncLocalVarNode(index);
1753 }
1754}
1755
1756JSValue* PreIncLocalVarNode::evaluate(ExecState* exec)
1757{
1758 ASSERT(exec->variableObject() == exec->scopeChain().top());
1759 JSValue** slot = &exec->localStorage()[m_index].value;
1760
1761 double n = (*slot)->toNumber(exec);
1762 JSValue* n2 = jsNumber(n + 1);
1763 *slot = n2;
1764 return n2;
1765}
1766
1767JSValue* PreIncResolveNode::evaluate(ExecState* exec)
1768{
1769 const ScopeChain& chain = exec->scopeChain();
1770 ScopeChainIterator iter = chain.begin();
1771 ScopeChainIterator end = chain.end();
1772
1773 // we must always have something in the scope chain
1774 ASSERT(iter != end);
1775
1776 PropertySlot slot;
1777 do {
1778 if ((*iter)->getPropertySlot(exec, m_ident, slot)) {
1779 // See the comment in PostIncResolveNode::evaluate().
1780
1781 JSObject* base = *iter;
1782 JSValue* v = slot.getValue(exec, base, m_ident);
1783
1784 double n = v->toNumber(exec);
1785 JSValue* n2 = jsNumber(n + 1);
1786 base->put(exec, m_ident, n2);
1787
1788 return n2;
1789 }
1790
1791 ++iter;
1792 } while (iter != end);
1793
1794 return throwUndefinedVariableError(exec, m_ident);
1795}
1796
1797void PreDecResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
1798{
1799 size_t index = symbolTable.get(m_ident.ustring().rep());
1800 if (index != missingSymbolMarker()) {
1801 if (isConstant(localStorage, index))
1802 new (this) PreDecConstNode(index);
1803 else
1804 new (this) PreDecLocalVarNode(index);
1805 }
1806}
1807
1808JSValue* PreDecLocalVarNode::evaluate(ExecState* exec)
1809{
1810 ASSERT(exec->variableObject() == exec->scopeChain().top());
1811 JSValue** slot = &exec->localStorage()[m_index].value;
1812
1813 double n = (*slot)->toNumber(exec);
1814 JSValue* n2 = jsNumber(n - 1);
1815 *slot = n2;
1816 return n2;
1817}
1818
1819JSValue* PreDecResolveNode::evaluate(ExecState* exec)
1820{
1821 const ScopeChain& chain = exec->scopeChain();
1822 ScopeChainIterator iter = chain.begin();
1823 ScopeChainIterator end = chain.end();
1824
1825 // we must always have something in the scope chain
1826 ASSERT(iter != end);
1827
1828 PropertySlot slot;
1829 do {
1830 if ((*iter)->getPropertySlot(exec, m_ident, slot)) {
1831 // See the comment in PostIncResolveNode::evaluate().
1832
1833 JSObject* base = *iter;
1834 JSValue* v = slot.getValue(exec, base, m_ident);
1835
1836 double n = v->toNumber(exec);
1837 JSValue* n2 = jsNumber(n - 1);
1838 base->put(exec, m_ident, n2);
1839
1840 return n2;
1841 }
1842
1843 ++iter;
1844 } while (iter != end);
1845
1846 return throwUndefinedVariableError(exec, m_ident);
1847}
1848
1849// ------------------------------ PreIncConstNode ----------------------------------
1850
1851JSValue* PreIncConstNode::evaluate(ExecState* exec)
1852{
1853 ASSERT(exec->variableObject() == exec->scopeChain().top());
1854 return jsNumber(exec->localStorage()[m_index].value->toNumber(exec) + 1);
1855}
1856
1857// ------------------------------ PreDecConstNode ----------------------------------
1858
1859JSValue* PreDecConstNode::evaluate(ExecState* exec)
1860{
1861 ASSERT(exec->variableObject() == exec->scopeChain().top());
1862 return jsNumber(exec->localStorage()[m_index].value->toNumber(exec) - 1);
1863}
1864
1865// ------------------------------ PostIncConstNode ----------------------------------
1866
1867JSValue* PostIncConstNode::evaluate(ExecState* exec)
1868{
1869 ASSERT(exec->variableObject() == exec->scopeChain().top());
1870 return jsNumber(exec->localStorage()[m_index].value->toNumber(exec));
1871}
1872
1873// ------------------------------ PostDecConstNode ----------------------------------
1874
1875JSValue* PostDecConstNode::evaluate(ExecState* exec)
1876{
1877 ASSERT(exec->variableObject() == exec->scopeChain().top());
1878 return jsNumber(exec->localStorage()[m_index].value->toNumber(exec));
1879}
1880
1881// ------------------------------ PrefixBracketNode ----------------------------------
1882
1883void PrefixBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1884{
1885 nodeStack.append(m_subscript.get());
1886 nodeStack.append(m_base.get());
1887}
1888
1889JSValue* PreIncBracketNode::evaluate(ExecState* exec)
1890{
1891 JSValue* baseValue = m_base->evaluate(exec);
1892 KJS_CHECKEXCEPTIONVALUE
1893 JSValue* subscript = m_subscript->evaluate(exec);
1894 KJS_CHECKEXCEPTIONVALUE
1895
1896 JSObject* base = baseValue->toObject(exec);
1897
1898 uint32_t propertyIndex;
1899 if (subscript->getUInt32(propertyIndex)) {
1900 PropertySlot slot;
1901 JSValue* v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1902 KJS_CHECKEXCEPTIONVALUE
1903
1904 JSValue* n2 = jsNumber(v->toNumber(exec) + 1);
1905 base->put(exec, propertyIndex, n2);
1906
1907 return n2;
1908 }
1909
1910 Identifier propertyName(subscript->toString(exec));
1911 PropertySlot slot;
1912 JSValue* v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1913 KJS_CHECKEXCEPTIONVALUE
1914
1915 JSValue* n2 = jsNumber(v->toNumber(exec) + 1);
1916 base->put(exec, propertyName, n2);
1917
1918 return n2;
1919}
1920
1921JSValue* PreDecBracketNode::evaluate(ExecState* exec)
1922{
1923 JSValue* baseValue = m_base->evaluate(exec);
1924 KJS_CHECKEXCEPTIONVALUE
1925 JSValue* subscript = m_subscript->evaluate(exec);
1926 KJS_CHECKEXCEPTIONVALUE
1927
1928 JSObject* base = baseValue->toObject(exec);
1929
1930 uint32_t propertyIndex;
1931 if (subscript->getUInt32(propertyIndex)) {
1932 PropertySlot slot;
1933 JSValue* v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
1934 KJS_CHECKEXCEPTIONVALUE
1935
1936 JSValue* n2 = jsNumber(v->toNumber(exec) - 1);
1937 base->put(exec, propertyIndex, n2);
1938
1939 return n2;
1940 }
1941
1942 Identifier propertyName(subscript->toString(exec));
1943 PropertySlot slot;
1944 JSValue* v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
1945 KJS_CHECKEXCEPTIONVALUE
1946
1947 JSValue* n2 = jsNumber(v->toNumber(exec) - 1);
1948 base->put(exec, propertyName, n2);
1949
1950 return n2;
1951}
1952
1953// ------------------------------ PrefixDotNode ----------------------------------
1954
1955void PrefixDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
1956{
1957 nodeStack.append(m_base.get());
1958}
1959
1960JSValue* PreIncDotNode::evaluate(ExecState* exec)
1961{
1962 JSValue* baseValue = m_base->evaluate(exec);
1963 KJS_CHECKEXCEPTIONVALUE
1964 JSObject* base = baseValue->toObject(exec);
1965
1966 PropertySlot slot;
1967 JSValue* v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1968 KJS_CHECKEXCEPTIONVALUE
1969
1970 double n = v->toNumber(exec);
1971 JSValue* n2 = jsNumber(n + 1);
1972 base->put(exec, m_ident, n2);
1973
1974 return n2;
1975}
1976
1977JSValue* PreDecDotNode::evaluate(ExecState* exec)
1978{
1979 JSValue* baseValue = m_base->evaluate(exec);
1980 KJS_CHECKEXCEPTIONVALUE
1981 JSObject* base = baseValue->toObject(exec);
1982
1983 PropertySlot slot;
1984 JSValue* v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
1985 KJS_CHECKEXCEPTIONVALUE
1986
1987 double n = v->toNumber(exec);
1988 JSValue* n2 = jsNumber(n - 1);
1989 base->put(exec, m_ident, n2);
1990
1991 return n2;
1992}
1993
1994// ------------------------------ PrefixErrorNode -----------------------------------
1995
1996JSValue* PrefixErrorNode::evaluate(ExecState* exec)
1997{
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();
2002}
2003
2004// ------------------------------ UnaryPlusNode --------------------------------
2005
2006void UnaryPlusNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2007{
2008 nodeStack.append(m_expr.get());
2009}
2010
2011// ECMA 11.4.6
2012JSValue* UnaryPlusNode::evaluate(ExecState* exec)
2013{
2014 JSValue* v = m_expr->evaluate(exec);
2015 KJS_CHECKEXCEPTIONVALUE
2016 return v->toJSNumber(exec);
2017}
2018
2019bool UnaryPlusNode::evaluateToBoolean(ExecState* exec)
2020{
2021 return m_expr->evaluateToBoolean(exec);
2022}
2023
2024double UnaryPlusNode::evaluateToNumber(ExecState* exec)
2025{
2026 return m_expr->evaluateToNumber(exec);
2027}
2028
2029int32_t UnaryPlusNode::evaluateToInt32(ExecState* exec)
2030{
2031 return m_expr->evaluateToInt32(exec);
2032}
2033
2034uint32_t UnaryPlusNode::evaluateToUInt32(ExecState* exec)
2035{
2036 return m_expr->evaluateToInt32(exec);
2037}
2038
2039// ------------------------------ NegateNode -----------------------------------
2040
2041void NegateNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2042{
2043 nodeStack.append(m_expr.get());
2044}
2045
2046// ECMA 11.4.7
2047JSValue* NegateNode::evaluate(ExecState* exec)
2048{
2049 // No need to check exception, caller will do so right after evaluate()
2050 return jsNumber(-m_expr->evaluateToNumber(exec));
2051}
2052
2053double NegateNode::evaluateToNumber(ExecState* exec)
2054{
2055 // No need to check exception, caller will do so right after evaluateToNumber()
2056 return -m_expr->evaluateToNumber(exec);
2057}
2058
2059// ------------------------------ BitwiseNotNode -------------------------------
2060
2061void BitwiseNotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2062{
2063 nodeStack.append(m_expr.get());
2064}
2065
2066// ECMA 11.4.8
2067int32_t BitwiseNotNode::inlineEvaluateToInt32(ExecState* exec)
2068{
2069 return ~m_expr->evaluateToInt32(exec);
2070}
2071
2072JSValue* BitwiseNotNode::evaluate(ExecState* exec)
2073{
2074 return jsNumber(inlineEvaluateToInt32(exec));
2075}
2076
2077double BitwiseNotNode::evaluateToNumber(ExecState* exec)
2078{
2079 return inlineEvaluateToInt32(exec);
2080}
2081
2082bool BitwiseNotNode::evaluateToBoolean(ExecState* exec)
2083{
2084 return inlineEvaluateToInt32(exec);
2085}
2086
2087int32_t BitwiseNotNode::evaluateToInt32(ExecState* exec)
2088{
2089 return inlineEvaluateToInt32(exec);
2090}
2091
2092uint32_t BitwiseNotNode::evaluateToUInt32(ExecState* exec)
2093{
2094 return inlineEvaluateToInt32(exec);
2095}
2096
2097// ------------------------------ LogicalNotNode -------------------------------
2098
2099void LogicalNotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2100{
2101 nodeStack.append(m_expr.get());
2102}
2103
2104// ECMA 11.4.9
2105JSValue* LogicalNotNode::evaluate(ExecState* exec)
2106{
2107 return jsBoolean(!m_expr->evaluateToBoolean(exec));
2108}
2109
2110bool LogicalNotNode::evaluateToBoolean(ExecState* exec)
2111{
2112 return !m_expr->evaluateToBoolean(exec);
2113}
2114
2115// ------------------------------ Multiplicative Nodes -----------------------------------
2116
2117void MultNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2118{
2119 nodeStack.append(m_term1.get());
2120 nodeStack.append(m_term2.get());
2121}
2122
2123// ECMA 11.5.1
2124double MultNode::inlineEvaluateToNumber(ExecState* exec)
2125{
2126 double n1 = m_term1->evaluateToNumber(exec);
2127 KJS_CHECKEXCEPTIONNUMBER
2128 double n2 = m_term2->evaluateToNumber(exec);
2129 return n1 * n2;
2130}
2131
2132JSValue* MultNode::evaluate(ExecState* exec)
2133{
2134 return jsNumber(inlineEvaluateToNumber(exec));
2135}
2136
2137double MultNode::evaluateToNumber(ExecState* exec)
2138{
2139 return inlineEvaluateToNumber(exec);
2140}
2141
2142bool MultNode::evaluateToBoolean(ExecState* exec)
2143{
2144 double result = inlineEvaluateToNumber(exec);
2145 return result > 0.0 || 0.0 > result; // NaN produces false as well
2146}
2147
2148int32_t MultNode::evaluateToInt32(ExecState* exec)
2149{
2150 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2151}
2152
2153uint32_t MultNode::evaluateToUInt32(ExecState* exec)
2154{
2155 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2156}
2157
2158void DivNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2159{
2160 nodeStack.append(m_term1.get());
2161 nodeStack.append(m_term2.get());
2162}
2163
2164// ECMA 11.5.2
2165double DivNode::inlineEvaluateToNumber(ExecState* exec)
2166{
2167 double n1 = m_term1->evaluateToNumber(exec);
2168 KJS_CHECKEXCEPTIONNUMBER
2169 double n2 = m_term2->evaluateToNumber(exec);
2170 return n1 / n2;
2171}
2172
2173JSValue* DivNode::evaluate(ExecState* exec)
2174{
2175 return jsNumber(inlineEvaluateToNumber(exec));
2176}
2177
2178double DivNode::evaluateToNumber(ExecState* exec)
2179{
2180 return inlineEvaluateToNumber(exec);
2181}
2182
2183int32_t DivNode::evaluateToInt32(ExecState* exec)
2184{
2185 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2186}
2187
2188uint32_t DivNode::evaluateToUInt32(ExecState* exec)
2189{
2190 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2191}
2192
2193void ModNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2194{
2195 nodeStack.append(m_term1.get());
2196 nodeStack.append(m_term2.get());
2197}
2198
2199// ECMA 11.5.3
2200double ModNode::inlineEvaluateToNumber(ExecState* exec)
2201{
2202 double n1 = m_term1->evaluateToNumber(exec);
2203 KJS_CHECKEXCEPTIONNUMBER
2204 double n2 = m_term2->evaluateToNumber(exec);
2205 return fmod(n1, n2);
2206}
2207
2208JSValue* ModNode::evaluate(ExecState* exec)
2209{
2210 return jsNumber(inlineEvaluateToNumber(exec));
2211}
2212
2213double ModNode::evaluateToNumber(ExecState* exec)
2214{
2215 return inlineEvaluateToNumber(exec);
2216}
2217
2218bool ModNode::evaluateToBoolean(ExecState* exec)
2219{
2220 double result = inlineEvaluateToNumber(exec);
2221 return result > 0.0 || 0.0 > result; // NaN produces false as well
2222}
2223
2224int32_t ModNode::evaluateToInt32(ExecState* exec)
2225{
2226 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2227}
2228
2229uint32_t ModNode::evaluateToUInt32(ExecState* exec)
2230{
2231 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2232}
2233
2234// ------------------------------ Additive Nodes --------------------------------------
2235
2236static JSValue* throwOutOfMemoryError(ExecState* exec)
2237{
2238 JSObject* error = Error::create(exec, GeneralError, "Out of memory");
2239 exec->setException(error);
2240 return error;
2241}
2242
2243static double throwOutOfMemoryErrorToNumber(ExecState* exec)
2244{
2245 JSObject* error = Error::create(exec, GeneralError, "Out of memory");
2246 exec->setException(error);
2247 return 0.0;
2248}
2249
2250// ECMA 11.6
2251static JSValue* addSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
2252{
2253 // exception for the Date exception in defaultValue()
2254 JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
2255 JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);
2256
2257 if (p1->isString() || p2->isString()) {
2258 UString value = p1->toString(exec) + p2->toString(exec);
2259 if (value.isNull())
2260 return throwOutOfMemoryError(exec);
2261 return jsString(value);
2262 }
2263
2264 return jsNumber(p1->toNumber(exec) + p2->toNumber(exec));
2265}
2266
2267static double addSlowCaseToNumber(ExecState* exec, JSValue* v1, JSValue* v2)
2268{
2269 // exception for the Date exception in defaultValue()
2270 JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
2271 JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);
2272
2273 if (p1->isString() || p2->isString()) {
2274 UString value = p1->toString(exec) + p2->toString(exec);
2275 if (value.isNull())
2276 return throwOutOfMemoryErrorToNumber(exec);
2277 return value.toDouble();
2278 }
2279
2280 return p1->toNumber(exec) + p2->toNumber(exec);
2281}
2282
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
2291// 1 Add case: 3 5
2292
2293static inline JSValue* add(ExecState* exec, JSValue* v1, JSValue* v2)
2294{
2295 JSType t1 = v1->type();
2296 JSType t2 = v2->type();
2297 const unsigned bothTypes = (t1 << 3) | t2;
2298
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();
2303 if (value.isNull())
2304 return throwOutOfMemoryError(exec);
2305 return jsString(value);
2306 }
2307
2308 // All other cases are pretty uncommon
2309 return addSlowCase(exec, v1, v2);
2310}
2311
2312static inline double addToNumber(ExecState* exec, JSValue* v1, JSValue* v2)
2313{
2314 JSType t1 = v1->type();
2315 JSType t2 = v2->type();
2316 const unsigned bothTypes = (t1 << 3) | t2;
2317
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();
2322 if (value.isNull())
2323 return throwOutOfMemoryErrorToNumber(exec);
2324 return value.toDouble();
2325 }
2326
2327 // All other cases are pretty uncommon
2328 return addSlowCaseToNumber(exec, v1, v2);
2329}
2330
2331void AddNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2332{
2333 nodeStack.append(m_term1.get());
2334 nodeStack.append(m_term2.get());
2335}
2336
2337// ECMA 11.6.1
2338JSValue* AddNode::evaluate(ExecState* exec)
2339{
2340 JSValue* v1 = m_term1->evaluate(exec);
2341 KJS_CHECKEXCEPTIONVALUE
2342
2343 JSValue* v2 = m_term2->evaluate(exec);
2344 KJS_CHECKEXCEPTIONVALUE
2345
2346 return add(exec, v1, v2);
2347}
2348
2349double AddNode::inlineEvaluateToNumber(ExecState* exec)
2350{
2351 JSValue* v1 = m_term1->evaluate(exec);
2352 KJS_CHECKEXCEPTIONNUMBER
2353
2354 JSValue* v2 = m_term2->evaluate(exec);
2355 KJS_CHECKEXCEPTIONNUMBER
2356
2357 return addToNumber(exec, v1, v2);
2358}
2359
2360double AddNode::evaluateToNumber(ExecState* exec)
2361{
2362 return inlineEvaluateToNumber(exec);
2363}
2364
2365int32_t AddNode::evaluateToInt32(ExecState* exec)
2366{
2367 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2368}
2369
2370uint32_t AddNode::evaluateToUInt32(ExecState* exec)
2371{
2372 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2373}
2374
2375double AddNumbersNode::inlineEvaluateToNumber(ExecState* exec)
2376{
2377 double n1 = m_term1->evaluateToNumber(exec);
2378 KJS_CHECKEXCEPTIONNUMBER
2379 double n2 = m_term2->evaluateToNumber(exec);
2380 return n1 + n2;
2381}
2382
2383JSValue* AddNumbersNode::evaluate(ExecState* exec)
2384{
2385 return jsNumber(inlineEvaluateToNumber(exec));
2386}
2387
2388double AddNumbersNode::evaluateToNumber(ExecState* exec)
2389{
2390 return inlineEvaluateToNumber(exec);
2391}
2392
2393int32_t AddNumbersNode::evaluateToInt32(ExecState* exec)
2394{
2395 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2396}
2397
2398uint32_t AddNumbersNode::evaluateToUInt32(ExecState* exec)
2399{
2400 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2401}
2402
2403JSValue* AddStringsNode::evaluate(ExecState* exec)
2404{
2405 JSValue* v1 = m_term1->evaluate(exec);
2406 KJS_CHECKEXCEPTIONVALUE
2407
2408 JSValue* v2 = m_term2->evaluate(exec);
2409 KJS_CHECKEXCEPTIONVALUE
2410
2411 return jsString(static_cast<StringImp*>(v1)->value() + static_cast<StringImp*>(v2)->value());
2412}
2413
2414JSValue* AddStringLeftNode::evaluate(ExecState* exec)
2415{
2416 JSValue* v1 = m_term1->evaluate(exec);
2417 KJS_CHECKEXCEPTIONVALUE
2418
2419 JSValue* v2 = m_term2->evaluate(exec);
2420 KJS_CHECKEXCEPTIONVALUE
2421
2422 JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);
2423 return jsString(static_cast<StringImp*>(v1)->value() + p2->toString(exec));
2424}
2425
2426JSValue* AddStringRightNode::evaluate(ExecState* exec)
2427{
2428 JSValue* v1 = m_term1->evaluate(exec);
2429 KJS_CHECKEXCEPTIONVALUE
2430
2431 JSValue* v2 = m_term2->evaluate(exec);
2432 KJS_CHECKEXCEPTIONVALUE
2433
2434 JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
2435 return jsString(p1->toString(exec) + static_cast<StringImp*>(v2)->value());
2436}
2437
2438void SubNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2439{
2440 nodeStack.append(m_term1.get());
2441 nodeStack.append(m_term2.get());
2442}
2443
2444// ECMA 11.6.2
2445double SubNode::inlineEvaluateToNumber(ExecState* exec)
2446{
2447 double n1 = m_term1->evaluateToNumber(exec);
2448 KJS_CHECKEXCEPTIONNUMBER
2449 double n2 = m_term2->evaluateToNumber(exec);
2450 return n1 - n2;
2451}
2452
2453JSValue* SubNode::evaluate(ExecState* exec)
2454{
2455 return jsNumber(inlineEvaluateToNumber(exec));
2456}
2457
2458double SubNode::evaluateToNumber(ExecState* exec)
2459{
2460 return inlineEvaluateToNumber(exec);
2461}
2462
2463int32_t SubNode::evaluateToInt32(ExecState* exec)
2464{
2465 return JSValue::toInt32(inlineEvaluateToNumber(exec));
2466}
2467
2468uint32_t SubNode::evaluateToUInt32(ExecState* exec)
2469{
2470 return JSValue::toUInt32(inlineEvaluateToNumber(exec));
2471}
2472
2473// ------------------------------ Shift Nodes ------------------------------------
2474
2475void LeftShiftNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2476{
2477 nodeStack.append(m_term1.get());
2478 nodeStack.append(m_term2.get());
2479}
2480
2481// ECMA 11.7.1
2482int32_t LeftShiftNode::inlineEvaluateToInt32(ExecState* exec)
2483{
2484 int i1 = m_term1->evaluateToInt32(exec);
2485 KJS_CHECKEXCEPTIONNUMBER
2486 unsigned int i2 = m_term2->evaluateToUInt32(exec) & 0x1f;
2487 return (i1 << i2);
2488}
2489
2490JSValue* LeftShiftNode::evaluate(ExecState* exec)
2491{
2492 return jsNumber(inlineEvaluateToInt32(exec));
2493}
2494
2495double LeftShiftNode::evaluateToNumber(ExecState* exec)
2496{
2497 return inlineEvaluateToInt32(exec);
2498}
2499
2500int32_t LeftShiftNode::evaluateToInt32(ExecState* exec)
2501{
2502 return inlineEvaluateToInt32(exec);
2503}
2504
2505uint32_t LeftShiftNode::evaluateToUInt32(ExecState* exec)
2506{
2507 return inlineEvaluateToInt32(exec);
2508}
2509
2510void RightShiftNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2511{
2512 nodeStack.append(m_term1.get());
2513 nodeStack.append(m_term2.get());
2514}
2515
2516// ECMA 11.7.2
2517int32_t RightShiftNode::inlineEvaluateToInt32(ExecState* exec)
2518{
2519 int i1 = m_term1->evaluateToInt32(exec);
2520 KJS_CHECKEXCEPTIONNUMBER
2521 unsigned int i2 = m_term2->evaluateToUInt32(exec) & 0x1f;
2522 return (i1 >> i2);
2523}
2524
2525JSValue* RightShiftNode::evaluate(ExecState* exec)
2526{
2527 return jsNumber(inlineEvaluateToInt32(exec));
2528}
2529
2530double RightShiftNode::evaluateToNumber(ExecState* exec)
2531{
2532 return inlineEvaluateToInt32(exec);
2533}
2534
2535int32_t RightShiftNode::evaluateToInt32(ExecState* exec)
2536{
2537 return inlineEvaluateToInt32(exec);
2538}
2539
2540uint32_t RightShiftNode::evaluateToUInt32(ExecState* exec)
2541{
2542 return inlineEvaluateToInt32(exec);
2543}
2544
2545void UnsignedRightShiftNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2546{
2547 nodeStack.append(m_term1.get());
2548 nodeStack.append(m_term2.get());
2549}
2550
2551// ECMA 11.7.3
2552uint32_t UnsignedRightShiftNode::inlineEvaluateToUInt32(ExecState* exec)
2553{
2554 unsigned int i1 = m_term1->evaluateToUInt32(exec);
2555 KJS_CHECKEXCEPTIONNUMBER
2556 unsigned int i2 = m_term2->evaluateToUInt32(exec) & 0x1f;
2557 return (i1 >> i2);
2558}
2559
2560JSValue* UnsignedRightShiftNode::evaluate(ExecState* exec)
2561{
2562 return jsNumber(inlineEvaluateToUInt32(exec));
2563}
2564
2565double UnsignedRightShiftNode::evaluateToNumber(ExecState* exec)
2566{
2567 return inlineEvaluateToUInt32(exec);
2568}
2569
2570int32_t UnsignedRightShiftNode::evaluateToInt32(ExecState* exec)
2571{
2572 return inlineEvaluateToUInt32(exec);
2573}
2574
2575uint32_t UnsignedRightShiftNode::evaluateToUInt32(ExecState* exec)
2576{
2577 return inlineEvaluateToUInt32(exec);
2578}
2579
2580// ------------------------------ Relational Nodes -------------------------------
2581
2582static inline bool lessThan(ExecState* exec, JSValue* v1, JSValue* v2)
2583{
2584 double n1;
2585 double n2;
2586 JSValue* p1;
2587 JSValue* p2;
2588 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
2589 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
2590
2591 if (wasNotString1 | wasNotString2)
2592 return n1 < n2;
2593
2594 return static_cast<const StringImp*>(p1)->value() < static_cast<const StringImp*>(p2)->value();
2595}
2596
2597static inline bool lessThanEq(ExecState* exec, JSValue* v1, JSValue* v2)
2598{
2599 double n1;
2600 double n2;
2601 JSValue* p1;
2602 JSValue* p2;
2603 bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
2604 bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
2605
2606 if (wasNotString1 | wasNotString2)
2607 return n1 <= n2;
2608
2609 return !(static_cast<const StringImp*>(p2)->value() < static_cast<const StringImp*>(p1)->value());
2610}
2611
2612void LessNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2613{
2614 nodeStack.append(m_expr2.get());
2615 nodeStack.append(m_expr1.get());
2616}
2617
2618// ECMA 11.8.1
2619bool LessNode::inlineEvaluateToBoolean(ExecState* exec)
2620{
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);
2626}
2627
2628JSValue* LessNode::evaluate(ExecState* exec)
2629{
2630 return jsBoolean(inlineEvaluateToBoolean(exec));
2631}
2632
2633bool LessNode::evaluateToBoolean(ExecState* exec)
2634{
2635 return inlineEvaluateToBoolean(exec);
2636}
2637
2638bool LessNumbersNode::inlineEvaluateToBoolean(ExecState* exec)
2639{
2640 double n1 = m_expr1->evaluateToNumber(exec);
2641 KJS_CHECKEXCEPTIONVALUE
2642 double n2 = m_expr2->evaluateToNumber(exec);
2643 return n1 < n2;
2644}
2645
2646JSValue* LessNumbersNode::evaluate(ExecState* exec)
2647{
2648 return jsBoolean(inlineEvaluateToBoolean(exec));
2649}
2650
2651bool LessNumbersNode::evaluateToBoolean(ExecState* exec)
2652{
2653 return inlineEvaluateToBoolean(exec);
2654}
2655
2656bool LessStringsNode::inlineEvaluateToBoolean(ExecState* exec)
2657{
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();
2662}
2663
2664JSValue* LessStringsNode::evaluate(ExecState* exec)
2665{
2666 return jsBoolean(inlineEvaluateToBoolean(exec));
2667}
2668
2669bool LessStringsNode::evaluateToBoolean(ExecState* exec)
2670{
2671 return inlineEvaluateToBoolean(exec);
2672}
2673
2674void GreaterNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2675{
2676 nodeStack.append(m_expr2.get());
2677 nodeStack.append(m_expr1.get());
2678}
2679
2680// ECMA 11.8.2
2681bool GreaterNode::inlineEvaluateToBoolean(ExecState* exec)
2682{
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);
2688}
2689
2690JSValue* GreaterNode::evaluate(ExecState* exec)
2691{
2692 return jsBoolean(inlineEvaluateToBoolean(exec));
2693}
2694
2695bool GreaterNode::evaluateToBoolean(ExecState* exec)
2696{
2697 return inlineEvaluateToBoolean(exec);
2698}
2699
2700void LessEqNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2701{
2702 nodeStack.append(m_expr2.get());
2703 nodeStack.append(m_expr1.get());
2704}
2705
2706// ECMA 11.8.3
2707bool LessEqNode::inlineEvaluateToBoolean(ExecState* exec)
2708{
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);
2714}
2715
2716JSValue* LessEqNode::evaluate(ExecState* exec)
2717{
2718 return jsBoolean(inlineEvaluateToBoolean(exec));
2719}
2720
2721bool LessEqNode::evaluateToBoolean(ExecState* exec)
2722{
2723 return inlineEvaluateToBoolean(exec);
2724}
2725
2726void GreaterEqNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2727{
2728 nodeStack.append(m_expr2.get());
2729 nodeStack.append(m_expr1.get());
2730}
2731
2732// ECMA 11.8.4
2733bool GreaterEqNode::inlineEvaluateToBoolean(ExecState* exec)
2734{
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);
2740}
2741
2742JSValue* GreaterEqNode::evaluate(ExecState* exec)
2743{
2744 return jsBoolean(inlineEvaluateToBoolean(exec));
2745}
2746
2747bool GreaterEqNode::evaluateToBoolean(ExecState* exec)
2748{
2749 return inlineEvaluateToBoolean(exec);
2750}
2751
2752void InstanceOfNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2753{
2754 nodeStack.append(m_expr2.get());
2755 nodeStack.append(m_expr1.get());
2756}
2757
2758// ECMA 11.8.6
2759JSValue* InstanceOfNode::evaluate(ExecState* exec)
2760{
2761 JSValue* v1 = m_expr1->evaluate(exec);
2762 KJS_CHECKEXCEPTIONVALUE
2763 JSValue* v2 = m_expr2->evaluate(exec);
2764 KJS_CHECKEXCEPTIONVALUE
2765
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());
2768
2769 JSObject* o2 = static_cast<JSObject*>(v2);
2770
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);
2777
2778 return jsBoolean(o2->hasInstance(exec, v1));
2779}
2780
2781bool InstanceOfNode::evaluateToBoolean(ExecState* exec)
2782{
2783 JSValue* v1 = m_expr1->evaluate(exec);
2784 KJS_CHECKEXCEPTIONBOOLEAN
2785 JSValue* v2 = m_expr2->evaluate(exec);
2786 KJS_CHECKEXCEPTIONBOOLEAN
2787
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());
2790 return false;
2791 }
2792
2793 JSObject* o2 = static_cast<JSObject*>(v2);
2794
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())
2800 return false;
2801
2802 return o2->hasInstance(exec, v1);
2803}
2804
2805void InNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2806{
2807 nodeStack.append(m_expr2.get());
2808 nodeStack.append(m_expr1.get());
2809}
2810
2811// ECMA 11.8.7
2812JSValue* InNode::evaluate(ExecState* exec)
2813{
2814 JSValue* v1 = m_expr1->evaluate(exec);
2815 KJS_CHECKEXCEPTIONVALUE
2816 JSValue* v2 = m_expr2->evaluate(exec);
2817 KJS_CHECKEXCEPTIONVALUE
2818
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());
2821
2822 return jsBoolean(static_cast<JSObject*>(v2)->hasProperty(exec, Identifier(v1->toString(exec))));
2823}
2824
2825bool InNode::evaluateToBoolean(ExecState* exec)
2826{
2827 JSValue* v1 = m_expr1->evaluate(exec);
2828 KJS_CHECKEXCEPTIONBOOLEAN
2829 JSValue* v2 = m_expr2->evaluate(exec);
2830 KJS_CHECKEXCEPTIONBOOLEAN
2831
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());
2834 return false;
2835 }
2836
2837 return static_cast<JSObject*>(v2)->hasProperty(exec, Identifier(v1->toString(exec)));
2838}
2839
2840// ------------------------------ Equality Nodes ------------------------------------
2841
2842void EqualNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2843{
2844 nodeStack.append(m_expr2.get());
2845 nodeStack.append(m_expr1.get());
2846}
2847
2848// ECMA 11.9.1
2849bool EqualNode::inlineEvaluateToBoolean(ExecState* exec)
2850{
2851 JSValue* v1 = m_expr1->evaluate(exec);
2852 KJS_CHECKEXCEPTIONBOOLEAN
2853 JSValue* v2 = m_expr2->evaluate(exec);
2854 KJS_CHECKEXCEPTIONBOOLEAN
2855
2856 return equal(exec, v1, v2);
2857}
2858
2859JSValue* EqualNode::evaluate(ExecState* exec)
2860{
2861 return jsBoolean(inlineEvaluateToBoolean(exec));
2862}
2863
2864bool EqualNode::evaluateToBoolean(ExecState* exec)
2865{
2866 return inlineEvaluateToBoolean(exec);
2867}
2868
2869void NotEqualNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2870{
2871 nodeStack.append(m_expr2.get());
2872 nodeStack.append(m_expr1.get());
2873}
2874
2875// ECMA 11.9.2
2876bool NotEqualNode::inlineEvaluateToBoolean(ExecState* exec)
2877{
2878 JSValue* v1 = m_expr1->evaluate(exec);
2879 KJS_CHECKEXCEPTIONBOOLEAN
2880 JSValue* v2 = m_expr2->evaluate(exec);
2881 KJS_CHECKEXCEPTIONBOOLEAN
2882
2883 return !equal(exec,v1, v2);
2884}
2885
2886JSValue* NotEqualNode::evaluate(ExecState* exec)
2887{
2888 return jsBoolean(inlineEvaluateToBoolean(exec));
2889}
2890
2891bool NotEqualNode::evaluateToBoolean(ExecState* exec)
2892{
2893 return inlineEvaluateToBoolean(exec);
2894}
2895
2896void StrictEqualNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2897{
2898 nodeStack.append(m_expr2.get());
2899 nodeStack.append(m_expr1.get());
2900}
2901
2902// ECMA 11.9.4
2903bool StrictEqualNode::inlineEvaluateToBoolean(ExecState* exec)
2904{
2905 JSValue* v1 = m_expr1->evaluate(exec);
2906 KJS_CHECKEXCEPTIONBOOLEAN
2907 JSValue* v2 = m_expr2->evaluate(exec);
2908 KJS_CHECKEXCEPTIONBOOLEAN
2909
2910 return strictEqual(exec,v1, v2);
2911}
2912
2913JSValue* StrictEqualNode::evaluate(ExecState* exec)
2914{
2915 return jsBoolean(inlineEvaluateToBoolean(exec));
2916}
2917
2918bool StrictEqualNode::evaluateToBoolean(ExecState* exec)
2919{
2920 return inlineEvaluateToBoolean(exec);
2921}
2922
2923void NotStrictEqualNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2924{
2925 nodeStack.append(m_expr2.get());
2926 nodeStack.append(m_expr1.get());
2927}
2928
2929// ECMA 11.9.5
2930bool NotStrictEqualNode::inlineEvaluateToBoolean(ExecState* exec)
2931{
2932 JSValue* v1 = m_expr1->evaluate(exec);
2933 KJS_CHECKEXCEPTIONBOOLEAN
2934 JSValue* v2 = m_expr2->evaluate(exec);
2935 KJS_CHECKEXCEPTIONBOOLEAN
2936
2937 return !strictEqual(exec,v1, v2);
2938}
2939
2940JSValue* NotStrictEqualNode::evaluate(ExecState* exec)
2941{
2942 return jsBoolean(inlineEvaluateToBoolean(exec));
2943}
2944
2945bool NotStrictEqualNode::evaluateToBoolean(ExecState* exec)
2946{
2947 return inlineEvaluateToBoolean(exec);
2948}
2949
2950// ------------------------------ Bit Operation Nodes ----------------------------------
2951
2952void BitAndNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2953{
2954 nodeStack.append(m_expr2.get());
2955 nodeStack.append(m_expr1.get());
2956}
2957
2958// ECMA 11.10
2959JSValue* BitAndNode::evaluate(ExecState* exec)
2960{
2961 JSValue* v1 = m_expr1->evaluate(exec);
2962 KJS_CHECKEXCEPTIONVALUE
2963 JSValue* v2 = m_expr2->evaluate(exec);
2964 KJS_CHECKEXCEPTIONVALUE
2965
2966 return jsNumberFromAnd(exec, v1, v2);
2967}
2968
2969int32_t BitAndNode::inlineEvaluateToInt32(ExecState* exec)
2970{
2971 int32_t i1 = m_expr1->evaluateToInt32(exec);
2972 KJS_CHECKEXCEPTIONNUMBER
2973 int32_t i2 = m_expr2->evaluateToInt32(exec);
2974 return (i1 & i2);
2975}
2976
2977double BitAndNode::evaluateToNumber(ExecState* exec)
2978{
2979 return inlineEvaluateToInt32(exec);
2980}
2981
2982bool BitAndNode::evaluateToBoolean(ExecState* exec)
2983{
2984 return inlineEvaluateToInt32(exec);
2985}
2986
2987int32_t BitAndNode::evaluateToInt32(ExecState* exec)
2988{
2989 return inlineEvaluateToInt32(exec);
2990}
2991
2992uint32_t BitAndNode::evaluateToUInt32(ExecState* exec)
2993{
2994 return inlineEvaluateToInt32(exec);
2995}
2996
2997void BitXOrNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
2998{
2999 nodeStack.append(m_expr2.get());
3000 nodeStack.append(m_expr1.get());
3001}
3002
3003int32_t BitXOrNode::inlineEvaluateToInt32(ExecState* exec)
3004{
3005 int i1 = m_expr1->evaluateToInt32(exec);
3006 KJS_CHECKEXCEPTIONNUMBER
3007 int i2 = m_expr2->evaluateToInt32(exec);
3008 return (i1 ^ i2);
3009}
3010
3011JSValue* BitXOrNode::evaluate(ExecState* exec)
3012{
3013 return jsNumber(inlineEvaluateToInt32(exec));
3014}
3015
3016double BitXOrNode::evaluateToNumber(ExecState* exec)
3017{
3018 return inlineEvaluateToInt32(exec);
3019}
3020
3021bool BitXOrNode::evaluateToBoolean(ExecState* exec)
3022{
3023 return inlineEvaluateToInt32(exec);
3024}
3025
3026int32_t BitXOrNode::evaluateToInt32(ExecState* exec)
3027{
3028 return inlineEvaluateToInt32(exec);
3029}
3030
3031uint32_t BitXOrNode::evaluateToUInt32(ExecState* exec)
3032{
3033 return inlineEvaluateToInt32(exec);
3034}
3035
3036void BitOrNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3037{
3038 nodeStack.append(m_expr2.get());
3039 nodeStack.append(m_expr1.get());
3040}
3041
3042int32_t BitOrNode::inlineEvaluateToInt32(ExecState* exec)
3043{
3044 int i1 = m_expr1->evaluateToInt32(exec);
3045 KJS_CHECKEXCEPTIONNUMBER
3046 int i2 = m_expr2->evaluateToInt32(exec);
3047 return (i1 | i2);
3048}
3049
3050JSValue* BitOrNode::evaluate(ExecState* exec)
3051{
3052 return jsNumber(inlineEvaluateToInt32(exec));
3053}
3054
3055double BitOrNode::evaluateToNumber(ExecState* exec)
3056{
3057 return inlineEvaluateToInt32(exec);
3058}
3059
3060bool BitOrNode::evaluateToBoolean(ExecState* exec)
3061{
3062 return inlineEvaluateToInt32(exec);
3063}
3064
3065int32_t BitOrNode::evaluateToInt32(ExecState* exec)
3066{
3067 return inlineEvaluateToInt32(exec);
3068}
3069
3070uint32_t BitOrNode::evaluateToUInt32(ExecState* exec)
3071{
3072 return inlineEvaluateToInt32(exec);
3073}
3074
3075// ------------------------------ Binary Logical Nodes ----------------------------
3076
3077void LogicalAndNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3078{
3079 nodeStack.append(m_expr2.get());
3080 nodeStack.append(m_expr1.get());
3081}
3082
3083// ECMA 11.11
3084JSValue* LogicalAndNode::evaluate(ExecState* exec)
3085{
3086 JSValue* v1 = m_expr1->evaluate(exec);
3087 KJS_CHECKEXCEPTIONVALUE
3088 bool b1 = v1->toBoolean(exec);
3089 KJS_CHECKEXCEPTIONVALUE
3090 if (!b1)
3091 return v1;
3092 JSValue* v2 = m_expr2->evaluate(exec);
3093 KJS_CHECKEXCEPTIONVALUE
3094 return v2;
3095}
3096
3097bool LogicalAndNode::evaluateToBoolean(ExecState* exec)
3098{
3099 bool b = m_expr1->evaluateToBoolean(exec);
3100 KJS_CHECKEXCEPTIONBOOLEAN
3101 return b && m_expr2->evaluateToBoolean(exec);
3102}
3103
3104void LogicalOrNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3105{
3106 nodeStack.append(m_expr2.get());
3107 nodeStack.append(m_expr1.get());
3108}
3109
3110JSValue* LogicalOrNode::evaluate(ExecState* exec)
3111{
3112 JSValue* v1 = m_expr1->evaluate(exec);
3113 KJS_CHECKEXCEPTIONVALUE
3114 if (v1->toBoolean(exec))
3115 return v1;
3116 return m_expr2->evaluate(exec);
3117}
3118
3119bool LogicalOrNode::evaluateToBoolean(ExecState* exec)
3120{
3121 bool b = m_expr1->evaluateToBoolean(exec);
3122 KJS_CHECKEXCEPTIONBOOLEAN
3123 return b || m_expr2->evaluateToBoolean(exec);
3124}
3125
3126// ------------------------------ ConditionalNode ------------------------------
3127
3128void ConditionalNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3129{
3130 nodeStack.append(m_expr2.get());
3131 nodeStack.append(m_expr1.get());
3132 nodeStack.append(m_logical.get());
3133}
3134
3135// ECMA 11.12
3136JSValue* ConditionalNode::evaluate(ExecState* exec)
3137{
3138 bool b = m_logical->evaluateToBoolean(exec);
3139 KJS_CHECKEXCEPTIONVALUE
3140 return b ? m_expr1->evaluate(exec) : m_expr2->evaluate(exec);
3141}
3142
3143bool ConditionalNode::evaluateToBoolean(ExecState* exec)
3144{
3145 bool b = m_logical->evaluateToBoolean(exec);
3146 KJS_CHECKEXCEPTIONBOOLEAN
3147 return b ? m_expr1->evaluateToBoolean(exec) : m_expr2->evaluateToBoolean(exec);
3148}
3149
3150double ConditionalNode::evaluateToNumber(ExecState* exec)
3151{
3152 bool b = m_logical->evaluateToBoolean(exec);
3153 KJS_CHECKEXCEPTIONNUMBER
3154 return b ? m_expr1->evaluateToNumber(exec) : m_expr2->evaluateToNumber(exec);
3155}
3156
3157int32_t ConditionalNode::evaluateToInt32(ExecState* exec)
3158{
3159 bool b = m_logical->evaluateToBoolean(exec);
3160 KJS_CHECKEXCEPTIONNUMBER
3161 return b ? m_expr1->evaluateToInt32(exec) : m_expr2->evaluateToInt32(exec);
3162}
3163
3164uint32_t ConditionalNode::evaluateToUInt32(ExecState* exec)
3165{
3166 bool b = m_logical->evaluateToBoolean(exec);
3167 KJS_CHECKEXCEPTIONNUMBER
3168 return b ? m_expr1->evaluateToUInt32(exec) : m_expr2->evaluateToUInt32(exec);
3169}
3170
3171// ECMA 11.13
3172
3173static ALWAYS_INLINE JSValue* valueForReadModifyAssignment(ExecState* exec, JSValue* current, ExpressionNode* right, Operator oper) KJS_FAST_CALL;
3174static ALWAYS_INLINE JSValue* valueForReadModifyAssignment(ExecState* exec, JSValue* current, ExpressionNode* right, Operator oper)
3175{
3176 JSValue* v;
3177 int i1;
3178 int i2;
3179 unsigned int ui;
3180 switch (oper) {
3181 case OpMultEq:
3182 v = jsNumber(current->toNumber(exec) * right->evaluateToNumber(exec));
3183 break;
3184 case OpDivEq:
3185 v = jsNumber(current->toNumber(exec) / right->evaluateToNumber(exec));
3186 break;
3187 case OpPlusEq:
3188 v = add(exec, current, right->evaluate(exec));
3189 break;
3190 case OpMinusEq:
3191 v = jsNumber(current->toNumber(exec) - right->evaluateToNumber(exec));
3192 break;
3193 case OpLShift:
3194 i1 = current->toInt32(exec);
3195 i2 = right->evaluateToInt32(exec);
3196 v = jsNumber(i1 << i2);
3197 break;
3198 case OpRShift:
3199 i1 = current->toInt32(exec);
3200 i2 = right->evaluateToInt32(exec);
3201 v = jsNumber(i1 >> i2);
3202 break;
3203 case OpURShift:
3204 ui = current->toUInt32(exec);
3205 i2 = right->evaluateToInt32(exec);
3206 v = jsNumber(ui >> i2);
3207 break;
3208 case OpAndEq:
3209 i1 = current->toInt32(exec);
3210 i2 = right->evaluateToInt32(exec);
3211 v = jsNumber(i1 & i2);
3212 break;
3213 case OpXOrEq:
3214 i1 = current->toInt32(exec);
3215 i2 = right->evaluateToInt32(exec);
3216 v = jsNumber(i1 ^ i2);
3217 break;
3218 case OpOrEq:
3219 i1 = current->toInt32(exec);
3220 i2 = right->evaluateToInt32(exec);
3221 v = jsNumber(i1 | i2);
3222 break;
3223 case OpModEq: {
3224 double d1 = current->toNumber(exec);
3225 double d2 = right->evaluateToNumber(exec);
3226 v = jsNumber(fmod(d1, d2));
3227 }
3228 break;
3229 default:
3230 ASSERT_NOT_REACHED();
3231 v = jsUndefined();
3232 }
3233
3234 return v;
3235}
3236
3237// ------------------------------ ReadModifyResolveNode -----------------------------------
3238
3239void ReadModifyResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack& nodeStack)
3240{
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);
3246 else
3247 new (this) ReadModifyLocalVarNode(index);
3248 }
3249}
3250
3251// ------------------------------ AssignResolveNode -----------------------------------
3252
3253void AssignResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack& nodeStack)
3254{
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;
3260 else
3261 new (this) AssignLocalVarNode(index);
3262 }
3263}
3264
3265// ------------------------------ ReadModifyLocalVarNode -----------------------------------
3266
3267JSValue* ReadModifyLocalVarNode::evaluate(ExecState* exec)
3268{
3269 ASSERT(exec->variableObject() == exec->scopeChain().top());
3270
3271 ASSERT(m_operator != OpEqual);
3272 JSValue* v = valueForReadModifyAssignment(exec, exec->localStorage()[m_index].value, m_right.get(), m_operator);
3273
3274 KJS_CHECKEXCEPTIONVALUE
3275
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().
3279
3280 exec->localStorage()[m_index].value = v;
3281 return v;
3282}
3283
3284// ------------------------------ AssignLocalVarNode -----------------------------------
3285
3286JSValue* AssignLocalVarNode::evaluate(ExecState* exec)
3287{
3288 ASSERT(exec->variableObject() == exec->scopeChain().top());
3289 JSValue* v = m_right->evaluate(exec);
3290
3291 KJS_CHECKEXCEPTIONVALUE
3292
3293 exec->localStorage()[m_index].value = v;
3294
3295 return v;
3296}
3297
3298// ------------------------------ ReadModifyConstNode -----------------------------------
3299
3300JSValue* ReadModifyConstNode::evaluate(ExecState* exec)
3301{
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
3307 return result;
3308}
3309
3310// ------------------------------ AssignConstNode -----------------------------------
3311
3312JSValue* AssignConstNode::evaluate(ExecState* exec)
3313{
3314 return m_right->evaluate(exec);
3315}
3316
3317JSValue* ReadModifyResolveNode::evaluate(ExecState* exec)
3318{
3319 const ScopeChain& chain = exec->scopeChain();
3320 ScopeChainIterator iter = chain.begin();
3321 ScopeChainIterator end = chain.end();
3322
3323 // We must always have something in the scope chain
3324 ASSERT(iter != end);
3325
3326 PropertySlot slot;
3327 JSObject* base;
3328 do {
3329 base = *iter;
3330 if (base->getPropertySlot(exec, m_ident, slot)) {
3331 // See the comment in PostIncResolveNode::evaluate().
3332
3333 base = *iter;
3334 goto found;
3335 }
3336
3337 ++iter;
3338 } while (iter != end);
3339
3340 ASSERT(m_operator != OpEqual);
3341 return throwUndefinedVariableError(exec, m_ident);
3342
3343found:
3344 JSValue* v;
3345
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);
3350
3351 KJS_CHECKEXCEPTIONVALUE
3352
3353 // Since valueForReadModifyAssignment() might cause an ActivationImp tear-off,
3354 // we need to get the base from the ScopeChainIterator again.
3355
3356 (*iter)->put(exec, m_ident, v);
3357 return v;
3358}
3359
3360JSValue* AssignResolveNode::evaluate(ExecState* exec)
3361{
3362 const ScopeChain& chain = exec->scopeChain();
3363 ScopeChainIterator iter = chain.begin();
3364 ScopeChainIterator end = chain.end();
3365
3366 // we must always have something in the scope chain
3367 ASSERT(iter != end);
3368
3369 PropertySlot slot;
3370 JSObject* base;
3371 do {
3372 base = *iter;
3373 if (base->getPropertySlot(exec, m_ident, slot)) {
3374 // See the comment in PostIncResolveNode::evaluate().
3375
3376 base = *iter;
3377 goto found;
3378 }
3379
3380 ++iter;
3381 } while (iter != end);
3382
3383found:
3384 JSValue* v = m_right->evaluate(exec);
3385
3386 KJS_CHECKEXCEPTIONVALUE
3387
3388 base->put(exec, m_ident, v);
3389 return v;
3390}
3391
3392// ------------------------------ ReadModifyDotNode -----------------------------------
3393
3394void AssignDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3395{
3396 nodeStack.append(m_right.get());
3397 nodeStack.append(m_base.get());
3398}
3399
3400JSValue* AssignDotNode::evaluate(ExecState* exec)
3401{
3402 JSValue* baseValue = m_base->evaluate(exec);
3403 KJS_CHECKEXCEPTIONVALUE
3404 JSObject* base = baseValue->toObject(exec);
3405
3406 JSValue* v = m_right->evaluate(exec);
3407
3408 KJS_CHECKEXCEPTIONVALUE
3409
3410 base->put(exec, m_ident, v);
3411 return v;
3412}
3413
3414void ReadModifyDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3415{
3416 nodeStack.append(m_right.get());
3417 nodeStack.append(m_base.get());
3418}
3419
3420JSValue* ReadModifyDotNode::evaluate(ExecState* exec)
3421{
3422 JSValue* baseValue = m_base->evaluate(exec);
3423 KJS_CHECKEXCEPTIONVALUE
3424 JSObject* base = baseValue->toObject(exec);
3425
3426 JSValue* v;
3427
3428 ASSERT(m_operator != OpEqual);
3429 PropertySlot slot;
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);
3433
3434 KJS_CHECKEXCEPTIONVALUE
3435
3436 base->put(exec, m_ident, v);
3437 return v;
3438}
3439
3440// ------------------------------ AssignErrorNode -----------------------------------
3441
3442JSValue* AssignErrorNode::evaluate(ExecState* exec)
3443{
3444 throwError(exec, ReferenceError, "Left side of assignment is not a reference.");
3445 handleException(exec);
3446 return jsUndefined();
3447}
3448
3449// ------------------------------ AssignBracketNode -----------------------------------
3450
3451void AssignBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3452{
3453 nodeStack.append(m_right.get());
3454 nodeStack.append(m_subscript.get());
3455 nodeStack.append(m_base.get());
3456}
3457
3458JSValue* AssignBracketNode::evaluate(ExecState* exec)
3459{
3460 JSValue* baseValue = m_base->evaluate(exec);
3461 KJS_CHECKEXCEPTIONVALUE
3462 JSValue* subscript = m_subscript->evaluate(exec);
3463 KJS_CHECKEXCEPTIONVALUE
3464
3465 JSObject* base = baseValue->toObject(exec);
3466
3467 uint32_t propertyIndex;
3468 if (subscript->getUInt32(propertyIndex)) {
3469 JSValue* v = m_right->evaluate(exec);
3470 KJS_CHECKEXCEPTIONVALUE
3471
3472 base->put(exec, propertyIndex, v);
3473 return v;
3474 }
3475
3476 Identifier propertyName(subscript->toString(exec));
3477 JSValue* v = m_right->evaluate(exec);
3478 KJS_CHECKEXCEPTIONVALUE
3479
3480 base->put(exec, propertyName, v);
3481 return v;
3482}
3483void ReadModifyBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3484{
3485 nodeStack.append(m_right.get());
3486 nodeStack.append(m_subscript.get());
3487 nodeStack.append(m_base.get());
3488}
3489
3490JSValue* ReadModifyBracketNode::evaluate(ExecState* exec)
3491{
3492 JSValue* baseValue = m_base->evaluate(exec);
3493 KJS_CHECKEXCEPTIONVALUE
3494 JSValue* subscript = m_subscript->evaluate(exec);
3495 KJS_CHECKEXCEPTIONVALUE
3496
3497 JSObject* base = baseValue->toObject(exec);
3498
3499 uint32_t propertyIndex;
3500 if (subscript->getUInt32(propertyIndex)) {
3501 JSValue* v;
3502 ASSERT(m_operator != OpEqual);
3503 PropertySlot slot;
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);
3507
3508 KJS_CHECKEXCEPTIONVALUE
3509
3510 base->put(exec, propertyIndex, v);
3511 return v;
3512 }
3513
3514 Identifier propertyName(subscript->toString(exec));
3515 JSValue* v;
3516
3517 ASSERT(m_operator != OpEqual);
3518 PropertySlot slot;
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);
3522
3523 KJS_CHECKEXCEPTIONVALUE
3524
3525 base->put(exec, propertyName, v);
3526 return v;
3527}
3528
3529// ------------------------------ CommaNode ------------------------------------
3530
3531void CommaNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3532{
3533 nodeStack.append(m_expr2.get());
3534 nodeStack.append(m_expr1.get());
3535}
3536
3537// ECMA 11.14
3538JSValue* CommaNode::evaluate(ExecState* exec)
3539{
3540 m_expr1->evaluate(exec);
3541 KJS_CHECKEXCEPTIONVALUE
3542 return m_expr2->evaluate(exec);
3543}
3544
3545// ------------------------------ ConstDeclNode ----------------------------------
3546
3547ConstDeclNode::ConstDeclNode(const Identifier& ident, ExpressionNode* init)
3548 : m_ident(ident)
3549 , m_init(init)
3550{
3551}
3552
3553void ConstDeclNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3554{
3555 if (m_next)
3556 nodeStack.append(m_next.get());
3557 if (m_init)
3558 nodeStack.append(m_init.get());
3559}
3560
3561void ConstDeclNode::handleSlowCase(ExecState* exec, const ScopeChain& chain, JSValue* val)
3562{
3563 ScopeChainIterator iter = chain.begin();
3564 ScopeChainIterator end = chain.end();
3565
3566 // We must always have something in the scope chain
3567 ASSERT(iter != end);
3568
3569 PropertySlot slot;
3570 JSObject* base;
3571
3572 do {
3573 base = *iter;
3574 if (base->getPropertySlot(exec, m_ident, slot))
3575 break;
3576
3577 ++iter;
3578 } while (iter != end);
3579
3580 unsigned flags = 0;
3581 base->getPropertyAttributes(m_ident, flags);
3582 flags |= ReadOnly;
3583
3584 base->put(exec, m_ident, val, flags);
3585}
3586
3587// ECMA 12.2
3588inline void ConstDeclNode::evaluateSingle(ExecState* exec)
3589{
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();
3593
3594 ASSERT(!chain.isEmpty());
3595
3596 bool inGlobalScope = ++chain.begin() == chain.end();
3597
3598 if (m_init) {
3599 if (inGlobalScope) {
3600 JSValue* val = m_init->evaluate(exec);
3601 int flags = Internal;
3602 if (exec->codeType() != EvalCode)
3603 flags |= DontDelete;
3604 flags |= ReadOnly;
3605 variableObject->put(exec, m_ident, val, flags);
3606 } else {
3607 JSValue* val = m_init->evaluate(exec);
3608 KJS_CHECKEXCEPTIONVOID
3609
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);
3615
3616 unsigned flags = 0;
3617 variableObject->getPropertyAttributes(m_ident, flags);
3618 flags |= ReadOnly;
3619
3620 variableObject->put(exec, m_ident, val, flags);
3621 }
3622 }
3623}
3624
3625JSValue* ConstDeclNode::evaluate(ExecState* exec)
3626{
3627 evaluateSingle(exec);
3628
3629 if (ConstDeclNode* n = m_next.get()) {
3630 do {
3631 n->evaluateSingle(exec);
3632 KJS_CHECKEXCEPTIONVALUE
3633 n = n->m_next.get();
3634 } while (n);
3635 }
3636 return jsUndefined();
3637}
3638
3639// ------------------------------ ConstStatementNode -----------------------------
3640
3641void ConstStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3642{
3643 ASSERT(m_next);
3644 nodeStack.append(m_next.get());
3645}
3646
3647// ECMA 12.2
3648JSValue* ConstStatementNode::execute(ExecState* exec)
3649{
3650 m_next->evaluate(exec);
3651 KJS_CHECKEXCEPTION
3652
3653 return exec->setNormalCompletion();
3654}
3655
3656// ------------------------------ Helper functions for handling Vectors of StatementNode -------------------------------
3657
3658static inline void statementListPushFIFO(StatementVector& statements, DeclarationStacks::NodeStack& stack)
3659{
3660 StatementVector::iterator it = statements.end();
3661 StatementVector::iterator begin = statements.begin();
3662 while (it != begin) {
3663 --it;
3664 stack.append((*it).get());
3665 }
3666}
3667
3668static inline Node* statementListInitializeVariableAccessStack(StatementVector& statements, DeclarationStacks::NodeStack& stack)
3669{
3670 if (statements.isEmpty())
3671 return 0;
3672
3673 StatementVector::iterator it = statements.end();
3674 StatementVector::iterator begin = statements.begin();
3675 StatementVector::iterator beginPlusOne = begin + 1;
3676
3677 while (it != beginPlusOne) {
3678 --it;
3679 stack.append((*it).get());
3680 }
3681
3682 return (*begin).get();
3683}
3684
3685static inline JSValue* statementListExecute(StatementVector& statements, ExecState* exec)
3686{
3687 JSValue* value = 0;
3688 size_t size = statements.size();
3689 for (size_t i = 0; i != size; ++i) {
3690 JSValue* statementValue = statements[i]->execute(exec);
3691 if (statementValue)
3692 value = statementValue;
3693 if (exec->completionType() != Normal)
3694 return value;
3695 }
3696 return exec->setNormalCompletion(value);
3697}
3698
3699// ------------------------------ BlockNode ------------------------------------
3700
3701BlockNode::BlockNode(SourceElements* children)
3702{
3703 if (children)
3704 children->releaseContentsIntoVector(m_children);
3705}
3706
3707void BlockNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3708{
3709 statementListPushFIFO(m_children, nodeStack);
3710}
3711
3712// ECMA 12.1
3713JSValue* BlockNode::execute(ExecState* exec)
3714{
3715 return statementListExecute(m_children, exec);
3716}
3717
3718// ------------------------------ EmptyStatementNode ---------------------------
3719
3720// ECMA 12.3
3721JSValue* EmptyStatementNode::execute(ExecState* exec)
3722{
3723 return exec->setNormalCompletion();
3724}
3725
3726// ------------------------------ ExprStatementNode ----------------------------
3727
3728void ExprStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3729{
3730 ASSERT(m_expr);
3731 nodeStack.append(m_expr.get());
3732}
3733
3734// ECMA 12.4
3735JSValue* ExprStatementNode::execute(ExecState* exec)
3736{
3737 JSValue* value = m_expr->evaluate(exec);
3738 KJS_CHECKEXCEPTION
3739
3740 return exec->setNormalCompletion(value);
3741}
3742
3743// ------------------------------ VarStatementNode ----------------------------
3744
3745void VarStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3746{
3747 ASSERT(m_expr);
3748 nodeStack.append(m_expr.get());
3749}
3750
3751JSValue* VarStatementNode::execute(ExecState* exec)
3752{
3753 m_expr->evaluate(exec);
3754 KJS_CHECKEXCEPTION
3755
3756 return exec->setNormalCompletion();
3757}
3758
3759// ------------------------------ IfNode ---------------------------------------
3760
3761void IfNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3762{
3763 nodeStack.append(m_ifBlock.get());
3764 nodeStack.append(m_condition.get());
3765}
3766
3767// ECMA 12.5
3768JSValue* IfNode::execute(ExecState* exec)
3769{
3770 bool b = m_condition->evaluateToBoolean(exec);
3771 KJS_CHECKEXCEPTION
3772
3773 if (b)
3774 return m_ifBlock->execute(exec);
3775 return exec->setNormalCompletion();
3776}
3777
3778void IfElseNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack& nodeStack)
3779{
3780 nodeStack.append(m_elseBlock.get());
3781 IfNode::optimizeVariableAccess(symbolTable, localStorage, nodeStack);
3782}
3783
3784// ECMA 12.5
3785JSValue* IfElseNode::execute(ExecState* exec)
3786{
3787 bool b = m_condition->evaluateToBoolean(exec);
3788 KJS_CHECKEXCEPTION
3789
3790 if (b)
3791 return m_ifBlock->execute(exec);
3792 return m_elseBlock->execute(exec);
3793}
3794
3795// ------------------------------ DoWhileNode ----------------------------------
3796
3797void DoWhileNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3798{
3799 nodeStack.append(m_statement.get());
3800 nodeStack.append(m_expr.get());
3801}
3802
3803// ECMA 12.6.1
3804JSValue* DoWhileNode::execute(ExecState* exec)
3805{
3806 JSValue* value = 0;
3807
3808 while (1) {
3809 exec->pushIteration();
3810 JSValue* statementValue = m_statement->execute(exec);
3811 exec->popIteration();
3812
3813 if (exec->dynamicGlobalObject()->timedOut())
3814 return setInterruptedCompletion(exec);
3815
3816 if (statementValue)
3817 value = statementValue;
3818
3819 if (exec->completionType() != Normal) {
3820 if (exec->completionType() == Continue && m_labelStack.contains(exec->breakOrContinueTarget()))
3821 goto continueDoWhileLoop;
3822 if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
3823 break;
3824 return statementValue;
3825 }
3826
3827 continueDoWhileLoop:
3828 bool b = m_expr->evaluateToBoolean(exec);
3829 KJS_CHECKEXCEPTION
3830 if (!b)
3831 break;
3832 }
3833
3834 return exec->setNormalCompletion(value);
3835}
3836
3837// ------------------------------ WhileNode ------------------------------------
3838
3839void WhileNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3840{
3841 nodeStack.append(m_statement.get());
3842 nodeStack.append(m_expr.get());
3843}
3844
3845// ECMA 12.6.2
3846JSValue* WhileNode::execute(ExecState* exec)
3847{
3848 JSValue* value = 0;
3849
3850 while (1) {
3851 bool b = m_expr->evaluateToBoolean(exec);
3852 KJS_CHECKEXCEPTION
3853 if (!b)
3854 break;
3855
3856 exec->pushIteration();
3857 JSValue* statementValue = m_statement->execute(exec);
3858 exec->popIteration();
3859
3860 if (exec->dynamicGlobalObject()->timedOut())
3861 return setInterruptedCompletion(exec);
3862
3863 if (statementValue)
3864 value = statementValue;
3865
3866 if (exec->completionType() != Normal) {
3867 if (exec->completionType() == Continue && m_labelStack.contains(exec->breakOrContinueTarget()))
3868 continue;
3869 if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
3870 break;
3871 return statementValue;
3872 }
3873 }
3874
3875 return exec->setNormalCompletion(value);
3876}
3877
3878// ------------------------------ ForNode --------------------------------------
3879
3880void ForNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3881{
3882 nodeStack.append(m_statement.get());
3883 nodeStack.append(m_expr3.get());
3884 nodeStack.append(m_expr2.get());
3885 nodeStack.append(m_expr1.get());
3886}
3887
3888// ECMA 12.6.3
3889JSValue* ForNode::execute(ExecState* exec)
3890{
3891 JSValue* value = 0;
3892
3893 m_expr1->evaluate(exec);
3894 KJS_CHECKEXCEPTION
3895
3896 while (1) {
3897 bool b = m_expr2->evaluateToBoolean(exec);
3898 KJS_CHECKEXCEPTION
3899 if (!b)
3900 break;
3901
3902 exec->pushIteration();
3903 JSValue* statementValue = m_statement->execute(exec);
3904 exec->popIteration();
3905 if (statementValue)
3906 value = statementValue;
3907
3908 if (exec->dynamicGlobalObject()->timedOut())
3909 return setInterruptedCompletion(exec);
3910
3911 if (exec->completionType() != Normal) {
3912 if (exec->completionType() == Continue && m_labelStack.contains(exec->breakOrContinueTarget()))
3913 goto continueForLoop;
3914 if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
3915 break;
3916 return statementValue;
3917 }
3918
3919 continueForLoop:
3920 m_expr3->evaluate(exec);
3921 KJS_CHECKEXCEPTION
3922 }
3923
3924 return exec->setNormalCompletion(value);
3925}
3926
3927// ------------------------------ ForInNode ------------------------------------
3928
3929ForInNode::ForInNode(ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
3930 : m_init(0L)
3931 , m_lexpr(l)
3932 , m_expr(expr)
3933 , m_statement(statement)
3934 , m_identIsVarDecl(false)
3935{
3936}
3937
3938ForInNode::ForInNode(const Identifier& ident, ExpressionNode* in, ExpressionNode* expr, StatementNode* statement)
3939 : m_ident(ident)
3940 , m_lexpr(new ResolveNode(ident))
3941 , m_expr(expr)
3942 , m_statement(statement)
3943 , m_identIsVarDecl(true)
3944{
3945 if (in)
3946 m_init = new AssignResolveNode(ident, in);
3947 // for( var foo = bar in baz )
3948}
3949
3950void ForInNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
3951{
3952 nodeStack.append(m_statement.get());
3953 nodeStack.append(m_expr.get());
3954 nodeStack.append(m_lexpr.get());
3955 if (m_init)
3956 nodeStack.append(m_init.get());
3957}
3958
3959// ECMA 12.6.4
3960JSValue* ForInNode::execute(ExecState* exec)
3961{
3962 JSValue* value = 0;
3963
3964 if (m_init) {
3965 m_init->evaluate(exec);
3966 KJS_CHECKEXCEPTION
3967 }
3968
3969 JSValue* e = m_expr->evaluate(exec);
3970 KJS_CHECKEXCEPTION
3971
3972 // For Null and Undefined, we want to make sure not to go through
3973 // the loop at all, because toObject will throw an exception.
3974 if (e->isUndefinedOrNull())
3975 return exec->setNormalCompletion();
3976
3977 JSObject* v = e->toObject(exec);
3978 PropertyNameArray propertyNames;
3979 v->getPropertyNames(exec, propertyNames);
3980
3981 PropertyNameArray::const_iterator end = propertyNames.end();
3982 for (PropertyNameArray::const_iterator it = propertyNames.begin(); it != end; ++it) {
3983 const Identifier& name = *it;
3984 if (!v->hasProperty(exec, name))
3985 continue;
3986
3987 JSValue* str = jsOwnedString(name.ustring());
3988
3989 if (m_lexpr->isResolveNode()) {
3990 const Identifier& ident = static_cast<ResolveNode*>(m_lexpr.get())->identifier();
3991
3992 const ScopeChain& chain = exec->scopeChain();
3993 ScopeChainIterator iter = chain.begin();
3994 ScopeChainIterator end = chain.end();
3995
3996 // we must always have something in the scope chain
3997 ASSERT(iter != end);
3998
3999 PropertySlot slot;
4000 JSObject* o;
4001 do {
4002 o = *iter;
4003 if (o->getPropertySlot(exec, ident, slot)) {
4004 o->put(exec, ident, str);
4005 break;
4006 }
4007 ++iter;
4008 } while (iter != end);
4009
4010 if (iter == end)
4011 o->put(exec, ident, str);
4012 } else if (m_lexpr->isDotAccessorNode()) {
4013 const Identifier& ident = static_cast<DotAccessorNode*>(m_lexpr.get())->identifier();
4014 JSValue* v = static_cast<DotAccessorNode*>(m_lexpr.get())->base()->evaluate(exec);
4015 KJS_CHECKEXCEPTION
4016 JSObject* o = v->toObject(exec);
4017
4018 o->put(exec, ident, str);
4019 } else {
4020 ASSERT(m_lexpr->isBracketAccessorNode());
4021 JSValue* v = static_cast<BracketAccessorNode*>(m_lexpr.get())->base()->evaluate(exec);
4022 KJS_CHECKEXCEPTION
4023 JSValue* v2 = static_cast<BracketAccessorNode*>(m_lexpr.get())->subscript()->evaluate(exec);
4024 KJS_CHECKEXCEPTION
4025 JSObject* o = v->toObject(exec);
4026
4027 uint32_t i;
4028 if (v2->getUInt32(i))
4029 o->put(exec, i, str);
4030 o->put(exec, Identifier(v2->toString(exec)), str);
4031 }
4032
4033 KJS_CHECKEXCEPTION
4034
4035 exec->pushIteration();
4036 JSValue* statementValue = m_statement->execute(exec);
4037 exec->popIteration();
4038 if (statementValue)
4039 value = statementValue;
4040
4041 if (exec->completionType() != Normal) {
4042 if (exec->completionType() == Continue && m_labelStack.contains(exec->breakOrContinueTarget()))
4043 continue;
4044 if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
4045 break;
4046 return statementValue;
4047 }
4048 }
4049
4050 return exec->setNormalCompletion(value);
4051}
4052
4053// ------------------------------ ContinueNode ---------------------------------
4054
4055// ECMA 12.7
4056JSValue* ContinueNode::execute(ExecState* exec)
4057{
4058 if (m_ident.isEmpty() && !exec->inIteration())
4059 return setErrorCompletion(exec, SyntaxError, "Invalid continue statement.");
4060 if (!m_ident.isEmpty() && !exec->seenLabels().contains(m_ident))
4061 return setErrorCompletion(exec, SyntaxError, "Label %s not found.", m_ident);
4062 return exec->setContinueCompletion(&m_ident);
4063}
4064
4065// ------------------------------ BreakNode ------------------------------------
4066
4067// ECMA 12.8
4068JSValue* BreakNode::execute(ExecState* exec)
4069{
4070 if (m_ident.isEmpty() && !exec->inIteration() && !exec->inSwitch())
4071 return setErrorCompletion(exec, SyntaxError, "Invalid break statement.");
4072 if (!m_ident.isEmpty() && !exec->seenLabels().contains(m_ident))
4073 return setErrorCompletion(exec, SyntaxError, "Label %s not found.");
4074 return exec->setBreakCompletion(&m_ident);
4075}
4076
4077// ------------------------------ ReturnNode -----------------------------------
4078
4079void ReturnNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4080{
4081 if (m_value)
4082 nodeStack.append(m_value.get());
4083}
4084
4085// ECMA 12.9
4086JSValue* ReturnNode::execute(ExecState* exec)
4087{
4088 CodeType codeType = exec->codeType();
4089 if (codeType != FunctionCode)
4090 return setErrorCompletion(exec, SyntaxError, "Invalid return statement.");
4091
4092 if (!m_value)
4093 return exec->setReturnValueCompletion(jsUndefined());
4094
4095 JSValue* v = m_value->evaluate(exec);
4096 KJS_CHECKEXCEPTION
4097
4098 return exec->setReturnValueCompletion(v);
4099}
4100
4101// ------------------------------ WithNode -------------------------------------
4102
4103void WithNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4104{
4105 // Can't optimize within statement because "with" introduces a dynamic scope.
4106 nodeStack.append(m_expr.get());
4107}
4108
4109// ECMA 12.10
4110JSValue* WithNode::execute(ExecState* exec)
4111{
4112 JSValue* v = m_expr->evaluate(exec);
4113 KJS_CHECKEXCEPTION
4114 JSObject* o = v->toObject(exec);
4115 KJS_CHECKEXCEPTION
4116 exec->dynamicGlobalObject()->tearOffActivation(exec);
4117 exec->pushScope(o);
4118 JSValue* value = m_statement->execute(exec);
4119 exec->popScope();
4120
4121 return value;
4122}
4123
4124// ------------------------------ CaseClauseNode -------------------------------
4125
4126void CaseClauseNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4127{
4128 if (m_expr)
4129 nodeStack.append(m_expr.get());
4130 statementListPushFIFO(m_children, nodeStack);
4131}
4132
4133// ECMA 12.11
4134JSValue* CaseClauseNode::evaluate(ExecState* exec)
4135{
4136 JSValue* v = m_expr->evaluate(exec);
4137 KJS_CHECKEXCEPTIONVALUE
4138
4139 return v;
4140}
4141
4142// ECMA 12.11
4143JSValue* CaseClauseNode::executeStatements(ExecState* exec)
4144{
4145 return statementListExecute(m_children, exec);
4146}
4147
4148// ------------------------------ ClauseListNode -------------------------------
4149
4150void ClauseListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4151{
4152 if (m_next)
4153 nodeStack.append(m_next.get());
4154 nodeStack.append(m_clause.get());
4155}
4156
4157// ------------------------------ CaseBlockNode --------------------------------
4158
4159CaseBlockNode::CaseBlockNode(ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2)
4160 : m_list1(list1)
4161 , m_defaultClause(defaultClause)
4162 , m_list2(list2)
4163{
4164}
4165
4166void CaseBlockNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4167{
4168 if (m_list2)
4169 nodeStack.append(m_list2.get());
4170 if (m_defaultClause)
4171 nodeStack.append(m_defaultClause.get());
4172 if (m_list1)
4173 nodeStack.append(m_list1.get());
4174}
4175
4176// ECMA 12.11
4177JSValue* CaseBlockNode::executeBlock(ExecState* exec, JSValue* input)
4178{
4179 ClauseListNode* a = m_list1.get();
4180 while (a) {
4181 CaseClauseNode* clause = a->getClause();
4182 a = a->getNext();
4183 JSValue* v = clause->evaluate(exec);
4184 KJS_CHECKEXCEPTION
4185 if (strictEqual(exec, input, v)) {
4186 JSValue* res = clause->executeStatements(exec);
4187 if (exec->completionType() != Normal)
4188 return res;
4189 for (; a; a = a->getNext()) {
4190 JSValue* res = a->getClause()->executeStatements(exec);
4191 if (exec->completionType() != Normal)
4192 return res;
4193 }
4194 break;
4195 }
4196 }
4197
4198 ClauseListNode* b = m_list2.get();
4199 while (b) {
4200 CaseClauseNode* clause = b->getClause();
4201 b = b->getNext();
4202 JSValue* v = clause->evaluate(exec);
4203 KJS_CHECKEXCEPTION
4204 if (strictEqual(exec, input, v)) {
4205 JSValue* res = clause->executeStatements(exec);
4206 if (exec->completionType() != Normal)
4207 return res;
4208 goto step18;
4209 }
4210 }
4211
4212 // default clause
4213 if (m_defaultClause) {
4214 JSValue* res = m_defaultClause->executeStatements(exec);
4215 if (exec->completionType() != Normal)
4216 return res;
4217 }
4218 b = m_list2.get();
4219step18:
4220 while (b) {
4221 CaseClauseNode* clause = b->getClause();
4222 JSValue* res = clause->executeStatements(exec);
4223 if (exec->completionType() != Normal)
4224 return res;
4225 b = b->getNext();
4226 }
4227
4228 // bail out on error
4229 KJS_CHECKEXCEPTION
4230
4231 return exec->setNormalCompletion();
4232}
4233
4234// ------------------------------ SwitchNode -----------------------------------
4235
4236void SwitchNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4237{
4238 nodeStack.append(m_block.get());
4239 nodeStack.append(m_expr.get());
4240}
4241
4242// ECMA 12.11
4243JSValue* SwitchNode::execute(ExecState* exec)
4244{
4245 JSValue* v = m_expr->evaluate(exec);
4246 KJS_CHECKEXCEPTION
4247
4248 exec->pushSwitch();
4249 JSValue* result = m_block->executeBlock(exec, v);
4250 exec->popSwitch();
4251
4252 if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
4253 exec->setCompletionType(Normal);
4254 return result;
4255}
4256
4257// ------------------------------ LabelNode ------------------------------------
4258
4259void LabelNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4260{
4261 nodeStack.append(m_statement.get());
4262}
4263
4264// ECMA 12.12
4265JSValue* LabelNode::execute(ExecState* exec)
4266{
4267 if (!exec->seenLabels().push(m_label))
4268 return setErrorCompletion(exec, SyntaxError, "Duplicated label %s found.", m_label);
4269 JSValue* result = m_statement->execute(exec);
4270 exec->seenLabels().pop();
4271
4272 if (exec->completionType() == Break && exec->breakOrContinueTarget() == m_label)
4273 exec->setCompletionType(Normal);
4274 return result;
4275}
4276
4277// ------------------------------ ThrowNode ------------------------------------
4278
4279void ThrowNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4280{
4281 nodeStack.append(m_expr.get());
4282}
4283
4284// ECMA 12.13
4285JSValue* ThrowNode::execute(ExecState* exec)
4286{
4287 JSValue* v = m_expr->evaluate(exec);
4288 KJS_CHECKEXCEPTION
4289
4290 handleException(exec, v);
4291 return exec->setThrowCompletion(v);
4292}
4293
4294// ------------------------------ TryNode --------------------------------------
4295
4296void TryNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
4297{
4298 // Can't optimize within catchBlock because "catch" introduces a dynamic scope.
4299 if (m_finallyBlock)
4300 nodeStack.append(m_finallyBlock.get());
4301 nodeStack.append(m_tryBlock.get());
4302}
4303
4304// ECMA 12.14
4305JSValue* TryNode::execute(ExecState* exec)
4306{
4307 JSValue* result = m_tryBlock->execute(exec);
4308
4309 if (m_catchBlock && exec->completionType() == Throw) {
4310 JSObject* obj = new JSObject;
4311 obj->put(exec, m_exceptionIdent, result, DontDelete);
4312 exec->dynamicGlobalObject()->tearOffActivation(exec);
4313 exec->pushScope(obj);
4314 result = m_catchBlock->execute(exec);
4315 exec->popScope();
4316 }
4317
4318 if (m_finallyBlock) {
4319 ComplType savedCompletionType = exec->completionType();
4320 JSValue* finallyResult = m_finallyBlock->execute(exec);
4321 if (exec->completionType() != Normal)
4322 result = finallyResult;
4323 else
4324 exec->setCompletionType(savedCompletionType);
4325 }
4326
4327 return result;
4328}
4329
4330// ------------------------------ FunctionBodyNode -----------------------------
4331
4332ScopeNode::ScopeNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4333 : BlockNode(children)
4334 , m_sourceURL(parser().sourceURL())
4335 , m_sourceId(parser().sourceId())
4336{
4337 if (varStack)
4338 m_varStack = *varStack;
4339 if (funcStack)
4340 m_functionStack = *funcStack;
4341}
4342
4343// ------------------------------ ProgramNode -----------------------------
4344
4345ProgramNode::ProgramNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4346 : ScopeNode(children, varStack, funcStack)
4347{
4348}
4349
4350ProgramNode* ProgramNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4351{
4352 return new ProgramNode(children, varStack, funcStack);
4353}
4354
4355// ------------------------------ EvalNode -----------------------------
4356
4357EvalNode::EvalNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4358 : ScopeNode(children, varStack, funcStack)
4359{
4360}
4361
4362EvalNode* EvalNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4363{
4364 return new EvalNode(children, varStack, funcStack);
4365}
4366
4367// ------------------------------ FunctionBodyNode -----------------------------
4368
4369FunctionBodyNode::FunctionBodyNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4370 : ScopeNode(children, varStack, funcStack)
4371 , m_initialized(false)
4372{
4373}
4374
4375FunctionBodyNode* FunctionBodyNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
4376{
4377 if (Debugger::debuggersPresent)
4378 return new FunctionBodyNodeWithDebuggerHooks(children, varStack, funcStack);
4379 return new FunctionBodyNode(children, varStack, funcStack);
4380}
4381
4382void FunctionBodyNode::initializeSymbolTable(ExecState* exec)
4383{
4384 SymbolTable& symbolTable = exec->variableObject()->symbolTable();
4385 ASSERT(symbolTable.isEmpty());
4386
4387 size_t localStorageIndex = 0;
4388
4389 // Order must match the order in processDeclarations.
4390
4391 for (size_t i = 0, size = m_parameters.size(); i < size; ++i, ++localStorageIndex) {
4392 UString::Rep* rep = m_parameters[i].ustring().rep();
4393 symbolTable.set(rep, localStorageIndex);
4394 }
4395
4396 for (size_t i = 0, size = m_functionStack.size(); i < size; ++i, ++localStorageIndex) {
4397 UString::Rep* rep = m_functionStack[i]->m_ident.ustring().rep();
4398 symbolTable.set(rep, localStorageIndex);
4399 }
4400
4401 for (size_t i = 0, size = m_varStack.size(); i < size; ++i, ++localStorageIndex) {
4402 Identifier& ident = m_varStack[i].first;
4403 if (ident == exec->propertyNames().arguments)
4404 continue;
4405 symbolTable.add(ident.ustring().rep(), localStorageIndex);
4406 }
4407}
4408
4409void ProgramNode::initializeSymbolTable(ExecState* exec)
4410{
4411 // If a previous script defined a symbol with the same name as one of our
4412 // symbols, to avoid breaking previously optimized nodes, we need to reuse
4413 // the symbol's existing storage index. So, we can't be as efficient as
4414 // FunctionBodyNode::initializeSymbolTable, which knows that no bindings
4415 // have yet been made.
4416
4417 JSVariableObject* variableObject = exec->variableObject();
4418 SymbolTable& symbolTable = variableObject->symbolTable();
4419
4420 size_t localStorageIndex = symbolTable.size();
4421 size_t size;
4422
4423 // Order must match the order in processDeclarations.
4424
4425 size = m_functionStack.size();
4426 m_functionIndexes.resize(size);
4427 for (size_t i = 0; i < size; ++i) {
4428 UString::Rep* rep = m_functionStack[i]->m_ident.ustring().rep();
4429 pair<SymbolTable::iterator, bool> result = symbolTable.add(rep, localStorageIndex);
4430 m_functionIndexes[i] = result.first->second;
4431 if (result.second)
4432 ++localStorageIndex;
4433 }
4434
4435 size = m_varStack.size();
4436 m_varIndexes.resize(size);
4437 for (size_t i = 0; i < size; ++i) {
4438 const Identifier& ident = m_varStack[i].first;
4439 if (variableObject->hasProperty(exec, ident)) {
4440 m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
4441 continue;
4442 }
4443
4444 UString::Rep* rep = ident.ustring().rep();
4445 pair<SymbolTable::iterator, bool> result = symbolTable.add(rep, localStorageIndex);
4446 if (!result.second) {
4447 m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
4448 continue;
4449 }
4450
4451 m_varIndexes[i] = result.first->second;
4452 ++localStorageIndex;
4453 }
4454}
4455
4456void ScopeNode::optimizeVariableAccess(ExecState* exec)
4457{
4458 NodeStack nodeStack;
4459 Node* node = statementListInitializeVariableAccessStack(m_children, nodeStack);
4460 if (!node)
4461 return;
4462
4463 const SymbolTable& symbolTable = exec->variableObject()->symbolTable();
4464 const LocalStorage& localStorage = exec->variableObject()->localStorage();
4465 while (true) {
4466 node->optimizeVariableAccess(symbolTable, localStorage, nodeStack);
4467
4468 size_t size = nodeStack.size();
4469 if (!size)
4470 break;
4471 --size;
4472 node = nodeStack[size];
4473 nodeStack.shrink(size);
4474 }
4475}
4476
4477void FunctionBodyNode::processDeclarations(ExecState* exec)
4478{
4479 if (!m_initialized)
4480 initializeSymbolTable(exec);
4481
4482 if (!m_functionStack.isEmpty())
4483 exec->dynamicGlobalObject()->tearOffActivation(exec);
4484
4485 LocalStorage& localStorage = exec->variableObject()->localStorage();
4486
4487 // We can't just resize localStorage here because that would temporarily
4488 // leave uninitialized entries, which would crash GC during the mark phase.
4489 size_t totalSize = m_varStack.size() + m_parameters.size() + m_functionStack.size();
4490 if (totalSize > localStorage.capacity()) // Doing this check inline avoids function call overhead.
4491 localStorage.reserveCapacity(totalSize);
4492
4493 int minAttributes = Internal | DontDelete;
4494
4495 // In order for our localStorage indexes to be correct, we must match the
4496 // order of addition in initializeSymbolTable().
4497
4498 const List& args = *exec->arguments();
4499 for (size_t i = 0, size = m_parameters.size(); i < size; ++i)
4500 localStorage.uncheckedAppend(LocalStorageEntry(args[i], DontDelete));
4501
4502 for (size_t i = 0, size = m_functionStack.size(); i < size; ++i) {
4503 FuncDeclNode* node = m_functionStack[i];
4504 localStorage.uncheckedAppend(LocalStorageEntry(node->makeFunction(exec), minAttributes));
4505 }
4506
4507 for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
4508 int attributes = minAttributes;
4509 if (m_varStack[i].second & DeclarationStacks::IsConstant)
4510 attributes |= ReadOnly;
4511 localStorage.uncheckedAppend(LocalStorageEntry(jsUndefined(), attributes));
4512 }
4513
4514 if (!m_initialized) {
4515 optimizeVariableAccess(exec);
4516 m_initialized = true;
4517 }
4518}
4519
4520static void gccIsCrazy() KJS_FAST_CALL;
4521static void gccIsCrazy()
4522{
4523}
4524
4525void ProgramNode::processDeclarations(ExecState* exec)
4526{
4527 // If you remove this call, some SunSpider tests, including
4528 // bitops-nsieve-bits.js, will regress substantially on Mac, due to a ~40%
4529 // increase in L2 cache misses. FIXME: <rdar://problem/5657439> WTF?
4530 gccIsCrazy();
4531
4532 initializeSymbolTable(exec);
4533
4534 LocalStorage& localStorage = exec->variableObject()->localStorage();
4535
4536 // We can't just resize localStorage here because that would temporarily
4537 // leave uninitialized entries, which would crash GC during the mark phase.
4538 localStorage.reserveCapacity(localStorage.size() + m_varStack.size() + m_functionStack.size());
4539
4540 int minAttributes = Internal | DontDelete;
4541
4542 // In order for our localStorage indexes to be correct, we must match the
4543 // order of addition in initializeSymbolTable().
4544
4545 for (size_t i = 0, size = m_functionStack.size(); i < size; ++i) {
4546 FuncDeclNode* node = m_functionStack[i];
4547 LocalStorageEntry entry = LocalStorageEntry(node->makeFunction(exec), minAttributes);
4548 size_t index = m_functionIndexes[i];
4549
4550 if (index == localStorage.size())
4551 localStorage.uncheckedAppend(entry);
4552 else {
4553 ASSERT(index < localStorage.size());
4554 localStorage[index] = entry;
4555 }
4556 }
4557
4558 for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
4559 size_t index = m_varIndexes[i];
4560 if (index == missingSymbolMarker())
4561 continue;
4562
4563 int attributes = minAttributes;
4564 if (m_varStack[i].second & DeclarationStacks::IsConstant)
4565 attributes |= ReadOnly;
4566 LocalStorageEntry entry = LocalStorageEntry(jsUndefined(), attributes);
4567
4568 ASSERT(index == localStorage.size());
4569 localStorage.uncheckedAppend(entry);
4570 }
4571
4572 optimizeVariableAccess(exec);
4573}
4574
4575void EvalNode::processDeclarations(ExecState* exec)
4576{
4577 // We could optimize access to pre-existing symbols here, but SunSpider
4578 // reports that to be a net loss.
4579
4580 size_t i;
4581 size_t size;
4582
4583 JSVariableObject* variableObject = exec->variableObject();
4584
4585 int minAttributes = Internal;
4586
4587 for (i = 0, size = m_varStack.size(); i < size; ++i) {
4588 Identifier& ident = m_varStack[i].first;
4589 if (variableObject->hasProperty(exec, ident))
4590 continue;
4591 int attributes = minAttributes;
4592 if (m_varStack[i].second & DeclarationStacks::IsConstant)
4593 attributes |= ReadOnly;
4594 variableObject->put(exec, ident, jsUndefined(), attributes);
4595 }
4596
4597 for (i = 0, size = m_functionStack.size(); i < size; ++i) {
4598 FuncDeclNode* node = m_functionStack[i];
4599 variableObject->put(exec, node->m_ident, node->makeFunction(exec), minAttributes);
4600 }
4601}
4602
4603UString FunctionBodyNode::paramString() const
4604{
4605 UString s("");
4606 size_t count = m_parameters.size();
4607 for (size_t pos = 0; pos < count; ++pos) {
4608 if (!s.isEmpty())
4609 s += ", ";
4610 s += m_parameters[pos].ustring();
4611 }
4612
4613 return s;
4614}
4615
4616JSValue* ProgramNode::execute(ExecState* exec)
4617{
4618 processDeclarations(exec);
4619 return ScopeNode::execute(exec);
4620}
4621
4622JSValue* EvalNode::execute(ExecState* exec)
4623{
4624 processDeclarations(exec);
4625 return ScopeNode::execute(exec);
4626}
4627
4628JSValue* FunctionBodyNode::execute(ExecState* exec)
4629{
4630 processDeclarations(exec);
4631 return ScopeNode::execute(exec);
4632}
4633
4634// ------------------------------ FunctionBodyNodeWithDebuggerHooks ---------------------------------
4635
4636FunctionBodyNodeWithDebuggerHooks::FunctionBodyNodeWithDebuggerHooks(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
4637 : FunctionBodyNode(children, varStack, funcStack)
4638{
4639}
4640
4641JSValue* FunctionBodyNodeWithDebuggerHooks::execute(ExecState* exec)
4642{
4643 if (Debugger* dbg = exec->dynamicGlobalObject()->debugger()) {
4644 if (!dbg->callEvent(exec, sourceId(), lineNo(), exec->function(), *exec->arguments())) {
4645 dbg->imp()->abort();
4646 return exec->setInterruptedCompletion();
4647 }
4648 }
4649
4650 JSValue* result = FunctionBodyNode::execute(exec);
4651
4652 if (Debugger* dbg = exec->dynamicGlobalObject()->debugger()) {
4653 if (exec->completionType() == Throw)
4654 exec->setException(result);
4655 if (!dbg->returnEvent(exec, sourceId(), lastLine(), exec->function())) {
4656 dbg->imp()->abort();
4657 return exec->setInterruptedCompletion();
4658 }
4659 }
4660
4661 return result;
4662}
4663
4664// ------------------------------ FuncDeclNode ---------------------------------
4665
4666void FuncDeclNode::addParams()
4667{
4668 for (ParameterNode* p = m_parameter.get(); p; p = p->nextParam())
4669 m_body->parameters().append(p->ident());
4670}
4671
4672FunctionImp* FuncDeclNode::makeFunction(ExecState* exec)
4673{
4674 FunctionImp* func = new FunctionImp(exec, m_ident, m_body.get(), exec->scopeChain());
4675
4676 JSObject* proto = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
4677 proto->putDirect(exec->propertyNames().constructor, func, ReadOnly | DontDelete | DontEnum);
4678 func->putDirect(exec->propertyNames().prototype, proto, Internal | DontDelete);
4679 func->putDirect(exec->propertyNames().length, jsNumber(m_body->parameters().size()), ReadOnly | DontDelete | DontEnum);
4680 return func;
4681}
4682
4683JSValue* FuncDeclNode::execute(ExecState* exec)
4684{
4685 return exec->setNormalCompletion();
4686}
4687
4688// ------------------------------ FuncExprNode ---------------------------------
4689
4690// ECMA 13
4691void FuncExprNode::addParams()
4692{
4693 for (ParameterNode* p = m_parameter.get(); p; p = p->nextParam())
4694 m_body->parameters().append(p->ident());
4695}
4696
4697JSValue* FuncExprNode::evaluate(ExecState* exec)
4698{
4699 exec->dynamicGlobalObject()->tearOffActivation(exec);
4700
4701 bool named = !m_ident.isNull();
4702 JSObject* functionScopeObject = 0;
4703
4704 if (named) {
4705 // named FunctionExpressions can recursively call themselves,
4706 // but they won't register with the current scope chain and should
4707 // be contained as single property in an anonymous object.
4708 functionScopeObject = new JSObject;
4709 exec->pushScope(functionScopeObject);
4710 }
4711
4712 FunctionImp* func = new FunctionImp(exec, m_ident, m_body.get(), exec->scopeChain());
4713 JSObject* proto = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
4714 proto->putDirect(exec->propertyNames().constructor, func, ReadOnly | DontDelete | DontEnum);
4715 func->putDirect(exec->propertyNames().prototype, proto, Internal | DontDelete);
4716
4717 if (named) {
4718 functionScopeObject->putDirect(m_ident, func, Internal | ReadOnly | (exec->codeType() == EvalCode ? 0 : DontDelete));
4719 exec->popScope();
4720 }
4721
4722 return func;
4723}
4724
4725} // namespace KJS