source: webkit/trunk/JavaScriptCore/kjs/nodes.cpp@ 31119

Last change on this file since 31119 was 31119, checked in by [email protected], 17 years ago

Optimise multi-scope function call resolution

Reviewed by Geoff

Refactor multiscope variable resolution and use to add
optimised FunctionCallResolveNode subclasses.

2.6% gain in sunspider performance, *25%* gain in controlflow-recursive

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