mjs | 6f821c8 | 2002-03-22 00:31:57 +0000 | [diff] [blame] | 1 | /* |
mjs | 6f821c8 | 2002-03-22 00:31:57 +0000 | [diff] [blame] | 2 | * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) |
| 3 | * Copyright (C) 2001 Peter Kelly (pmk@post.com) |
fpizlo@apple.com | 1c4a32c | 2012-09-17 20:56:39 +0000 | [diff] [blame] | 4 | * Copyright (C) 2003, 2007, 2008, 2012 Apple Inc. All rights reserved. |
mjs | 6f821c8 | 2002-03-22 00:31:57 +0000 | [diff] [blame] | 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 |
mjs | cdff33b | 2006-01-23 21:41:36 +0000 | [diff] [blame] | 18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
ggaren | 07d4ce6 | 2005-07-14 18:27:04 +0000 | [diff] [blame] | 19 | * Boston, MA 02110-1301, USA. |
mjs | 6f821c8 | 2002-03-22 00:31:57 +0000 | [diff] [blame] | 20 | * |
| 21 | */ |
| 22 | |
mjs | b64c50a | 2005-10-03 21:13:12 +0000 | [diff] [blame] | 23 | #include "config.h" |
mhahnenberg@apple.com | c1bc9d3 | 2013-01-24 21:39:55 +0000 | [diff] [blame] | 24 | #include "JSCJSValue.h" |
darin | c13d2ca | 2005-08-08 04:07:46 +0000 | [diff] [blame] | 25 | |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 26 | #include "BooleanConstructor.h" |
| 27 | #include "BooleanPrototype.h" |
mhahnenberg@apple.com | ff62ccb | 2014-06-09 18:53:32 +0000 | [diff] [blame] | 28 | #include "CustomGetterSetter.h" |
barraclough@apple.com | 9c099f9 | 2010-06-06 23:34:36 +0000 | [diff] [blame] | 29 | #include "Error.h" |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 30 | #include "ExceptionHelpers.h" |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 31 | #include "GetterSetter.h" |
commit-queue@webkit.org | 906a4ec | 2014-09-09 00:21:24 +0000 | [diff] [blame] | 32 | #include "JSCJSValueInlines.h" |
weinig@apple.com | 860df8c | 2008-06-29 22:22:32 +0000 | [diff] [blame] | 33 | #include "JSFunction.h" |
mhahnenberg@apple.com | c1bc9d3 | 2013-01-24 21:39:55 +0000 | [diff] [blame] | 34 | #include "JSGlobalObject.h" |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 35 | #include "NumberObject.h" |
commit-queue@webkit.org | 906a4ec | 2014-09-09 00:21:24 +0000 | [diff] [blame] | 36 | #include "StructureInlines.h" |
darin | 6c5f29d | 2006-07-05 04:13:32 +0000 | [diff] [blame] | 37 | #include <wtf/MathExtras.h> |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 38 | #include <wtf/StringExtras.h> |
mjs | 6f821c8 | 2002-03-22 00:31:57 +0000 | [diff] [blame] | 39 | |
cwzwarich@webkit.org | 3f782f6 | 2008-09-08 01:28:33 +0000 | [diff] [blame] | 40 | namespace JSC { |
mjs | 6f821c8 | 2002-03-22 00:31:57 +0000 | [diff] [blame] | 41 | |
mjs | 6f821c8 | 2002-03-22 00:31:57 +0000 | [diff] [blame] | 42 | // ECMA 9.4 |
ggaren@apple.com | dc067b6 | 2009-05-01 22:43:39 +0000 | [diff] [blame] | 43 | double JSValue::toInteger(ExecState* exec) const |
mjs | 6f821c8 | 2002-03-22 00:31:57 +0000 | [diff] [blame] | 44 | { |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 45 | if (isInt32()) |
| 46 | return asInt32(); |
darin | 1622f9e | 2007-10-26 07:51:25 +0000 | [diff] [blame] | 47 | double d = toNumber(exec); |
zandobersek@gmail.com | 9182d47 | 2013-02-13 23:01:21 +0000 | [diff] [blame] | 48 | return std::isnan(d) ? 0.0 : trunc(d); |
darin | 1622f9e | 2007-10-26 07:51:25 +0000 | [diff] [blame] | 49 | } |
| 50 | |
ggaren@apple.com | dc067b6 | 2009-05-01 22:43:39 +0000 | [diff] [blame] | 51 | double JSValue::toIntegerPreserveNaN(ExecState* exec) const |
darin | 1622f9e | 2007-10-26 07:51:25 +0000 | [diff] [blame] | 52 | { |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 53 | if (isInt32()) |
| 54 | return asInt32(); |
darin | 1622f9e | 2007-10-26 07:51:25 +0000 | [diff] [blame] | 55 | return trunc(toNumber(exec)); |
mjs | 6f821c8 | 2002-03-22 00:31:57 +0000 | [diff] [blame] | 56 | } |
| 57 | |
commit-queue@webkit.org | 1750e1e | 2015-09-15 17:43:27 +0000 | [diff] [blame] | 58 | double JSValue::toLength(ExecState* exec) const |
| 59 | { |
| 60 | // ECMA 7.1.15 |
| 61 | // http://www.ecma-international.org/ecma-262/6.0/#sec-tolength |
| 62 | double d = toInteger(exec); |
| 63 | if (d <= 0) |
| 64 | return 0.0; |
| 65 | if (std::isinf(d)) |
| 66 | return 9007199254740991.0; // 2 ** 53 - 1 |
| 67 | return std::min(d, 9007199254740991.0); |
| 68 | } |
| 69 | |
barraclough@apple.com | 0658510 | 2011-07-22 05:34:08 +0000 | [diff] [blame] | 70 | double JSValue::toNumberSlowCase(ExecState* exec) const |
| 71 | { |
| 72 | ASSERT(!isInt32() && !isDouble()); |
| 73 | if (isCell()) |
| 74 | return asCell()->toNumber(exec); |
| 75 | if (isTrue()) |
| 76 | return 1.0; |
fpizlo@apple.com | beef452 | 2014-04-16 22:44:00 +0000 | [diff] [blame] | 77 | return isUndefined() ? PNaN : 0; // null and false both convert to 0. |
barraclough@apple.com | 0658510 | 2011-07-22 05:34:08 +0000 | [diff] [blame] | 78 | } |
| 79 | |
oliver@apple.com | 3b6dc57 | 2011-03-28 23:39:16 +0000 | [diff] [blame] | 80 | JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 81 | { |
| 82 | ASSERT(!isCell()); |
| 83 | |
| 84 | if (isInt32() || isDouble()) |
oliver@apple.com | 3b6dc57 | 2011-03-28 23:39:16 +0000 | [diff] [blame] | 85 | return constructNumber(exec, globalObject, asValue()); |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 86 | if (isTrue() || isFalse()) |
oliver@apple.com | 3b6dc57 | 2011-03-28 23:39:16 +0000 | [diff] [blame] | 87 | return constructBooleanFromImmediateBoolean(exec, globalObject, asValue()); |
barraclough@apple.com | 8da6d97 | 2010-11-16 21:11:26 +0000 | [diff] [blame] | 88 | |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 89 | ASSERT(isUndefinedOrNull()); |
akling@apple.com | 3d28686 | 2013-10-08 03:29:05 +0000 | [diff] [blame] | 90 | VM& vm = exec->vm(); |
| 91 | vm.throwException(exec, createNotAnObjectError(exec, *this)); |
mark.lam@apple.com | 5088f6b | 2016-03-08 20:57:25 +0000 | [diff] [blame] | 92 | return nullptr; |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 93 | } |
| 94 | |
oliver@apple.com | e2fe4ce | 2013-07-25 03:59:41 +0000 | [diff] [blame] | 95 | JSValue JSValue::toThisSlowCase(ExecState* exec, ECMAMode ecmaMode) const |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 96 | { |
| 97 | ASSERT(!isCell()); |
| 98 | |
oliver@apple.com | e2fe4ce | 2013-07-25 03:59:41 +0000 | [diff] [blame] | 99 | if (ecmaMode == StrictMode) |
| 100 | return *this; |
| 101 | |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 102 | if (isInt32() || isDouble()) |
oliver@apple.com | 3b6dc57 | 2011-03-28 23:39:16 +0000 | [diff] [blame] | 103 | return constructNumber(exec, exec->lexicalGlobalObject(), asValue()); |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 104 | if (isTrue() || isFalse()) |
oliver@apple.com | 3b6dc57 | 2011-03-28 23:39:16 +0000 | [diff] [blame] | 105 | return constructBooleanFromImmediateBoolean(exec, exec->lexicalGlobalObject(), asValue()); |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 106 | ASSERT(isUndefinedOrNull()); |
| 107 | return exec->globalThisValue(); |
| 108 | } |
| 109 | |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 110 | JSObject* JSValue::synthesizePrototype(ExecState* exec) const |
| 111 | { |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 112 | if (isCell()) { |
utatane.tea@gmail.com | 947fa4e | 2015-01-31 01:23:56 +0000 | [diff] [blame] | 113 | if (isString()) |
| 114 | return exec->lexicalGlobalObject()->stringPrototype(); |
| 115 | ASSERT(isSymbol()); |
| 116 | return exec->lexicalGlobalObject()->symbolPrototype(); |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 117 | } |
| 118 | |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 119 | if (isNumber()) |
| 120 | return exec->lexicalGlobalObject()->numberPrototype(); |
| 121 | if (isBoolean()) |
| 122 | return exec->lexicalGlobalObject()->booleanPrototype(); |
| 123 | |
barraclough@apple.com | 8da6d97 | 2010-11-16 21:11:26 +0000 | [diff] [blame] | 124 | ASSERT(isUndefinedOrNull()); |
akling@apple.com | 3d28686 | 2013-10-08 03:29:05 +0000 | [diff] [blame] | 125 | VM& vm = exec->vm(); |
| 126 | vm.throwException(exec, createNotAnObjectError(exec, *this)); |
mark.lam@apple.com | 5088f6b | 2016-03-08 20:57:25 +0000 | [diff] [blame] | 127 | return nullptr; |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 128 | } |
| 129 | |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 130 | // ECMA 8.7.2 |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 131 | bool JSValue::putToPrimitive(ExecState* exec, PropertyName propertyName, JSValue value, PutPropertySlot& slot) |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 132 | { |
ggaren@apple.com | 9a9a4b5 | 2013-04-18 19:32:17 +0000 | [diff] [blame] | 133 | VM& vm = exec->vm(); |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 134 | |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 135 | if (Optional<uint32_t> index = parseIndex(propertyName)) |
| 136 | return putToPrimitiveByIndex(exec, index.value(), value, slot.isStrictMode()); |
fpizlo@apple.com | 1c4a32c | 2012-09-17 20:56:39 +0000 | [diff] [blame] | 137 | |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 138 | // Check if there are any setters or getters in the prototype chain |
| 139 | JSObject* obj = synthesizePrototype(exec); |
mark.lam@apple.com | 5088f6b | 2016-03-08 20:57:25 +0000 | [diff] [blame] | 140 | if (UNLIKELY(!obj)) |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 141 | return false; |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 142 | JSValue prototype; |
| 143 | if (propertyName != exec->propertyNames().underscoreProto) { |
| 144 | for (; !obj->structure()->hasReadOnlyOrGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) { |
sbarati@apple.com | fa85752 | 2016-03-07 01:00:33 +0000 | [diff] [blame] | 145 | prototype = obj->getPrototypeDirect(); |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 146 | if (prototype.isNull()) { |
| 147 | if (slot.isStrictMode()) |
| 148 | throwTypeError(exec, StrictModeReadonlyPropertyWriteError); |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 149 | return false; |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 150 | } |
| 151 | } |
| 152 | } |
| 153 | |
| 154 | for (; ; obj = asObject(prototype)) { |
| 155 | unsigned attributes; |
fpizlo@apple.com | 2c4a7e9 | 2014-08-06 05:27:46 +0000 | [diff] [blame] | 156 | PropertyOffset offset = obj->structure()->get(vm, propertyName, attributes); |
fpizlo@apple.com | d68b1f8 | 2012-07-05 22:55:51 +0000 | [diff] [blame] | 157 | if (offset != invalidOffset) { |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 158 | if (attributes & ReadOnly) { |
| 159 | if (slot.isStrictMode()) |
commit-queue@webkit.org | 3f922f9 | 2013-08-29 00:28:42 +0000 | [diff] [blame] | 160 | exec->vm().throwException(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError)); |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 161 | return false; |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 162 | } |
| 163 | |
ggaren@apple.com | 329c153 | 2013-01-11 21:33:47 +0000 | [diff] [blame] | 164 | JSValue gs = obj->getDirect(offset); |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 165 | if (gs.isGetterSetter()) |
| 166 | return callSetter(exec, *this, gs, value, slot.isStrictMode() ? StrictMode : NotStrictMode); |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 167 | |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 168 | if (gs.isCustomGetterSetter()) |
| 169 | return callCustomSetter(exec, gs, attributes & CustomAccessor, obj, slot.thisValue(), value); |
mhahnenberg@apple.com | ff62ccb | 2014-06-09 18:53:32 +0000 | [diff] [blame] | 170 | |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 171 | // If there's an existing property on the object or one of its |
| 172 | // prototypes it should be replaced, so break here. |
| 173 | break; |
| 174 | } |
| 175 | |
sbarati@apple.com | fa85752 | 2016-03-07 01:00:33 +0000 | [diff] [blame] | 176 | prototype = obj->getPrototype(vm, exec); |
| 177 | if (vm.exception()) |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 178 | return false; |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 179 | if (prototype.isNull()) |
| 180 | break; |
| 181 | } |
| 182 | |
| 183 | if (slot.isStrictMode()) |
| 184 | throwTypeError(exec, StrictModeReadonlyPropertyWriteError); |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 185 | return false; |
barraclough@apple.com | dca6b2e | 2012-02-29 01:39:15 +0000 | [diff] [blame] | 186 | } |
| 187 | |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 188 | bool JSValue::putToPrimitiveByIndex(ExecState* exec, unsigned propertyName, JSValue value, bool shouldThrow) |
fpizlo@apple.com | 1c4a32c | 2012-09-17 20:56:39 +0000 | [diff] [blame] | 189 | { |
| 190 | if (propertyName > MAX_ARRAY_INDEX) { |
oliver@apple.com | 6884841 | 2014-01-02 20:56:20 +0000 | [diff] [blame] | 191 | PutPropertySlot slot(*this, shouldThrow); |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 192 | return putToPrimitive(exec, Identifier::from(exec, propertyName), value, slot); |
fpizlo@apple.com | 1c4a32c | 2012-09-17 20:56:39 +0000 | [diff] [blame] | 193 | } |
| 194 | |
mark.lam@apple.com | 5088f6b | 2016-03-08 20:57:25 +0000 | [diff] [blame] | 195 | JSObject* prototype = synthesizePrototype(exec); |
| 196 | if (UNLIKELY(!prototype)) { |
| 197 | ASSERT(exec->hadException()); |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 198 | return false; |
mark.lam@apple.com | 5088f6b | 2016-03-08 20:57:25 +0000 | [diff] [blame] | 199 | } |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 200 | bool putResult = false; |
| 201 | if (prototype->attemptToInterceptPutByIndexOnHoleForPrototype(exec, *this, propertyName, value, shouldThrow, putResult)) |
| 202 | return putResult; |
fpizlo@apple.com | 1c4a32c | 2012-09-17 20:56:39 +0000 | [diff] [blame] | 203 | |
| 204 | if (shouldThrow) |
| 205 | throwTypeError(exec, StrictModeReadonlyPropertyWriteError); |
utatane.tea@gmail.com | 78b50c6 | 2016-03-11 17:28:46 +0000 | [diff] [blame] | 206 | return false; |
fpizlo@apple.com | 1c4a32c | 2012-09-17 20:56:39 +0000 | [diff] [blame] | 207 | } |
| 208 | |
fpizlo@apple.com | 9fe4913 | 2012-12-04 19:29:13 +0000 | [diff] [blame] | 209 | void JSValue::dump(PrintStream& out) const |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 210 | { |
oliver@apple.com | 237b146 | 2013-07-25 04:05:36 +0000 | [diff] [blame] | 211 | dumpInContext(out, 0); |
| 212 | } |
| 213 | |
| 214 | void JSValue::dumpInContext(PrintStream& out, DumpContext* context) const |
| 215 | { |
fpizlo@apple.com | b41e682 | 2014-07-25 20:55:17 +0000 | [diff] [blame] | 216 | dumpInContextAssumingStructure( |
| 217 | out, context, (!!*this && isCell()) ? asCell()->structure() : nullptr); |
| 218 | } |
| 219 | |
| 220 | void JSValue::dumpInContextAssumingStructure( |
| 221 | PrintStream& out, DumpContext* context, Structure* structure) const |
| 222 | { |
ggaren@apple.com | 53e48d5 | 2009-10-02 18:06:49 +0000 | [diff] [blame] | 223 | if (!*this) |
fpizlo@apple.com | 9fe4913 | 2012-12-04 19:29:13 +0000 | [diff] [blame] | 224 | out.print("<JSValue()>"); |
ggaren@apple.com | 53e48d5 | 2009-10-02 18:06:49 +0000 | [diff] [blame] | 225 | else if (isInt32()) |
fpizlo@apple.com | 9fe4913 | 2012-12-04 19:29:13 +0000 | [diff] [blame] | 226 | out.printf("Int32: %d", asInt32()); |
fpizlo@apple.com | 746c6d07 | 2011-09-07 02:47:51 +0000 | [diff] [blame] | 227 | else if (isDouble()) { |
| 228 | #if USE(JSVALUE64) |
fpizlo@apple.com | 9fe4913 | 2012-12-04 19:29:13 +0000 | [diff] [blame] | 229 | out.printf("Double: %lld, %lf", (long long)reinterpretDoubleToInt64(asDouble()), asDouble()); |
fpizlo@apple.com | 746c6d07 | 2011-09-07 02:47:51 +0000 | [diff] [blame] | 230 | #else |
| 231 | union { |
| 232 | double asDouble; |
| 233 | uint32_t asTwoInt32s[2]; |
| 234 | } u; |
| 235 | u.asDouble = asDouble(); |
fpizlo@apple.com | 9fe4913 | 2012-12-04 19:29:13 +0000 | [diff] [blame] | 236 | out.printf("Double: %08x:%08x, %lf", u.asTwoInt32s[1], u.asTwoInt32s[0], asDouble()); |
fpizlo@apple.com | 746c6d07 | 2011-09-07 02:47:51 +0000 | [diff] [blame] | 237 | #endif |
fpizlo@apple.com | 0e9910a | 2012-10-09 23:39:53 +0000 | [diff] [blame] | 238 | } else if (isCell()) { |
fpizlo@apple.com | b41e682 | 2014-07-25 20:55:17 +0000 | [diff] [blame] | 239 | if (structure->classInfo()->isSubClassOf(JSString::info())) { |
fpizlo@apple.com | 3fa6f5d | 2013-02-09 19:33:00 +0000 | [diff] [blame] | 240 | JSString* string = jsCast<JSString*>(asCell()); |
oliver@apple.com | b3e5acb | 2013-07-25 04:02:53 +0000 | [diff] [blame] | 241 | out.print("String"); |
fpizlo@apple.com | 3fa6f5d | 2013-02-09 19:33:00 +0000 | [diff] [blame] | 242 | if (string->isRope()) |
oliver@apple.com | b3e5acb | 2013-07-25 04:02:53 +0000 | [diff] [blame] | 243 | out.print(" (rope)"); |
| 244 | const StringImpl* impl = string->tryGetValueImpl(); |
| 245 | if (impl) { |
| 246 | if (impl->isAtomic()) |
| 247 | out.print(" (atomic)"); |
barraclough@apple.com | 0cde90d | 2014-03-20 21:05:49 +0000 | [diff] [blame] | 248 | if (impl->isAtomic()) |
oliver@apple.com | b3e5acb | 2013-07-25 04:02:53 +0000 | [diff] [blame] | 249 | out.print(" (identifier)"); |
utatane.tea@gmail.com | b6f60b2 | 2015-03-31 21:25:14 +0000 | [diff] [blame] | 250 | if (impl->isSymbol()) |
| 251 | out.print(" (symbol)"); |
oliver@apple.com | b3e5acb | 2013-07-25 04:02:53 +0000 | [diff] [blame] | 252 | } else |
| 253 | out.print(" (unresolved)"); |
| 254 | out.print(": ", impl); |
fpizlo@apple.com | b41e682 | 2014-07-25 20:55:17 +0000 | [diff] [blame] | 255 | } else if (structure->classInfo()->isSubClassOf(Structure::info())) |
oliver@apple.com | 237b146 | 2013-07-25 04:05:36 +0000 | [diff] [blame] | 256 | out.print("Structure: ", inContext(*jsCast<Structure*>(asCell()), context)); |
oliver@apple.com | 880e6c3 | 2013-07-25 04:03:25 +0000 | [diff] [blame] | 257 | else { |
fpizlo@apple.com | 0520bd4 | 2012-12-18 22:32:52 +0000 | [diff] [blame] | 258 | out.print("Cell: ", RawPointer(asCell())); |
fpizlo@apple.com | b41e682 | 2014-07-25 20:55:17 +0000 | [diff] [blame] | 259 | out.print(" (", inContext(*structure, context), ")"); |
fpizlo@apple.com | 1e89af3 | 2012-11-19 02:55:14 +0000 | [diff] [blame] | 260 | } |
fpizlo@apple.com | 5739957 | 2014-03-05 22:01:57 +0000 | [diff] [blame] | 261 | #if USE(JSVALUE64) |
| 262 | out.print(", ID: ", asCell()->structureID()); |
| 263 | #endif |
fpizlo@apple.com | 0e9910a | 2012-10-09 23:39:53 +0000 | [diff] [blame] | 264 | } else if (isTrue()) |
fpizlo@apple.com | 9fe4913 | 2012-12-04 19:29:13 +0000 | [diff] [blame] | 265 | out.print("True"); |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 266 | else if (isFalse()) |
fpizlo@apple.com | 9fe4913 | 2012-12-04 19:29:13 +0000 | [diff] [blame] | 267 | out.print("False"); |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 268 | else if (isNull()) |
fpizlo@apple.com | 9fe4913 | 2012-12-04 19:29:13 +0000 | [diff] [blame] | 269 | out.print("Null"); |
sfalken@apple.com | d5e7ced | 2010-06-24 18:28:06 +0000 | [diff] [blame] | 270 | else if (isUndefined()) |
fpizlo@apple.com | 9fe4913 | 2012-12-04 19:29:13 +0000 | [diff] [blame] | 271 | out.print("Undefined"); |
sfalken@apple.com | d5e7ced | 2010-06-24 18:28:06 +0000 | [diff] [blame] | 272 | else |
fpizlo@apple.com | 9fe4913 | 2012-12-04 19:29:13 +0000 | [diff] [blame] | 273 | out.print("INVALID"); |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 274 | } |
ggaren@apple.com | 540d71a6 | 2009-07-30 20:57:44 +0000 | [diff] [blame] | 275 | |
msaboff@apple.com | 149f8e1 | 2014-06-25 06:45:50 +0000 | [diff] [blame] | 276 | void JSValue::dumpForBacktrace(PrintStream& out) const |
| 277 | { |
| 278 | if (!*this) |
| 279 | out.print("<JSValue()>"); |
| 280 | else if (isInt32()) |
| 281 | out.printf("%d", asInt32()); |
| 282 | else if (isDouble()) |
| 283 | out.printf("%lf", asDouble()); |
| 284 | else if (isCell()) { |
| 285 | if (asCell()->inherits(JSString::info())) { |
| 286 | JSString* string = jsCast<JSString*>(asCell()); |
| 287 | const StringImpl* impl = string->tryGetValueImpl(); |
| 288 | if (impl) |
| 289 | out.print("\"", impl, "\""); |
| 290 | else |
| 291 | out.print("(unresolved string)"); |
| 292 | } else if (asCell()->inherits(Structure::info())) { |
| 293 | out.print("Structure[ ", asCell()->structure()->classInfo()->className); |
| 294 | #if USE(JSVALUE64) |
| 295 | out.print(" ID: ", asCell()->structureID()); |
| 296 | #endif |
| 297 | out.print("]: ", RawPointer(asCell())); |
| 298 | } else { |
| 299 | out.print("Cell[", asCell()->structure()->classInfo()->className); |
| 300 | #if USE(JSVALUE64) |
| 301 | out.print(" ID: ", asCell()->structureID()); |
| 302 | #endif |
| 303 | out.print("]: ", RawPointer(asCell())); |
| 304 | } |
| 305 | } else if (isTrue()) |
| 306 | out.print("True"); |
| 307 | else if (isFalse()) |
| 308 | out.print("False"); |
| 309 | else if (isNull()) |
| 310 | out.print("Null"); |
| 311 | else if (isUndefined()) |
| 312 | out.print("Undefined"); |
| 313 | else |
| 314 | out.print("INVALID"); |
| 315 | } |
| 316 | |
barraclough@apple.com | e7858b1 | 2010-09-20 01:23:33 +0000 | [diff] [blame] | 317 | // This in the ToInt32 operation is defined in section 9.5 of the ECMA-262 spec. |
| 318 | // Note that this operation is identical to ToUInt32 other than to interpretation |
| 319 | // of the resulting bit-pattern (as such this metod is also called to implement |
| 320 | // ToUInt32). |
| 321 | // |
| 322 | // The operation can be descibed as round towards zero, then select the 32 least |
| 323 | // bits of the resulting value in 2s-complement representation. |
| 324 | int32_t toInt32(double number) |
mjs | 6f821c8 | 2002-03-22 00:31:57 +0000 | [diff] [blame] | 325 | { |
barraclough@apple.com | e7858b1 | 2010-09-20 01:23:33 +0000 | [diff] [blame] | 326 | int64_t bits = WTF::bitwise_cast<int64_t>(number); |
| 327 | int32_t exp = (static_cast<int32_t>(bits >> 52) & 0x7ff) - 0x3ff; |
| 328 | |
| 329 | // If exponent < 0 there will be no bits to the left of the decimal point |
| 330 | // after rounding; if the exponent is > 83 then no bits of precision can be |
| 331 | // left in the low 32-bit range of the result (IEEE-754 doubles have 52 bits |
| 332 | // of fractional precision). |
| 333 | // Note this case handles 0, -0, and all infinte, NaN, & denormal value. |
| 334 | if (exp < 0 || exp > 83) |
darin | c13d2ca | 2005-08-08 04:07:46 +0000 | [diff] [blame] | 335 | return 0; |
barraclough@apple.com | e7858b1 | 2010-09-20 01:23:33 +0000 | [diff] [blame] | 336 | |
| 337 | // Select the appropriate 32-bits from the floating point mantissa. If the |
| 338 | // exponent is 52 then the bits we need to select are already aligned to the |
| 339 | // lowest bits of the 64-bit integer representation of tghe number, no need |
| 340 | // to shift. If the exponent is greater than 52 we need to shift the value |
| 341 | // left by (exp - 52), if the value is less than 52 we need to shift right |
| 342 | // accordingly. |
| 343 | int32_t result = (exp > 52) |
| 344 | ? static_cast<int32_t>(bits << (exp - 52)) |
| 345 | : static_cast<int32_t>(bits >> (52 - exp)); |
| 346 | |
| 347 | // IEEE-754 double precision values are stored omitting an implicit 1 before |
| 348 | // the decimal point; we need to reinsert this now. We may also the shifted |
| 349 | // invalid bits into the result that are not a part of the mantissa (the sign |
| 350 | // and exponent bits from the floatingpoint representation); mask these out. |
| 351 | if (exp < 32) { |
| 352 | int32_t missingOne = 1 << exp; |
| 353 | result &= missingOne - 1; |
| 354 | result += missingOne; |
ddkilzer | 20e0d1b | 2006-07-11 03:16:41 +0000 | [diff] [blame] | 355 | } |
mjs | 6f821c8 | 2002-03-22 00:31:57 +0000 | [diff] [blame] | 356 | |
barraclough@apple.com | e7858b1 | 2010-09-20 01:23:33 +0000 | [diff] [blame] | 357 | // If the input value was negative (we could test either 'number' or 'bits', |
| 358 | // but testing 'bits' is likely faster) invert the result appropriately. |
| 359 | return bits < 0 ? -result : result; |
darin | a51d07b | 2004-02-02 21:23:17 +0000 | [diff] [blame] | 360 | } |
| 361 | |
oliver@apple.com | 5dea615 | 2010-05-21 18:19:42 +0000 | [diff] [blame] | 362 | bool JSValue::isValidCallee() |
| 363 | { |
oliver@apple.com | 2346a3e | 2011-09-07 19:40:41 +0000 | [diff] [blame] | 364 | return asObject(asCell())->globalObject(); |
oliver@apple.com | 5dea615 | 2010-05-21 18:19:42 +0000 | [diff] [blame] | 365 | } |
| 366 | |
fpizlo@apple.com | 1167374 | 2016-03-03 02:06:18 +0000 | [diff] [blame] | 367 | JSString* JSValue::toStringSlowCase(ExecState* exec, bool returnEmptyStringOnError) const |
ggaren@apple.com | fbf6d9a | 2011-10-19 02:54:29 +0000 | [diff] [blame] | 368 | { |
fpizlo@apple.com | 1167374 | 2016-03-03 02:06:18 +0000 | [diff] [blame] | 369 | auto errorValue = [&] () -> JSString* { |
| 370 | if (returnEmptyStringOnError) |
| 371 | return jsEmptyString(exec); |
| 372 | return nullptr; |
| 373 | }; |
| 374 | |
ggaren@apple.com | 9a9a4b5 | 2013-04-18 19:32:17 +0000 | [diff] [blame] | 375 | VM& vm = exec->vm(); |
ggaren@apple.com | 64be5e9 | 2012-01-24 07:34:10 +0000 | [diff] [blame] | 376 | ASSERT(!isString()); |
darin@apple.com | 6d8af84 | 2015-06-24 02:33:18 +0000 | [diff] [blame] | 377 | if (isInt32()) { |
| 378 | auto integer = asInt32(); |
| 379 | if (static_cast<unsigned>(integer) <= 9) |
| 380 | return vm.smallStrings.singleCharacterString(integer + '0'); |
| 381 | return jsNontrivialString(&vm, vm.numericStrings.add(integer)); |
| 382 | } |
ggaren@apple.com | fbf6d9a | 2011-10-19 02:54:29 +0000 | [diff] [blame] | 383 | if (isDouble()) |
ggaren@apple.com | 9a9a4b5 | 2013-04-18 19:32:17 +0000 | [diff] [blame] | 384 | return jsString(&vm, vm.numericStrings.add(asDouble())); |
ggaren@apple.com | fbf6d9a | 2011-10-19 02:54:29 +0000 | [diff] [blame] | 385 | if (isTrue()) |
ggaren@apple.com | 9a9a4b5 | 2013-04-18 19:32:17 +0000 | [diff] [blame] | 386 | return vm.smallStrings.trueString(); |
ggaren@apple.com | fbf6d9a | 2011-10-19 02:54:29 +0000 | [diff] [blame] | 387 | if (isFalse()) |
ggaren@apple.com | 9a9a4b5 | 2013-04-18 19:32:17 +0000 | [diff] [blame] | 388 | return vm.smallStrings.falseString(); |
ggaren@apple.com | fbf6d9a | 2011-10-19 02:54:29 +0000 | [diff] [blame] | 389 | if (isNull()) |
ggaren@apple.com | 9a9a4b5 | 2013-04-18 19:32:17 +0000 | [diff] [blame] | 390 | return vm.smallStrings.nullString(); |
ggaren@apple.com | fbf6d9a | 2011-10-19 02:54:29 +0000 | [diff] [blame] | 391 | if (isUndefined()) |
ggaren@apple.com | 9a9a4b5 | 2013-04-18 19:32:17 +0000 | [diff] [blame] | 392 | return vm.smallStrings.undefinedString(); |
utatane.tea@gmail.com | 947fa4e | 2015-01-31 01:23:56 +0000 | [diff] [blame] | 393 | if (isSymbol()) { |
utatane.tea@gmail.com | 5d80e95 | 2016-05-04 01:21:38 +0000 | [diff] [blame] | 394 | throwTypeError(exec, "Cannot convert a symbol to a string"); |
fpizlo@apple.com | 1167374 | 2016-03-03 02:06:18 +0000 | [diff] [blame] | 395 | return errorValue(); |
utatane.tea@gmail.com | 947fa4e | 2015-01-31 01:23:56 +0000 | [diff] [blame] | 396 | } |
ggaren@apple.com | fbf6d9a | 2011-10-19 02:54:29 +0000 | [diff] [blame] | 397 | |
| 398 | ASSERT(isCell()); |
ggaren@apple.com | 64be5e9 | 2012-01-24 07:34:10 +0000 | [diff] [blame] | 399 | JSValue value = asCell()->toPrimitive(exec, PreferString); |
fpizlo@apple.com | 1167374 | 2016-03-03 02:06:18 +0000 | [diff] [blame] | 400 | if (vm.exception()) |
| 401 | return errorValue(); |
ggaren@apple.com | 64be5e9 | 2012-01-24 07:34:10 +0000 | [diff] [blame] | 402 | ASSERT(!value.isObject()); |
fpizlo@apple.com | 1167374 | 2016-03-03 02:06:18 +0000 | [diff] [blame] | 403 | JSString* result = value.toString(exec); |
| 404 | if (vm.exception()) |
| 405 | return errorValue(); |
| 406 | return result; |
ggaren@apple.com | fbf6d9a | 2011-10-19 02:54:29 +0000 | [diff] [blame] | 407 | } |
| 408 | |
benjamin@webkit.org | cff06e4 | 2012-08-30 21:23:51 +0000 | [diff] [blame] | 409 | String JSValue::toWTFStringSlowCase(ExecState* exec) const |
benjamin@webkit.org | 8063cc7 | 2012-04-06 00:12:25 +0000 | [diff] [blame] | 410 | { |
darin@apple.com | 6d8af84 | 2015-06-24 02:33:18 +0000 | [diff] [blame] | 411 | VM& vm = exec->vm(); |
| 412 | if (isInt32()) |
| 413 | return vm.numericStrings.add(asInt32()); |
| 414 | if (isDouble()) |
| 415 | return vm.numericStrings.add(asDouble()); |
| 416 | if (isTrue()) |
| 417 | return vm.propertyNames->trueKeyword.string(); |
| 418 | if (isFalse()) |
| 419 | return vm.propertyNames->falseKeyword.string(); |
| 420 | if (isNull()) |
| 421 | return vm.propertyNames->nullKeyword.string(); |
| 422 | if (isUndefined()) |
| 423 | return vm.propertyNames->undefinedKeyword.string(); |
| 424 | return toString(exec)->value(exec); |
benjamin@webkit.org | 8063cc7 | 2012-04-06 00:12:25 +0000 | [diff] [blame] | 425 | } |
| 426 | |
cwzwarich@webkit.org | 3f782f6 | 2008-09-08 01:28:33 +0000 | [diff] [blame] | 427 | } // namespace JSC |