JSValueRef.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. /*
  2. * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. * 1. Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * 2. Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  16. * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
  17. * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  18. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  19. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  20. * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
  21. * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  23. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "config.h"
  26. #include "JSValueRef.h"
  27. #include "APICast.h"
  28. #include "APIShims.h"
  29. #include "JSAPIWrapperObject.h"
  30. #include "JSCallbackObject.h"
  31. #include <runtime/JSCJSValue.h>
  32. #include <runtime/JSGlobalObject.h>
  33. #include <runtime/JSONObject.h>
  34. #include <runtime/JSString.h>
  35. #include <runtime/LiteralParser.h>
  36. #include <runtime/Operations.h>
  37. #include <runtime/Protect.h>
  38. #include <wtf/Assertions.h>
  39. #include <wtf/text/StringHash.h>
  40. #include <wtf/text/WTFString.h>
  41. #include <algorithm> // for std::min
  42. #if PLATFORM(MAC)
  43. #include <mach-o/dyld.h>
  44. #endif
  45. using namespace JSC;
  46. #if PLATFORM(MAC)
  47. static bool evernoteHackNeeded()
  48. {
  49. static const int32_t webkitLastVersionWithEvernoteHack = 35133959;
  50. static bool hackNeeded = CFEqual(CFBundleGetIdentifier(CFBundleGetMainBundle()), CFSTR("com.evernote.Evernote"))
  51. && NSVersionOfLinkTimeLibrary("JavaScriptCore") <= webkitLastVersionWithEvernoteHack;
  52. return hackNeeded;
  53. }
  54. #endif
  55. ::JSType JSValueGetType(JSContextRef ctx, JSValueRef value)
  56. {
  57. if (!ctx) {
  58. ASSERT_NOT_REACHED();
  59. return kJSTypeUndefined;
  60. }
  61. ExecState* exec = toJS(ctx);
  62. APIEntryShim entryShim(exec);
  63. JSValue jsValue = toJS(exec, value);
  64. if (jsValue.isUndefined())
  65. return kJSTypeUndefined;
  66. if (jsValue.isNull())
  67. return kJSTypeNull;
  68. if (jsValue.isBoolean())
  69. return kJSTypeBoolean;
  70. if (jsValue.isNumber())
  71. return kJSTypeNumber;
  72. if (jsValue.isString())
  73. return kJSTypeString;
  74. ASSERT(jsValue.isObject());
  75. return kJSTypeObject;
  76. }
  77. bool JSValueIsUndefined(JSContextRef ctx, JSValueRef value)
  78. {
  79. if (!ctx) {
  80. ASSERT_NOT_REACHED();
  81. return false;
  82. }
  83. ExecState* exec = toJS(ctx);
  84. APIEntryShim entryShim(exec);
  85. JSValue jsValue = toJS(exec, value);
  86. return jsValue.isUndefined();
  87. }
  88. bool JSValueIsNull(JSContextRef ctx, JSValueRef value)
  89. {
  90. if (!ctx) {
  91. ASSERT_NOT_REACHED();
  92. return false;
  93. }
  94. ExecState* exec = toJS(ctx);
  95. APIEntryShim entryShim(exec);
  96. JSValue jsValue = toJS(exec, value);
  97. return jsValue.isNull();
  98. }
  99. bool JSValueIsBoolean(JSContextRef ctx, JSValueRef value)
  100. {
  101. if (!ctx) {
  102. ASSERT_NOT_REACHED();
  103. return false;
  104. }
  105. ExecState* exec = toJS(ctx);
  106. APIEntryShim entryShim(exec);
  107. JSValue jsValue = toJS(exec, value);
  108. return jsValue.isBoolean();
  109. }
  110. bool JSValueIsNumber(JSContextRef ctx, JSValueRef value)
  111. {
  112. if (!ctx) {
  113. ASSERT_NOT_REACHED();
  114. return false;
  115. }
  116. ExecState* exec = toJS(ctx);
  117. APIEntryShim entryShim(exec);
  118. JSValue jsValue = toJS(exec, value);
  119. return jsValue.isNumber();
  120. }
  121. bool JSValueIsString(JSContextRef ctx, JSValueRef value)
  122. {
  123. if (!ctx) {
  124. ASSERT_NOT_REACHED();
  125. return false;
  126. }
  127. ExecState* exec = toJS(ctx);
  128. APIEntryShim entryShim(exec);
  129. JSValue jsValue = toJS(exec, value);
  130. return jsValue.isString();
  131. }
  132. bool JSValueIsObject(JSContextRef ctx, JSValueRef value)
  133. {
  134. if (!ctx) {
  135. ASSERT_NOT_REACHED();
  136. return false;
  137. }
  138. ExecState* exec = toJS(ctx);
  139. APIEntryShim entryShim(exec);
  140. JSValue jsValue = toJS(exec, value);
  141. return jsValue.isObject();
  142. }
  143. bool JSValueIsObjectOfClass(JSContextRef ctx, JSValueRef value, JSClassRef jsClass)
  144. {
  145. if (!ctx || !jsClass) {
  146. ASSERT_NOT_REACHED();
  147. return false;
  148. }
  149. ExecState* exec = toJS(ctx);
  150. APIEntryShim entryShim(exec);
  151. JSValue jsValue = toJS(exec, value);
  152. if (JSObject* o = jsValue.getObject()) {
  153. if (o->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
  154. return jsCast<JSCallbackObject<JSGlobalObject>*>(o)->inherits(jsClass);
  155. if (o->inherits(&JSCallbackObject<JSDestructibleObject>::s_info))
  156. return jsCast<JSCallbackObject<JSDestructibleObject>*>(o)->inherits(jsClass);
  157. #if JSC_OBJC_API_ENABLED
  158. if (o->inherits(&JSCallbackObject<JSAPIWrapperObject>::s_info))
  159. return jsCast<JSCallbackObject<JSAPIWrapperObject>*>(o)->inherits(jsClass);
  160. #endif
  161. }
  162. return false;
  163. }
  164. bool JSValueIsEqual(JSContextRef ctx, JSValueRef a, JSValueRef b, JSValueRef* exception)
  165. {
  166. if (!ctx) {
  167. ASSERT_NOT_REACHED();
  168. return false;
  169. }
  170. ExecState* exec = toJS(ctx);
  171. APIEntryShim entryShim(exec);
  172. JSValue jsA = toJS(exec, a);
  173. JSValue jsB = toJS(exec, b);
  174. bool result = JSValue::equal(exec, jsA, jsB); // false if an exception is thrown
  175. if (exec->hadException()) {
  176. if (exception)
  177. *exception = toRef(exec, exec->exception());
  178. exec->clearException();
  179. }
  180. return result;
  181. }
  182. bool JSValueIsStrictEqual(JSContextRef ctx, JSValueRef a, JSValueRef b)
  183. {
  184. if (!ctx) {
  185. ASSERT_NOT_REACHED();
  186. return false;
  187. }
  188. ExecState* exec = toJS(ctx);
  189. APIEntryShim entryShim(exec);
  190. JSValue jsA = toJS(exec, a);
  191. JSValue jsB = toJS(exec, b);
  192. return JSValue::strictEqual(exec, jsA, jsB);
  193. }
  194. bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObjectRef constructor, JSValueRef* exception)
  195. {
  196. if (!ctx) {
  197. ASSERT_NOT_REACHED();
  198. return false;
  199. }
  200. ExecState* exec = toJS(ctx);
  201. APIEntryShim entryShim(exec);
  202. JSValue jsValue = toJS(exec, value);
  203. JSObject* jsConstructor = toJS(constructor);
  204. if (!jsConstructor->structure()->typeInfo().implementsHasInstance())
  205. return false;
  206. bool result = jsConstructor->hasInstance(exec, jsValue); // false if an exception is thrown
  207. if (exec->hadException()) {
  208. if (exception)
  209. *exception = toRef(exec, exec->exception());
  210. exec->clearException();
  211. }
  212. return result;
  213. }
  214. JSValueRef JSValueMakeUndefined(JSContextRef ctx)
  215. {
  216. if (!ctx) {
  217. ASSERT_NOT_REACHED();
  218. return 0;
  219. }
  220. ExecState* exec = toJS(ctx);
  221. APIEntryShim entryShim(exec);
  222. return toRef(exec, jsUndefined());
  223. }
  224. JSValueRef JSValueMakeNull(JSContextRef ctx)
  225. {
  226. if (!ctx) {
  227. ASSERT_NOT_REACHED();
  228. return 0;
  229. }
  230. ExecState* exec = toJS(ctx);
  231. APIEntryShim entryShim(exec);
  232. return toRef(exec, jsNull());
  233. }
  234. JSValueRef JSValueMakeBoolean(JSContextRef ctx, bool value)
  235. {
  236. if (!ctx) {
  237. ASSERT_NOT_REACHED();
  238. return 0;
  239. }
  240. ExecState* exec = toJS(ctx);
  241. APIEntryShim entryShim(exec);
  242. return toRef(exec, jsBoolean(value));
  243. }
  244. JSValueRef JSValueMakeNumber(JSContextRef ctx, double value)
  245. {
  246. if (!ctx) {
  247. ASSERT_NOT_REACHED();
  248. return 0;
  249. }
  250. ExecState* exec = toJS(ctx);
  251. APIEntryShim entryShim(exec);
  252. // Our JSValue representation relies on a standard bit pattern for NaN. NaNs
  253. // generated internally to JavaScriptCore naturally have that representation,
  254. // but an external NaN might not.
  255. if (std::isnan(value))
  256. value = QNaN;
  257. return toRef(exec, jsNumber(value));
  258. }
  259. JSValueRef JSValueMakeString(JSContextRef ctx, JSStringRef string)
  260. {
  261. if (!ctx) {
  262. ASSERT_NOT_REACHED();
  263. return 0;
  264. }
  265. ExecState* exec = toJS(ctx);
  266. APIEntryShim entryShim(exec);
  267. return toRef(exec, jsString(exec, string->string()));
  268. }
  269. JSValueRef JSValueMakeFromJSONString(JSContextRef ctx, JSStringRef string)
  270. {
  271. if (!ctx) {
  272. ASSERT_NOT_REACHED();
  273. return 0;
  274. }
  275. ExecState* exec = toJS(ctx);
  276. APIEntryShim entryShim(exec);
  277. String str = string->string();
  278. unsigned length = str.length();
  279. if (length && str.is8Bit()) {
  280. LiteralParser<LChar> parser(exec, str.characters8(), length, StrictJSON);
  281. return toRef(exec, parser.tryLiteralParse());
  282. }
  283. LiteralParser<UChar> parser(exec, str.characters(), length, StrictJSON);
  284. return toRef(exec, parser.tryLiteralParse());
  285. }
  286. JSStringRef JSValueCreateJSONString(JSContextRef ctx, JSValueRef apiValue, unsigned indent, JSValueRef* exception)
  287. {
  288. if (!ctx) {
  289. ASSERT_NOT_REACHED();
  290. return 0;
  291. }
  292. ExecState* exec = toJS(ctx);
  293. APIEntryShim entryShim(exec);
  294. JSValue value = toJS(exec, apiValue);
  295. String result = JSONStringify(exec, value, indent);
  296. if (exception)
  297. *exception = 0;
  298. if (exec->hadException()) {
  299. if (exception)
  300. *exception = toRef(exec, exec->exception());
  301. exec->clearException();
  302. return 0;
  303. }
  304. return OpaqueJSString::create(result).leakRef();
  305. }
  306. bool JSValueToBoolean(JSContextRef ctx, JSValueRef value)
  307. {
  308. if (!ctx) {
  309. ASSERT_NOT_REACHED();
  310. return false;
  311. }
  312. ExecState* exec = toJS(ctx);
  313. APIEntryShim entryShim(exec);
  314. JSValue jsValue = toJS(exec, value);
  315. return jsValue.toBoolean(exec);
  316. }
  317. double JSValueToNumber(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
  318. {
  319. if (!ctx) {
  320. ASSERT_NOT_REACHED();
  321. return QNaN;
  322. }
  323. ExecState* exec = toJS(ctx);
  324. APIEntryShim entryShim(exec);
  325. JSValue jsValue = toJS(exec, value);
  326. double number = jsValue.toNumber(exec);
  327. if (exec->hadException()) {
  328. if (exception)
  329. *exception = toRef(exec, exec->exception());
  330. exec->clearException();
  331. number = QNaN;
  332. }
  333. return number;
  334. }
  335. JSStringRef JSValueToStringCopy(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
  336. {
  337. if (!ctx) {
  338. ASSERT_NOT_REACHED();
  339. return 0;
  340. }
  341. ExecState* exec = toJS(ctx);
  342. APIEntryShim entryShim(exec);
  343. JSValue jsValue = toJS(exec, value);
  344. RefPtr<OpaqueJSString> stringRef(OpaqueJSString::create(jsValue.toString(exec)->value(exec)));
  345. if (exec->hadException()) {
  346. if (exception)
  347. *exception = toRef(exec, exec->exception());
  348. exec->clearException();
  349. stringRef.clear();
  350. }
  351. return stringRef.release().leakRef();
  352. }
  353. JSObjectRef JSValueToObject(JSContextRef ctx, JSValueRef value, JSValueRef* exception)
  354. {
  355. if (!ctx) {
  356. ASSERT_NOT_REACHED();
  357. return 0;
  358. }
  359. ExecState* exec = toJS(ctx);
  360. APIEntryShim entryShim(exec);
  361. JSValue jsValue = toJS(exec, value);
  362. JSObjectRef objectRef = toRef(jsValue.toObject(exec));
  363. if (exec->hadException()) {
  364. if (exception)
  365. *exception = toRef(exec, exec->exception());
  366. exec->clearException();
  367. objectRef = 0;
  368. }
  369. return objectRef;
  370. }
  371. void JSValueProtect(JSContextRef ctx, JSValueRef value)
  372. {
  373. if (!ctx) {
  374. ASSERT_NOT_REACHED();
  375. return;
  376. }
  377. ExecState* exec = toJS(ctx);
  378. APIEntryShim entryShim(exec);
  379. JSValue jsValue = toJSForGC(exec, value);
  380. gcProtect(jsValue);
  381. }
  382. void JSValueUnprotect(JSContextRef ctx, JSValueRef value)
  383. {
  384. #if PLATFORM(MAC)
  385. if ((!value || !ctx) && evernoteHackNeeded())
  386. return;
  387. #endif
  388. ExecState* exec = toJS(ctx);
  389. APIEntryShim entryShim(exec);
  390. JSValue jsValue = toJSForGC(exec, value);
  391. gcUnprotect(jsValue);
  392. }