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

Last change on this file since 34754 was 34754, checked in by Darin Adler, 17 years ago

JavaScriptCore:

2008-06-23 Darin Adler <Darin Adler>

Reviewed by Geoff.

More preparation toward making functions work on primitive types without
creating wrapper objects. No speedup this time, but prepares for a future
speedup without slowing things down.

SunSpider reports no change.

  • Eliminated the implementsCall, callAsFunction and construct virtual functions from JSObject. Instead, the CallData and ConstructData for a native function includes a function pointer that the caller can use directly. Changed all call sites to use CallData and ConstructData.
  • Changed the "this" argument to native functions to be a JSValue rather than a JSObject. This prepares us for passing primitives into these functions. The conversion to an object now must be done inside the function. Critically, if it's a function that can be called on a DOM window object, then we have to be sure to call toThisObject on the argument before we use it for anything even if it's already an object.
  • Eliminated the practice of using constructor objects in the global object to make objects of the various basic types. Since these constructors can't be replaced by script, there's no reason to involve a constructor object at all. Added functions to do the construction directly.
  • Made some more class members private and protected, including virtual function overrides. This can catch code using unnecessarily slow virtual function code paths when the type of an object is known statically. If we later find a new reason use the members outside the class it's easy to make them public again.
  • Moved the declarations of the native implementations for functions out of header files. These can have internal linkage and be declared inside the source file.
  • Changed PrototypeFunction to take function pointers with the right arguments to be put directly into CallData. This eliminates the need to have a separate PrototypeReflexiveFunction, and reveals that the real purpose of that class included something else specific to eval -- storage of a cached global object. So renamed PrototypeReflexiveFunction to GlobalEvalFunction.
  • API/JSCallbackConstructor.cpp: (KJS::constructJSCallback): (KJS::JSCallbackConstructor::getConstructData):
  • API/JSCallbackConstructor.h:
  • API/JSCallbackFunction.cpp: (KJS::JSCallbackFunction::implementsHasInstance): (KJS::JSCallbackFunction::call): (KJS::JSCallbackFunction::getCallData):
  • API/JSCallbackFunction.h: (KJS::JSCallbackFunction::classInfo):
  • API/JSCallbackObject.h: (KJS::JSCallbackObject::classRef): (KJS::JSCallbackObject::classInfo):
  • API/JSCallbackObjectFunctions.h: (KJS::::getConstructData): (KJS::::construct): (KJS::::getCallData): (KJS::::call):
  • API/JSObjectRef.cpp: (JSObjectMakeFunction): (JSObjectIsFunction): (JSObjectCallAsFunction): (JSObjectCallAsConstructor):
  • JavaScriptCore.exp:
  • VM/Machine.cpp: (KJS::jsTypeStringForValue): (KJS::Machine::privateExecute):
  • kjs/ArrayPrototype.cpp: (KJS::arrayProtoFuncToString): (KJS::arrayProtoFuncToLocaleString): (KJS::arrayProtoFuncJoin): (KJS::arrayProtoFuncConcat): (KJS::arrayProtoFuncPop): (KJS::arrayProtoFuncPush): (KJS::arrayProtoFuncReverse): (KJS::arrayProtoFuncShift): (KJS::arrayProtoFuncSlice): (KJS::arrayProtoFuncSort): (KJS::arrayProtoFuncSplice): (KJS::arrayProtoFuncUnShift): (KJS::arrayProtoFuncFilter): (KJS::arrayProtoFuncMap): (KJS::arrayProtoFuncEvery): (KJS::arrayProtoFuncForEach): (KJS::arrayProtoFuncSome): (KJS::arrayProtoFuncIndexOf): (KJS::arrayProtoFuncLastIndexOf): (KJS::ArrayConstructor::ArrayConstructor): (KJS::constructArrayWithSizeQuirk): (KJS::constructWithArrayConstructor): (KJS::ArrayConstructor::getConstructData): (KJS::callArrayConstructor): (KJS::ArrayConstructor::getCallData):
  • kjs/ArrayPrototype.h:
  • kjs/BooleanObject.cpp: (KJS::booleanProtoFuncToString): (KJS::booleanProtoFuncValueOf): (KJS::constructBoolean): (KJS::constructWithBooleanConstructor): (KJS::BooleanConstructor::getConstructData): (KJS::callBooleanConstructor): (KJS::BooleanConstructor::getCallData): (KJS::constructBooleanFromImmediateBoolean):
  • kjs/BooleanObject.h:
  • kjs/CallData.h: (KJS::):
  • kjs/ConstructData.h: (KJS::):
  • kjs/FunctionPrototype.cpp: (KJS::callFunctionPrototype): (KJS::FunctionPrototype::getCallData): (KJS::functionProtoFuncToString): (KJS::functionProtoFuncApply): (KJS::functionProtoFuncCall): (KJS::constructWithFunctionConstructor): (KJS::FunctionConstructor::getConstructData): (KJS::callFunctionConstructor): (KJS::FunctionConstructor::getCallData): (KJS::constructFunction):
  • kjs/FunctionPrototype.h:
  • kjs/JSArray.cpp: (KJS::AVLTreeAbstractorForArrayCompare::compare_key_key): (KJS::JSArray::sort): (KJS::constructEmptyArray): (KJS::constructArray):
  • kjs/JSArray.h: (KJS::JSArray::classInfo):
  • kjs/JSFunction.cpp: (KJS::JSFunction::call): (KJS::globalFuncEval): (KJS::globalFuncParseInt): (KJS::globalFuncParseFloat): (KJS::globalFuncIsNaN): (KJS::globalFuncIsFinite): (KJS::globalFuncDecodeURI): (KJS::globalFuncDecodeURIComponent): (KJS::globalFuncEncodeURI): (KJS::globalFuncEncodeURIComponent): (KJS::globalFuncEscape): (KJS::globalFuncUnescape): (KJS::globalFuncKJSPrint): (KJS::PrototypeFunction::PrototypeFunction): (KJS::PrototypeFunction::getCallData): (KJS::GlobalEvalFunction::GlobalEvalFunction): (KJS::GlobalEvalFunction::mark):
  • kjs/JSFunction.h: (KJS::InternalFunction::classInfo): (KJS::InternalFunction::functionName): (KJS::JSFunction::classInfo): (KJS::GlobalEvalFunction::cachedGlobalObject):
  • kjs/JSGlobalObject.cpp: (KJS::JSGlobalObject::reset): (KJS::JSGlobalObject::mark):
  • kjs/JSGlobalObject.h: (KJS::JSGlobalObject::JSGlobalObject): (KJS::JSGlobalObject::evalFunction):
  • kjs/JSImmediate.cpp: (KJS::JSImmediate::toObject):
  • kjs/JSNotAnObject.cpp:
  • kjs/JSNotAnObject.h:
  • kjs/JSObject.cpp: (KJS::JSObject::put): (KJS::callDefaultValueFunction): (KJS::JSObject::defaultValue): (KJS::JSObject::lookupGetter): (KJS::JSObject::lookupSetter): (KJS::JSObject::hasInstance): (KJS::JSObject::fillGetterPropertySlot): (KJS::Error::create): (KJS::constructEmptyObject):
  • kjs/JSObject.h: (KJS::GetterSetter::GetterSetter): (KJS::GetterSetter::getter): (KJS::GetterSetter::setGetter): (KJS::GetterSetter::setter): (KJS::GetterSetter::setSetter):
  • kjs/JSValue.cpp: (KJS::JSCell::deleteProperty): (KJS::call): (KJS::construct):
  • kjs/JSValue.h:
  • kjs/MathObject.cpp: (KJS::mathProtoFuncAbs): (KJS::mathProtoFuncACos): (KJS::mathProtoFuncASin): (KJS::mathProtoFuncATan): (KJS::mathProtoFuncATan2): (KJS::mathProtoFuncCeil): (KJS::mathProtoFuncCos): (KJS::mathProtoFuncExp): (KJS::mathProtoFuncFloor): (KJS::mathProtoFuncLog): (KJS::mathProtoFuncMax): (KJS::mathProtoFuncMin): (KJS::mathProtoFuncPow): (KJS::mathProtoFuncRandom): (KJS::mathProtoFuncRound): (KJS::mathProtoFuncSin): (KJS::mathProtoFuncSqrt): (KJS::mathProtoFuncTan):
  • kjs/MathObject.h:
  • kjs/NumberObject.cpp: (KJS::numberProtoFuncToString): (KJS::numberProtoFuncToLocaleString): (KJS::numberProtoFuncValueOf): (KJS::numberProtoFuncToFixed): (KJS::numberProtoFuncToExponential): (KJS::numberProtoFuncToPrecision): (KJS::NumberConstructor::NumberConstructor): (KJS::constructWithNumberConstructor): (KJS::NumberConstructor::getConstructData): (KJS::callNumberConstructor): (KJS::NumberConstructor::getCallData): (KJS::constructNumber): (KJS::constructNumberFromImmediateNumber):
  • kjs/NumberObject.h: (KJS::NumberObject::classInfo): (KJS::NumberConstructor::classInfo):
  • kjs/PropertySlot.cpp: (KJS::PropertySlot::functionGetter):
  • kjs/RegExpObject.cpp: (KJS::regExpProtoFuncTest): (KJS::regExpProtoFuncExec): (KJS::regExpProtoFuncCompile): (KJS::regExpProtoFuncToString): (KJS::callRegExpObject): (KJS::RegExpObject::getCallData): (KJS::constructRegExp): (KJS::constructWithRegExpConstructor): (KJS::RegExpConstructor::getConstructData): (KJS::callRegExpConstructor): (KJS::RegExpConstructor::getCallData):
  • kjs/RegExpObject.h: (KJS::RegExpConstructor::classInfo):
  • kjs/Shell.cpp: (GlobalObject::GlobalObject): (functionPrint): (functionDebug): (functionGC): (functionVersion): (functionRun): (functionLoad): (functionReadline): (functionQuit):
  • kjs/date_object.cpp: (KJS::gmtoffset): (KJS::formatLocaleDate): (KJS::fillStructuresUsingDateArgs): (KJS::DateInstance::getTime): (KJS::DateInstance::getUTCTime): (KJS::DateConstructor::DateConstructor): (KJS::constructDate): (KJS::DateConstructor::getConstructData): (KJS::callDate): (KJS::DateConstructor::getCallData): (KJS::dateParse): (KJS::dateNow): (KJS::dateUTC): (KJS::dateProtoFuncToString): (KJS::dateProtoFuncToUTCString): (KJS::dateProtoFuncToDateString): (KJS::dateProtoFuncToTimeString): (KJS::dateProtoFuncToLocaleString): (KJS::dateProtoFuncToLocaleDateString): (KJS::dateProtoFuncToLocaleTimeString): (KJS::dateProtoFuncValueOf): (KJS::dateProtoFuncGetTime): (KJS::dateProtoFuncGetFullYear): (KJS::dateProtoFuncGetUTCFullYear): (KJS::dateProtoFuncToGMTString): (KJS::dateProtoFuncGetMonth): (KJS::dateProtoFuncGetUTCMonth): (KJS::dateProtoFuncGetDate): (KJS::dateProtoFuncGetUTCDate): (KJS::dateProtoFuncGetDay): (KJS::dateProtoFuncGetUTCDay): (KJS::dateProtoFuncGetHours): (KJS::dateProtoFuncGetUTCHours): (KJS::dateProtoFuncGetMinutes): (KJS::dateProtoFuncGetUTCMinutes): (KJS::dateProtoFuncGetSeconds): (KJS::dateProtoFuncGetUTCSeconds): (KJS::dateProtoFuncGetMilliSeconds): (KJS::dateProtoFuncGetUTCMilliseconds): (KJS::dateProtoFuncGetTimezoneOffset): (KJS::dateProtoFuncSetTime): (KJS::setNewValueFromTimeArgs): (KJS::setNewValueFromDateArgs): (KJS::dateProtoFuncSetMilliSeconds): (KJS::dateProtoFuncSetUTCMilliseconds): (KJS::dateProtoFuncSetSeconds): (KJS::dateProtoFuncSetUTCSeconds): (KJS::dateProtoFuncSetMinutes): (KJS::dateProtoFuncSetUTCMinutes): (KJS::dateProtoFuncSetHours): (KJS::dateProtoFuncSetUTCHours): (KJS::dateProtoFuncSetDate): (KJS::dateProtoFuncSetUTCDate): (KJS::dateProtoFuncSetMonth): (KJS::dateProtoFuncSetUTCMonth): (KJS::dateProtoFuncSetFullYear): (KJS::dateProtoFuncSetUTCFullYear): (KJS::dateProtoFuncSetYear): (KJS::dateProtoFuncGetYear):
  • kjs/date_object.h: (KJS::DateInstance::internalNumber): (KJS::DateInstance::classInfo):
  • kjs/error_object.cpp: (KJS::errorProtoFuncToString): (KJS::constructError): (KJS::constructWithErrorConstructor): (KJS::ErrorConstructor::getConstructData): (KJS::callErrorConstructor): (KJS::ErrorConstructor::getCallData): (KJS::NativeErrorConstructor::construct): (KJS::constructWithNativeErrorConstructor): (KJS::NativeErrorConstructor::getConstructData): (KJS::callNativeErrorConstructor): (KJS::NativeErrorConstructor::getCallData):
  • kjs/error_object.h: (KJS::NativeErrorConstructor::classInfo):
  • kjs/internal.cpp: (KJS::JSNumberCell::toObject): (KJS::JSNumberCell::toThisObject): (KJS::GetterSetter::mark): (KJS::GetterSetter::toPrimitive): (KJS::GetterSetter::toBoolean): (KJS::GetterSetter::toNumber): (KJS::GetterSetter::toString): (KJS::GetterSetter::toObject): (KJS::InternalFunction::InternalFunction): (KJS::InternalFunction::implementsHasInstance):
  • kjs/lookup.h: (KJS::HashEntry::):
  • kjs/nodes.cpp: (KJS::FuncDeclNode::makeFunction): (KJS::FuncExprNode::makeFunction):
  • kjs/object_object.cpp: (KJS::objectProtoFuncValueOf): (KJS::objectProtoFuncHasOwnProperty): (KJS::objectProtoFuncIsPrototypeOf): (KJS::objectProtoFuncDefineGetter): (KJS::objectProtoFuncDefineSetter): (KJS::objectProtoFuncLookupGetter): (KJS::objectProtoFuncLookupSetter): (KJS::objectProtoFuncPropertyIsEnumerable): (KJS::objectProtoFuncToLocaleString): (KJS::objectProtoFuncToString): (KJS::ObjectConstructor::ObjectConstructor): (KJS::constructObject): (KJS::constructWithObjectConstructor): (KJS::ObjectConstructor::getConstructData): (KJS::callObjectConstructor): (KJS::ObjectConstructor::getCallData):
  • kjs/object_object.h:
  • kjs/string_object.cpp: (KJS::replace): (KJS::stringProtoFuncToString): (KJS::stringProtoFuncValueOf): (KJS::stringProtoFuncCharAt): (KJS::stringProtoFuncCharCodeAt): (KJS::stringProtoFuncConcat): (KJS::stringProtoFuncIndexOf): (KJS::stringProtoFuncLastIndexOf): (KJS::stringProtoFuncMatch): (KJS::stringProtoFuncSearch): (KJS::stringProtoFuncReplace): (KJS::stringProtoFuncSlice): (KJS::stringProtoFuncSplit): (KJS::stringProtoFuncSubstr): (KJS::stringProtoFuncSubstring): (KJS::stringProtoFuncToLowerCase): (KJS::stringProtoFuncToUpperCase): (KJS::stringProtoFuncToLocaleLowerCase): (KJS::stringProtoFuncToLocaleUpperCase): (KJS::stringProtoFuncLocaleCompare): (KJS::stringProtoFuncBig): (KJS::stringProtoFuncSmall): (KJS::stringProtoFuncBlink): (KJS::stringProtoFuncBold): (KJS::stringProtoFuncFixed): (KJS::stringProtoFuncItalics): (KJS::stringProtoFuncStrike): (KJS::stringProtoFuncSub): (KJS::stringProtoFuncSup): (KJS::stringProtoFuncFontcolor): (KJS::stringProtoFuncFontsize): (KJS::stringProtoFuncAnchor): (KJS::stringProtoFuncLink): (KJS::stringFromCharCode): (KJS::StringConstructor::StringConstructor): (KJS::constructWithStringConstructor): (KJS::StringConstructor::getConstructData): (KJS::callStringConstructor): (KJS::StringConstructor::getCallData):
  • kjs/string_object.h:

