source: webkit/trunk/JavaScriptCore/runtime/JSObject.h@ 61623

Last change on this file since 61623 was 60762, checked in by [email protected], 15 years ago

Bug 40214 - Clean up error construction / throwing in JSC.

Reviewed by Sam Weinig.

The one egregious insanity here is that creating an error requires
a VM-entry-esqe-host call (the string argument is wrapped as a JS
object & pushed on the RegisterFile, then unwrapped back to a
UString). Changing this also means you only require a global
object, not an ExecState, to create an error.

The methods to create error objects are also parameterized
requiring a switch on the type, which can be made cleaner and
faster by moving to a separate method per error type. Code to add
divot information to error had been duplicated, and is coalesced
back into a single function.

Convenience methods added to create & throw type & syntax error
with a default error message, since this is a common case.

Also, errors are currently thrown either using
"throwError(exec, error)" or "exec->setException(error)" - unify
on the former, since this is more commonly used. Add
"throwVMError(exec, error)" equivalents, as a convenience for
cases where the result was being wrapped in "JSValue::encode(...)".

JavaScriptCore:

  • API/JSCallbackConstructor.cpp:

(JSC::constructJSCallback):

  • API/JSCallbackFunction.cpp:

(JSC::JSCallbackFunction::call):

  • API/JSCallbackObjectFunctions.h:

(JSC::::getOwnPropertySlot):
(JSC::::put):
(JSC::::deleteProperty):
(JSC::::construct):
(JSC::::hasInstance):
(JSC::::call):
(JSC::::toNumber):
(JSC::::toString):
(JSC::::staticValueGetter):
(JSC::::staticFunctionGetter):
(JSC::::callbackGetter):

  • API/JSObjectRef.cpp:

(JSObjectMakeError):

(JSC::BytecodeGenerator::emitNewError):
(JSC::BytecodeGenerator::emitThrowExpressionTooDeepException):

  • bytecompiler/BytecodeGenerator.h:
  • bytecompiler/NodesCodegen.cpp:

(JSC::ThrowableExpressionData::emitThrowError):
(JSC::RegExpNode::emitBytecode):
(JSC::PostfixErrorNode::emitBytecode):
(JSC::PrefixErrorNode::emitBytecode):
(JSC::AssignErrorNode::emitBytecode):
(JSC::ForInNode::emitBytecode):
(JSC::ContinueNode::emitBytecode):
(JSC::BreakNode::emitBytecode):
(JSC::ReturnNode::emitBytecode):
(JSC::LabelNode::emitBytecode):

  • interpreter/CallFrame.h:
  • interpreter/Interpreter.cpp:

(JSC::Interpreter::throwException):
(JSC::Interpreter::privateExecute):

  • jit/JITStubs.cpp:

(JSC::DEFINE_STUB_FUNCTION):

  • jsc.cpp:

(functionRun):
(functionLoad):
(functionCheckSyntax):

  • parser/Nodes.h:
  • runtime/ArrayConstructor.cpp:

(JSC::constructArrayWithSizeQuirk):

  • runtime/ArrayPrototype.cpp:

(JSC::arrayProtoFuncToString):
(JSC::arrayProtoFuncToLocaleString):
(JSC::arrayProtoFuncJoin):
(JSC::arrayProtoFuncFilter):
(JSC::arrayProtoFuncMap):
(JSC::arrayProtoFuncEvery):
(JSC::arrayProtoFuncForEach):
(JSC::arrayProtoFuncSome):
(JSC::arrayProtoFuncReduce):
(JSC::arrayProtoFuncReduceRight):

  • runtime/BooleanPrototype.cpp:

(JSC::booleanProtoFuncToString):
(JSC::booleanProtoFuncValueOf):

  • runtime/DatePrototype.cpp:

(JSC::dateProtoFuncToString):
(JSC::dateProtoFuncToUTCString):
(JSC::dateProtoFuncToISOString):
(JSC::dateProtoFuncToDateString):
(JSC::dateProtoFuncToTimeString):
(JSC::dateProtoFuncToLocaleString):
(JSC::dateProtoFuncToLocaleDateString):
(JSC::dateProtoFuncToLocaleTimeString):
(JSC::dateProtoFuncGetTime):
(JSC::dateProtoFuncGetFullYear):
(JSC::dateProtoFuncGetUTCFullYear):
(JSC::dateProtoFuncToGMTString):
(JSC::dateProtoFuncGetMonth):
(JSC::dateProtoFuncGetUTCMonth):
(JSC::dateProtoFuncGetDate):
(JSC::dateProtoFuncGetUTCDate):
(JSC::dateProtoFuncGetDay):
(JSC::dateProtoFuncGetUTCDay):
(JSC::dateProtoFuncGetHours):
(JSC::dateProtoFuncGetUTCHours):
(JSC::dateProtoFuncGetMinutes):
(JSC::dateProtoFuncGetUTCMinutes):
(JSC::dateProtoFuncGetSeconds):
(JSC::dateProtoFuncGetUTCSeconds):
(JSC::dateProtoFuncGetMilliSeconds):
(JSC::dateProtoFuncGetUTCMilliseconds):
(JSC::dateProtoFuncGetTimezoneOffset):
(JSC::dateProtoFuncSetTime):
(JSC::setNewValueFromTimeArgs):
(JSC::setNewValueFromDateArgs):
(JSC::dateProtoFuncSetMilliSeconds):
(JSC::dateProtoFuncSetUTCMilliseconds):
(JSC::dateProtoFuncSetSeconds):
(JSC::dateProtoFuncSetUTCSeconds):
(JSC::dateProtoFuncSetMinutes):
(JSC::dateProtoFuncSetUTCMinutes):
(JSC::dateProtoFuncSetHours):
(JSC::dateProtoFuncSetUTCHours):
(JSC::dateProtoFuncSetDate):
(JSC::dateProtoFuncSetUTCDate):
(JSC::dateProtoFuncSetMonth):
(JSC::dateProtoFuncSetUTCMonth):
(JSC::dateProtoFuncSetFullYear):
(JSC::dateProtoFuncSetUTCFullYear):
(JSC::dateProtoFuncSetYear):
(JSC::dateProtoFuncGetYear):
(JSC::dateProtoFuncToJSON):

  • runtime/Error.cpp:

