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

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

Rubber-stamped by Darin Adler.

  • Fix whitespace in nodes.h/cpp and nodes2string.cpp.

(NOTE: Specific changed functions elided for space and clarity)

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