JavaScriptGlue:

2008-06-23 Darin Adler <Darin Adler>

Reviewed by Geoff.

  • JSValueWrapper.cpp: (JSValueWrapper::JSObjectCallFunction): Updated to use getCallData and call instead of the old callAsFunction.

WebCore:

2008-06-23 Darin Adler <Darin Adler>

Reviewed by Geoff.

Update for JavaScript changes.

  • Use CallData and ConstructData instead of the obsolete implementsCall, callAsFunction, and construct functions.
  • Updated native function arguments, specifically to allow a JSValue rather than a JSObject for the this argument, and to call toThisObject as needed when treating it as an object.
  • Made some more class members private and protected, including virtual function overrides.
  • Eliminated the use of getCallData in the JavaScript bridging code as a way to check if an instance supports invokeDefaultMethod.
  • Eliminated unnecessary polymorphism in the NodeIterator and TreeWalker classes. They were using virtual functions simply to share an instance of the RefCounted template, which was not helpful.
  • bindings/js/JSAudioConstructor.cpp: (WebCore::constructAudio): (WebCore::JSAudioConstructor::getConstructData):
  • bindings/js/JSAudioConstructor.h: (WebCore::JSAudioConstructor::document): (WebCore::JSAudioConstructor::classInfo):
  • bindings/js/JSClipboardCustom.cpp: (WebCore::JSClipboard::types):
  • bindings/js/JSCustomSQLStatementCallback.cpp: (WebCore::JSCustomSQLStatementCallback::handleEvent):
  • bindings/js/JSCustomSQLStatementErrorCallback.cpp: (WebCore::JSCustomSQLStatementErrorCallback::handleEvent):
  • bindings/js/JSCustomSQLTransactionCallback.cpp: (WebCore::JSCustomSQLTransactionCallback::handleEvent):
  • bindings/js/JSCustomSQLTransactionErrorCallback.cpp: (WebCore::JSCustomSQLTransactionErrorCallback::handleEvent):
  • bindings/js/JSCustomVoidCallback.cpp: (WebCore::JSCustomVoidCallback::handleEvent):
  • bindings/js/JSCustomXPathNSResolver.cpp: (WebCore::JSCustomXPathNSResolver::lookupNamespaceURI):
  • bindings/js/JSDOMBinding.h: (WebCore::DOMObject::DOMObject):
  • bindings/js/JSDOMWindowBase.cpp: (WebCore::windowProtoFuncAToB): (WebCore::windowProtoFuncBToA): (WebCore::windowProtoFuncOpen): (WebCore::windowProtoFuncSetTimeout): (WebCore::windowProtoFuncClearTimeout): (WebCore::windowProtoFuncSetInterval): (WebCore::windowProtoFuncAddEventListener): (WebCore::windowProtoFuncRemoveEventListener): (WebCore::windowProtoFuncShowModalDialog): (WebCore::windowProtoFuncNotImplemented): (WebCore::toJSDOMWindow):
  • bindings/js/JSDOMWindowBase.h:
  • bindings/js/JSDOMWindowShell.h: (WebCore::JSDOMWindowShell::classInfo):
  • bindings/js/JSEventListener.cpp: (WebCore::JSAbstractEventListener::handleEvent): (WebCore::JSLazyEventListener::parseCode):
  • bindings/js/JSEventTargetBase.cpp: (WebCore::retrieveEventTargetAndCorrespondingNode): (WebCore::jsEventTargetAddEventListener): (WebCore::jsEventTargetRemoveEventListener): (WebCore::jsEventTargetDispatchEvent):
  • bindings/js/JSEventTargetBase.h:
  • bindings/js/JSHTMLAppletElementCustom.cpp: (WebCore::JSHTMLAppletElement::customGetOwnPropertySlot): (WebCore::JSHTMLAppletElement::customPut): (WebCore::JSHTMLAppletElement::getCallData):
  • bindings/js/JSHTMLCollectionCustom.cpp: (WebCore::callHTMLCollection): (WebCore::JSHTMLCollection::getCallData):
  • bindings/js/JSHTMLDocumentCustom.cpp: (WebCore::JSHTMLDocument::open):
  • bindings/js/JSHTMLEmbedElementCustom.cpp: (WebCore::JSHTMLEmbedElement::customGetOwnPropertySlot): (WebCore::JSHTMLEmbedElement::customPut): (WebCore::JSHTMLEmbedElement::getCallData):
  • bindings/js/JSHTMLInputElementBase.cpp: (WebCore::jsHTMLInputElementBaseFunctionSetSelectionRange):
  • bindings/js/JSHTMLInputElementBase.h:
  • bindings/js/JSHTMLObjectElementCustom.cpp: (WebCore::JSHTMLObjectElement::customGetOwnPropertySlot): (WebCore::JSHTMLObjectElement::customPut): (WebCore::JSHTMLObjectElement::getCallData):
  • bindings/js/JSHTMLOptionElementConstructor.cpp: (WebCore::constructHTMLOptionElement): (WebCore::JSHTMLOptionElementConstructor::getConstructData):
  • bindings/js/JSHTMLOptionElementConstructor.h: (WebCore::JSHTMLOptionElementConstructor::document): (WebCore::JSHTMLOptionElementConstructor::classInfo):
  • bindings/js/JSImageConstructor.cpp: (WebCore::constructImage): (WebCore::JSImageConstructor::getConstructData):
  • bindings/js/JSImageConstructor.h: (WebCore::JSImageConstructor::document): (WebCore::JSImageConstructor::classInfo):
  • bindings/js/JSInspectedObjectWrapper.h: (WebCore::JSInspectedObjectWrapper::classInfo):
  • bindings/js/JSInspectorCallbackWrapper.cpp: (WebCore::JSInspectorCallbackWrapper::prepareIncomingValue):
  • bindings/js/JSJavaScriptCallFrameCustom.cpp: (WebCore::JSJavaScriptCallFrame::scopeChain):
  • bindings/js/JSNodeFilterCondition.cpp: (WebCore::JSNodeFilterCondition::JSNodeFilterCondition): (WebCore::JSNodeFilterCondition::mark): (WebCore::JSNodeFilterCondition::acceptNode):
  • bindings/js/JSNodeFilterCondition.h: (WebCore::JSNodeFilterCondition::create):
  • bindings/js/JSNodeFilterCustom.cpp: (WebCore::toNodeFilter):
  • bindings/js/JSNodeListCustom.cpp: (WebCore::callNodeList): (WebCore::JSNodeList::getCallData): (WebCore::JSNodeList::canGetItemsForName): (WebCore::JSNodeList::nameGetter):
  • bindings/js/JSPluginElementFunctions.cpp: (WebCore::runtimeObjectGetter): (WebCore::runtimeObjectPropertyGetter): (WebCore::runtimeObjectCustomGetOwnPropertySlot): (WebCore::runtimeObjectCustomPut): (WebCore::runtimeObjectGetCallData): (WebCore::pluginInstance): (WebCore::getRuntimeObject): (WebCore::callPlugin):
  • bindings/js/JSPluginElementFunctions.h:
  • bindings/js/JSQuarantinedObjectWrapper.cpp: (WebCore::JSQuarantinedObjectWrapper::put): (WebCore::JSQuarantinedObjectWrapper::construct): (WebCore::JSQuarantinedObjectWrapper::getConstructData): (WebCore::JSQuarantinedObjectWrapper::hasInstance): (WebCore::JSQuarantinedObjectWrapper::call): (WebCore::JSQuarantinedObjectWrapper::getCallData):
  • bindings/js/JSQuarantinedObjectWrapper.h: (WebCore::JSQuarantinedObjectWrapper::className):
  • bindings/js/JSRGBColor.cpp:
  • bindings/js/JSXMLHttpRequestConstructor.cpp: (WebCore::constructXMLHttpRequest): (WebCore::JSXMLHttpRequestConstructor::getConstructData):
  • bindings/js/JSXMLHttpRequestConstructor.h: (WebCore::JSXMLHttpRequestConstructor::document): (WebCore::JSXMLHttpRequestConstructor::classInfo):
  • bindings/js/JSXSLTProcessorConstructor.cpp: (WebCore::constructXSLTProcessor): (WebCore::JSXSLTProcessorConstructor::getConstructData):
  • bindings/js/JSXSLTProcessorConstructor.h: (WebCore::JSXSLTProcessorConstructor::classInfo):
  • bindings/js/ScheduledAction.cpp: (WebCore::ScheduledAction::ScheduledAction): (WebCore::ScheduledAction::execute):
  • bindings/js/ScheduledAction.h:
  • bindings/objc/WebScriptObject.mm: (-[WebScriptObject callWebScriptMethod:withArguments:]):
  • bindings/scripts/CodeGeneratorJS.pm:
  • bridge/NP_jsobject.cpp: (_NPN_InvokeDefault): (_NPN_Invoke):
  • bridge/c/c_instance.cpp: (KJS::Bindings::CInstance::supportsInvokeDefaultMethod):
  • bridge/c/c_instance.h:
  • bridge/jni/jni_jsobject.mm: (JavaJSObject::call):
  • bridge/objc/objc_instance.h:
  • bridge/objc/objc_instance.mm: (ObjcInstance::supportsInvokeDefaultMethod):
  • bridge/objc/objc_runtime.h: (KJS::Bindings::ObjcFallbackObjectImp::propertyName): (KJS::Bindings::ObjcFallbackObjectImp::classInfo):
  • bridge/objc/objc_runtime.mm: (Bindings::webScriptObjectClass): (Bindings::webUndefinedClass): (ObjcFallbackObjectImp::ObjcFallbackObjectImp): (callObjCFallbackObject): (ObjcFallbackObjectImp::getCallData):
  • bridge/qt/qt_instance.h:
  • bridge/runtime.cpp: (KJS::Bindings::Instance::createRuntimeObject): (KJS::Bindings::Instance::getInstance):
  • bridge/runtime.h: (KJS::Bindings::Field::~Field): (KJS::Bindings::Method::~Method): (KJS::Bindings::Class::~Class): (KJS::Bindings::Instance::supportsInvokeDefaultMethod):
  • bridge/runtime_method.cpp: (KJS::callRuntimeMethod): (KJS::RuntimeMethod::getCallData):
  • bridge/runtime_method.h: (KJS::RuntimeMethod::methods):
  • bridge/runtime_object.cpp: (RuntimeObjectImp::defaultValue): (callRuntimeObject): (RuntimeObjectImp::getCallData):
  • bridge/runtime_object.h: (KJS::RuntimeObjectImp::getInternalInstance): (KJS::RuntimeObjectImp::classInfo):
  • dom/NodeIterator.h:
  • dom/Traversal.cpp:
  • dom/Traversal.h:
  • dom/TreeWalker.h:
  • Property svn:eol-style set to native