(JSC::createError):
(JSC::createEvalError):
(JSC::createRangeError):
(JSC::createReferenceError):
(JSC::createSyntaxError):
(JSC::createTypeError):
(JSC::createURIError):
(JSC::addErrorSourceInfo):
(JSC::addErrorDivotInfo):
(JSC::addErrorInfo):
(JSC::hasErrorInfo):
(JSC::throwError):
(JSC::throwTypeError):
(JSC::throwSyntaxError):

  • runtime/Error.h:

(JSC::throwVMError):
(JSC::throwVMTypeError):

  • runtime/ErrorConstructor.cpp:

(JSC::constructWithErrorConstructor):
(JSC::callErrorConstructor):

  • runtime/ErrorConstructor.h:
  • runtime/ErrorInstance.cpp:

(JSC::ErrorInstance::ErrorInstance):
(JSC::ErrorInstance::create):

  • runtime/ErrorInstance.h:
  • runtime/ErrorPrototype.cpp:

(JSC::ErrorPrototype::ErrorPrototype):

  • runtime/ExceptionHelpers.cpp:

(JSC::createStackOverflowError):
(JSC::createUndefinedVariableError):
(JSC::createInvalidParamError):
(JSC::createNotAConstructorError):
(JSC::createNotAFunctionError):
(JSC::createNotAnObjectError):
(JSC::throwOutOfMemoryError):

  • runtime/ExceptionHelpers.h:
  • runtime/Executable.cpp:

(JSC::EvalExecutable::compile):
(JSC::ProgramExecutable::checkSyntax):
(JSC::ProgramExecutable::compile):

  • runtime/FunctionConstructor.cpp:

(JSC::constructFunction):

  • runtime/FunctionPrototype.cpp:

(JSC::functionProtoFuncToString):
(JSC::functionProtoFuncApply):
(JSC::functionProtoFuncCall):

  • runtime/Identifier.cpp:

(JSC::Identifier::from):

  • runtime/Identifier.h:
  • runtime/JSArray.cpp:

(JSC::JSArray::put):

  • runtime/JSFunction.cpp:

(JSC::callHostFunctionAsConstructor):

  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::encode):
(JSC::decode):
(JSC::globalFuncEval):

  • runtime/JSONObject.cpp:

(JSC::Stringifier::appendStringifiedValue):
(JSC::Walker::walk):
(JSC::JSONProtoFuncParse):
(JSC::JSONProtoFuncStringify):

  • runtime/JSObject.cpp:

(JSC::throwSetterError):
(JSC::JSObject::put):
(JSC::JSObject::putWithAttributes):
(JSC::JSObject::defaultValue):
(JSC::JSObject::hasInstance):
(JSC::JSObject::defineOwnProperty):

  • runtime/JSObject.h:
  • runtime/JSValue.cpp:

(JSC::JSValue::toObjectSlowCase):
(JSC::JSValue::synthesizeObject):
(JSC::JSValue::synthesizePrototype):

  • runtime/NativeErrorConstructor.cpp:

(JSC::constructWithNativeErrorConstructor):
(JSC::callNativeErrorConstructor):

  • runtime/NativeErrorConstructor.h:
  • runtime/NumberPrototype.cpp:

(JSC::numberProtoFuncToString):
(JSC::numberProtoFuncToLocaleString):
(JSC::numberProtoFuncValueOf):
(JSC::numberProtoFuncToFixed):
(JSC::numberProtoFuncToExponential):
(JSC::numberProtoFuncToPrecision):

  • runtime/ObjectConstructor.cpp:

(JSC::objectConstructorGetPrototypeOf):
(JSC::objectConstructorGetOwnPropertyDescriptor):
(JSC::objectConstructorGetOwnPropertyNames):
(JSC::objectConstructorKeys):
(JSC::toPropertyDescriptor):
(JSC::objectConstructorDefineProperty):
(JSC::objectConstructorDefineProperties):
(JSC::objectConstructorCreate):

  • runtime/ObjectPrototype.cpp:

(JSC::objectProtoFuncDefineGetter):
(JSC::objectProtoFuncDefineSetter):

  • runtime/RegExpConstructor.cpp:

(JSC::constructRegExp):

  • runtime/RegExpObject.cpp:

