kocienda | 66a6d36 | 2001-08-24 14:24:45 +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 | 75104a3 | 2014-04-15 23:33:11 +0000 | [diff] [blame] | 4 | * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2014 Apple Inc. All rights reserved. |
kocienda | 66a6d36 | 2001-08-24 14:24:45 +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 | * |
kocienda | 66a6d36 | 2001-08-24 14:24:45 +0000 | [diff] [blame] | 21 | */ |
| 22 | |
darin@apple.com | 5c0863d | 2008-06-16 04:17:44 +0000 | [diff] [blame] | 23 | #ifndef JSString_h |
| 24 | #define JSString_h |
weinig@apple.com | be6603a | 2013-12-10 01:28:05 +0000 | [diff] [blame] | 25 | |
ggaren@apple.com | 5169fc9 | 2008-11-17 22:11:26 +0000 | [diff] [blame] | 26 | #include "CallFrame.h" |
oliver@apple.com | d04e0a0 | 2014-02-01 01:37:59 +0000 | [diff] [blame] | 27 | #include "CommonIdentifiers.h" |
cwzwarich@webkit.org | 858b2b6 | 2008-11-05 23:37:21 +0000 | [diff] [blame] | 28 | #include "Identifier.h" |
oliver@apple.com | 4b4f785 | 2009-08-26 16:52:15 +0000 | [diff] [blame] | 29 | #include "PropertyDescriptor.h" |
weinig@apple.com | efdce0f | 2008-06-30 20:52:03 +0000 | [diff] [blame] | 30 | #include "PropertySlot.h" |
oliver@apple.com | ed66e77 | 2011-04-05 01:33:58 +0000 | [diff] [blame] | 31 | #include "Structure.h" |
weinig@apple.com | be6603a | 2013-12-10 01:28:05 +0000 | [diff] [blame] | 32 | #include <array> |
akling@apple.com | 7e84ac5 | 2015-05-19 17:06:23 +0000 | [diff] [blame] | 33 | #include <wtf/text/StringView.h> |
ggaren | 5102fa1 | 2006-02-10 06:42:01 +0000 | [diff] [blame] | 34 | |
cwzwarich@webkit.org | 3f782f6 | 2008-09-08 01:28:33 +0000 | [diff] [blame] | 35 | namespace JSC { |
kocienda | 66a6d36 | 2001-08-24 14:24:45 +0000 | [diff] [blame] | 36 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 37 | class JSString; |
| 38 | class JSRopeString; |
| 39 | class LLIntOffsetsExtractor; |
darin@apple.com | e794585 | 2008-08-31 06:58:07 +0000 | [diff] [blame] | 40 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 41 | JSString* jsEmptyString(VM*); |
| 42 | JSString* jsEmptyString(ExecState*); |
| 43 | JSString* jsString(VM*, const String&); // returns empty string if passed null string |
| 44 | JSString* jsString(ExecState*, const String&); // returns empty string if passed null string |
darin@apple.com | e794585 | 2008-08-31 06:58:07 +0000 | [diff] [blame] | 45 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 46 | JSString* jsSingleCharacterString(VM*, UChar); |
| 47 | JSString* jsSingleCharacterString(ExecState*, UChar); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 48 | JSString* jsSubstring(VM*, const String&, unsigned offset, unsigned length); |
| 49 | JSString* jsSubstring(ExecState*, const String&, unsigned offset, unsigned length); |
darin@apple.com | 3954c6a | 2015-06-27 22:53:12 +0000 | [diff] [blame] | 50 | JSString* jsSubstring8(VM*, const String&, unsigned offset, unsigned length); |
| 51 | JSString* jsSubstring8(ExecState*, const String&, unsigned offset, unsigned length); |
darin@apple.com | e794585 | 2008-08-31 06:58:07 +0000 | [diff] [blame] | 52 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 53 | // Non-trivial strings are two or more characters long. |
| 54 | // These functions are faster than just calling jsString. |
| 55 | JSString* jsNontrivialString(VM*, const String&); |
| 56 | JSString* jsNontrivialString(ExecState*, const String&); |
andersca@apple.com | c69ac4e | 2014-10-02 16:14:25 +0000 | [diff] [blame] | 57 | JSString* jsNontrivialString(ExecState*, String&&); |
darin@apple.com | e794585 | 2008-08-31 06:58:07 +0000 | [diff] [blame] | 58 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 59 | // Should be used for strings that are owned by an object that will |
| 60 | // likely outlive the JSValue this makes, such as the parse tree or a |
| 61 | // DOM object that contains a String |
| 62 | JSString* jsOwnedString(VM*, const String&); |
| 63 | JSString* jsOwnedString(ExecState*, const String&); |
darin@apple.com | e794585 | 2008-08-31 06:58:07 +0000 | [diff] [blame] | 64 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 65 | JSRopeString* jsStringBuilder(VM*); |
ggaren@apple.com | fbf6d9a | 2011-10-19 02:54:29 +0000 | [diff] [blame] | 66 | |
darin@apple.com | 3954c6a | 2015-06-27 22:53:12 +0000 | [diff] [blame] | 67 | bool isJSString(JSValue); |
| 68 | JSString* asString(JSValue); |
| 69 | |
darin@apple.com | 6d8af84 | 2015-06-24 02:33:18 +0000 | [diff] [blame] | 70 | struct StringViewWithUnderlyingString { |
| 71 | StringView view; |
| 72 | String underlyingString; |
| 73 | }; |
| 74 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 75 | class JSString : public JSCell { |
| 76 | public: |
| 77 | friend class JIT; |
| 78 | friend class VM; |
| 79 | friend class SpecializedThunkJIT; |
| 80 | friend class JSRopeString; |
| 81 | friend class MarkStack; |
| 82 | friend class SlotVisitor; |
| 83 | friend struct ThunkHelpers; |
msaboff@apple.com | 6e74e92 | 2012-04-27 23:51:17 +0000 | [diff] [blame] | 84 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 85 | typedef JSCell Base; |
akling@apple.com | 4b9e000 | 2015-04-13 19:12:48 +0000 | [diff] [blame] | 86 | static const unsigned StructureFlags = Base::StructureFlags | OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero | StructureIsImmortal; |
msaboff@apple.com | 6e74e92 | 2012-04-27 23:51:17 +0000 | [diff] [blame] | 87 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 88 | static const bool needsDestruction = true; |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 89 | static void destroy(JSCell*); |
msaboff@apple.com | 6e74e92 | 2012-04-27 23:51:17 +0000 | [diff] [blame] | 90 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 91 | private: |
| 92 | JSString(VM& vm, PassRefPtr<StringImpl> value) |
| 93 | : JSCell(vm, vm.stringStructure.get()) |
| 94 | , m_flags(0) |
| 95 | , m_value(value) |
darin@apple.com | 5a49442 | 2008-10-18 23:08:12 +0000 | [diff] [blame] | 96 | { |
darin@apple.com | 5a49442 | 2008-10-18 23:08:12 +0000 | [diff] [blame] | 97 | } |
| 98 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 99 | JSString(VM& vm) |
| 100 | : JSCell(vm, vm.stringStructure.get()) |
| 101 | , m_flags(0) |
darin@apple.com | e794585 | 2008-08-31 06:58:07 +0000 | [diff] [blame] | 102 | { |
fpizlo@apple.com | 494f2d9 | 2013-03-20 23:16:01 +0000 | [diff] [blame] | 103 | } |
| 104 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 105 | void finishCreation(VM& vm, size_t length) |
fpizlo@apple.com | 494f2d9 | 2013-03-20 23:16:01 +0000 | [diff] [blame] | 106 | { |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 107 | ASSERT(!m_value.isNull()); |
| 108 | Base::finishCreation(vm); |
| 109 | m_length = length; |
| 110 | setIs8Bit(m_value.impl()->is8Bit()); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 111 | } |
| 112 | |
| 113 | void finishCreation(VM& vm, size_t length, size_t cost) |
| 114 | { |
| 115 | ASSERT(!m_value.isNull()); |
| 116 | Base::finishCreation(vm); |
| 117 | m_length = length; |
| 118 | setIs8Bit(m_value.impl()->is8Bit()); |
ggaren@apple.com | e2ebb8c | 2015-03-11 21:29:57 +0000 | [diff] [blame] | 119 | Heap::heap(this)->reportExtraMemoryAllocated(cost); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 120 | } |
| 121 | |
| 122 | protected: |
| 123 | void finishCreation(VM& vm) |
| 124 | { |
| 125 | Base::finishCreation(vm); |
| 126 | m_length = 0; |
| 127 | setIs8Bit(true); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 128 | } |
| 129 | |
| 130 | public: |
| 131 | static JSString* create(VM& vm, PassRefPtr<StringImpl> value) |
| 132 | { |
| 133 | ASSERT(value); |
| 134 | int32_t length = value->length(); |
| 135 | RELEASE_ASSERT(length >= 0); |
| 136 | size_t cost = value->cost(); |
| 137 | JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value); |
| 138 | newString->finishCreation(vm, length, cost); |
| 139 | return newString; |
| 140 | } |
| 141 | static JSString* createHasOtherOwner(VM& vm, PassRefPtr<StringImpl> value) |
| 142 | { |
| 143 | ASSERT(value); |
| 144 | size_t length = value->length(); |
| 145 | JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value); |
| 146 | newString->finishCreation(vm, length); |
| 147 | return newString; |
| 148 | } |
| 149 | |
| 150 | Identifier toIdentifier(ExecState*) const; |
| 151 | AtomicString toAtomicString(ExecState*) const; |
utatane.tea@gmail.com | e0741fb | 2015-06-02 17:36:16 +0000 | [diff] [blame] | 152 | RefPtr<AtomicStringImpl> toExistingAtomicString(ExecState*) const; |
darin@apple.com | 3954c6a | 2015-06-27 22:53:12 +0000 | [diff] [blame] | 153 | |
| 154 | class SafeView; |
| 155 | SafeView view(ExecState*) const; |
darin@apple.com | 6d8af84 | 2015-06-24 02:33:18 +0000 | [diff] [blame] | 156 | StringViewWithUnderlyingString viewWithUnderlyingString(ExecState&) const; |
darin@apple.com | 3954c6a | 2015-06-27 22:53:12 +0000 | [diff] [blame] | 157 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 158 | const String& value(ExecState*) const; |
| 159 | const String& tryGetValue() const; |
| 160 | const StringImpl* tryGetValueImpl() const; |
| 161 | unsigned length() const { return m_length; } |
| 162 | |
| 163 | JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; |
fpizlo@apple.com | 5b9b41b | 2015-05-29 20:26:37 +0000 | [diff] [blame] | 164 | bool toBoolean() const { return !!m_length; } |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 165 | bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const; |
| 166 | JSObject* toObject(ExecState*, JSGlobalObject*) const; |
| 167 | double toNumber(ExecState*) const; |
| 168 | |
| 169 | bool getStringPropertySlot(ExecState*, PropertyName, PropertySlot&); |
| 170 | bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); |
| 171 | bool getStringPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&); |
| 172 | |
| 173 | bool canGetIndex(unsigned i) { return i < m_length; } |
| 174 | JSString* getIndex(ExecState*, unsigned); |
| 175 | |
ggaren@apple.com | c09535a | 2015-10-06 01:59:02 +0000 | [diff] [blame] | 176 | static Structure* createStructure(VM&, JSGlobalObject*, JSValue); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 177 | |
| 178 | static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); } |
| 179 | static size_t offsetOfFlags() { return OBJECT_OFFSETOF(JSString, m_flags); } |
| 180 | static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); } |
| 181 | |
| 182 | DECLARE_EXPORT_INFO; |
| 183 | |
| 184 | static void dumpToStream(const JSCell*, PrintStream&); |
| 185 | static void visitChildren(JSCell*, SlotVisitor&); |
| 186 | |
| 187 | enum { |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 188 | Is8Bit = 1u |
| 189 | }; |
| 190 | |
| 191 | protected: |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 192 | friend class JSValue; |
| 193 | |
| 194 | bool isRope() const { return m_value.isNull(); } |
akling@apple.com | 07a49c0 | 2015-06-12 04:09:11 +0000 | [diff] [blame] | 195 | bool isSubstring() const; |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 196 | bool is8Bit() const { return m_flags & Is8Bit; } |
| 197 | void setIs8Bit(bool flag) const |
| 198 | { |
| 199 | if (flag) |
| 200 | m_flags |= Is8Bit; |
| 201 | else |
| 202 | m_flags &= ~Is8Bit; |
| 203 | } |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 204 | |
| 205 | mutable unsigned m_flags; |
| 206 | |
| 207 | // A string is represented either by a String or a rope of fibers. |
| 208 | unsigned m_length; |
| 209 | mutable String m_value; |
| 210 | |
| 211 | private: |
| 212 | friend class LLIntOffsetsExtractor; |
| 213 | |
| 214 | static JSValue toThis(JSCell*, ExecState*, ECMAMode); |
| 215 | |
| 216 | String& string() { ASSERT(!isRope()); return m_value; } |
darin@apple.com | 3954c6a | 2015-06-27 22:53:12 +0000 | [diff] [blame] | 217 | StringView unsafeView(ExecState&) const; |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 218 | |
| 219 | friend JSValue jsString(ExecState*, JSString*, JSString*); |
| 220 | friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length); |
| 221 | }; |
| 222 | |
akling@apple.com | 4b9e000 | 2015-04-13 19:12:48 +0000 | [diff] [blame] | 223 | class JSRopeString final : public JSString { |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 224 | friend class JSString; |
| 225 | |
| 226 | friend JSRopeString* jsStringBuilder(VM*); |
| 227 | |
utatane.tea@gmail.com | ec85d88 | 2015-01-06 19:33:19 +0000 | [diff] [blame] | 228 | public: |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 229 | class RopeBuilder { |
| 230 | public: |
| 231 | RopeBuilder(VM& vm) |
| 232 | : m_vm(vm) |
| 233 | , m_jsString(jsStringBuilder(&vm)) |
| 234 | , m_index(0) |
| 235 | { |
| 236 | } |
| 237 | |
| 238 | bool append(JSString* jsString) |
| 239 | { |
| 240 | if (m_index == JSRopeString::s_maxInternalRopeLength) |
| 241 | expand(); |
| 242 | if (static_cast<int32_t>(m_jsString->length() + jsString->length()) < 0) { |
| 243 | m_jsString = nullptr; |
| 244 | return false; |
| 245 | } |
| 246 | m_jsString->append(m_vm, m_index++, jsString); |
| 247 | return true; |
| 248 | } |
| 249 | |
| 250 | JSRopeString* release() |
| 251 | { |
| 252 | RELEASE_ASSERT(m_jsString); |
| 253 | JSRopeString* tmp = m_jsString; |
| 254 | m_jsString = 0; |
| 255 | return tmp; |
| 256 | } |
| 257 | |
| 258 | unsigned length() const { return m_jsString->m_length; } |
| 259 | |
| 260 | private: |
| 261 | void expand(); |
| 262 | |
| 263 | VM& m_vm; |
| 264 | JSRopeString* m_jsString; |
| 265 | size_t m_index; |
| 266 | }; |
| 267 | |
| 268 | private: |
| 269 | JSRopeString(VM& vm) |
| 270 | : JSString(vm) |
| 271 | { |
| 272 | } |
| 273 | |
| 274 | void finishCreation(VM& vm, JSString* s1, JSString* s2) |
| 275 | { |
| 276 | Base::finishCreation(vm); |
| 277 | m_length = s1->length() + s2->length(); |
| 278 | setIs8Bit(s1->is8Bit() && s2->is8Bit()); |
| 279 | setIsSubstring(false); |
| 280 | fiber(0).set(vm, this, s1); |
| 281 | fiber(1).set(vm, this, s2); |
| 282 | fiber(2).clear(); |
| 283 | } |
| 284 | |
| 285 | void finishCreation(VM& vm, JSString* s1, JSString* s2, JSString* s3) |
| 286 | { |
| 287 | Base::finishCreation(vm); |
| 288 | m_length = s1->length() + s2->length() + s3->length(); |
| 289 | setIs8Bit(s1->is8Bit() && s2->is8Bit() && s3->is8Bit()); |
| 290 | setIsSubstring(false); |
| 291 | fiber(0).set(vm, this, s1); |
| 292 | fiber(1).set(vm, this, s2); |
| 293 | fiber(2).set(vm, this, s3); |
| 294 | } |
| 295 | |
akling@apple.com | 07a49c0 | 2015-06-12 04:09:11 +0000 | [diff] [blame] | 296 | void finishCreation(ExecState& exec, JSString& base, unsigned offset, unsigned length) |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 297 | { |
akling@apple.com | 07a49c0 | 2015-06-12 04:09:11 +0000 | [diff] [blame] | 298 | VM& vm = exec.vm(); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 299 | Base::finishCreation(vm); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 300 | ASSERT(!sumOverflows<int32_t>(offset, length)); |
akling@apple.com | 07a49c0 | 2015-06-12 04:09:11 +0000 | [diff] [blame] | 301 | ASSERT(offset + length <= base.length()); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 302 | m_length = length; |
akling@apple.com | 07a49c0 | 2015-06-12 04:09:11 +0000 | [diff] [blame] | 303 | setIs8Bit(base.is8Bit()); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 304 | setIsSubstring(true); |
akling@apple.com | 07a49c0 | 2015-06-12 04:09:11 +0000 | [diff] [blame] | 305 | if (base.isSubstring()) { |
| 306 | JSRopeString& baseRope = static_cast<JSRopeString&>(base); |
| 307 | substringBase().set(vm, this, baseRope.substringBase().get()); |
| 308 | substringOffset() = baseRope.substringOffset() + offset; |
| 309 | } else { |
| 310 | substringBase().set(vm, this, &base); |
| 311 | substringOffset() = offset; |
| 312 | |
| 313 | // For now, let's not allow substrings with a rope base. |
| 314 | // Resolve non-substring rope bases so we don't have to deal with it. |
| 315 | // FIXME: Evaluate if this would be worth adding more branches. |
| 316 | if (base.isRope()) |
| 317 | static_cast<JSRopeString&>(base).resolveRope(&exec); |
| 318 | } |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 319 | } |
| 320 | |
| 321 | void finishCreation(VM& vm) |
| 322 | { |
| 323 | JSString::finishCreation(vm); |
| 324 | setIsSubstring(false); |
| 325 | fiber(0).clear(); |
| 326 | fiber(1).clear(); |
| 327 | fiber(2).clear(); |
| 328 | } |
| 329 | |
| 330 | void append(VM& vm, size_t index, JSString* jsString) |
| 331 | { |
| 332 | fiber(index).set(vm, this, jsString); |
| 333 | m_length += jsString->m_length; |
| 334 | RELEASE_ASSERT(static_cast<int32_t>(m_length) >= 0); |
| 335 | setIs8Bit(is8Bit() && jsString->is8Bit()); |
| 336 | } |
| 337 | |
| 338 | static JSRopeString* createNull(VM& vm) |
| 339 | { |
| 340 | JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); |
| 341 | newString->finishCreation(vm); |
| 342 | return newString; |
| 343 | } |
| 344 | |
| 345 | public: |
| 346 | static JSString* create(VM& vm, JSString* s1, JSString* s2) |
| 347 | { |
| 348 | JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); |
| 349 | newString->finishCreation(vm, s1, s2); |
| 350 | return newString; |
| 351 | } |
| 352 | static JSString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3) |
| 353 | { |
| 354 | JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm); |
| 355 | newString->finishCreation(vm, s1, s2, s3); |
| 356 | return newString; |
| 357 | } |
| 358 | |
akling@apple.com | 07a49c0 | 2015-06-12 04:09:11 +0000 | [diff] [blame] | 359 | static JSString* create(ExecState& exec, JSString& base, unsigned offset, unsigned length) |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 360 | { |
akling@apple.com | 07a49c0 | 2015-06-12 04:09:11 +0000 | [diff] [blame] | 361 | JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(exec.vm().heap)) JSRopeString(exec.vm()); |
| 362 | newString->finishCreation(exec, base, offset, length); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 363 | return newString; |
| 364 | } |
| 365 | |
| 366 | void visitFibers(SlotVisitor&); |
| 367 | |
| 368 | static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString, u); } |
| 369 | |
| 370 | static const unsigned s_maxInternalRopeLength = 3; |
| 371 | |
| 372 | private: |
| 373 | friend JSValue jsStringFromRegisterArray(ExecState*, Register*, unsigned); |
| 374 | friend JSValue jsStringFromArguments(ExecState*, JSValue); |
| 375 | |
| 376 | JS_EXPORT_PRIVATE void resolveRope(ExecState*) const; |
| 377 | JS_EXPORT_PRIVATE void resolveRopeToAtomicString(ExecState*) const; |
utatane.tea@gmail.com | e0741fb | 2015-06-02 17:36:16 +0000 | [diff] [blame] | 378 | JS_EXPORT_PRIVATE RefPtr<AtomicStringImpl> resolveRopeToExistingAtomicString(ExecState*) const; |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 379 | void resolveRopeSlowCase8(LChar*) const; |
| 380 | void resolveRopeSlowCase(UChar*) const; |
| 381 | void outOfMemory(ExecState*) const; |
| 382 | void resolveRopeInternal8(LChar*) const; |
| 383 | void resolveRopeInternal8NoSubstring(LChar*) const; |
| 384 | void resolveRopeInternal16(UChar*) const; |
| 385 | void resolveRopeInternal16NoSubstring(UChar*) const; |
| 386 | void clearFibers() const; |
darin@apple.com | 3954c6a | 2015-06-27 22:53:12 +0000 | [diff] [blame] | 387 | StringView unsafeView(ExecState&) const; |
darin@apple.com | 6d8af84 | 2015-06-24 02:33:18 +0000 | [diff] [blame] | 388 | StringViewWithUnderlyingString viewWithUnderlyingString(ExecState&) const; |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 389 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 390 | WriteBarrierBase<JSString>& fiber(unsigned i) const |
| 391 | { |
| 392 | ASSERT(!isSubstring()); |
| 393 | ASSERT(i < s_maxInternalRopeLength); |
| 394 | return u[i].string; |
| 395 | } |
| 396 | |
| 397 | WriteBarrierBase<JSString>& substringBase() const |
| 398 | { |
| 399 | return u[1].string; |
| 400 | } |
| 401 | |
| 402 | uintptr_t& substringOffset() const |
| 403 | { |
| 404 | return u[2].number; |
| 405 | } |
| 406 | |
| 407 | static uintptr_t notSubstringSentinel() |
| 408 | { |
| 409 | return 0; |
| 410 | } |
| 411 | |
| 412 | static uintptr_t substringSentinel() |
| 413 | { |
| 414 | return 1; |
| 415 | } |
| 416 | |
| 417 | bool isSubstring() const |
| 418 | { |
| 419 | return u[0].number == substringSentinel(); |
| 420 | } |
| 421 | |
| 422 | void setIsSubstring(bool isSubstring) |
| 423 | { |
| 424 | u[0].number = isSubstring ? substringSentinel() : notSubstringSentinel(); |
| 425 | } |
| 426 | |
| 427 | mutable union { |
| 428 | uintptr_t number; |
| 429 | WriteBarrierBase<JSString> string; |
| 430 | } u[s_maxInternalRopeLength]; |
| 431 | }; |
| 432 | |
darin@apple.com | 3954c6a | 2015-06-27 22:53:12 +0000 | [diff] [blame] | 433 | class JSString::SafeView { |
| 434 | public: |
| 435 | SafeView(); |
| 436 | explicit SafeView(ExecState&, const JSString&); |
| 437 | operator StringView() const; |
| 438 | StringView get() const; |
| 439 | |
| 440 | private: |
| 441 | ExecState* m_state { nullptr }; |
| 442 | |
| 443 | // The following pointer is marked "volatile" to make the compiler leave it on the stack |
| 444 | // or in a register as long as this object is alive, even after the last use of the pointer. |
| 445 | // That's needed to prevent garbage collecting the string and possibly deleting the block |
| 446 | // with the characters in it, and then using the StringView after that. |
| 447 | const JSString* volatile m_string { nullptr }; |
| 448 | }; |
| 449 | |
| 450 | JS_EXPORT_PRIVATE JSString* jsStringWithCacheSlowCase(VM&, StringImpl&); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 451 | |
| 452 | inline const StringImpl* JSString::tryGetValueImpl() const |
| 453 | { |
| 454 | return m_value.impl(); |
| 455 | } |
| 456 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 457 | inline JSString* asString(JSValue value) |
| 458 | { |
| 459 | ASSERT(value.asCell()->isString()); |
| 460 | return jsCast<JSString*>(value.asCell()); |
| 461 | } |
| 462 | |
| 463 | inline JSString* jsEmptyString(VM* vm) |
| 464 | { |
| 465 | return vm->smallStrings.emptyString(); |
| 466 | } |
| 467 | |
| 468 | ALWAYS_INLINE JSString* jsSingleCharacterString(VM* vm, UChar c) |
| 469 | { |
| 470 | if (c <= maxSingleCharacterString) |
| 471 | return vm->smallStrings.singleCharacterString(c); |
| 472 | return JSString::create(*vm, String(&c, 1).impl()); |
| 473 | } |
| 474 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 475 | inline JSString* jsNontrivialString(VM* vm, const String& s) |
| 476 | { |
| 477 | ASSERT(s.length() > 1); |
| 478 | return JSString::create(*vm, s.impl()); |
| 479 | } |
| 480 | |
andersca@apple.com | c69ac4e | 2014-10-02 16:14:25 +0000 | [diff] [blame] | 481 | inline JSString* jsNontrivialString(VM* vm, String&& s) |
| 482 | { |
| 483 | ASSERT(s.length() > 1); |
| 484 | return JSString::create(*vm, s.releaseImpl()); |
| 485 | } |
| 486 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 487 | ALWAYS_INLINE Identifier JSString::toIdentifier(ExecState* exec) const |
| 488 | { |
utatane.tea@gmail.com | b6f60b2 | 2015-03-31 21:25:14 +0000 | [diff] [blame] | 489 | return Identifier::fromString(exec, toAtomicString(exec)); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 490 | } |
| 491 | |
| 492 | ALWAYS_INLINE AtomicString JSString::toAtomicString(ExecState* exec) const |
| 493 | { |
| 494 | if (isRope()) |
| 495 | static_cast<const JSRopeString*>(this)->resolveRopeToAtomicString(exec); |
| 496 | return AtomicString(m_value); |
| 497 | } |
| 498 | |
utatane.tea@gmail.com | e0741fb | 2015-06-02 17:36:16 +0000 | [diff] [blame] | 499 | ALWAYS_INLINE RefPtr<AtomicStringImpl> JSString::toExistingAtomicString(ExecState* exec) const |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 500 | { |
| 501 | if (isRope()) |
| 502 | return static_cast<const JSRopeString*>(this)->resolveRopeToExistingAtomicString(exec); |
| 503 | if (m_value.impl()->isAtomic()) |
| 504 | return static_cast<AtomicStringImpl*>(m_value.impl()); |
utatane.tea@gmail.com | 874750c | 2015-05-20 04:19:14 +0000 | [diff] [blame] | 505 | return AtomicStringImpl::lookUp(m_value.impl()); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 506 | } |
| 507 | |
| 508 | inline const String& JSString::value(ExecState* exec) const |
| 509 | { |
| 510 | if (isRope()) |
| 511 | static_cast<const JSRopeString*>(this)->resolveRope(exec); |
| 512 | return m_value; |
| 513 | } |
| 514 | |
| 515 | inline const String& JSString::tryGetValue() const |
| 516 | { |
| 517 | if (isRope()) |
| 518 | static_cast<const JSRopeString*>(this)->resolveRope(0); |
| 519 | return m_value; |
| 520 | } |
| 521 | |
| 522 | inline JSString* JSString::getIndex(ExecState* exec, unsigned i) |
| 523 | { |
| 524 | ASSERT(canGetIndex(i)); |
darin@apple.com | 3954c6a | 2015-06-27 22:53:12 +0000 | [diff] [blame] | 525 | return jsSingleCharacterString(exec, unsafeView(*exec)[i]); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 526 | } |
| 527 | |
| 528 | inline JSString* jsString(VM* vm, const String& s) |
| 529 | { |
| 530 | int size = s.length(); |
| 531 | if (!size) |
ggaren@apple.com | 9a9a4b5 | 2013-04-18 19:32:17 +0000 | [diff] [blame] | 532 | return vm->smallStrings.emptyString(); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 533 | if (size == 1) { |
| 534 | UChar c = s.characterAt(0); |
ggaren@apple.com | e74d2d0 | 2011-03-14 22:31:29 +0000 | [diff] [blame] | 535 | if (c <= maxSingleCharacterString) |
oliver@apple.com | 7e5973d | 2013-07-25 04:03:30 +0000 | [diff] [blame] | 536 | return vm->smallStrings.singleCharacterString(c); |
darin@apple.com | e794585 | 2008-08-31 06:58:07 +0000 | [diff] [blame] | 537 | } |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 538 | return JSString::create(*vm, s.impl()); |
| 539 | } |
darin@apple.com | e794585 | 2008-08-31 06:58:07 +0000 | [diff] [blame] | 540 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 541 | inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length) |
| 542 | { |
| 543 | ASSERT(offset <= static_cast<unsigned>(s->length())); |
| 544 | ASSERT(length <= static_cast<unsigned>(s->length())); |
| 545 | ASSERT(offset + length <= static_cast<unsigned>(s->length())); |
| 546 | VM& vm = exec->vm(); |
| 547 | if (!length) |
| 548 | return vm.smallStrings.emptyString(); |
akling@apple.com | 4ffeb2b | 2015-06-17 18:54:13 +0000 | [diff] [blame] | 549 | if (!offset && length == s->length()) |
| 550 | return s; |
akling@apple.com | 07a49c0 | 2015-06-12 04:09:11 +0000 | [diff] [blame] | 551 | return JSRopeString::create(*exec, *s, offset, length); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 552 | } |
| 553 | |
| 554 | inline JSString* jsSubstring8(VM* vm, const String& s, unsigned offset, unsigned length) |
| 555 | { |
| 556 | ASSERT(offset <= static_cast<unsigned>(s.length())); |
| 557 | ASSERT(length <= static_cast<unsigned>(s.length())); |
| 558 | ASSERT(offset + length <= static_cast<unsigned>(s.length())); |
| 559 | if (!length) |
| 560 | return vm->smallStrings.emptyString(); |
| 561 | if (length == 1) { |
benjamin@webkit.org | c08af73 | 2012-08-30 23:41:29 +0000 | [diff] [blame] | 562 | UChar c = s.characterAt(offset); |
commit-queue@webkit.org | 7cbe089 | 2014-02-09 08:19:36 +0000 | [diff] [blame] | 563 | if (c <= maxSingleCharacterString) |
| 564 | return vm->smallStrings.singleCharacterString(c); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 565 | } |
| 566 | return JSString::createHasOtherOwner(*vm, StringImpl::createSubstringSharingImpl8(s.impl(), offset, length)); |
| 567 | } |
| 568 | |
| 569 | inline JSString* jsSubstring(VM* vm, const String& s, unsigned offset, unsigned length) |
| 570 | { |
| 571 | ASSERT(offset <= static_cast<unsigned>(s.length())); |
| 572 | ASSERT(length <= static_cast<unsigned>(s.length())); |
| 573 | ASSERT(offset + length <= static_cast<unsigned>(s.length())); |
| 574 | if (!length) |
| 575 | return vm->smallStrings.emptyString(); |
| 576 | if (length == 1) { |
| 577 | UChar c = s.characterAt(offset); |
| 578 | if (c <= maxSingleCharacterString) |
| 579 | return vm->smallStrings.singleCharacterString(c); |
| 580 | } |
| 581 | return JSString::createHasOtherOwner(*vm, StringImpl::createSubstringSharingImpl(s.impl(), offset, length)); |
| 582 | } |
| 583 | |
| 584 | inline JSString* jsOwnedString(VM* vm, const String& s) |
| 585 | { |
| 586 | int size = s.length(); |
| 587 | if (!size) |
| 588 | return vm->smallStrings.emptyString(); |
| 589 | if (size == 1) { |
| 590 | UChar c = s.characterAt(0); |
| 591 | if (c <= maxSingleCharacterString) |
| 592 | return vm->smallStrings.singleCharacterString(c); |
| 593 | } |
| 594 | return JSString::createHasOtherOwner(*vm, s.impl()); |
| 595 | } |
| 596 | |
| 597 | inline JSRopeString* jsStringBuilder(VM* vm) |
| 598 | { |
| 599 | return JSRopeString::createNull(*vm); |
| 600 | } |
| 601 | |
| 602 | inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); } |
| 603 | inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); } |
| 604 | inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->vm(), c); } |
| 605 | inline JSString* jsSubstring8(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring8(&exec->vm(), s, offset, length); } |
| 606 | inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->vm(), s, offset, length); } |
| 607 | inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->vm(), s); } |
andersca@apple.com | c69ac4e | 2014-10-02 16:14:25 +0000 | [diff] [blame] | 608 | inline JSString* jsNontrivialString(ExecState* exec, String&& s) { return jsNontrivialString(&exec->vm(), WTF::move(s)); } |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 609 | inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); } |
| 610 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 611 | ALWAYS_INLINE JSString* jsStringWithCache(ExecState* exec, const String& s) |
| 612 | { |
| 613 | VM& vm = exec->vm(); |
| 614 | StringImpl* stringImpl = s.impl(); |
| 615 | if (!stringImpl || !stringImpl->length()) |
| 616 | return jsEmptyString(&vm); |
| 617 | |
| 618 | if (stringImpl->length() == 1) { |
| 619 | UChar singleCharacter = (*stringImpl)[0u]; |
| 620 | if (singleCharacter <= maxSingleCharacterString) |
| 621 | return vm.smallStrings.singleCharacterString(static_cast<unsigned char>(singleCharacter)); |
darin@apple.com | e794585 | 2008-08-31 06:58:07 +0000 | [diff] [blame] | 622 | } |
| 623 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 624 | if (JSString* lastCachedString = vm.lastCachedString.get()) { |
| 625 | if (lastCachedString->tryGetValueImpl() == stringImpl) |
| 626 | return lastCachedString; |
darin@apple.com | e794585 | 2008-08-31 06:58:07 +0000 | [diff] [blame] | 627 | } |
| 628 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 629 | return jsStringWithCacheSlowCase(vm, *stringImpl); |
| 630 | } |
| 631 | |
| 632 | ALWAYS_INLINE JSString* jsStringWithCache(ExecState* exec, const AtomicString& s) |
| 633 | { |
| 634 | return jsStringWithCache(exec, s.string()); |
| 635 | } |
| 636 | |
| 637 | ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot) |
| 638 | { |
| 639 | if (propertyName == exec->propertyNames().length) { |
| 640 | slot.setValue(this, DontEnum | DontDelete | ReadOnly, jsNumber(m_length)); |
| 641 | return true; |
akling@apple.com | 83343ba | 2014-05-05 18:08:25 +0000 | [diff] [blame] | 642 | } |
| 643 | |
utatane.tea@gmail.com | c7c203c | 2015-04-06 12:40:33 +0000 | [diff] [blame] | 644 | Optional<uint32_t> index = parseIndex(propertyName); |
| 645 | if (index && index.value() < m_length) { |
| 646 | slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, index.value())); |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 647 | return true; |
akling@apple.com | 63e3543 | 2014-05-05 06:24:44 +0000 | [diff] [blame] | 648 | } |
| 649 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 650 | return false; |
| 651 | } |
| 652 | |
| 653 | ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) |
| 654 | { |
| 655 | if (propertyName < m_length) { |
| 656 | slot.setValue(this, DontDelete | ReadOnly, getIndex(exec, propertyName)); |
| 657 | return true; |
akling@apple.com | 63e3543 | 2014-05-05 06:24:44 +0000 | [diff] [blame] | 658 | } |
| 659 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 660 | return false; |
| 661 | } |
oliver@apple.com | 42e5917 | 2013-07-25 04:03:27 +0000 | [diff] [blame] | 662 | |
darin@apple.com | 3954c6a | 2015-06-27 22:53:12 +0000 | [diff] [blame] | 663 | inline bool isJSString(JSValue v) |
| 664 | { |
| 665 | return v.isCell() && v.asCell()->type() == StringType; |
| 666 | } |
| 667 | |
| 668 | ALWAYS_INLINE StringView JSRopeString::unsafeView(ExecState& state) const |
| 669 | { |
| 670 | if (isSubstring()) { |
| 671 | if (is8Bit()) |
| 672 | return StringView(substringBase()->m_value.characters8() + substringOffset(), m_length); |
| 673 | return StringView(substringBase()->m_value.characters16() + substringOffset(), m_length); |
| 674 | } |
| 675 | resolveRope(&state); |
| 676 | return m_value; |
| 677 | } |
| 678 | |
| 679 | ALWAYS_INLINE StringViewWithUnderlyingString JSRopeString::viewWithUnderlyingString(ExecState& state) const |
| 680 | { |
| 681 | if (isSubstring()) { |
| 682 | auto& base = substringBase()->m_value; |
| 683 | if (is8Bit()) |
| 684 | return { { base.characters8() + substringOffset(), m_length }, base }; |
| 685 | return { { base.characters16() + substringOffset(), m_length }, base }; |
| 686 | } |
| 687 | resolveRope(&state); |
| 688 | return { m_value, m_value }; |
| 689 | } |
| 690 | |
| 691 | ALWAYS_INLINE StringView JSString::unsafeView(ExecState& state) const |
| 692 | { |
| 693 | if (isRope()) |
| 694 | return static_cast<const JSRopeString*>(this)->unsafeView(state); |
| 695 | return m_value; |
| 696 | } |
| 697 | |
| 698 | ALWAYS_INLINE StringViewWithUnderlyingString JSString::viewWithUnderlyingString(ExecState& state) const |
| 699 | { |
| 700 | if (isRope()) |
| 701 | return static_cast<const JSRopeString&>(*this).viewWithUnderlyingString(state); |
| 702 | return { m_value, m_value }; |
| 703 | } |
| 704 | |
| 705 | inline bool JSString::isSubstring() const |
| 706 | { |
| 707 | return isRope() && static_cast<const JSRopeString*>(this)->isSubstring(); |
| 708 | } |
| 709 | |
| 710 | inline JSString::SafeView::SafeView() |
| 711 | { |
| 712 | } |
| 713 | |
| 714 | inline JSString::SafeView::SafeView(ExecState& state, const JSString& string) |
| 715 | : m_state(&state) |
| 716 | , m_string(&string) |
| 717 | { |
| 718 | } |
| 719 | |
| 720 | inline JSString::SafeView::operator StringView() const |
| 721 | { |
| 722 | return m_string->unsafeView(*m_state); |
| 723 | } |
| 724 | |
| 725 | inline StringView JSString::SafeView::get() const |
| 726 | { |
| 727 | return *this; |
| 728 | } |
| 729 | |
| 730 | ALWAYS_INLINE JSString::SafeView JSString::view(ExecState* exec) const |
| 731 | { |
| 732 | return SafeView(*exec, *this); |
| 733 | } |
oliver@apple.com | 42e5917 | 2013-07-25 04:03:27 +0000 | [diff] [blame] | 734 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 735 | // --- JSValue inlines ---------------------------- |
oliver@apple.com | 42e5917 | 2013-07-25 04:03:27 +0000 | [diff] [blame] | 736 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 737 | inline bool JSValue::toBoolean(ExecState* exec) const |
| 738 | { |
| 739 | if (isInt32()) |
| 740 | return asInt32(); |
| 741 | if (isDouble()) |
| 742 | return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN |
| 743 | if (isCell()) |
| 744 | return asCell()->toBoolean(exec); |
| 745 | return isTrue(); // false, null, and undefined all convert to false. |
| 746 | } |
oliver@apple.com | 42e5917 | 2013-07-25 04:03:27 +0000 | [diff] [blame] | 747 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 748 | inline JSString* JSValue::toString(ExecState* exec) const |
| 749 | { |
| 750 | if (isString()) |
| 751 | return jsCast<JSString*>(asCell()); |
| 752 | return toStringSlowCase(exec); |
| 753 | } |
oliver@apple.com | 42e5917 | 2013-07-25 04:03:27 +0000 | [diff] [blame] | 754 | |
mark.lam@apple.com | 188640e | 2014-09-04 19:10:36 +0000 | [diff] [blame] | 755 | inline String JSValue::toWTFString(ExecState* exec) const |
| 756 | { |
| 757 | if (isString()) |
| 758 | return static_cast<JSString*>(asCell())->value(exec); |
| 759 | return toWTFStringSlowCase(exec); |
| 760 | } |
oliver@apple.com | 42e5917 | 2013-07-25 04:03:27 +0000 | [diff] [blame] | 761 | |
cwzwarich@webkit.org | 3f782f6 | 2008-09-08 01:28:33 +0000 | [diff] [blame] | 762 | } // namespace JSC |
kocienda | 66a6d36 | 2001-08-24 14:24:45 +0000 | [diff] [blame] | 763 | |
weinig@apple.com | efdce0f | 2008-06-30 20:52:03 +0000 | [diff] [blame] | 764 | #endif // JSString_h |