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

Last change on this file since 27494 was 27494, checked in by eseidel, 18 years ago

2007-11-06 Eric Seidel <[email protected]>

Reviewed by darin.

This fixes a regressed layout test for string + object


SunSpider claims this was an overall 0.3% speedup, although some individual tests were slower.

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