(JSC::RegExpObject::match):

  • runtime/RegExpPrototype.cpp:

(JSC::regExpProtoFuncTest):
(JSC::regExpProtoFuncExec):
(JSC::regExpProtoFuncCompile):
(JSC::regExpProtoFuncToString):

  • runtime/StringPrototype.cpp:

(JSC::stringProtoFuncToString):

WebCore:

  • WebCore.xcodeproj/project.pbxproj:
  • bindings/js/JSArrayBufferConstructor.h:

(WebCore::construct):

  • bindings/js/JSArrayBufferViewHelper.h:

(WebCore::setWebGLArrayHelper):

  • bindings/js/JSAudioConstructor.cpp:

(WebCore::constructAudio):

  • bindings/js/JSCanvasRenderingContext2DCustom.cpp:

(WebCore::JSCanvasRenderingContext2D::setFillColor):
(WebCore::JSCanvasRenderingContext2D::setStrokeColor):
(WebCore::JSCanvasRenderingContext2D::drawImage):
(WebCore::JSCanvasRenderingContext2D::drawImageFromRect):
(WebCore::JSCanvasRenderingContext2D::setShadow):
(WebCore::JSCanvasRenderingContext2D::createPattern):
(WebCore::JSCanvasRenderingContext2D::fillText):
(WebCore::JSCanvasRenderingContext2D::strokeText):

  • bindings/js/JSClipboardCustom.cpp:

(WebCore::JSClipboard::clearData):
(WebCore::JSClipboard::getData):
(WebCore::JSClipboard::setDragImage):

  • bindings/js/JSDOMBinding.cpp:

(WebCore::setDOMException):
(WebCore::toJSSequence):

  • bindings/js/JSDOMWrapper.cpp:

(WebCore::DOMObject::defineOwnProperty):

  • bindings/js/JSDesktopNotificationsCustom.cpp:

(WebCore::JSNotificationCenter::requestPermission):

  • bindings/js/JSEventSourceConstructor.cpp:

(WebCore::constructEventSource):

  • bindings/js/JSHTMLDocumentCustom.cpp:

(WebCore::JSHTMLDocument::open):

  • bindings/js/JSHTMLInputElementCustom.cpp:

(WebCore::JSHTMLInputElement::selectionStart):
(WebCore::JSHTMLInputElement::setSelectionStart):
(WebCore::JSHTMLInputElement::selectionEnd):
(WebCore::JSHTMLInputElement::setSelectionEnd):
(WebCore::JSHTMLInputElement::setSelectionRange):

  • bindings/js/JSImageConstructor.cpp:

(WebCore::constructImage):

  • bindings/js/JSJavaScriptCallFrameCustom.cpp:

(WebCore::JSJavaScriptCallFrame::evaluate):

  • bindings/js/JSMessageChannelConstructor.cpp:

(WebCore::JSMessageChannelConstructor::construct):

  • bindings/js/JSMessagePortCustom.cpp:

(WebCore::fillMessagePortArray):

  • bindings/js/JSOptionConstructor.cpp:

(WebCore::constructHTMLOptionElement):

  • bindings/js/JSSVGMatrixCustom.cpp:

(WebCore::JSSVGMatrix::multiply):

  • bindings/js/JSSharedWorkerConstructor.cpp:

(WebCore::constructSharedWorker):

  • bindings/js/JSWebGLRenderingContextCustom.cpp:

(WebCore::JSWebGLRenderingContext::bufferData):
(WebCore::JSWebGLRenderingContext::bufferSubData):
(WebCore::getObjectParameter):
(WebCore::JSWebGLRenderingContext::getFramebufferAttachmentParameter):
(WebCore::JSWebGLRenderingContext::getParameter):
(WebCore::JSWebGLRenderingContext::getProgramParameter):
(WebCore::JSWebGLRenderingContext::getShaderParameter):
(WebCore::JSWebGLRenderingContext::getUniform):
(WebCore::JSWebGLRenderingContext::texImage2D):
(WebCore::JSWebGLRenderingContext::texSubImage2D):
(WebCore::dataFunctionf):
(WebCore::dataFunctioni):
(WebCore::dataFunctionMatrix):

  • bindings/js/JSWebSocketConstructor.cpp:

(WebCore::constructWebSocket):

  • bindings/js/JSWebSocketCustom.cpp:

(WebCore::JSWebSocket::send):

  • bindings/js/JSWorkerConstructor.cpp:

(WebCore::constructWorker):

  • bindings/js/JSXMLHttpRequestConstructor.cpp:

(WebCore::constructXMLHttpRequest):

  • bindings/js/JSXMLHttpRequestCustom.cpp:

(WebCore::JSXMLHttpRequest::open):

  • bindings/js/SerializedScriptValue.cpp:

(WebCore::BaseWalker::throwStackOverflow):
(WebCore::BaseWalker::throwInterruptedException):
(WebCore::SerializingTreeWalker::startArray):
(WebCore::SerializingTreeWalker::startObject):

  • bindings/js/WorkerScriptController.cpp:

(WebCore::WorkerScriptController::setException):

  • bindings/scripts/CodeGeneratorJS.pm:
  • bridge/c/c_instance.cpp:

