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

Last change on this file since 30679 was 30679, checked in by Adam Roben, 17 years ago

Remove unused DebuggerImp::abort and DebuggerImp::aborted

Reviewed by Tim and Sam.

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