File size: 64.9 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 "ArrayPrototype.h"
30#include "CodeGenerator.h"
31#include "ExecState.h"
32#include "FunctionPrototype.h"
33#include "JSGlobalObject.h"
34#include "Parser.h"
35#include "PropertyNameArray.h"
36#include "RegExpObject.h"
37#include "debugger.h"
38#include "lexer.h"
39#include "operations.h"
40#include <math.h>
41#include <wtf/Assertions.h>
42#include <wtf/HashCountedSet.h>
43#include <wtf/HashSet.h>
44#include <wtf/MathExtras.h>
45
46namespace KJS {
47
48static inline UString::Rep* rep(const Identifier& ident)
49{
50 return ident.ustring().rep();
51}
52
53// ------------------------------ Node -----------------------------------------
54
55#ifndef NDEBUG
56#ifndef LOG_CHANNEL_PREFIX
57#define LOG_CHANNEL_PREFIX Log
58#endif
59static WTFLogChannel LogKJSNodeLeaks = { 0x00000000, "", WTFLogChannelOn };
60
61struct ParserRefCountedCounter {
62 static unsigned count;
63 ParserRefCountedCounter()
64 {
65 if (count)
66 LOG(KJSNodeLeaks, "LEAK: %u KJS::Node\n", count);
67 }
68};
69unsigned ParserRefCountedCounter::count = 0;
70static ParserRefCountedCounter parserRefCountedCounter;
71#endif
72
73static HashSet<ParserRefCounted*>* newTrackedObjects;
74static HashCountedSet<ParserRefCounted*>* trackedObjectExtraRefCounts;
75
76ParserRefCounted::ParserRefCounted()
77{
78#ifndef NDEBUG
79 ++ParserRefCountedCounter::count;
80#endif
81 if (!newTrackedObjects)
82 newTrackedObjects = new HashSet<ParserRefCounted*>;
83 newTrackedObjects->add(this);
84 ASSERT(newTrackedObjects->contains(this));
85}
86
87ParserRefCounted::~ParserRefCounted()
88{
89#ifndef NDEBUG
90 --ParserRefCountedCounter::count;
91#endif
92}
93
94void ParserRefCounted::ref()
95{
96 // bumping from 0 to 1 is just removing from the new nodes set
97 if (newTrackedObjects) {
98 HashSet<ParserRefCounted*>::iterator it = newTrackedObjects->find(this);
99 if (it != newTrackedObjects->end()) {
100 newTrackedObjects->remove(it);
101 ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(this));
102 return;
103 }
104 }
105
106 ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
107
108 if (!trackedObjectExtraRefCounts)
109 trackedObjectExtraRefCounts = new HashCountedSet<ParserRefCounted*>;
110 trackedObjectExtraRefCounts->add(this);
111}
112
113void ParserRefCounted::deref()
114{
115 ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
116
117 if (!trackedObjectExtraRefCounts) {
118 delete this;
119 return;
120 }
121
122 HashCountedSet<ParserRefCounted*>::iterator it = trackedObjectExtraRefCounts->find(this);
123 if (it == trackedObjectExtraRefCounts->end())
124 delete this;
125 else
126 trackedObjectExtraRefCounts->remove(it);
127}
128
129bool ParserRefCounted::hasOneRef()
130{
131 if (newTrackedObjects && newTrackedObjects->contains(this)) {
132 ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(this));
133 return false;
134 }
135
136 ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
137
138 if (!trackedObjectExtraRefCounts)
139 return true;
140
141 return !trackedObjectExtraRefCounts->contains(this);
142}
143
144void ParserRefCounted::deleteNewObjects()
145{
146 if (!newTrackedObjects)
147 return;
148
149#ifndef NDEBUG
150 HashSet<ParserRefCounted*>::iterator end = newTrackedObjects->end();
151 for (HashSet<ParserRefCounted*>::iterator it = newTrackedObjects->begin(); it != end; ++it)
152 ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(*it));
153#endif
154 deleteAllValues(*newTrackedObjects);
155 delete newTrackedObjects;
156 newTrackedObjects = 0;
157}
158
159Node::Node()
160 : m_expectedReturnType(ObjectType)
161{
162 m_line = JSGlobalData::threadInstance().lexer->lineNo();
163}
164
165Node::Node(JSType expectedReturn)
166 : m_expectedReturnType(expectedReturn)
167{
168 m_line = JSGlobalData::threadInstance().lexer->lineNo();
169}
170
171static void substitute(UString& string, const UString& substring) KJS_FAST_CALL;
172static void substitute(UString& string, const UString& substring)
173{
174 int position = string.find("%s");
175 ASSERT(position != -1);
176 UString newString = string.substr(0, position);
177 newString.append(substring);
178 newString.append(string.substr(position + 2));
179 string = newString;
180}
181
182static inline int currentSourceId(ExecState* exec) KJS_FAST_CALL;
183static inline int currentSourceId(ExecState*)
184{
185 ASSERT_NOT_REACHED();
186 return 0;
187}
188
189static inline const UString currentSourceURL(ExecState* exec) KJS_FAST_CALL;
190static inline const UString currentSourceURL(ExecState*)
191{
192 ASSERT_NOT_REACHED();
193 return UString();
194}
195
196RegisterID* Node::emitThrowError(CodeGenerator& generator, ErrorType e, const char* msg)
197{
198 RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalExec(), msg));
199 generator.emitThrow(exception);
200 return exception;
201}
202
203RegisterID* Node::emitThrowError(CodeGenerator& generator, ErrorType e, const char* msg, const Identifier& label)
204{
205 UString message = msg;
206 substitute(message, label.ustring());
207 RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalExec(), message));
208 generator.emitThrow(exception);
209 return exception;
210}
211
212// ------------------------------ StatementNode --------------------------------
213
214StatementNode::StatementNode()
215 : m_lastLine(-1)
216{
217 m_line = -1;
218}
219
220void StatementNode::setLoc(int firstLine, int lastLine)
221{
222 m_line = firstLine;
223 m_lastLine = lastLine;
224}
225
226// ------------------------------ SourceElements --------------------------------
227
228void SourceElements::append(PassRefPtr<StatementNode> statement)
229{
230 if (statement->isEmptyStatement())
231 return;
232
233 m_statements.append(statement);
234}
235
236// ------------------------------ BreakpointCheckStatement --------------------------------
237
238BreakpointCheckStatement::BreakpointCheckStatement(PassRefPtr<StatementNode> statement)
239 : m_statement(statement)
240{
241 ASSERT(m_statement);
242}
243
244void BreakpointCheckStatement::streamTo(SourceStream& stream) const
245{
246 m_statement->streamTo(stream);
247}
248
249// ------------------------------ NullNode -------------------------------------
250
251RegisterID* NullNode::emitCode(CodeGenerator& generator, RegisterID* dst)
252{
253 return generator.emitLoad(generator.finalDestination(dst), jsNull());
254}
255
256// ------------------------------ BooleanNode ----------------------------------
257
258RegisterID* BooleanNode::emitCode(CodeGenerator& generator, RegisterID* dst)
259{
260 return generator.emitLoad(generator.finalDestination(dst), m_value);
261}
262
263// ------------------------------ NumberNode -----------------------------------
264
265RegisterID* NumberNode::emitCode(CodeGenerator& generator, RegisterID* dst)
266{
267 return generator.emitLoad(generator.finalDestination(dst), m_double);
268}
269
270// ------------------------------ StringNode -----------------------------------
271
272RegisterID* StringNode::emitCode(CodeGenerator& generator, RegisterID* dst)
273{
274 // FIXME: should we try to atomize constant strings?
275 return generator.emitLoad(generator.finalDestination(dst), jsOwnedString(generator.globalExec(), m_value));
276}
277
278// ------------------------------ RegExpNode -----------------------------------
279
280RegisterID* RegExpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
281{
282 if (!m_regExp->isValid())
283 return emitThrowError(generator, SyntaxError, ("Invalid regular expression: " + UString(m_regExp->errorMessage())).UTF8String().c_str());
284 return generator.emitNewRegExp(generator.finalDestination(dst), m_regExp.get());
285}
286
287// ------------------------------ ThisNode -------------------------------------
288
289RegisterID* ThisNode::emitCode(CodeGenerator& generator, RegisterID* dst)
290{
291 return generator.moveToDestinationIfNeeded(dst, generator.thisRegister());
292}
293
294// ------------------------------ ResolveNode ----------------------------------
295
296bool ResolveNode::isPure(CodeGenerator& generator) const
297{
298 return generator.isLocal(m_ident);
299}
300
301RegisterID* ResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
302{
303 if (RegisterID* local = generator.registerForLocal(m_ident))
304 return generator.moveToDestinationIfNeeded(dst, local);
305
306 return generator.emitResolve(generator.finalDestination(dst), m_ident);
307}
308
309// ------------------------------ ArrayNode ------------------------------------
310
311
312RegisterID* ArrayNode::emitCode(CodeGenerator& generator, RegisterID* dst)
313{
314 RefPtr<RegisterID> newArray = generator.emitNewArray(generator.tempDestination(dst));
315 unsigned length = 0;
316
317 RegisterID* value;
318 for (ElementNode* n = m_element.get(); n; n = n->m_next.get()) {
319 value = generator.emitNode(n->m_node.get());
320 length += n->m_elision;
321 generator.emitPutByIndex(newArray.get(), length++, value);
322 }
323
324 value = generator.emitLoad(generator.newTemporary(), jsNumber(generator.globalExec(), m_elision + length));
325 generator.emitPutById(newArray.get(), generator.propertyNames().length, value);
326
327 return generator.moveToDestinationIfNeeded(dst, newArray.get());
328}
329
330// ------------------------------ ObjectLiteralNode ----------------------------
331
332RegisterID* ObjectLiteralNode::emitCode(CodeGenerator& generator, RegisterID* dst)
333{
334 if (m_list)
335 return generator.emitNode(dst, m_list.get());
336 else
337 return generator.emitNewObject(generator.finalDestination(dst));
338}
339
340// ------------------------------ PropertyListNode -----------------------------
341
342RegisterID* PropertyListNode::emitCode(CodeGenerator& generator, RegisterID* dst)
343{
344 RefPtr<RegisterID> newObj = generator.tempDestination(dst);
345
346 generator.emitNewObject(newObj.get());
347
348 for (PropertyListNode* p = this; p; p = p->m_next.get()) {
349 RegisterID* value = generator.emitNode(p->m_node->m_assign.get());
350
351 switch (p->m_node->m_type) {
352 case PropertyNode::Constant: {
353 generator.emitPutById(newObj.get(), p->m_node->name(), value);
354 break;
355 }
356 case PropertyNode::Getter: {
357 generator.emitPutGetter(newObj.get(), p->m_node->name(), value);
358 break;
359 }
360 case PropertyNode::Setter: {
361 generator.emitPutSetter(newObj.get(), p->m_node->name(), value);
362 break;
363 }
364 default:
365 ASSERT_NOT_REACHED();
366 }
367 }
368
369 return generator.moveToDestinationIfNeeded(dst, newObj.get());
370}
371
372// ------------------------------ BracketAccessorNode --------------------------------
373
374RegisterID* BracketAccessorNode::emitCode(CodeGenerator& generator, RegisterID* dst)
375{
376 RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments, m_subscript->isPure(generator));
377 RegisterID* property = generator.emitNode(m_subscript.get());
378
379 return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property);
380}
381
382// ------------------------------ DotAccessorNode --------------------------------
383
384RegisterID* DotAccessorNode::emitCode(CodeGenerator& generator, RegisterID* dst)
385{
386 RegisterID* base = generator.emitNode(m_base.get());
387 return generator.emitGetById(generator.finalDestination(dst), base, m_ident);
388}
389
390// ------------------------------ ArgumentListNode -----------------------------
391
392RegisterID* ArgumentListNode::emitCode(CodeGenerator& generator, RegisterID* dst)
393{
394 ASSERT(m_expr);
395 return generator.emitNode(dst, m_expr.get());
396}
397
398// ------------------------------ NewExprNode ----------------------------------
399
400RegisterID* NewExprNode::emitCode(CodeGenerator& generator, RegisterID* dst)
401{
402 RefPtr<RegisterID> r0 = generator.emitNode(m_expr.get());
403 return generator.emitConstruct(generator.finalDestination(dst), r0.get(), m_args.get());
404}
405
406RegisterID* EvalFunctionCallNode::emitCode(CodeGenerator& generator, RegisterID* dst)
407{
408 RefPtr<RegisterID> base = generator.tempDestination(dst);
409 RegisterID* func = generator.newTemporary();
410 generator.emitResolveWithBase(base.get(), func, generator.propertyNames().eval);
411 return generator.emitCallEval(generator.finalDestination(dst, base.get()), func, base.get(), m_args.get());
412}
413
414RegisterID* FunctionCallValueNode::emitCode(CodeGenerator& generator, RegisterID* dst)
415{
416 RefPtr<RegisterID> func = generator.emitNode(m_expr.get());
417 return generator.emitCall(generator.finalDestination(dst), func.get(), 0, m_args.get());
418}
419
420RegisterID* FunctionCallResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
421{
422 if (RegisterID* local = generator.registerForLocal(m_ident))
423 return generator.emitCall(generator.finalDestination(dst), local, 0, m_args.get());
424
425 int index = 0;
426 size_t depth = 0;
427 if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) {
428 RegisterID* func = generator.emitGetScopedVar(generator.newTemporary(), depth, index);
429 return generator.emitCall(generator.finalDestination(dst), func, 0, m_args.get());
430 }
431
432 RefPtr<RegisterID> base = generator.tempDestination(dst);
433 RegisterID* func = generator.newTemporary();
434 generator.emitResolveFunction(base.get(), func, m_ident);
435 return generator.emitCall(generator.finalDestination(dst, base.get()), func, base.get(), m_args.get());
436}
437
438RegisterID* FunctionCallBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
439{
440 RefPtr<RegisterID> base = generator.emitNode(m_base.get());
441 RegisterID* property = generator.emitNode(m_subscript.get());
442 RegisterID* function = generator.emitGetByVal(generator.newTemporary(), base.get(), property);
443 return generator.emitCall(generator.finalDestination(dst, base.get()), function, base.get(), m_args.get());
444}
445
446RegisterID* FunctionCallDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
447{
448 RefPtr<RegisterID> base = generator.emitNode(m_base.get());
449 RegisterID* function = generator.emitGetById(generator.newTemporary(), base.get(), m_ident);
450 return generator.emitCall(generator.finalDestination(dst, base.get()), function, base.get(), m_args.get());
451}
452
453// ------------------------------ PostfixResolveNode ----------------------------------
454
455RegisterID* PostIncResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
456{
457 // FIXME: I think we can detect the absense of dependent expressions here,
458 // and emit a PreInc instead of a PostInc. A post-pass to eliminate dead
459 // code would work, too.
460 if (RegisterID* local = generator.registerForLocal(m_ident)) {
461 if (generator.isLocalConstant(m_ident))
462 return generator.emitToJSNumber(generator.finalDestination(dst), local);
463
464 return generator.emitPostInc(generator.finalDestination(dst), local);
465 }
466
467 int index = 0;
468 size_t depth = 0;
469 if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) {
470 RefPtr<RegisterID> value = generator.emitGetScopedVar(generator.newTemporary(), depth, index);
471 RegisterID* oldValue = generator.emitPostInc(generator.finalDestination(dst), value.get());
472 generator.emitPutScopedVar(depth, index, value.get());
473 return oldValue;
474 }
475
476 RefPtr<RegisterID> value = generator.newTemporary();
477 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident);
478 RegisterID* oldValue = generator.emitPostInc(generator.finalDestination(dst), value.get());
479 generator.emitPutById(base.get(), m_ident, value.get());
480 return oldValue;
481}
482
483RegisterID* PostDecResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
484{
485 // FIXME: I think we can detect the absense of dependent expressions here,
486 // and emit a PreDec instead of a PostDec. A post-pass to eliminate dead
487 // code would work, too.
488 if (RegisterID* local = generator.registerForLocal(m_ident)) {
489 if (generator.isLocalConstant(m_ident))
490 return generator.emitToJSNumber(generator.finalDestination(dst), local);
491
492 return generator.emitPostDec(generator.finalDestination(dst), local);
493 }
494
495 int index = 0;
496 size_t depth = 0;
497 if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) {
498 RefPtr<RegisterID> value = generator.emitGetScopedVar(generator.newTemporary(), depth, index);
499 RegisterID* oldValue = generator.emitPostDec(generator.finalDestination(dst), value.get());
500 generator.emitPutScopedVar(depth, index, value.get());
501 return oldValue;
502 }
503
504 RefPtr<RegisterID> value = generator.newTemporary();
505 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident);
506 RegisterID* oldValue = generator.emitPostDec(generator.finalDestination(dst), value.get());
507 generator.emitPutById(base.get(), m_ident, value.get());
508 return oldValue;
509}
510
511// ------------------------------ PostfixBracketNode ----------------------------------
512
513RegisterID* PostIncBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
514{
515 RefPtr<RegisterID> base = generator.emitNode(m_base.get());
516 RefPtr<RegisterID> property = generator.emitNode(m_subscript.get());
517 RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get());
518 RegisterID* oldValue = generator.emitPostInc(generator.finalDestination(dst), value.get());
519 generator.emitPutByVal(base.get(), property.get(), value.get());
520 return oldValue;
521}
522
523RegisterID* PostDecBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
524{
525 RefPtr<RegisterID> base = generator.emitNode(m_base.get());
526 RefPtr<RegisterID> property = generator.emitNode(m_subscript.get());
527 RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get());
528 RegisterID* oldValue = generator.emitPostDec(generator.finalDestination(dst), value.get());
529 generator.emitPutByVal(base.get(), property.get(), value.get());
530 return oldValue;
531}
532
533// ------------------------------ PostfixDotNode ----------------------------------
534
535RegisterID* PostIncDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
536{
537 RefPtr<RegisterID> base = generator.emitNode(m_base.get());
538 RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident);
539 RegisterID* oldValue = generator.emitPostInc(generator.finalDestination(dst), value.get());
540 generator.emitPutById(base.get(), m_ident, value.get());
541 return oldValue;
542}
543
544RegisterID* PostDecDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
545{
546 RefPtr<RegisterID> base = generator.emitNode(m_base.get());
547 RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident);
548 RegisterID* oldValue = generator.emitPostDec(generator.finalDestination(dst), value.get());
549 generator.emitPutById(base.get(), m_ident, value.get());
550 return oldValue;
551}
552
553// ------------------------------ PostfixErrorNode -----------------------------------
554
555RegisterID* PostfixErrorNode::emitCode(CodeGenerator& generator, RegisterID*)
556{
557 return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus ? "Postfix ++ operator applied to value that is not a reference." : "Postfix -- operator applied to value that is not a reference.");
558}
559
560// ------------------------------ DeleteResolveNode -----------------------------------
561
562RegisterID* DeleteResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
563{
564 if (generator.registerForLocal(m_ident))
565 return generator.emitLoad(generator.finalDestination(dst), false);
566
567 RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), m_ident);
568 return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident);
569}
570
571// ------------------------------ DeleteBracketNode -----------------------------------
572
573RegisterID* DeleteBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
574{
575 RefPtr<RegisterID> r0 = generator.emitNode(m_base.get());
576 RefPtr<RegisterID> r1 = generator.emitNode(m_subscript.get());
577 return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1.get());
578}
579
580// ------------------------------ DeleteDotNode -----------------------------------
581
582RegisterID* DeleteDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
583{
584 RegisterID* r0 = generator.emitNode(m_base.get());
585 return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident);
586}
587
588// ------------------------------ DeleteValueNode -----------------------------------
589
590RegisterID* DeleteValueNode::emitCode(CodeGenerator& generator, RegisterID* dst)
591{
592 generator.emitNode(m_expr.get());
593
594 // delete on a non-location expression ignores the value and returns true
595 return generator.emitLoad(generator.finalDestination(dst), true);
596}
597
598// ------------------------------ VoidNode -------------------------------------
599
600RegisterID* VoidNode::emitCode(CodeGenerator& generator, RegisterID* dst)
601{
602 RefPtr<RegisterID> r0 = generator.emitNode(m_expr.get());
603 return generator.emitLoad(generator.finalDestination(dst, r0.get()), jsUndefined());
604}
605
606// ------------------------------ TypeOfValueNode -----------------------------------
607
608RegisterID* TypeOfResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
609{
610 if (RegisterID* local = generator.registerForLocal(m_ident))
611 return generator.emitTypeOf(generator.finalDestination(dst), local);
612
613 RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), m_ident);
614 generator.emitGetById(scratch.get(), scratch.get(), m_ident);
615 return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get());
616}
617
618// ------------------------------ TypeOfValueNode -----------------------------------
619
620RegisterID* TypeOfValueNode::emitCode(CodeGenerator& generator, RegisterID* dst)
621{
622 RefPtr<RegisterID> src = generator.emitNode(m_expr.get());
623 return generator.emitTypeOf(generator.finalDestination(dst), src.get());
624}
625
626// ------------------------------ PrefixResolveNode ----------------------------------
627
628RegisterID* PreIncResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
629{
630 if (RegisterID* local = generator.registerForLocal(m_ident)) {
631 if (generator.isLocalConstant(m_ident)) {
632 RefPtr<RegisterID> r0 = generator.emitLoad(generator.finalDestination(dst), 1.0);
633 return generator.emitBinaryOp(op_add, r0.get(), local, r0.get());
634 }
635
636 generator.emitPreInc(local);
637 return generator.moveToDestinationIfNeeded(dst, local);
638 }
639
640 int index = 0;
641 size_t depth = 0;
642 if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) {
643 RefPtr<RegisterID> propDst = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index);
644 generator.emitPreInc(propDst.get());
645 generator.emitPutScopedVar(depth, index, propDst.get());
646 return generator.moveToDestinationIfNeeded(dst, propDst.get());;
647 }
648
649 RefPtr<RegisterID> propDst = generator.tempDestination(dst);
650 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), m_ident);
651 generator.emitPreInc(propDst.get());
652 generator.emitPutById(base.get(), m_ident, propDst.get());
653 return generator.moveToDestinationIfNeeded(dst, propDst.get());
654}
655
656RegisterID* PreDecResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
657{
658 if (RegisterID* local = generator.registerForLocal(m_ident)) {
659 if (generator.isLocalConstant(m_ident)) {
660 RefPtr<RegisterID> r0 = generator.emitLoad(generator.finalDestination(dst), -1.0);
661 return generator.emitBinaryOp(op_add, r0.get(), local, r0.get());
662 }
663
664 generator.emitPreDec(local);
665 return generator.moveToDestinationIfNeeded(dst, local);
666 }
667
668 int index = 0;
669 size_t depth = 0;
670 if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) {
671 RefPtr<RegisterID> propDst = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index);
672 generator.emitPreDec(propDst.get());
673 generator.emitPutScopedVar(depth, index, propDst.get());
674 return generator.moveToDestinationIfNeeded(dst, propDst.get());;
675 }
676
677 RefPtr<RegisterID> propDst = generator.tempDestination(dst);
678 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), m_ident);
679 generator.emitPreDec(propDst.get());
680 generator.emitPutById(base.get(), m_ident, propDst.get());
681 return generator.moveToDestinationIfNeeded(dst, propDst.get());
682}
683
684// ------------------------------ PrefixBracketNode ----------------------------------
685
686RegisterID* PreIncBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
687{
688 RefPtr<RegisterID> base = generator.emitNode(m_base.get());
689 RefPtr<RegisterID> property = generator.emitNode(m_subscript.get());
690 RefPtr<RegisterID> propDst = generator.tempDestination(dst);
691 RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get());
692 generator.emitPreInc(value);
693 generator.emitPutByVal(base.get(), property.get(), value);
694 return generator.moveToDestinationIfNeeded(dst, propDst.get());
695}
696
697RegisterID* PreDecBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
698{
699
700 RefPtr<RegisterID> base = generator.emitNode(m_base.get());
701 RefPtr<RegisterID> property = generator.emitNode(m_subscript.get());
702 RefPtr<RegisterID> propDst = generator.tempDestination(dst);
703 RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get());
704 generator.emitPreDec(value);
705 generator.emitPutByVal(base.get(), property.get(), value);
706 return generator.moveToDestinationIfNeeded(dst, propDst.get());
707}
708
709// ------------------------------ PrefixDotNode ----------------------------------
710
711RegisterID* PreIncDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
712{
713 RefPtr<RegisterID> base = generator.emitNode(m_base.get());
714 RefPtr<RegisterID> propDst = generator.tempDestination(dst);
715 RegisterID* value = generator.emitGetById(propDst.get(), base.get(), m_ident);
716 generator.emitPreInc(value);
717 generator.emitPutById(base.get(), m_ident, value);
718 return generator.moveToDestinationIfNeeded(dst, propDst.get());
719}
720
721RegisterID* PreDecDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
722{
723 RefPtr<RegisterID> base = generator.emitNode(m_base.get());
724 RefPtr<RegisterID> propDst = generator.tempDestination(dst);
725 RegisterID* value = generator.emitGetById(propDst.get(), base.get(), m_ident);
726 generator.emitPreDec(value);
727 generator.emitPutById(base.get(), m_ident, value);
728 return generator.moveToDestinationIfNeeded(dst, propDst.get());
729}
730
731// ------------------------------ PrefixErrorNode -----------------------------------
732
733RegisterID* PrefixErrorNode::emitCode(CodeGenerator& generator, RegisterID*)
734{
735 return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus ? "Prefix ++ operator applied to value that is not a reference." : "Prefix -- operator applied to value that is not a reference.");
736}
737
738// ------------------------------ Unary Operation Nodes -----------------------------------
739
740RegisterID* UnaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
741{
742 RegisterID* src = generator.emitNode(m_expr.get());
743 return generator.emitUnaryOp(opcode(), generator.finalDestination(dst), src);
744}
745
746// ------------------------------ Binary Operation Nodes -----------------------------------
747
748RegisterID* BinaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
749{
750 RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_term1.get(), m_rightHasAssignments, m_term2->isPure(generator));
751 RegisterID* src2 = generator.emitNode(m_term2.get());
752 return generator.emitBinaryOp(opcode(), generator.finalDestination(dst, src1.get()), src1.get(), src2);
753}
754
755RegisterID* ReverseBinaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
756{
757 RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_term1.get(), m_rightHasAssignments, m_term2->isPure(generator));
758 RegisterID* src2 = generator.emitNode(m_term2.get());
759 return generator.emitBinaryOp(opcode(), generator.finalDestination(dst, src1.get()), src2, src1.get());
760}
761
762// ------------------------------ Binary Logical Nodes ----------------------------
763
764RegisterID* LogicalAndNode::emitCode(CodeGenerator& generator, RegisterID* dst)
765{
766 RefPtr<RegisterID> temp = generator.tempDestination(dst);
767 RefPtr<LabelID> target = generator.newLabel();
768
769 generator.emitNode(temp.get(), m_expr1.get());
770 generator.emitJumpIfFalse(temp.get(), target.get());
771 generator.emitNode(temp.get(), m_expr2.get());
772 generator.emitLabel(target.get());
773
774 return generator.moveToDestinationIfNeeded(dst, temp.get());
775}
776
777RegisterID* LogicalOrNode::emitCode(CodeGenerator& generator, RegisterID* dst)
778{
779 RefPtr<RegisterID> temp = generator.tempDestination(dst);
780 RefPtr<LabelID> target = generator.newLabel();
781
782 generator.emitNode(temp.get(), m_expr1.get());
783 generator.emitJumpIfTrue(temp.get(), target.get());
784 generator.emitNode(temp.get(), m_expr2.get());
785 generator.emitLabel(target.get());
786
787 return generator.moveToDestinationIfNeeded(dst, temp.get());
788}
789
790// ------------------------------ ConditionalNode ------------------------------
791
792RegisterID* ConditionalNode::emitCode(CodeGenerator& generator, RegisterID* dst)
793{
794 RefPtr<RegisterID> newDst = generator.finalDestination(dst);
795 RefPtr<LabelID> beforeElse = generator.newLabel();
796 RefPtr<LabelID> afterElse = generator.newLabel();
797
798 RegisterID* cond = generator.emitNode(m_logical.get());
799 generator.emitJumpIfFalse(cond, beforeElse.get());
800
801 generator.emitNode(newDst.get(), m_expr1.get());
802 generator.emitJump(afterElse.get());
803
804 generator.emitLabel(beforeElse.get());
805 generator.emitNode(newDst.get(), m_expr2.get());
806
807 generator.emitLabel(afterElse.get());
808
809 return newDst.get();
810}
811
812// ------------------------------ ReadModifyResolveNode -----------------------------------
813
814// FIXME: should this be moved to be a method on CodeGenerator?
815static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(CodeGenerator& generator, RegisterID* dst, RegisterID* src1, RegisterID* src2, Operator oper)
816{
817 OpcodeID opcode;
818 switch (oper) {
819 case OpMultEq:
820 opcode = op_mul;
821 break;
822 case OpDivEq:
823 opcode = op_div;
824 break;
825 case OpPlusEq:
826 opcode = op_add;
827 break;
828 case OpMinusEq:
829 opcode = op_sub;
830 break;
831 case OpLShift:
832 opcode = op_lshift;
833 break;
834 case OpRShift:
835 opcode = op_rshift;
836 break;
837 case OpURShift:
838 opcode = op_urshift;
839 break;
840 case OpAndEq:
841 opcode = op_bitand;
842 break;
843 case OpXOrEq:
844 opcode = op_bitxor;
845 break;
846 case OpOrEq:
847 opcode = op_bitor;
848 break;
849 case OpModEq:
850 opcode = op_mod;
851 break;
852 default:
853 ASSERT_NOT_REACHED();
854 return dst;
855 }
856
857 return generator.emitBinaryOp(opcode, dst, src1, src2);
858}
859
860RegisterID* ReadModifyResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
861{
862 if (RegisterID* local = generator.registerForLocal(m_ident)) {
863 if (generator.isLocalConstant(m_ident)) {
864 RegisterID* src2 = generator.emitNode(m_right.get());
865 return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, src2, m_operator);
866 }
867
868 if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) {
869 RefPtr<RegisterID> result = generator.newTemporary();
870 generator.emitMove(result.get(), local);
871 RegisterID* src2 = generator.emitNode(m_right.get());
872 emitReadModifyAssignment(generator, result.get(), result.get(), src2, m_operator);
873 generator.emitMove(local, result.get());
874 return generator.moveToDestinationIfNeeded(dst, result.get());
875 }
876
877 RegisterID* src2 = generator.emitNode(m_right.get());
878 RegisterID* result = emitReadModifyAssignment(generator, local, local, src2, m_operator);
879 return generator.moveToDestinationIfNeeded(dst, result);
880 }
881
882 int index = 0;
883 size_t depth = 0;
884 if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) {
885 RefPtr<RegisterID> src1 = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index);
886 RegisterID* src2 = generator.emitNode(m_right.get());
887 RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator);
888 generator.emitPutScopedVar(depth, index, result);
889 return result;
890 }
891
892 RefPtr<RegisterID> src1 = generator.tempDestination(dst);
893 RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident);
894 RegisterID* src2 = generator.emitNode(m_right.get());
895 RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator);
896 return generator.emitPutById(base.get(), m_ident, result);
897}
898
899// ------------------------------ AssignResolveNode -----------------------------------
900
901RegisterID* AssignResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
902{
903 if (RegisterID* local = generator.registerForLocal(m_ident)) {
904 if (generator.isLocalConstant(m_ident))
905 return generator.emitNode(dst, m_right.get());
906
907 RegisterID* result = generator.emitNode(local, m_right.get());
908 return generator.moveToDestinationIfNeeded(dst, result);
909 }
910
911 int index = 0;
912 size_t depth = 0;
913 if (generator.findScopedProperty(m_ident, index, depth) && index != missingSymbolMarker()) {
914 RegisterID* value = generator.emitNode(dst, m_right.get());
915 generator.emitPutScopedVar(depth, index, value);
916 return value;
917 }
918
919 RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident);
920 RegisterID* value = generator.emitNode(dst, m_right.get());
921 return generator.emitPutById(base.get(), m_ident, value);
922}
923
924// ------------------------------ AssignDotNode -----------------------------------
925
926RegisterID* AssignDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
927{
928 RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_rightHasAssignments, m_right->isPure(generator));
929 RefPtr<RegisterID> value = generator.destinationForAssignResult(dst);
930 RegisterID* result = generator.emitNode(value.get(), m_right.get());
931 generator.emitPutById(base.get(), m_ident, result);
932 return generator.moveToDestinationIfNeeded(dst, result);
933}
934
935// ------------------------------ ReadModifyDotNode -----------------------------------
936
937RegisterID* ReadModifyDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
938{
939 RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_rightHasAssignments, m_right->isPure(generator));
940 RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
941 RegisterID* change = generator.emitNode(m_right.get());
942 RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator);
943 return generator.emitPutById(base.get(), m_ident, updatedValue);
944}
945
946// ------------------------------ AssignErrorNode -----------------------------------
947
948RegisterID* AssignErrorNode::emitCode(CodeGenerator& generator, RegisterID*)
949{
950 return emitThrowError(generator, ReferenceError, "Left side of assignment is not a reference.");
951}
952
953// ------------------------------ AssignBracketNode -----------------------------------
954
955RegisterID* AssignBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
956{
957 RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator));
958 RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript.get(), m_rightHasAssignments, m_right->isPure(generator));
959 RefPtr<RegisterID> value = generator.destinationForAssignResult(dst);
960 RegisterID* result = generator.emitNode(value.get(), m_right.get());
961 generator.emitPutByVal(base.get(), property.get(), result);
962 return generator.moveToDestinationIfNeeded(dst, result);
963}
964
965RegisterID* ReadModifyBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
966{
967 RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator));
968 RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript.get(), m_rightHasAssignments, m_right->isPure(generator));
969
970 RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
971 RegisterID* change = generator.emitNode(m_right.get());
972 RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator);
973
974 generator.emitPutByVal(base.get(), property.get(), updatedValue);
975
976 return updatedValue;
977}
978
979// ------------------------------ CommaNode ------------------------------------
980
981RegisterID* CommaNode::emitCode(CodeGenerator& generator, RegisterID* dst)
982{
983 generator.emitNode(m_expr1.get());
984 return generator.emitNode(dst, m_expr2.get());
985}
986
987// ------------------------------ ConstDeclNode ----------------------------------
988
989ConstDeclNode::ConstDeclNode(const Identifier& ident, ExpressionNode* init)
990 : m_ident(ident)
991 , m_init(init)
992{
993}
994
995RegisterID* ConstDeclNode::emitCodeSingle(CodeGenerator& generator)
996{
997 if (RegisterID* local = generator.registerForLocalConstInit(m_ident)) {
998 if (!m_init)
999 return local;
1000
1001 return generator.emitNode(local, m_init.get());
1002 }
1003
1004 // FIXME: While this code should only be hit in eval code, it will potentially
1005 // assign to the wrong base if m_ident exists in an intervening dynamic scope.
1006 RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident);
1007 RegisterID* value = generator.emitNode(m_init.get());
1008 return generator.emitPutById(base.get(), m_ident, value);
1009}
1010
1011RegisterID* ConstDeclNode::emitCode(CodeGenerator& generator, RegisterID*)
1012{
1013 RegisterID* result = 0;
1014 for (ConstDeclNode* n = this; n; n = n->m_next.get())
1015 result = n->emitCodeSingle(generator);
1016
1017 return result;
1018}
1019
1020// ------------------------------ ConstStatementNode -----------------------------
1021
1022RegisterID* ConstStatementNode::emitCode(CodeGenerator& generator, RegisterID*)
1023{
1024 return generator.emitNode(m_next.get());
1025}
1026
1027// ------------------------------ Helper functions for handling Vectors of StatementNode -------------------------------
1028
1029static inline RegisterID* statementListEmitCode(StatementVector& statements, CodeGenerator& generator, RegisterID* dst = 0)
1030{
1031 RefPtr<RegisterID> r0 = dst;
1032
1033 StatementVector::iterator end = statements.end();
1034 for (StatementVector::iterator it = statements.begin(); it != end; ++it) {
1035 StatementNode* n = it->get();
1036 generator.emitDebugHook(WillExecuteStatement, n->firstLine(), n->lastLine());
1037 if (RegisterID* r1 = generator.emitNode(dst, n))
1038 r0 = r1;
1039 }
1040
1041 return r0.get();
1042}
1043
1044static inline void statementListPushFIFO(StatementVector& statements, DeclarationStacks::NodeStack& stack)
1045{
1046 StatementVector::iterator it = statements.end();
1047 StatementVector::iterator begin = statements.begin();
1048 while (it != begin) {
1049 --it;
1050 stack.append((*it).get());
1051 }
1052}
1053
1054static inline Node* statementListInitializeVariableAccessStack(StatementVector& statements, DeclarationStacks::NodeStack& stack)
1055{
1056 if (statements.isEmpty())
1057 return 0;
1058
1059 StatementVector::iterator it = statements.end();
1060 StatementVector::iterator begin = statements.begin();
1061 StatementVector::iterator beginPlusOne = begin + 1;
1062
1063 while (it != beginPlusOne) {
1064 --it;
1065 stack.append((*it).get());
1066 }
1067
1068 return (*begin).get();
1069}
1070
1071// ------------------------------ BlockNode ------------------------------------
1072
1073BlockNode::BlockNode(SourceElements* children)
1074{
1075 if (children)
1076 children->releaseContentsIntoVector(m_children);
1077}
1078
1079RegisterID* BlockNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1080{
1081 return statementListEmitCode(m_children, generator, dst);
1082}
1083
1084// ------------------------------ EmptyStatementNode ---------------------------
1085
1086RegisterID* EmptyStatementNode::emitCode(CodeGenerator&, RegisterID* dst)
1087{
1088 return dst;
1089}
1090
1091// ------------------------------ DebuggerStatementNode ---------------------------
1092
1093RegisterID* DebuggerStatementNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1094{
1095 generator.emitDebugHook(DidReachBreakpoint, firstLine(), lastLine());
1096 return dst;
1097}
1098
1099// ------------------------------ ExprStatementNode ----------------------------
1100
1101RegisterID* ExprStatementNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1102{
1103 ASSERT(m_expr);
1104 return generator.emitNode(dst, m_expr.get());
1105}
1106
1107// ------------------------------ VarStatementNode ----------------------------
1108
1109RegisterID* VarStatementNode::emitCode(CodeGenerator& generator, RegisterID*)
1110{
1111 ASSERT(m_expr);
1112 return generator.emitNode(m_expr.get());
1113}
1114
1115// ------------------------------ IfNode ---------------------------------------
1116
1117RegisterID* IfNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1118{
1119 RefPtr<LabelID> afterThen = generator.newLabel();
1120
1121 RegisterID* cond = generator.emitNode(m_condition.get());
1122 generator.emitJumpIfFalse(cond, afterThen.get());
1123
1124 generator.emitNode(dst, m_ifBlock.get());
1125 generator.emitLabel(afterThen.get());
1126
1127 // FIXME: This should return the last statement exectuted so that it can be returned as a Completion
1128 return 0;
1129}
1130
1131RegisterID* IfElseNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1132{
1133 RefPtr<LabelID> beforeElse = generator.newLabel();
1134 RefPtr<LabelID> afterElse = generator.newLabel();
1135
1136 RegisterID* cond = generator.emitNode(m_condition.get());
1137 generator.emitJumpIfFalse(cond, beforeElse.get());
1138
1139 generator.emitNode(dst, m_ifBlock.get());
1140 generator.emitJump(afterElse.get());
1141
1142 generator.emitLabel(beforeElse.get());
1143 generator.emitNode(dst, m_elseBlock.get());
1144
1145 generator.emitLabel(afterElse.get());
1146
1147 // FIXME: This should return the last statement exectuted so that it can be returned as a Completion
1148 return 0;
1149}
1150
1151// ------------------------------ DoWhileNode ----------------------------------
1152
1153RegisterID* DoWhileNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1154{
1155 RefPtr<LabelID> topOfLoop = generator.newLabel();
1156 generator.emitLabel(topOfLoop.get());
1157
1158 RefPtr<LabelID> continueTarget = generator.newLabel();
1159 RefPtr<LabelID> breakTarget = generator.newLabel();
1160
1161 generator.pushJumpContext(&m_labelStack, continueTarget.get(), breakTarget.get(), true);
1162 RefPtr<RegisterID> result = generator.emitNode(dst, m_statement.get());
1163 generator.popJumpContext();
1164
1165 generator.emitLabel(continueTarget.get());
1166 RegisterID* cond = generator.emitNode(m_expr.get());
1167 generator.emitJumpIfTrueMayCombine(cond, topOfLoop.get());
1168 generator.emitLabel(breakTarget.get());
1169 return result.get();
1170}
1171
1172// ------------------------------ WhileNode ------------------------------------
1173
1174RegisterID* WhileNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1175{
1176 RefPtr<LabelID> topOfLoop = generator.newLabel();
1177 RefPtr<LabelID> continueTarget = generator.newLabel();
1178 RefPtr<LabelID> breakTarget = generator.newLabel();
1179
1180 generator.emitJump(continueTarget.get());
1181 generator.emitLabel(topOfLoop.get());
1182
1183 generator.pushJumpContext(&m_labelStack, continueTarget.get(), breakTarget.get(), true);
1184 generator.emitNode(dst, m_statement.get());
1185 generator.popJumpContext();
1186
1187 generator.emitLabel(continueTarget.get());
1188 RegisterID* cond = generator.emitNode(m_expr.get());
1189 generator.emitJumpIfTrueMayCombine(cond, topOfLoop.get());
1190
1191 generator.emitLabel(breakTarget.get());
1192
1193 // FIXME: This should return the last statement executed so that it can be returned as a Completion
1194 return 0;
1195}
1196
1197// ------------------------------ ForNode --------------------------------------
1198
1199RegisterID* ForNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1200{
1201 if (m_expr1)
1202 generator.emitNode(m_expr1.get());
1203
1204 RefPtr<LabelID> topOfLoop = generator.newLabel();
1205 RefPtr<LabelID> beforeCondition = generator.newLabel();
1206 RefPtr<LabelID> continueTarget = generator.newLabel();
1207 RefPtr<LabelID> breakTarget = generator.newLabel();
1208 generator.emitJump(beforeCondition.get());
1209
1210 generator.emitLabel(topOfLoop.get());
1211 generator.pushJumpContext(&m_labelStack, continueTarget.get(), breakTarget.get(), true);
1212 RefPtr<RegisterID> result = generator.emitNode(dst, m_statement.get());
1213 generator.popJumpContext();
1214 generator.emitLabel(continueTarget.get());
1215 if (m_expr3)
1216 generator.emitNode(m_expr3.get());
1217
1218 generator.emitLabel(beforeCondition.get());
1219 if (m_expr2) {
1220 RegisterID* cond = generator.emitNode(m_expr2.get());
1221 generator.emitJumpIfTrueMayCombine(cond, topOfLoop.get());
1222 } else {
1223 generator.emitJump(topOfLoop.get());
1224 }
1225 generator.emitLabel(breakTarget.get());
1226 return result.get();
1227}
1228
1229// ------------------------------ ForInNode ------------------------------------
1230
1231ForInNode::ForInNode(ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
1232 : m_init(0L)
1233 , m_lexpr(l)
1234 , m_expr(expr)
1235 , m_statement(statement)
1236 , m_identIsVarDecl(false)
1237{
1238}
1239
1240ForInNode::ForInNode(const Identifier& ident, ExpressionNode* in, ExpressionNode* expr, StatementNode* statement)
1241 : m_ident(ident)
1242 , m_lexpr(new ResolveNode(ident))
1243 , m_expr(expr)
1244 , m_statement(statement)
1245 , m_identIsVarDecl(true)
1246{
1247 if (in)
1248 m_init = new AssignResolveNode(ident, in, true);
1249 // for( var foo = bar in baz )
1250}
1251
1252RegisterID* ForInNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1253{
1254 RefPtr<LabelID> loopStart = generator.newLabel();
1255 RefPtr<LabelID> continueTarget = generator.newLabel();
1256 RefPtr<LabelID> breakTarget = generator.newLabel();
1257
1258 if (m_init)
1259 generator.emitNode(m_init.get());
1260 RegisterID* forInBase = generator.emitNode(m_expr.get());
1261 RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), forInBase);
1262 generator.emitJump(continueTarget.get());
1263 generator.emitLabel(loopStart.get());
1264 RegisterID* propertyName;
1265 if (m_lexpr->isResolveNode()) {
1266 const Identifier& ident = static_cast<ResolveNode*>(m_lexpr.get())->identifier();
1267 propertyName = generator.registerForLocal(ident);
1268 if (!propertyName) {
1269 propertyName = generator.newTemporary();
1270 RefPtr<RegisterID> protect = propertyName;
1271 RegisterID* base = generator.emitResolveBase(generator.newTemporary(), ident);
1272 generator.emitPutById(base, ident, propertyName);
1273 }
1274 } else if (m_lexpr->isDotAccessorNode()) {
1275 DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr.get());
1276 const Identifier& ident = assignNode->identifier();
1277 propertyName = generator.newTemporary();
1278 RefPtr<RegisterID> protect = propertyName;
1279 RegisterID* base = generator.emitNode(assignNode->base());
1280 generator.emitPutById(base, ident, propertyName);
1281 } else {
1282 ASSERT(m_lexpr->isBracketAccessorNode());
1283 BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr.get());
1284 propertyName = generator.newTemporary();
1285 RefPtr<RegisterID> protect = propertyName;
1286 RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
1287 RegisterID* subscript = generator.emitNode(assignNode->subscript());
1288 generator.emitPutByVal(base.get(), subscript, propertyName);
1289 }
1290
1291 generator.pushJumpContext(&m_labelStack, continueTarget.get(), breakTarget.get(), true);
1292 generator.emitNode(dst, m_statement.get());
1293 generator.popJumpContext();
1294
1295 generator.emitLabel(continueTarget.get());
1296 generator.emitNextPropertyName(propertyName, iter.get(), loopStart.get());
1297 generator.emitLabel(breakTarget.get());
1298 return dst;
1299}
1300
1301// ------------------------------ ContinueNode ---------------------------------
1302
1303// ECMA 12.7
1304RegisterID* ContinueNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1305{
1306 if (!generator.inContinueContext())
1307 return emitThrowError(generator, SyntaxError, "Invalid continue statement.");
1308
1309 JumpContext* targetContext = generator.jumpContextForContinue(m_ident);
1310
1311 if (!targetContext) {
1312 if (m_ident.isEmpty())
1313 return emitThrowError(generator, SyntaxError, "Invalid continue statement.");
1314 else
1315 return emitThrowError(generator, SyntaxError, "Label %s not found.", m_ident);
1316 }
1317
1318 if (!targetContext->continueTarget)
1319 return emitThrowError(generator, SyntaxError, "Invalid continue statement.");
1320
1321 generator.emitJumpScopes(targetContext->continueTarget, targetContext->scopeDepth);
1322
1323 return dst;
1324}
1325
1326// ------------------------------ BreakNode ------------------------------------
1327
1328// ECMA 12.8
1329RegisterID* BreakNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1330{
1331 if (!generator.inJumpContext())
1332 return emitThrowError(generator, SyntaxError, "Invalid break statement.");
1333
1334 JumpContext* targetContext = generator.jumpContextForBreak(m_ident);
1335
1336 if (!targetContext) {
1337 if (m_ident.isEmpty())
1338 return emitThrowError(generator, SyntaxError, "Invalid break statement.");
1339 else
1340 return emitThrowError(generator, SyntaxError, "Label %s not found.", m_ident);
1341 }
1342
1343 ASSERT(targetContext->breakTarget);
1344
1345 generator.emitJumpScopes(targetContext->breakTarget, targetContext->scopeDepth);
1346
1347 return dst;
1348}
1349
1350// ------------------------------ ReturnNode -----------------------------------
1351
1352RegisterID* ReturnNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1353{
1354 if (generator.codeType() != FunctionCode)
1355 return emitThrowError(generator, SyntaxError, "Invalid return statement.");
1356
1357 RegisterID* r0 = m_value ? generator.emitNode(dst, m_value.get()) : generator.emitLoad(generator.finalDestination(dst), jsUndefined());
1358 if (generator.scopeDepth()) {
1359 RefPtr<LabelID> l0 = generator.newLabel();
1360 generator.emitJumpScopes(l0.get(), 0);
1361 generator.emitLabel(l0.get());
1362 }
1363 generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine());
1364 return generator.emitReturn(r0);
1365}
1366
1367// ------------------------------ WithNode -------------------------------------
1368
1369RegisterID* WithNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1370{
1371 RefPtr<RegisterID> scope = generator.emitNode(m_expr.get()); // scope must be protected until popped
1372 generator.emitPushScope(scope.get());
1373 RegisterID* result = generator.emitNode(dst, m_statement.get());
1374 generator.emitPopScope();
1375 return result;
1376}
1377
1378// ------------------------------ CaseBlockNode --------------------------------
1379
1380RegisterID* CaseBlockNode::emitCodeForBlock(CodeGenerator& generator, RegisterID* switchExpression, RegisterID* dst)
1381{
1382 Vector<RefPtr<LabelID>, 8> labelVector;
1383
1384 // Setup jumps
1385 for (ClauseListNode* list = m_list1.get(); list; list = list->getNext()) {
1386 RegisterID* clauseVal = generator.emitNode(list->getClause()->expr());
1387 generator.emitBinaryOp(op_stricteq, clauseVal, clauseVal, switchExpression);
1388 labelVector.append(generator.newLabel());
1389 generator.emitJumpIfTrueMayCombine(clauseVal, labelVector[labelVector.size() - 1].get());
1390 }
1391
1392 for (ClauseListNode* list = m_list2.get(); list; list = list->getNext()) {
1393 RegisterID* clauseVal = generator.emitNode(list->getClause()->expr());
1394 generator.emitBinaryOp(op_stricteq, clauseVal, clauseVal, switchExpression);
1395 labelVector.append(generator.newLabel());
1396 generator.emitJumpIfTrueMayCombine(clauseVal, labelVector[labelVector.size() - 1].get());
1397 }
1398
1399 RefPtr<LabelID> defaultLabel;
1400 defaultLabel = generator.newLabel();
1401 generator.emitJump(defaultLabel.get());
1402
1403 RegisterID* result = 0;
1404
1405 size_t i = 0;
1406 for (ClauseListNode* list = m_list1.get(); list; list = list->getNext()) {
1407 generator.emitLabel(labelVector[i++].get());
1408 result = statementListEmitCode(list->getClause()->children(), generator, dst);
1409 }
1410
1411 if (m_defaultClause) {
1412 generator.emitLabel(defaultLabel.get());
1413 result = statementListEmitCode(m_defaultClause->children(), generator, dst);
1414 }
1415
1416 for (ClauseListNode* list = m_list2.get(); list; list = list->getNext()) {
1417 generator.emitLabel(labelVector[i++].get());
1418 result = statementListEmitCode(list->getClause()->children(), generator, dst);
1419 }
1420 if (!m_defaultClause)
1421 generator.emitLabel(defaultLabel.get());
1422
1423 ASSERT(i == labelVector.size());
1424
1425 return result;
1426}
1427
1428// ------------------------------ SwitchNode -----------------------------------
1429
1430RegisterID* SwitchNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1431{
1432 RefPtr<LabelID> breakTarget = generator.newLabel();
1433
1434 RefPtr<RegisterID> r0 = generator.emitNode(m_expr.get());
1435 generator.pushJumpContext(&m_labelStack, 0, breakTarget.get(), true);
1436 RegisterID* r1 = m_block->emitCodeForBlock(generator, r0.get(), dst);
1437 generator.popJumpContext();
1438
1439 generator.emitLabel(breakTarget.get());
1440
1441 return r1;
1442}
1443
1444// ------------------------------ LabelNode ------------------------------------
1445
1446RegisterID* LabelNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1447{
1448 if (generator.jumpContextForBreak(m_label))
1449 return emitThrowError(generator, SyntaxError, "Duplicated label %s found.", m_label);
1450
1451 RefPtr<LabelID> l0 = generator.newLabel();
1452 m_labelStack.push(m_label);
1453 generator.pushJumpContext(&m_labelStack, 0, l0.get(), false);
1454
1455 RegisterID* r0 = generator.emitNode(dst, m_statement.get());
1456
1457 generator.popJumpContext();
1458 m_labelStack.pop();
1459
1460 generator.emitLabel(l0.get());
1461 return r0;
1462}
1463
1464// ------------------------------ ThrowNode ------------------------------------
1465
1466RegisterID* ThrowNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1467{
1468 generator.emitThrow(generator.emitNode(dst, m_expr.get()));
1469 return dst;
1470}
1471
1472// ------------------------------ TryNode --------------------------------------
1473
1474RegisterID* TryNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1475{
1476 RefPtr<LabelID> tryStartLabel = generator.newLabel();
1477 RefPtr<LabelID> tryEndLabel = generator.newLabel();
1478 RefPtr<LabelID> finallyStart;
1479 RefPtr<RegisterID> finallyReturnAddr;
1480 if (m_finallyBlock) {
1481 finallyStart = generator.newLabel();
1482 finallyReturnAddr = generator.newTemporary();
1483 generator.pushFinallyContext(finallyStart.get(), finallyReturnAddr.get());
1484 }
1485 generator.emitLabel(tryStartLabel.get());
1486 generator.emitNode(dst, m_tryBlock.get());
1487 generator.emitLabel(tryEndLabel.get());
1488
1489 if (m_catchBlock) {
1490 RefPtr<LabelID> handlerEndLabel = generator.newLabel();
1491 generator.emitJump(handlerEndLabel.get());
1492 RefPtr<RegisterID> exceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), tryEndLabel.get());
1493 RefPtr<RegisterID> newScope = generator.emitNewObject(generator.newTemporary()); // scope must be protected until popped
1494 generator.emitPutById(newScope.get(), m_exceptionIdent, exceptionRegister.get());
1495 exceptionRegister = 0; // Release register used for temporaries
1496 generator.emitPushScope(newScope.get());
1497 generator.emitNode(dst, m_catchBlock.get());
1498 generator.emitPopScope();
1499 generator.emitLabel(handlerEndLabel.get());
1500 }
1501
1502 if (m_finallyBlock) {
1503 generator.popFinallyContext();
1504 // there may be important registers live at the time we jump
1505 // to a finally block (such as for a return or throw) so we
1506 // ref the highest register ever used as a conservative
1507 // approach to not clobbering anything important
1508 RefPtr<RegisterID> highestUsedRegister = generator.highestUsedRegister();
1509 RefPtr<LabelID> finallyEndLabel = generator.newLabel();
1510 generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get());
1511 generator.emitJump(finallyEndLabel.get());
1512
1513 // Finally block for exception path
1514 RefPtr<RegisterID> tempExceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), generator.emitLabel(generator.newLabel().get()).get());
1515 generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get());
1516 generator.emitThrow(tempExceptionRegister.get());
1517
1518 // emit the finally block itself
1519 generator.emitLabel(finallyStart.get());
1520 generator.emitNode(dst, m_finallyBlock.get());
1521 generator.emitSubroutineReturn(finallyReturnAddr.get());
1522
1523 generator.emitLabel(finallyEndLabel.get());
1524 }
1525
1526 return dst;
1527}
1528
1529
1530// ------------------------------ FunctionBodyNode -----------------------------
1531
1532ScopeNode::ScopeNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack, bool usesEval, bool needsClosure)
1533 : BlockNode(children)
1534 , m_sourceURL(JSGlobalData::threadInstance().parser->sourceURL())
1535 , m_sourceId(JSGlobalData::threadInstance().parser->sourceId())
1536 , m_usesEval(usesEval)
1537 , m_needsClosure(needsClosure)
1538{
1539 if (varStack)
1540 m_varStack = *varStack;
1541 if (funcStack)
1542 m_functionStack = *funcStack;
1543}
1544
1545// ------------------------------ ProgramNode -----------------------------
1546
1547ProgramNode::ProgramNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack, bool usesEval, bool needsClosure)
1548 : ScopeNode(children, varStack, funcStack, usesEval, needsClosure)
1549{
1550}
1551
1552ProgramNode* ProgramNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack, bool usesEval, bool needsClosure)
1553{
1554 return new ProgramNode(children, varStack, funcStack, usesEval, needsClosure);
1555}
1556
1557// ------------------------------ EvalNode -----------------------------
1558
1559EvalNode::EvalNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack, bool usesEval, bool needsClosure)
1560 : ScopeNode(children, varStack, funcStack, usesEval, needsClosure)
1561{
1562}
1563
1564RegisterID* EvalNode::emitCode(CodeGenerator& generator, RegisterID*)
1565{
1566 generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine());
1567
1568 RefPtr<RegisterID> dstRegister = generator.newTemporary();
1569 generator.emitLoad(dstRegister.get(), jsUndefined());
1570 statementListEmitCode(m_children, generator, dstRegister.get());
1571
1572 generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine());
1573 generator.emitEnd(dstRegister.get());
1574 return 0;
1575}
1576
1577void EvalNode::generateCode(ScopeChainNode* sc)
1578{
1579 ScopeChain scopeChain(sc);
1580 JSGlobalObject* globalObject = scopeChain.globalObject();
1581
1582 SymbolTable symbolTable;
1583
1584 m_code.set(new EvalCodeBlock(this, globalObject));
1585
1586 CodeGenerator generator(this, globalObject->debugger(), scopeChain, &symbolTable, m_code.get());
1587 generator.generate();
1588}
1589
1590EvalNode* EvalNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack, bool usesEval, bool needsClosure)
1591{
1592 return new EvalNode(children, varStack, funcStack, usesEval, needsClosure);
1593}
1594
1595// ------------------------------ FunctionBodyNode -----------------------------
1596
1597FunctionBodyNode::FunctionBodyNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack, bool usesEval, bool needsClosure)
1598 : ScopeNode(children, varStack, funcStack, usesEval, needsClosure)
1599{
1600}
1601
1602void FunctionBodyNode::mark()
1603{
1604 if (m_code)
1605 m_code->mark();
1606}
1607
1608FunctionBodyNode* FunctionBodyNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack, bool usesEval, bool needsClosure)
1609{
1610 return new FunctionBodyNode(children, varStack, funcStack, usesEval, needsClosure);
1611}
1612
1613void FunctionBodyNode::generateCode(ScopeChainNode* sc)
1614{
1615 ScopeChain scopeChain(sc);
1616 JSGlobalObject* globalObject = scopeChain.globalObject();
1617
1618 m_code.set(new CodeBlock(this, FunctionCode));
1619
1620 CodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_symbolTable, m_code.get());
1621 generator.generate();
1622}
1623
1624RegisterID* FunctionBodyNode::emitCode(CodeGenerator& generator, RegisterID*)
1625{
1626 generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine());
1627 statementListEmitCode(m_children, generator);
1628 if (!m_children.size() || !m_children.last()->isReturnNode()) {
1629 RegisterID* r0 = generator.emitLoad(generator.newTemporary(), jsUndefined());
1630 generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine());
1631 generator.emitReturn(r0);
1632 }
1633 return 0;
1634}
1635
1636RegisterID* ProgramNode::emitCode(CodeGenerator& generator, RegisterID*)
1637{
1638 generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine());
1639
1640 RefPtr<RegisterID> dstRegister = generator.newTemporary();
1641 generator.emitLoad(dstRegister.get(), jsUndefined());
1642 statementListEmitCode(m_children, generator, dstRegister.get());
1643
1644 generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine());
1645 generator.emitEnd(dstRegister.get());
1646 return 0;
1647}
1648
1649void ProgramNode::generateCode(ScopeChainNode* sc, bool canCreateGlobals)
1650{
1651 ScopeChain scopeChain(sc);
1652 JSGlobalObject* globalObject = scopeChain.globalObject();
1653
1654 m_code.set(new ProgramCodeBlock(this, GlobalCode, globalObject));
1655
1656 CodeGenerator generator(this, globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_code.get(), m_varStack, m_functionStack, canCreateGlobals);
1657 generator.generate();
1658}
1659
1660UString FunctionBodyNode::paramString() const
1661{
1662 UString s("");
1663 size_t count = m_parameters.size();
1664 for (size_t pos = 0; pos < count; ++pos) {
1665 if (!s.isEmpty())
1666 s += ", ";
1667 s += m_parameters[pos].ustring();
1668 }
1669
1670 return s;
1671}
1672
1673// ------------------------------ FuncDeclNode ---------------------------------
1674
1675void FuncDeclNode::addParams()
1676{
1677 for (ParameterNode* p = m_parameter.get(); p; p = p->nextParam())
1678 m_body->parameters().append(p->ident());
1679}
1680
1681JSFunction* FuncDeclNode::makeFunction(ExecState* exec, ScopeChainNode* scopeChain)
1682{
1683 JSFunction* func = new (exec) JSFunction(exec, m_ident, m_body.get(), scopeChain);
1684
1685 JSObject* proto = constructEmptyObject(exec);
1686 proto->putDirect(exec->propertyNames().constructor, func, DontEnum);
1687 func->putDirect(exec->propertyNames().prototype, proto, DontDelete);
1688 func->putDirect(exec->propertyNames().length, jsNumber(exec, m_body->parameters().size()), ReadOnly | DontDelete | DontEnum);
1689 return func;
1690}
1691
1692RegisterID* FuncDeclNode::emitCode(CodeGenerator&, RegisterID* dst)
1693{
1694 return dst;
1695}
1696
1697// ------------------------------ FuncExprNode ---------------------------------
1698
1699RegisterID* FuncExprNode::emitCode(CodeGenerator& generator, RegisterID* dst)
1700{
1701 return generator.emitNewFunctionExpression(generator.finalDestination(dst), this);
1702}
1703
1704JSFunction* FuncExprNode::makeFunction(ExecState* exec, ScopeChainNode* scopeChain)
1705{
1706 JSFunction* func = new (exec) JSFunction(exec, m_ident, m_body.get(), scopeChain);
1707 JSObject* proto = constructEmptyObject(exec);
1708 proto->putDirect(exec->propertyNames().constructor, func, DontEnum);
1709 func->putDirect(exec->propertyNames().prototype, proto, DontDelete);
1710
1711 /*
1712 The Identifier in a FunctionExpression can be referenced from inside
1713 the FunctionExpression's FunctionBody to allow the function to call
1714 itself recursively. However, unlike in a FunctionDeclaration, the
1715 Identifier in a FunctionExpression cannot be referenced from and
1716 does not affect the scope enclosing the FunctionExpression.
1717 */
1718
1719 if (!m_ident.isNull()) {
1720 JSObject* functionScopeObject = new (exec) JSObject;
1721 functionScopeObject->putDirect(m_ident, func, ReadOnly | DontDelete);
1722 func->scope().push(functionScopeObject);
1723 }
1724
1725 return func;
1726}
1727
1728// ECMA 13
1729void FuncExprNode::addParams()
1730{
1731 for (ParameterNode* p = m_parameter.get(); p; p = p->nextParam())
1732 m_body->parameters().append(p->ident());
1733}
1734
1735} // namespace KJS
Note: See TracBrowser for help on using the repository browser.