(JSC::Bindings::CInstance::moveGlobalExceptionToExecState):
(JSC::Bindings::CInstance::invokeMethod):
(JSC::Bindings::CInstance::invokeDefaultMethod):
(JSC::Bindings::CInstance::invokeConstruct):

  • bridge/jni/jsc/JNIBridgeJSC.cpp:

(JavaField::dispatchValueFromInstance):
(JavaField::dispatchSetValueToInstance):

  • bridge/jni/jsc/JavaInstanceJSC.cpp:

(JavaInstance::invokeMethod):

  • bridge/objc/objc_instance.mm:

(ObjcInstance::moveGlobalExceptionToExecState):
(ObjcInstance::invokeMethod):

  • bridge/objc/objc_runtime.mm:

(JSC::Bindings::ObjcField::valueFromInstance):
(JSC::Bindings::ObjcField::setValueToInstance):
(JSC::Bindings::ObjcArray::setValueAt):
(JSC::Bindings::ObjcArray::valueAt):
(JSC::Bindings::callObjCFallbackObject):

  • bridge/objc/objc_utility.h:
  • bridge/objc/objc_utility.mm:

(JSC::Bindings::throwError):

  • bridge/runtime_array.cpp:

(JSC::RuntimeArray::put):

  • bridge/runtime_method.cpp:

(JSC::callRuntimeMethod):

  • bridge/runtime_object.cpp:

(JSC::Bindings::RuntimeObject::throwInvalidAccessError):

WebKit/mac:

  • Plugins/Hosted/NetscapePluginInstanceProxy.mm:

(WebKit::NetscapePluginInstanceProxy::moveGlobalExceptionToExecState):

  • Plugins/Hosted/ProxyInstance.mm:

(WebKit::ProxyInstance::invokeMethod):

  • Property svn:eol-style set to native
