Improved type safety by implementing opaque JSValue/JSObject typing through
abuse of 'const', not void*. Also fixed an alarming number of bugs
exposed by this new type safety.
I made one design change in JavaScriptCore, which is that the JSObject
constructor should take a JSValue* as its prototype argument, not a JSObject*,
since we allow the prototype to be any JSValue*, including jsNull(), for
example.
* API/APICast.h:
(toJS):
* API/JSBase.h:
* API/JSCallbackConstructor.cpp:
(KJS::JSCallbackConstructor::construct):
* API/JSCallbackFunction.cpp:
(KJS::JSCallbackFunction::callAsFunction):
* API/JSCallbackObject.cpp:
(KJS::JSCallbackObject::JSCallbackObject):
(KJS::JSCallbackObject::getOwnPropertySlot):
(KJS::JSCallbackObject::put):
(KJS::JSCallbackObject::construct):
(KJS::JSCallbackObject::callAsFunction):
(KJS::JSCallbackObject::staticFunctionGetter):
* API/JSCallbackObject.h:
* API/JSContextRef.cpp:
(JSEvaluate):
* API/JSNode.c:
(JSNodePrototype_appendChild):
(JSNodePrototype_removeChild):
(JSNodePrototype_replaceChild):
* API/JSObjectRef.cpp:
(JSObjectMake):
(JSFunctionMakeWithBody):
(JSObjectGetProperty):
(JSObjectCallAsFunction):
(JSObjectCallAsConstructor):
* API/JSObjectRef.h:
* API/testapi.c:
(main):
* ChangeLog:
* kjs/object.h:
(KJS::JSObject::JSObject):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@15310
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
inline KJS::JSValue* toJS(JSValueRef v)
{
- return reinterpret_cast<KJS::JSValue*>(v);
+ return reinterpret_cast<KJS::JSValue*>(const_cast<__JSValue*>(v));
}
inline KJS::UString::Rep* toJS(JSInternalStringRef b)
/* JavaScript data types */
/*! @typedef JSValueRef A JavaScript value. The base type for all JavaScript values, and polymorphic functions on them. */
-typedef void* JSValueRef;
+typedef const struct __JSValue* JSValueRef;
/*! @typedef JSObjectRef A JavaScript object. A JSObject is a JSValue. */
-typedef struct __JSObject* JSObjectRef;
+typedef struct __JSValue* JSObjectRef;
#endif // JSBase_h
size_t argc = args.size();
JSValueRef argv[argc];
for (size_t i = 0; i < argc; i++)
- argv[i] = args[i];
+ argv[i] = toRef(args[i]);
return toJS(m_callback(execRef, thisRef, argc, argv));
}
size_t argc = args.size();
JSValueRef argv[argc];
for (size_t i = 0; i < argc; i++)
- argv[i] = args[i];
+ argv[i] = toRef(args[i]);
return toJS(m_callback(execRef, thisRef, thisObjRef, argc, argv));
}
init(context, jsClass);
}
-JSCallbackObject::JSCallbackObject(JSContextRef context, JSClassRef jsClass, JSObject* prototype)
+JSCallbackObject::JSCallbackObject(JSContextRef context, JSClassRef jsClass, JSValue* prototype)
: JSObject(prototype)
{
init(context, jsClass);
// cache the value so we don't have to compute it again
// FIXME: This violates the PropertySlot design a little bit.
// We should either use this optimization everywhere, or nowhere.
- slot.setCustom(reinterpret_cast<JSObject*>(returnValue), cachedValueGetter);
+ slot.setCustom(reinterpret_cast<JSObject*>(toJS(returnValue)), cachedValueGetter);
return true;
}
}
JSContextRef context = toRef(exec);
JSObjectRef thisRef = toRef(this);
JSInternalStringRef propertyNameRef = toRef(propertyName.ustring().rep());
+ JSValueRef valueRef = toRef(value);
for (JSClassRef jsClass = m_class; jsClass; jsClass = jsClass->parent) {
if (JSSetPropertyCallback setPropertyCallback = jsClass->callbacks.setProperty) {
- if (setPropertyCallback(context, thisRef, propertyNameRef, value))
+ if (setPropertyCallback(context, thisRef, propertyNameRef, valueRef))
return;
}
if (entry->attributes & kJSPropertyAttributeReadOnly)
return;
if (JSSetPropertyCallback setPropertyCallback = entry->setProperty) {
- if (setPropertyCallback(context, thisRef, propertyNameRef, value))
+ if (setPropertyCallback(context, thisRef, propertyNameRef, valueRef))
return;
}
}
size_t argc = args.size();
JSValueRef argv[argc];
for (size_t i = 0; i < argc; i++)
- argv[i] = args[i];
+ argv[i] = toRef(args[i]);
return toJS(callAsConstructorCallback(execRef, thisRef, argc, argv));
}
}
size_t argc = args.size();
JSValueRef argv[argc];
for (size_t i = 0; i < argc; i++)
- argv[i] = args[i];
+ argv[i] = toRef(args[i]);
return toJS(callAsFunctionCallback(execRef, thisRef, thisObjRef, argc, argv));
}
}
JSCallbackObject* thisObj = static_cast<JSCallbackObject*>(slot.slotBase());
if (JSValue* cachedOrOverrideValue = thisObj->getDirect(propertyName))
- return toJS(cachedOrOverrideValue);
+ return cachedOrOverrideValue;
for (JSClassRef jsClass = thisObj->m_class; jsClass; jsClass = jsClass->parent) {
if (__JSClass::StaticFunctionsTable* staticFunctions = jsClass->staticFunctions) {
{
public:
JSCallbackObject(JSContextRef, JSClassRef);
- JSCallbackObject(JSContextRef, JSClassRef, JSObject* prototype);
+ JSCallbackObject(JSContextRef, JSClassRef, JSValue* prototype);
virtual ~JSCallbackObject();
virtual UString className() const;
if (completion.complType() == Throw) {
if (exception)
- *exception = completion.value();
+ *exception = toRef(completion.value());
return 0;
}
JSInternalStringRelease(messageBuf);
} else {
Node* node = JSObjectGetPrivate(thisObject);
- Node* child = JSObjectGetPrivate(argv[0]);
+ Node* child = JSObjectGetPrivate(JSValueToObject(context, argv[0]));
Node_appendChild(node, child);
}
if (JSValueIsObjectOfClass(thisObject, JSNode_class(context))) {
if (JSValueIsObjectOfClass(argv[0], JSNode_class(context))) {
Node* node = JSObjectGetPrivate(thisObject);
- Node* child = JSObjectGetPrivate(argv[0]);
+ Node* child = JSObjectGetPrivate(JSValueToObject(context, argv[0]));
Node_removeChild(node, child);
}
if (JSValueIsObjectOfClass(argv[0], JSNode_class(context))) {
if (JSValueIsObjectOfClass(argv[1], JSNode_class(context))) {
Node* node = JSObjectGetPrivate(thisObject);
- Node* newChild = JSObjectGetPrivate(argv[0]);
- Node* oldChild = JSObjectGetPrivate(argv[1]);
+ Node* newChild = JSObjectGetPrivate(JSValueToObject(context, argv[0]));
+ Node* oldChild = JSObjectGetPrivate(JSValueToObject(context, argv[1]));
Node_replaceChild(node, newChild, oldChild);
}
using namespace KJS;
-JSObjectRef JSObjectMake(JSContextRef context, JSClassRef jsClass, JSObjectRef prototype)
+JSObjectRef JSObjectMake(JSContextRef context, JSClassRef jsClass, JSValueRef prototype)
{
JSLock lock;
ExecState* exec = toJS(context);
- JSObject* jsPrototype = toJS(prototype);
+ JSValue* jsPrototype = toJS(prototype);
if (!prototype)
jsPrototype = exec->lexicalInterpreter()->builtinObjectPrototype();
RefPtr<FunctionBodyNode> bodyNode = Parser::parse(jsSourceURL, startingLineNumber, bodyRep->data(), bodyRep->size(), &sid, &errLine, &errMsg);
if (!bodyNode) {
if (exception)
- *exception = Error::create(exec, SyntaxError, errMsg, errLine, sid, jsSourceURL);
+ *exception = toRef(Error::create(exec, SyntaxError, errMsg, errLine, sid, jsSourceURL));
return 0;
}
JSValue* jsValue = jsObject->get(exec, Identifier(nameRep));
if (jsValue->isUndefined())
return 0;
- return jsValue;
+ return toRef(jsValue);
}
bool JSObjectSetProperty(JSContextRef context, JSObjectRef object, JSInternalStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes)
JSValueRef result = toRef(jsObject->call(exec, jsThisObject, argList)); // returns NULL if object->implementsCall() is false
if (exec->hadException()) {
if (exception)
- *exception = exec->exception();
+ *exception = toRef(exec->exception());
exec->clearException();
result = 0;
}
JSObjectRef result = toRef(jsObject->construct(exec, argList)); // returns NULL if object->implementsCall() is false
if (exec->hadException()) {
if (exception)
- *exception = exec->exception();
+ *exception = toRef(exec->exception());
exec->clearException();
result = 0;
}
@param prototype The prototype to assign to the object. Pass NULL to use the default object prototype.
@result A JSObject with the given class and prototype.
*/
-JSObjectRef JSObjectMake(JSContextRef context, JSClassRef jsClass, JSObjectRef prototype);
+JSObjectRef JSObjectMake(JSContextRef context, JSClassRef jsClass, JSValueRef prototype);
/*!
@function
JSInternalStringRef lineBuf = JSInternalStringCreateUTF8("line");
assert(!JSFunctionMakeWithBody(context, functionBuf, NULL, 1, &exception));
assert(JSValueIsObject(exception));
- v = JSObjectGetProperty(context, exception, lineBuf);
+ v = JSObjectGetProperty(context, JSValueToObject(context, exception), lineBuf);
assert(v);
assertEqualsAsNumber(v, 2); // FIXME: Lexer::setCode bumps startingLineNumber by 1 -- we need to change internal callers so that it doesn't have to (saying '0' to mean '1' in the API would be really confusing -- it's really confusing internally, in fact)
JSInternalStringRelease(functionBuf);
JSInternalStringRelease(myObjectBuf);
JSInternalStringRef printBuf = JSInternalStringCreateUTF8("print");
- JSValueRef printFunction = JSFunctionMake(context, print_callAsFunction);
+ JSObjectRef printFunction = JSFunctionMake(context, print_callAsFunction);
JSObjectSetProperty(context, globalObject, printBuf, printFunction, kJSPropertyAttributeNone);
JSInternalStringRelease(printBuf);
assert(JSObjectGetPrivate(printFunction) == (void*)1);
JSInternalStringRef myConstructorBuf = JSInternalStringCreateUTF8("MyConstructor");
- JSValueRef myConstructor = JSConstructorMake(context, myConstructor_callAsConstructor);
+ JSObjectRef myConstructor = JSConstructorMake(context, myConstructor_callAsConstructor);
JSObjectSetProperty(context, globalObject, myConstructorBuf, myConstructor, kJSPropertyAttributeNone);
JSInternalStringRelease(myConstructorBuf);
assert(JSObjectGetPrivate(myConstructor) == (void*)1);
o = JSObjectMake(context, NULL, NULL);
- JSObjectSetProperty(context, o, jsOneString, JSNumberMake(1), kJSPropertyAttributeNone);
- JSObjectSetProperty(context, o, jsCFString, JSNumberMake(1), kJSPropertyAttributeDontEnum);
+ JSObjectSetProperty(context, o, jsOneStringBuf, JSNumberMake(1), kJSPropertyAttributeNone);
+ JSObjectSetProperty(context, o, jsCFStringBuf, JSNumberMake(1), kJSPropertyAttributeDontEnum);
JSPropertyEnumeratorRef enumerator = JSObjectCreatePropertyEnumerator(context, o);
int count = 0;
while (JSPropertyEnumeratorGetNext(enumerator))
+2006-07-10 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Darin.
+
+ Improved type safety by implementing opaque JSValue/JSObject typing through
+ abuse of 'const', not void*. Also fixed an alarming number of bugs
+ exposed by this new type safety.
+
+ I made one design change in JavaScriptCore, which is that the JSObject
+ constructor should take a JSValue* as its prototype argument, not a JSObject*,
+ since we allow the prototype to be any JSValue*, including jsNull(), for
+ example.
+
+ * API/APICast.h:
+ (toJS):
+ * API/JSBase.h:
+ * API/JSCallbackConstructor.cpp:
+ (KJS::JSCallbackConstructor::construct):
+ * API/JSCallbackFunction.cpp:
+ (KJS::JSCallbackFunction::callAsFunction):
+ * API/JSCallbackObject.cpp:
+ (KJS::JSCallbackObject::JSCallbackObject):
+ (KJS::JSCallbackObject::getOwnPropertySlot):
+ (KJS::JSCallbackObject::put):
+ (KJS::JSCallbackObject::construct):
+ (KJS::JSCallbackObject::callAsFunction):
+ (KJS::JSCallbackObject::staticFunctionGetter):
+ * API/JSCallbackObject.h:
+ * API/JSContextRef.cpp:
+ (JSEvaluate):
+ * API/JSNode.c:
+ (JSNodePrototype_appendChild):
+ (JSNodePrototype_removeChild):
+ (JSNodePrototype_replaceChild):
+ * API/JSObjectRef.cpp:
+ (JSObjectMake):
+ (JSFunctionMakeWithBody):
+ (JSObjectGetProperty):
+ (JSObjectCallAsFunction):
+ (JSObjectCallAsConstructor):
+ * API/JSObjectRef.h:
+ * API/testapi.c:
+ (main):
+ * ChangeLog:
+ * kjs/object.h:
+ (KJS::JSObject::JSObject):
+
2006-07-10 Geoffrey Garen <ggaren@apple.com>
Approved by Maciej, Darin.
*
* @param proto The prototype
*/
- JSObject(JSObject *proto, bool destructorIsThreadSafe = true);
+ JSObject(JSValue* proto, bool destructorIsThreadSafe = true);
/**
* Creates a new JSObject with a prototype of jsNull()
JSObject *throwError(ExecState *, ErrorType, const char *message);
JSObject *throwError(ExecState *, ErrorType);
-inline JSObject::JSObject(JSObject *proto, bool destructorIsThreadSafe)
+inline JSObject::JSObject(JSValue* proto, bool destructorIsThreadSafe)
: JSCell(destructorIsThreadSafe)
, _proto(proto)
, _internalValue(0)