JSCJSValue.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /*
  2. * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  3. * Copyright (C) 2001 Peter Kelly (pmk@post.com)
  4. * Copyright (C) 2003, 2007, 2008, 2012 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. #include "config.h"
  23. #include "JSCJSValue.h"
  24. #include "BooleanConstructor.h"
  25. #include "BooleanPrototype.h"
  26. #include "Error.h"
  27. #include "ExceptionHelpers.h"
  28. #include "GetterSetter.h"
  29. #include "JSCJSValueInlines.h"
  30. #include "JSFunction.h"
  31. #include "JSGlobalObject.h"
  32. #include "JSNotAnObject.h"
  33. #include "NumberObject.h"
  34. #include <wtf/MathExtras.h>
  35. #include <wtf/StringExtras.h>
  36. namespace JSC {
  37. #if !(ENABLE(DETACHED_JIT) && BUILDING_DETACHED_JIT)
  38. // ECMA 9.4
  39. double JSValue::toInteger(ExecState* exec) const
  40. {
  41. if (isInt32())
  42. return asInt32();
  43. double d = toNumber(exec);
  44. return std::isnan(d) ? 0.0 : trunc(d);
  45. }
  46. double JSValue::toIntegerPreserveNaN(ExecState* exec) const
  47. {
  48. if (isInt32())
  49. return asInt32();
  50. return trunc(toNumber(exec));
  51. }
  52. double JSValue::toNumberSlowCase(ExecState* exec) const
  53. {
  54. ASSERT(!isInt32() && !isDouble());
  55. if (isCell())
  56. return asCell()->toNumber(exec);
  57. if (isTrue())
  58. return 1.0;
  59. return isUndefined() ? QNaN : 0; // null and false both convert to 0.
  60. }
  61. JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const
  62. {
  63. ASSERT(!isCell());
  64. if (isInt32() || isDouble())
  65. return constructNumber(exec, globalObject, asValue());
  66. if (isTrue() || isFalse())
  67. return constructBooleanFromImmediateBoolean(exec, globalObject, asValue());
  68. ASSERT(isUndefinedOrNull());
  69. throwError(exec, createNotAnObjectError(exec, *this));
  70. return JSNotAnObject::create(exec);
  71. }
  72. JSObject* JSValue::toThisObjectSlowCase(ExecState* exec) const
  73. {
  74. ASSERT(!isCell());
  75. if (isInt32() || isDouble())
  76. return constructNumber(exec, exec->lexicalGlobalObject(), asValue());
  77. if (isTrue() || isFalse())
  78. return constructBooleanFromImmediateBoolean(exec, exec->lexicalGlobalObject(), asValue());
  79. ASSERT(isUndefinedOrNull());
  80. return exec->globalThisValue();
  81. }
  82. JSObject* JSValue::synthesizePrototype(ExecState* exec) const
  83. {
  84. if (isCell()) {
  85. ASSERT(isString());
  86. return exec->lexicalGlobalObject()->stringPrototype();
  87. }
  88. if (isNumber())
  89. return exec->lexicalGlobalObject()->numberPrototype();
  90. if (isBoolean())
  91. return exec->lexicalGlobalObject()->booleanPrototype();
  92. ASSERT(isUndefinedOrNull());
  93. throwError(exec, createNotAnObjectError(exec, *this));
  94. return JSNotAnObject::create(exec);
  95. }
  96. // ECMA 8.7.2
  97. void JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot)
  98. {
  99. VM& vm = exec->vm();
  100. unsigned index = propertyName.asIndex();
  101. if (index != PropertyName::NotAnIndex) {
  102. putToPrimitiveByIndex(exec, index, value, slot.isStrictMode());
  103. return;
  104. }
  105. // Check if there are any setters or getters in the prototype chain
  106. JSObject* obj = synthesizePrototype(exec);
  107. JSValue prototype;
  108. if (propertyName != exec->propertyNames().underscoreProto) {
  109. for (; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
  110. prototype = obj->prototype();
  111. if (prototype.isNull()) {
  112. if (slot.isStrictMode())
  113. throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
  114. return;
  115. }
  116. }
  117. }
  118. for (; ; obj = asObject(prototype)) {
  119. unsigned attributes;
  120. JSCell* specificValue;
  121. PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes, specificValue);
  122. if (offset != invalidOffset) {
  123. if (attributes & ReadOnly) {
  124. if (slot.isStrictMode())
  125. throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
  126. return;
  127. }
  128. JSValue gs = obj->getDirect(offset);
  129. if (gs.isGetterSetter()) {
  130. JSObject* setterFunc = asGetterSetter(gs)->setter();
  131. if (!setterFunc) {
  132. if (slot.isStrictMode())
  133. throwError(exec, createTypeError(exec, ASCIILiteral("setting a property that has only a getter")));
  134. return;
  135. }
  136. CallData callData;
  137. CallType callType = setterFunc->methodTable()->getCallData(setterFunc, callData);
  138. MarkedArgumentBuffer args;
  139. args.append(value);
  140. // If this is WebCore's global object then we need to substitute the shell.
  141. call(exec, setterFunc, callType, callData, *this, args);
  142. return;
  143. }
  144. // If there's an existing property on the object or one of its
  145. // prototypes it should be replaced, so break here.
  146. break;
  147. }
  148. prototype = obj->prototype();
  149. if (prototype.isNull())
  150. break;
  151. }
  152. if (slot.isStrictMode())
  153. throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
  154. return;
  155. }
  156. void JSValue::putToPrimitiveByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow)
  157. {
  158. if (propertyName > MAX_ARRAY_INDEX) {
  159. PutPropertySlot slot(shouldThrow);
  160. putToPrimitive(exec, Identifier::from(exec, propertyName), value, slot);
  161. return;
  162. }
  163. if (synthesizePrototype(exec)->attemptToInterceptPutByIndexOnHoleForPrototype(exec, *this, propertyName, value, shouldThrow))
  164. return;
  165. if (shouldThrow)
  166. throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
  167. }
  168. void JSValue::dump(PrintStream& out) const
  169. {
  170. if (!*this)
  171. out.print("<JSValue()>");
  172. else if (isInt32())
  173. out.printf("Int32: %d", asInt32());
  174. else if (isDouble()) {
  175. #if USE(JSVALUE64)
  176. out.printf("Double: %lld, %lf", (long long)reinterpretDoubleToInt64(asDouble()), asDouble());
  177. #else
  178. union {
  179. double asDouble;
  180. uint32_t asTwoInt32s[2];
  181. } u;
  182. u.asDouble = asDouble();
  183. out.printf("Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble());
  184. #endif
  185. } else if (isCell()) {
  186. if (asCell()->inherits(&JSString::s_info)) {
  187. JSString* string = jsCast<JSString*>(asCell());
  188. out.print("String: ");
  189. if (string->isRope())
  190. out.print("(rope) ");
  191. out.print(string->tryGetValue());
  192. } else if (asCell()->inherits(&Structure::s_info)) {
  193. Structure* structure = jsCast<Structure*>(asCell());
  194. out.print(
  195. "Structure: ", RawPointer(structure), ": ", structure->classInfo()->className,
  196. ", ", IndexingTypeDump(structure->indexingTypeIncludingHistory()));
  197. } else {
  198. out.print("Cell: ", RawPointer(asCell()));
  199. if (isObject() && asObject(*this)->butterfly())
  200. out.print("->", RawPointer(asObject(*this)->butterfly()));
  201. out.print(
  202. " (", RawPointer(asCell()->structure()), ": ", asCell()->structure()->classInfo()->className,
  203. ", ", IndexingTypeDump(asCell()->structure()->indexingTypeIncludingHistory()), ")");
  204. }
  205. } else if (isTrue())
  206. out.print("True");
  207. else if (isFalse())
  208. out.print("False");
  209. else if (isNull())
  210. out.print("Null");
  211. else if (isUndefined())
  212. out.print("Undefined");
  213. else
  214. out.print("INVALID");
  215. }
  216. #endif // #if !(ENABLE(DETACHED_JIT) && BUILDING_DETACHED_JIT)
  217. // This in the ToInt32 operation is defined in section 9.5 of the ECMA-262 spec.
  218. // Note that this operation is identical to ToUInt32 other than to interpretation
  219. // of the resulting bit-pattern (as such this metod is also called to implement
  220. // ToUInt32).
  221. //
  222. // The operation can be descibed as round towards zero, then select the 32 least
  223. // bits of the resulting value in 2s-complement representation.
  224. int32_t toInt32(double number)
  225. {
  226. int64_t bits = WTF::bitwise_cast<int64_t>(number);
  227. int32_t exp = (static_cast<int32_t>(bits >> 52) & 0x7ff) - 0x3ff;
  228. // If exponent < 0 there will be no bits to the left of the decimal point
  229. // after rounding; if the exponent is > 83 then no bits of precision can be
  230. // left in the low 32-bit range of the result (IEEE-754 doubles have 52 bits
  231. // of fractional precision).
  232. // Note this case handles 0, -0, and all infinte, NaN, & denormal value.
  233. if (exp < 0 || exp > 83)
  234. return 0;
  235. // Select the appropriate 32-bits from the floating point mantissa. If the
  236. // exponent is 52 then the bits we need to select are already aligned to the
  237. // lowest bits of the 64-bit integer representation of tghe number, no need
  238. // to shift. If the exponent is greater than 52 we need to shift the value
  239. // left by (exp - 52), if the value is less than 52 we need to shift right
  240. // accordingly.
  241. int32_t result = (exp > 52)
  242. ? static_cast<int32_t>(bits << (exp - 52))
  243. : static_cast<int32_t>(bits >> (52 - exp));
  244. // IEEE-754 double precision values are stored omitting an implicit 1 before
  245. // the decimal point; we need to reinsert this now. We may also the shifted
  246. // invalid bits into the result that are not a part of the mantissa (the sign
  247. // and exponent bits from the floatingpoint representation); mask these out.
  248. if (exp < 32) {
  249. int32_t missingOne = 1 << exp;
  250. result &= missingOne - 1;
  251. result += missingOne;
  252. }
  253. // If the input value was negative (we could test either 'number' or 'bits',
  254. // but testing 'bits' is likely faster) invert the result appropriately.
  255. return bits < 0 ? -result : result;
  256. }
  257. #if !(ENABLE(DETACHED_JIT) && BUILDING_DETACHED_JIT)
  258. bool JSValue::isValidCallee()
  259. {
  260. return asObject(asCell())->globalObject();
  261. }
  262. JSString* JSValue::toStringSlowCase(ExecState* exec) const
  263. {
  264. VM& vm = exec->vm();
  265. ASSERT(!isString());
  266. if (isInt32())
  267. return jsString(&vm, vm.numericStrings.add(asInt32()));
  268. if (isDouble())
  269. return jsString(&vm, vm.numericStrings.add(asDouble()));
  270. if (isTrue())
  271. return vm.smallStrings.trueString();
  272. if (isFalse())
  273. return vm.smallStrings.falseString();
  274. if (isNull())
  275. return vm.smallStrings.nullString();
  276. if (isUndefined())
  277. return vm.smallStrings.undefinedString();
  278. ASSERT(isCell());
  279. JSValue value = asCell()->toPrimitive(exec, PreferString);
  280. if (exec->hadException())
  281. return jsEmptyString(exec);
  282. ASSERT(!value.isObject());
  283. return value.toString(exec);
  284. }
  285. String JSValue::toWTFStringSlowCase(ExecState* exec) const
  286. {
  287. return inlineJSValueNotStringtoString(*this, exec);
  288. }
  289. #endif // #if !(ENABLE(DETACHED_JIT) && BUILDING_DETACHED_JIT)
  290. } // namespace JSC