File size: 30.4 KB
Line 
1/*
2 * Copyright (C) 1999-2001 Harri Porten ([email protected])
3 * Copyright (C) 2001 Peter Kelly ([email protected])
4 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 *
21 */
22
23#ifndef JSObject_h
24#define JSObject_h
25
26#include "ArgList.h"
27#include "ClassInfo.h"
28#include "CommonIdentifiers.h"
29#include "Completion.h"
30#include "CallFrame.h"
31#include "JSCell.h"
32#include "JSNumberCell.h"
33#include "MarkStack.h"
34#include "PropertySlot.h"
35#include "PutPropertySlot.h"
36#include "ScopeChain.h"
37#include "Structure.h"
38#include "JSGlobalData.h"
39#include "JSString.h"
40#include <wtf/StdLibExtras.h>
41
42namespace JSC {
43
44 inline JSCell* getJSFunction(JSGlobalData& globalData, JSValue value)
45 {
46 if (value.isCell() && (value.asCell()->vptr() == globalData.jsFunctionVPtr))
47 return value.asCell();
48 return 0;
49 }
50
51 class HashEntry;
52 class InternalFunction;
53 class PropertyDescriptor;
54 class PropertyNameArray;
55 class Structure;
56 struct HashTable;
57
58 // ECMA 262-3 8.6.1
59 // Property attributes
60 enum Attribute {
61 None = 0,
62 ReadOnly = 1 << 1, // property can be only read, not written
63 DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
64 DontDelete = 1 << 3, // property can't be deleted
65 Function = 1 << 4, // property is a function - only used by static hashtables
66 Getter = 1 << 5, // property is a getter
67 Setter = 1 << 6 // property is a setter
68 };
69
70 typedef EncodedJSValue* PropertyStorage;
71 typedef const EncodedJSValue* ConstPropertyStorage;
72
73 class JSObject : public JSCell {
74 friend class BatchedTransitionOptimizer;
75 friend class JIT;
76 friend class JSCell;
77 friend void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot);
78
79 public:
80 explicit JSObject(NonNullPassRefPtr<Structure>);
81
82 virtual void markChildren(MarkStack&);
83 ALWAYS_INLINE void markChildrenDirect(MarkStack& markStack);
84
85 // The inline virtual destructor cannot be the first virtual function declared
86 // in the class as it results in the vtable being generated as a weak symbol
87 virtual ~JSObject();
88
89 JSValue prototype() const;
90 void setPrototype(JSValue prototype);
91 bool setPrototypeWithCycleCheck(JSValue prototype);
92
93 void setStructure(NonNullPassRefPtr<Structure>);
94 Structure* inheritorID();
95
96 virtual UString className() const;
97
98 JSValue get(ExecState*, const Identifier& propertyName) const;
99 JSValue get(ExecState*, unsigned propertyName) const;
100
101 bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
102 bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
103 bool getPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
104
105 virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
106 virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
107 virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&);
108
109 virtual void put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&);
110 virtual void put(ExecState*, unsigned propertyName, JSValue value);
111
112 virtual void putWithAttributes(JSGlobalData*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot);
113 virtual void putWithAttributes(JSGlobalData*, const Identifier& propertyName, JSValue value, unsigned attributes);
114 virtual void putWithAttributes(JSGlobalData*, unsigned propertyName, JSValue value, unsigned attributes);
115 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot);
116 virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes);
117 virtual void putWithAttributes(ExecState*, unsigned propertyName, JSValue value, unsigned attributes);
118
119 bool propertyIsEnumerable(ExecState*, const Identifier& propertyName) const;
120
121 bool hasProperty(ExecState*, const Identifier& propertyName) const;
122 bool hasProperty(ExecState*, unsigned propertyName) const;
123 bool hasOwnProperty(ExecState*, const Identifier& propertyName) const;
124
125 virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
126 virtual bool deleteProperty(ExecState*, unsigned propertyName);
127
128 virtual JSValue defaultValue(ExecState*, PreferredPrimitiveType) const;
129
130 virtual bool hasInstance(ExecState*, JSValue, JSValue prototypeProperty);
131
132 virtual void getPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
133 virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&, EnumerationMode mode = ExcludeDontEnumProperties);
134
135 virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
136 virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value);
137 virtual bool toBoolean(ExecState*) const;
138 virtual double toNumber(ExecState*) const;
139 virtual UString toString(ExecState*) const;
140 virtual JSObject* toObject(ExecState*) const;
141
142 virtual JSObject* toThisObject(ExecState*) const;
143 virtual JSObject* unwrappedObject();
144
145 bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const;
146
147 // This get function only looks at the property map.
148 JSValue getDirect(const Identifier& propertyName) const
149 {
150 size_t offset = m_structure->get(propertyName);
151 return offset != WTF::notFound ? getDirectOffset(offset) : JSValue();
152 }
153
154 JSValue* getDirectLocation(const Identifier& propertyName)
155 {
156 size_t offset = m_structure->get(propertyName);
157 return offset != WTF::notFound ? locationForOffset(offset) : 0;
158 }
159
160 JSValue* getDirectLocation(const Identifier& propertyName, unsigned& attributes)
161 {
162 JSCell* specificFunction;
163 size_t offset = m_structure->get(propertyName, attributes, specificFunction);
164 return offset != WTF::notFound ? locationForOffset(offset) : 0;
165 }
166
167 size_t offsetForLocation(JSValue* location) const
168 {
169 return location - reinterpret_cast<const JSValue*>(propertyStorage());
170 }
171
172 void transitionTo(Structure*);
173
174 void removeDirect(const Identifier& propertyName);
175 bool hasCustomProperties() { return !m_structure->isEmpty(); }
176 bool hasGetterSetterProperties() { return m_structure->hasGetterSetterProperties(); }
177
178 void putDirect(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
179 void putDirect(const Identifier& propertyName, JSValue value, unsigned attr = 0);
180
181 void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
182 void putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
183 void putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr = 0);
184 void putDirectFunction(ExecState* exec, JSFunction* function, unsigned attr = 0);
185
186 void putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attr = 0);
187 void putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attr = 0);
188 void putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr = 0);
189 void putDirectFunctionWithoutTransition(ExecState* exec, JSFunction* function, unsigned attr = 0);
190
191 // Fast access to known property offsets.
192 JSValue getDirectOffset(size_t offset) const { return JSValue::decode(propertyStorage()[offset]); }
193 void putDirectOffset(size_t offset, JSValue value) { propertyStorage()[offset] = JSValue::encode(value); }
194
195 void fillGetterPropertySlot(PropertySlot&, JSValue* location);
196
197 virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes = 0);
198 virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes = 0);
199 virtual JSValue lookupGetter(ExecState*, const Identifier& propertyName);
200 virtual JSValue lookupSetter(ExecState*, const Identifier& propertyName);
201 virtual bool defineOwnProperty(ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
202
203 virtual bool isGlobalObject() const { return false; }
204 virtual bool isVariableObject() const { return false; }
205 virtual bool isActivationObject() const { return false; }
206 virtual bool isNotAnObjectErrorStub() const { return false; }
207
208 virtual ComplType exceptionType() const { return Throw; }
209
210 void allocatePropertyStorage(size_t oldSize, size_t newSize);
211 void allocatePropertyStorageInline(size_t oldSize, size_t newSize);
212 bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); }
213
214 static const unsigned inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3;
215 static const unsigned nonInlineBaseStorageCapacity = 16;
216
217 static PassRefPtr<Structure> createStructure(JSValue prototype)
218 {
219 return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags), AnonymousSlotCount);
220 }
221
222 void flattenDictionaryObject()
223 {
224 m_structure->flattenDictionaryStructure(this);
225 }
226
227 void putAnonymousValue(unsigned index, JSValue value)
228 {
229 ASSERT(index < m_structure->anonymousSlotCount());
230 *locationForOffset(index) = value;
231 }
232 JSValue getAnonymousValue(unsigned index) const
233 {
234 ASSERT(index < m_structure->anonymousSlotCount());
235 return *locationForOffset(index);
236 }
237
238 protected:
239 static const unsigned StructureFlags = 0;
240
241 private:
242 // Nobody should ever ask any of these questions on something already known to be a JSObject.
243 using JSCell::isAPIValueWrapper;
244 using JSCell::isGetterSetter;
245 using JSCell::toObject;
246 void getObject();
247 void getString(ExecState* exec);
248 void isObject();
249 void isString();
250#if USE(JSVALUE32)
251 void isNumber();
252#endif
253
254 ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
255 PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); }
256
257 const JSValue* locationForOffset(size_t offset) const
258 {
259 return reinterpret_cast<const JSValue*>(&propertyStorage()[offset]);
260 }
261
262 JSValue* locationForOffset(size_t offset)
263 {
264 return reinterpret_cast<JSValue*>(&propertyStorage()[offset]);
265 }
266
267 void putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot, JSCell*);
268 void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr, bool checkReadOnly, PutPropertySlot& slot);
269 void putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue value, unsigned attr = 0);
270
271 bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
272
273 const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
274 Structure* createInheritorID();
275
276 union {
277 PropertyStorage m_externalStorage;
278 EncodedJSValue m_inlineStorage[inlineStorageCapacity];
279 };
280
281 RefPtr<Structure> m_inheritorID;
282 };
283
284inline JSObject* asObject(JSCell* cell)
285{
286 ASSERT(cell->isObject());
287 return static_cast<JSObject*>(cell);
288}
289
290inline JSObject* asObject(JSValue value)
291{
292 return asObject(value.asCell());
293}
294
295inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure)
296 : JSCell(structure.releaseRef()) // ~JSObject balances this ref()
297{
298 ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity);
299 ASSERT(m_structure->isEmpty());
300 ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
301#if USE(JSVALUE64) || USE(JSVALUE32_64)
302 ASSERT(OBJECT_OFFSETOF(JSObject, m_inlineStorage) % sizeof(double) == 0);
303#endif
304}
305
306inline JSObject::~JSObject()
307{
308 ASSERT(m_structure);
309 if (!isUsingInlineStorage())
310 delete [] m_externalStorage;
311 m_structure->deref();
312}
313
314inline JSValue JSObject::prototype() const
315{
316 return m_structure->storedPrototype();
317}
318
319inline bool JSObject::setPrototypeWithCycleCheck(JSValue prototype)
320{
321 JSValue nextPrototypeValue = prototype;
322 while (nextPrototypeValue && nextPrototypeValue.isObject()) {
323 JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject();
324 if (nextPrototype == this)
325 return false;
326 nextPrototypeValue = nextPrototype->prototype();
327 }
328 setPrototype(prototype);
329 return true;
330}
331
332inline void JSObject::setPrototype(JSValue prototype)
333{
334 ASSERT(prototype);
335 RefPtr<Structure> newStructure = Structure::changePrototypeTransition(m_structure, prototype);
336 setStructure(newStructure.release());
337}
338
339inline void JSObject::setStructure(NonNullPassRefPtr<Structure> structure)
340{
341 m_structure->deref();
342 m_structure = structure.releaseRef(); // ~JSObject balances this ref()
343}
344
345inline Structure* JSObject::inheritorID()
346{
347 if (m_inheritorID)
348 return m_inheritorID.get();
349 return createInheritorID();
350}
351
352inline bool Structure::isUsingInlineStorage() const
353{
354 return (propertyStorageCapacity() == JSObject::inlineStorageCapacity);
355}
356
357inline bool JSCell::inherits(const ClassInfo* info) const
358{
359 for (const ClassInfo* ci = classInfo(); ci; ci = ci->parentClass) {
360 if (ci == info)
361 return true;
362 }
363 return false;
364}
365
366// this method is here to be after the inline declaration of JSCell::inherits
367inline bool JSValue::inherits(const ClassInfo* classInfo) const
368{
369 return isCell() && asCell()->inherits(classInfo);
370}
371
372ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
373{
374 if (JSValue* location = getDirectLocation(propertyName)) {
375 if (m_structure->hasGetterSetterProperties() && location[0].isGetterSetter())
376 fillGetterPropertySlot(slot, location);
377 else
378 slot.setValueSlot(this, location, offsetForLocation(location));
379 return true;
380 }
381
382 // non-standard Netscape extension
383 if (propertyName == exec->propertyNames().underscoreProto) {
384 slot.setValue(prototype());
385 return true;
386 }
387
388 return false;
389}
390
391// It may seem crazy to inline a function this large, especially a virtual function,
392// but it makes a big difference to property lookup that derived classes can inline their
393// base class call to this.
394ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
395{
396 return inlineGetOwnPropertySlot(exec, propertyName, slot);
397}
398
399ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
400{
401 if (!structure()->typeInfo().overridesGetOwnPropertySlot())
402 return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot);
403 return getOwnPropertySlot(exec, propertyName, slot);
404}
405
406// It may seem crazy to inline a function this large but it makes a big difference
407// since this is function very hot in variable lookup
408ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
409{
410 JSObject* object = this;
411 while (true) {
412 if (object->fastGetOwnPropertySlot(exec, propertyName, slot))
413 return true;
414 JSValue prototype = object->prototype();
415 if (!prototype.isObject())
416 return false;
417 object = asObject(prototype);
418 }
419}
420
421ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
422{
423 JSObject* object = this;
424 while (true) {
425 if (object->getOwnPropertySlot(exec, propertyName, slot))
426 return true;
427 JSValue prototype = object->prototype();
428 if (!prototype.isObject())
429 return false;
430 object = asObject(prototype);
431 }
432}
433
434inline JSValue JSObject::get(ExecState* exec, const Identifier& propertyName) const
435{
436 PropertySlot slot(this);
437 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
438 return slot.getValue(exec, propertyName);
439
440 return jsUndefined();
441}
442
443inline JSValue JSObject::get(ExecState* exec, unsigned propertyName) const
444{
445 PropertySlot slot(this);
446 if (const_cast<JSObject*>(this)->getPropertySlot(exec, propertyName, slot))
447 return slot.getValue(exec, propertyName);
448
449 return jsUndefined();
450}
451
452inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
453{
454 ASSERT(value);
455 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
456
457 if (m_structure->isDictionary()) {
458 unsigned currentAttributes;
459 JSCell* currentSpecificFunction;
460 size_t offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
461 if (offset != WTF::notFound) {
462 // If there is currently a specific function, and there now either isn't,
463 // or the new value is different, then despecify.
464 if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
465 m_structure->despecifyDictionaryFunction(propertyName);
466 if (checkReadOnly && currentAttributes & ReadOnly)
467 return;
468 putDirectOffset(offset, value);
469 // At this point, the objects structure only has a specific value set if previously there
470 // had been one set, and if the new value being specified is the same (otherwise we would
471 // have despecified, above). So, if currentSpecificFunction is not set, or if the new
472 // value is different (or there is no new value), then the slot now has no value - and
473 // as such it is cachable.
474 // If there was previously a value, and the new value is the same, then we cannot cache.
475 if (!currentSpecificFunction || (specificFunction != currentSpecificFunction))
476 slot.setExistingProperty(this, offset);
477 return;
478 }
479
480 size_t currentCapacity = m_structure->propertyStorageCapacity();
481 offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, specificFunction);
482 if (currentCapacity != m_structure->propertyStorageCapacity())
483 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
484
485 ASSERT(offset < m_structure->propertyStorageCapacity());
486 putDirectOffset(offset, value);
487 // See comment on setNewProperty call below.
488 if (!specificFunction)
489 slot.setNewProperty(this, offset);
490 return;
491 }
492
493 size_t offset;
494 size_t currentCapacity = m_structure->propertyStorageCapacity();
495 if (RefPtr<Structure> structure = Structure::addPropertyTransitionToExistingStructure(m_structure, propertyName, attributes, specificFunction, offset)) {
496 if (currentCapacity != structure->propertyStorageCapacity())
497 allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
498
499 ASSERT(offset < structure->propertyStorageCapacity());
500 setStructure(structure.release());
501 putDirectOffset(offset, value);
502 // This is a new property; transitions with specific values are not currently cachable,
503 // so leave the slot in an uncachable state.
504 if (!specificFunction)
505 slot.setNewProperty(this, offset);
506 return;
507 }
508
509 unsigned currentAttributes;
510 JSCell* currentSpecificFunction;
511 offset = m_structure->get(propertyName, currentAttributes, currentSpecificFunction);
512 if (offset != WTF::notFound) {
513 if (checkReadOnly && currentAttributes & ReadOnly)
514 return;
515
516 // There are three possibilities here:
517 // (1) There is an existing specific value set, and we're overwriting with *the same value*.
518 // * Do nothing - no need to despecify, but that means we can't cache (a cached
519 // put could write a different value). Leave the slot in an uncachable state.
520 // (2) There is a specific value currently set, but we're writing a different value.
521 // * First, we have to despecify. Having done so, this is now a regular slot
522 // with no specific value, so go ahead & cache like normal.
523 // (3) Normal case, there is no specific value set.
524 // * Go ahead & cache like normal.
525 if (currentSpecificFunction) {
526 // case (1) Do the put, then return leaving the slot uncachable.
527 if (specificFunction == currentSpecificFunction) {
528 putDirectOffset(offset, value);
529 return;
530 }
531 // case (2) Despecify, fall through to (3).
532 setStructure(Structure::despecifyFunctionTransition(m_structure, propertyName));
533 }
534
535 // case (3) set the slot, do the put, return.
536 slot.setExistingProperty(this, offset);
537 putDirectOffset(offset, value);
538 return;
539 }
540
541 // If we have a specific function, we may have got to this point if there is
542 // already a transition with the correct property name and attributes, but
543 // specialized to a different function. In this case we just want to give up
544 // and despecialize the transition.
545 // In this case we clear the value of specificFunction which will result
546 // in us adding a non-specific transition, and any subsequent lookup in
547 // Structure::addPropertyTransitionToExistingStructure will just use that.
548 if (specificFunction && m_structure->hasTransition(propertyName, attributes))
549 specificFunction = 0;
550
551 RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset);
552
553 if (currentCapacity != structure->propertyStorageCapacity())
554 allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity());
555
556 ASSERT(offset < structure->propertyStorageCapacity());
557 setStructure(structure.release());
558 putDirectOffset(offset, value);
559 // This is a new property; transitions with specific values are not currently cachable,
560 // so leave the slot in an uncachable state.
561 if (!specificFunction)
562 slot.setNewProperty(this, offset);
563}
564
565inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
566{
567 ASSERT(value);
568 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
569
570 putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, getJSFunction(globalData, value));
571}
572
573inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
574{
575 PutPropertySlot slot;
576 putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value));
577}
578
579inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
580{
581 ASSERT(value);
582 ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
583
584 putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, 0);
585}
586
587inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes)
588{
589 PutPropertySlot slot;
590 putDirectInternal(propertyName, value, attributes, false, slot, 0);
591}
592
593inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
594{
595 putDirectInternal(propertyName, value, attributes, checkReadOnly, slot, value);
596}
597
598inline void JSObject::putDirectFunction(const Identifier& propertyName, JSCell* value, unsigned attr)
599{
600 PutPropertySlot slot;
601 putDirectInternal(propertyName, value, attr, false, slot, value);
602}
603
604inline void JSObject::putDirectWithoutTransition(const Identifier& propertyName, JSValue value, unsigned attributes)
605{
606 size_t currentCapacity = m_structure->propertyStorageCapacity();
607 size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, 0);
608 if (currentCapacity != m_structure->propertyStorageCapacity())
609 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
610 putDirectOffset(offset, value);
611}
612
613inline void JSObject::putDirectFunctionWithoutTransition(const Identifier& propertyName, JSCell* value, unsigned attributes)
614{
615 size_t currentCapacity = m_structure->propertyStorageCapacity();
616 size_t offset = m_structure->addPropertyWithoutTransition(propertyName, attributes, value);
617 if (currentCapacity != m_structure->propertyStorageCapacity())
618 allocatePropertyStorage(currentCapacity, m_structure->propertyStorageCapacity());
619 putDirectOffset(offset, value);
620}
621
622inline void JSObject::transitionTo(Structure* newStructure)
623{
624 if (m_structure->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
625 allocatePropertyStorage(m_structure->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
626 setStructure(newStructure);
627}
628
629inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
630{
631 return defaultValue(exec, preferredType);
632}
633
634inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName) const
635{
636 PropertySlot slot(asValue());
637 return get(exec, propertyName, slot);
638}
639
640inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const
641{
642 if (UNLIKELY(!isCell())) {
643 JSObject* prototype = synthesizePrototype(exec);
644 if (propertyName == exec->propertyNames().underscoreProto)
645 return prototype;
646 if (!prototype->getPropertySlot(exec, propertyName, slot))
647 return jsUndefined();
648 return slot.getValue(exec, propertyName);
649 }
650 JSCell* cell = asCell();
651 while (true) {
652 if (cell->fastGetOwnPropertySlot(exec, propertyName, slot))
653 return slot.getValue(exec, propertyName);
654 JSValue prototype = asObject(cell)->prototype();
655 if (!prototype.isObject())
656 return jsUndefined();
657 cell = asObject(prototype);
658 }
659}
660
661inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
662{
663 PropertySlot slot(asValue());
664 return get(exec, propertyName, slot);
665}
666
667inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
668{
669 if (UNLIKELY(!isCell())) {
670 JSObject* prototype = synthesizePrototype(exec);
671 if (!prototype->getPropertySlot(exec, propertyName, slot))
672 return jsUndefined();
673 return slot.getValue(exec, propertyName);
674 }
675 JSCell* cell = const_cast<JSCell*>(asCell());
676 while (true) {
677 if (cell->getOwnPropertySlot(exec, propertyName, slot))
678 return slot.getValue(exec, propertyName);
679 JSValue prototype = asObject(cell)->prototype();
680 if (!prototype.isObject())
681 return jsUndefined();
682 cell = prototype.asCell();
683 }
684}
685
686inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
687{
688 if (UNLIKELY(!isCell())) {
689 synthesizeObject(exec)->put(exec, propertyName, value, slot);
690 return;
691 }
692 asCell()->put(exec, propertyName, value, slot);
693}
694
695inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value)
696{
697 if (UNLIKELY(!isCell())) {
698 synthesizeObject(exec)->put(exec, propertyName, value);
699 return;
700 }
701 asCell()->put(exec, propertyName, value);
702}
703
704ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_t newSize)
705{
706 ASSERT(newSize > oldSize);
707
708 // It's important that this function not rely on m_structure, since
709 // we might be in the middle of a transition.
710 bool wasInline = (oldSize == JSObject::inlineStorageCapacity);
711
712 PropertyStorage oldPropertyStorage = (wasInline ? m_inlineStorage : m_externalStorage);
713 PropertyStorage newPropertyStorage = new EncodedJSValue[newSize];
714
715 for (unsigned i = 0; i < oldSize; ++i)
716 newPropertyStorage[i] = oldPropertyStorage[i];
717
718 if (!wasInline)
719 delete [] oldPropertyStorage;
720
721 m_externalStorage = newPropertyStorage;
722}
723
724ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack)
725{
726 JSCell::markChildren(markStack);
727
728 markStack.append(prototype());
729
730 PropertyStorage storage = propertyStorage();
731 size_t storageSize = m_structure->propertyStorageSize();
732 markStack.appendValues(reinterpret_cast<JSValue*>(storage), storageSize);
733}
734
735// --- JSValue inlines ----------------------------
736
737ALWAYS_INLINE UString JSValue::toThisString(ExecState* exec) const
738{
739 return isString() ? static_cast<JSString*>(asCell())->value(exec) : toThisObject(exec)->toString(exec);
740}
741
742inline JSString* JSValue::toThisJSString(ExecState* exec) const
743{
744 return isString() ? static_cast<JSString*>(asCell()) : jsString(exec, toThisObject(exec)->toString(exec));
745}
746
747} // namespace JSC
748
749#endif // JSObject_h
Note: See TracBrowser for help on using the repository browser.