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

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

Reviewed by Eric Seidel.


Cleaned up the JavaScript grammar a bit.


  1. Changed BlockNode to always hold a child vector (which may be empty), eliminating a few NULL-check branches in the common execution case.


  1. Changed the Block production to correctly report its starting and ending line numbers to the debugger. (It used to report its ending line as its starting line.) Also, removed duplicate line-reporting code inside the BlockNode constructor.


  1. Moved curly braces up from FunctionBody production into parent productions. (I had to move the line number reporting code, too, since it depends on the location of the curly braces.) This matches the ECMA spec more closely, and makes some future changes I plan easier.


  1. Fixed statementList* convenience functions to deal appropriately with empty Vectors.

SunSpider reports a small and statistically insignificant speedup.

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