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

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

Replace post-parse pass to find declarations with logic in the parser itself

Reviewed by Geoff.

Instead of finding declarations in a pass following the initial parsing of
a program, we incorporate the logic directly into the parser. This lays
the groundwork for further optimisations (such as improving performance in
declaration expressions -- var x = y; -- to match that of standard assignment)
in addition to providing a 0.4% performance improvement in SunSpider.

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