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

Last change on this file since 27252 was 27252, checked in by oliver, 18 years ago

Debranching various Node::evaluate implementations

Reviewed by Maciej.

Split the read-modify-write assignment cases out of AssignResolveNode and into ReadModifyResolveNode
Split the increment and decrement cases for Prefix- and Postfix- ResolveNode, BracketNode, and DotNode

Gains 1.6% on SunSpider

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