X-Git-Url: https://git.saurik.com/apple/javascriptcore.git/blobdiff_plain/9dae56ea45a0f5f8136a5c93d6f3a7f99399ca73..refs/heads/master:/API/JSValueRef.cpp diff --git a/API/JSValueRef.cpp b/API/JSValueRef.cpp index 7080952..54405e2 100644 --- a/API/JSValueRef.cpp +++ b/API/JSValueRef.cpp @@ -10,40 +10,91 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "JSValueRef.h" -#include #include "APICast.h" +#include "DateInstance.h" +#include "Exception.h" +#include "JSAPIWrapperObject.h" +#include "JSCInlines.h" +#include "JSCJSValue.h" #include "JSCallbackObject.h" +#include "JSGlobalObject.h" +#include "JSONObject.h" +#include "JSString.h" +#include "LiteralParser.h" +#include "Protect.h" +#include +#include +#include +#include -#include -#include -#include -#include -#include -#include +#if PLATFORM(MAC) +#include +#endif -#include +#if ENABLE(REMOTE_INSPECTOR) +#include "JSGlobalObjectInspectorController.h" +#endif -#include // for std::min +using namespace JSC; -JSType JSValueGetType(JSContextRef, JSValueRef value) +enum class ExceptionStatus { + DidThrow, + DidNotThrow +}; + +static ExceptionStatus handleExceptionIfNeeded(ExecState* exec, JSValueRef* returnedExceptionRef) { - JSC::JSValuePtr jsValue = toJS(value); + if (exec->hadException()) { + Exception* exception = exec->exception(); + if (returnedExceptionRef) + *returnedExceptionRef = toRef(exec, exception->value()); + exec->clearException(); +#if ENABLE(REMOTE_INSPECTOR) + exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exception); +#endif + return ExceptionStatus::DidThrow; + } + return ExceptionStatus::DidNotThrow; +} + +#if PLATFORM(MAC) +static bool evernoteHackNeeded() +{ + static const int32_t webkitLastVersionWithEvernoteHack = 35133959; + static bool hackNeeded = CFEqual(CFBundleGetIdentifier(CFBundleGetMainBundle()), CFSTR("com.evernote.Evernote")) + && NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitLastVersionWithEvernoteHack; + + return hackNeeded; +} +#endif + +::JSType JSValueGetType(JSContextRef ctx, JSValueRef value) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return kJSTypeUndefined; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + JSValue jsValue = toJS(exec, value); + if (jsValue.isUndefined()) return kJSTypeUndefined; if (jsValue.isNull()) @@ -58,213 +109,363 @@ JSType JSValueGetType(JSContextRef, JSValueRef value) return kJSTypeObject; } -using namespace JSC; // placed here to avoid conflict between JSC::JSType and JSType, above. +bool JSValueIsUndefined(JSContextRef ctx, JSValueRef value) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); -bool JSValueIsUndefined(JSContextRef, JSValueRef value) + return toJS(exec, value).isUndefined(); +} + +bool JSValueIsNull(JSContextRef ctx, JSValueRef value) { - JSValuePtr jsValue = toJS(value); - return jsValue.isUndefined(); + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toJS(exec, value).isNull(); } -bool JSValueIsNull(JSContextRef, JSValueRef value) +bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value) { - JSValuePtr jsValue = toJS(value); - return jsValue.isNull(); + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toJS(exec, value).isBoolean(); } -bool JSValueIsBoolean(JSContextRef, JSValueRef value) +bool JSValueIsNumber(JSContextRef ctx, JSValueRef value) { - JSValuePtr jsValue = toJS(value); - return jsValue.isBoolean(); + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toJS(exec, value).isNumber(); } -bool JSValueIsNumber(JSContextRef, JSValueRef value) +bool JSValueIsString(JSContextRef ctx, JSValueRef value) { - JSValuePtr jsValue = toJS(value); - return jsValue.isNumber(); + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toJS(exec, value).isString(); } -bool JSValueIsString(JSContextRef, JSValueRef value) +bool JSValueIsObject(JSContextRef ctx, JSValueRef value) { - JSValuePtr jsValue = toJS(value); - return jsValue.isString(); + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toJS(exec, value).isObject(); } -bool JSValueIsObject(JSContextRef, JSValueRef value) +bool JSValueIsArray(JSContextRef ctx, JSValueRef value) { - JSValuePtr jsValue = toJS(value); - return jsValue.isObject(); + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toJS(exec, value).inherits(JSArray::info()); +} + +bool JSValueIsDate(JSContextRef ctx, JSValueRef value) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toJS(exec, value).inherits(DateInstance::info()); } -bool JSValueIsObjectOfClass(JSContextRef, JSValueRef value, JSClassRef jsClass) +bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass) { - JSValuePtr jsValue = toJS(value); + if (!ctx || !jsClass) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + JSValue jsValue = toJS(exec, value); if (JSObject* o = jsValue.getObject()) { - if (o->inherits(&JSCallbackObject::info)) - return static_cast*>(o)->inherits(jsClass); - else if (o->inherits(&JSCallbackObject::info)) - return static_cast*>(o)->inherits(jsClass); + if (o->inherits(JSProxy::info())) + o = jsCast(o)->target(); + + if (o->inherits(JSCallbackObject::info())) + return jsCast*>(o)->inherits(jsClass); + if (o->inherits(JSCallbackObject::info())) + return jsCast*>(o)->inherits(jsClass); +#if JSC_OBJC_API_ENABLED + if (o->inherits(JSCallbackObject::info())) + return jsCast*>(o)->inherits(jsClass); +#endif } return false; } bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); - exec->globalData().heap.registerThread(); - JSLock lock(exec); + JSLockHolder locker(exec); - JSValuePtr jsA = toJS(a); - JSValuePtr jsB = toJS(b); + JSValue jsA = toJS(exec, a); + JSValue jsB = toJS(exec, b); - bool result = JSValuePtr::equal(exec, jsA, jsB); // false if an exception is thrown - if (exec->hadException()) { - if (exception) - *exception = toRef(exec->exception()); - exec->clearException(); - } + bool result = JSValue::equal(exec, jsA, jsB); // false if an exception is thrown + handleExceptionIfNeeded(exec, exception); + return result; } -bool JSValueIsStrictEqual(JSContextRef, JSValueRef a, JSValueRef b) +bool JSValueIsStrictEqual(JSContextRef ctx, JSValueRef a, JSValueRef b) { - JSValuePtr jsA = toJS(a); - JSValuePtr jsB = toJS(b); - - bool result = JSValuePtr::strictEqual(jsA, jsB); - return result; + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + JSValue jsA = toJS(exec, a); + JSValue jsB = toJS(exec, b); + + return JSValue::strictEqual(exec, jsA, jsB); } bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObjectRef constructor, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); - exec->globalData().heap.registerThread(); - JSLock lock(exec); + JSLockHolder locker(exec); + + JSValue jsValue = toJS(exec, value); - JSValuePtr jsValue = toJS(value); JSObject* jsConstructor = toJS(constructor); if (!jsConstructor->structure()->typeInfo().implementsHasInstance()) return false; - bool result = jsConstructor->hasInstance(exec, jsValue, jsConstructor->get(exec, exec->propertyNames().prototype)); // false if an exception is thrown - if (exec->hadException()) { - if (exception) - *exception = toRef(exec->exception()); - exec->clearException(); - } + bool result = jsConstructor->hasInstance(exec, jsValue); // false if an exception is thrown + handleExceptionIfNeeded(exec, exception); return result; } -JSValueRef JSValueMakeUndefined(JSContextRef) +JSValueRef JSValueMakeUndefined(JSContextRef ctx) { - return toRef(jsUndefined()); + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toRef(exec, jsUndefined()); } -JSValueRef JSValueMakeNull(JSContextRef) +JSValueRef JSValueMakeNull(JSContextRef ctx) { - return toRef(jsNull()); + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toRef(exec, jsNull()); } -JSValueRef JSValueMakeBoolean(JSContextRef, bool value) +JSValueRef JSValueMakeBoolean(JSContextRef ctx, bool value) { - return toRef(jsBoolean(value)); + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + + return toRef(exec, jsBoolean(value)); } JSValueRef JSValueMakeNumber(JSContextRef ctx, double value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); - exec->globalData().heap.registerThread(); - JSLock lock(exec); + JSLockHolder locker(exec); - return toRef(jsNumber(exec, value)); + return toRef(exec, jsNumber(purifyNaN(value))); } JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); - exec->globalData().heap.registerThread(); - JSLock lock(exec); + JSLockHolder locker(exec); - return toRef(jsString(exec, string->ustring())); + return toRef(exec, jsString(exec, string ? string->string() : String())); +} + +JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + String str = string->string(); + unsigned length = str.length(); + if (!length || str.is8Bit()) { + LiteralParser parser(exec, str.characters8(), length, StrictJSON); + return toRef(exec, parser.tryLiteralParse()); + } + LiteralParser parser(exec, str.characters16(), length, StrictJSON); + return toRef(exec, parser.tryLiteralParse()); +} + +JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef apiValue, unsigned indent, JSValueRef* exception) +{ + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } + ExecState* exec = toJS(ctx); + JSLockHolder locker(exec); + JSValue value = toJS(exec, apiValue); + String result = JSONStringify(exec, value, indent); + if (exception) + *exception = 0; + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) + return 0; + return OpaqueJSString::create(result).leakRef(); } bool JSValueToBoolean(JSContextRef ctx, JSValueRef value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return false; + } ExecState* exec = toJS(ctx); - JSValuePtr jsValue = toJS(value); + JSLockHolder locker(exec); + + JSValue jsValue = toJS(exec, value); return jsValue.toBoolean(exec); } double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return PNaN; + } ExecState* exec = toJS(ctx); - exec->globalData().heap.registerThread(); - JSLock lock(exec); + JSLockHolder locker(exec); - JSValuePtr jsValue = toJS(value); + JSValue jsValue = toJS(exec, value); double number = jsValue.toNumber(exec); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec->exception()); - exec->clearException(); - number = NaN; - } + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) + number = PNaN; return number; } JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); - exec->globalData().heap.registerThread(); - JSLock lock(exec); + JSLockHolder locker(exec); - JSValuePtr jsValue = toJS(value); + JSValue jsValue = toJS(exec, value); - RefPtr stringRef(OpaqueJSString::create(jsValue.toString(exec))); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec->exception()); - exec->clearException(); - stringRef.clear(); - } - return stringRef.release().releaseRef(); + RefPtr stringRef(OpaqueJSString::create(jsValue.toString(exec)->value(exec))); + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) + stringRef = nullptr; + return stringRef.release().leakRef(); } JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exception) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return 0; + } ExecState* exec = toJS(ctx); - exec->globalData().heap.registerThread(); - JSLock lock(exec); + JSLockHolder locker(exec); - JSValuePtr jsValue = toJS(value); + JSValue jsValue = toJS(exec, value); JSObjectRef objectRef = toRef(jsValue.toObject(exec)); - if (exec->hadException()) { - if (exception) - *exception = toRef(exec->exception()); - exec->clearException(); + if (handleExceptionIfNeeded(exec, exception) == ExceptionStatus::DidThrow) objectRef = 0; - } return objectRef; -} +} void JSValueProtect(JSContextRef ctx, JSValueRef value) { + if (!ctx) { + ASSERT_NOT_REACHED(); + return; + } ExecState* exec = toJS(ctx); - exec->globalData().heap.registerThread(); - JSLock lock(exec); + JSLockHolder locker(exec); - JSValuePtr jsValue = toJS(value); + JSValue jsValue = toJSForGC(exec, value); gcProtect(jsValue); } void JSValueUnprotect(JSContextRef ctx, JSValueRef value) { +#if PLATFORM(MAC) + if ((!value || !ctx) && evernoteHackNeeded()) + return; +#endif + ExecState* exec = toJS(ctx); - exec->globalData().heap.registerThread(); - JSLock lock(exec); + JSLockHolder locker(exec); - JSValuePtr jsValue = toJS(value); + JSValue jsValue = toJSForGC(exec, value); gcUnprotect(jsValue); }