JSString.h 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585
  1. /*
  2. * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
  3. * Copyright (C) 2001 Peter Kelly (pmk@post.com)
  4. * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2014 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. #ifndef JSString_h
  23. #define JSString_h
  24. #include "CallFrame.h"
  25. #include "CommonIdentifiers.h"
  26. #include "Identifier.h"
  27. #include "JITStubEntries.h"
  28. #include "PropertyDescriptor.h"
  29. #include "PropertySlot.h"
  30. #include "Structure.h"
  31. namespace JSC {
  32. class JSString;
  33. class JSRopeString;
  34. class LLIntOffsetsExtractor;
  35. JSString* jsEmptyString(VM*);
  36. JSString* jsEmptyString(ExecState*);
  37. JSString* jsString(VM*, const String&); // returns empty string if passed null string
  38. JSString* jsString(ExecState*, const String&); // returns empty string if passed null string
  39. JSString* jsSingleCharacterString(VM*, UChar);
  40. JSString* jsSingleCharacterString(ExecState*, UChar);
  41. JSString* jsSingleCharacterSubstring(ExecState*, const String&, unsigned offset);
  42. JSString* jsSubstring(VM*, const String&, unsigned offset, unsigned length);
  43. JSString* jsSubstring(ExecState*, const String&, unsigned offset, unsigned length);
  44. // Non-trivial strings are two or more characters long.
  45. // These functions are faster than just calling jsString.
  46. JSString* jsNontrivialString(VM*, const String&);
  47. JSString* jsNontrivialString(ExecState*, const String&);
  48. // Should be used for strings that are owned by an object that will
  49. // likely outlive the JSValue this makes, such as the parse tree or a
  50. // DOM object that contains a String
  51. JSString* jsOwnedString(VM*, const String&);
  52. JSString* jsOwnedString(ExecState*, const String&);
  53. JSRopeString* jsStringBuilder(VM*);
  54. class JSString : public JSCell {
  55. public:
  56. friend class JIT;
  57. friend class VM;
  58. friend class SpecializedThunkJIT;
  59. friend class JSRopeString;
  60. friend class MarkStack;
  61. friend class SlotVisitor;
  62. friend struct ThunkHelpers;
  63. typedef JSCell Base;
  64. static const bool needsDestruction = true;
  65. static const bool hasImmortalStructure = true;
  66. static void destroy(JSCell*);
  67. private:
  68. JSString(VM& vm, PassRefPtr<StringImpl> value)
  69. : JSCell(vm, vm.stringStructure.get())
  70. , m_flags(0)
  71. , m_value(value)
  72. {
  73. }
  74. JSString(VM& vm)
  75. : JSCell(vm, vm.stringStructure.get())
  76. , m_flags(0)
  77. {
  78. }
  79. void finishCreation(VM& vm, size_t length)
  80. {
  81. ASSERT(!m_value.isNull());
  82. Base::finishCreation(vm);
  83. m_length = length;
  84. setIs8Bit(m_value.impl()->is8Bit());
  85. vm.m_newStringsSinceLastHashCons++;
  86. }
  87. void finishCreation(VM& vm, size_t length, size_t cost)
  88. {
  89. ASSERT(!m_value.isNull());
  90. Base::finishCreation(vm);
  91. m_length = length;
  92. setIs8Bit(m_value.impl()->is8Bit());
  93. Heap::heap(this)->reportExtraMemoryCost(cost);
  94. vm.m_newStringsSinceLastHashCons++;
  95. }
  96. protected:
  97. void finishCreation(VM& vm)
  98. {
  99. Base::finishCreation(vm);
  100. m_length = 0;
  101. setIs8Bit(true);
  102. vm.m_newStringsSinceLastHashCons++;
  103. }
  104. public:
  105. static JSString* create(VM& vm, PassRefPtr<StringImpl> value)
  106. {
  107. ASSERT(value);
  108. int32_t length = value->length();
  109. RELEASE_ASSERT(length >= 0);
  110. size_t cost = value->cost();
  111. JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value);
  112. newString->finishCreation(vm, length, cost);
  113. return newString;
  114. }
  115. static JSString* createHasOtherOwner(VM& vm, PassRefPtr<StringImpl> value)
  116. {
  117. ASSERT(value);
  118. size_t length = value->length();
  119. JSString* newString = new (NotNull, allocateCell<JSString>(vm.heap)) JSString(vm, value);
  120. newString->finishCreation(vm, length);
  121. return newString;
  122. }
  123. const String& value(ExecState*) const;
  124. const String& tryGetValue() const;
  125. unsigned length() { return m_length; }
  126. JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
  127. JS_EXPORT_PRIVATE bool toBoolean() const;
  128. bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
  129. JSObject* toObject(ExecState*, JSGlobalObject*) const;
  130. double toNumber(ExecState*) const;
  131. bool getStringPropertySlot(ExecState*, PropertyName, PropertySlot&);
  132. bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
  133. bool getStringPropertyDescriptor(ExecState*, PropertyName, PropertyDescriptor&);
  134. bool canGetIndex(unsigned i) { return i < m_length; }
  135. JSString* getIndex(ExecState*, unsigned);
  136. #if !(ENABLE(DETACHED_JIT) && BUILDING_DETACHED_JIT)
  137. static Structure* createStructure(VM& vm, JSGlobalObject* globalObject, JSValue proto)
  138. {
  139. return Structure::create(vm, globalObject, proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | InterceptsGetOwnPropertySlotByIndexEvenWhenLengthIsNotZero), &s_info);
  140. }
  141. #endif
  142. static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); }
  143. static size_t offsetOfFlags() { return OBJECT_OFFSETOF(JSString, m_flags); }
  144. static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); }
  145. #if ENABLE(DETACHED_JIT) && BUILDING_DETACHED_JIT
  146. private:
  147. static JS_EXPORTDATA const ClassInfo s_info;
  148. #else
  149. public:
  150. static JS_EXPORTDATA const ClassInfo s_info;
  151. #endif
  152. public:
  153. static void visitChildren(JSCell*, SlotVisitor&);
  154. enum {
  155. HashConsLock = 1u << 2,
  156. IsHashConsSingleton = 1u << 1,
  157. Is8Bit = 1u
  158. };
  159. protected:
  160. friend class JSValue;
  161. bool isRope() const { return m_value.isNull(); }
  162. bool is8Bit() const { return m_flags & Is8Bit; }
  163. void setIs8Bit(bool flag)
  164. {
  165. if (flag)
  166. m_flags |= Is8Bit;
  167. else
  168. m_flags &= ~Is8Bit;
  169. }
  170. bool shouldTryHashCons();
  171. bool isHashConsSingleton() const { return m_flags & IsHashConsSingleton; }
  172. void clearHashConsSingleton() { m_flags &= ~IsHashConsSingleton; }
  173. void setHashConsSingleton() { m_flags |= IsHashConsSingleton; }
  174. bool tryHashConsLock();
  175. void releaseHashConsLock();
  176. unsigned m_flags;
  177. // A string is represented either by a String or a rope of fibers.
  178. unsigned m_length;
  179. mutable String m_value;
  180. private:
  181. friend class LLIntOffsetsExtractor;
  182. static JSObject* toThisObject(JSCell*, ExecState*);
  183. // Actually getPropertySlot, not getOwnPropertySlot (see JSCell).
  184. static bool getOwnPropertySlot(JSCell*, ExecState*, PropertyName, PropertySlot&);
  185. static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
  186. String& string() { ASSERT(!isRope()); return m_value; }
  187. friend JSValue jsString(ExecState*, JSString*, JSString*);
  188. friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length);
  189. };
  190. class JSRopeString : public JSString {
  191. friend class JSString;
  192. friend JSRopeString* jsStringBuilder(VM*);
  193. class RopeBuilder {
  194. public:
  195. RopeBuilder(VM& vm)
  196. : m_vm(vm)
  197. , m_jsString(jsStringBuilder(&vm))
  198. , m_index(0)
  199. {
  200. }
  201. bool append(JSString* jsString)
  202. {
  203. if (m_index == JSRopeString::s_maxInternalRopeLength)
  204. expand();
  205. if (static_cast<int32_t>(m_jsString->length() + jsString->length()) < 0) {
  206. m_jsString = nullptr;
  207. return false;
  208. }
  209. m_jsString->append(m_vm, m_index++, jsString);
  210. return true;
  211. }
  212. JSRopeString* release()
  213. {
  214. RELEASE_ASSERT(m_jsString);
  215. JSRopeString* tmp = m_jsString;
  216. m_jsString = 0;
  217. return tmp;
  218. }
  219. unsigned length() { return m_jsString->m_length; }
  220. private:
  221. void expand();
  222. VM& m_vm;
  223. JSRopeString* m_jsString;
  224. size_t m_index;
  225. };
  226. private:
  227. JSRopeString(VM& vm)
  228. : JSString(vm)
  229. {
  230. }
  231. void finishCreation(VM& vm, JSString* s1, JSString* s2)
  232. {
  233. Base::finishCreation(vm);
  234. m_length = s1->length() + s2->length();
  235. setIs8Bit(s1->is8Bit() && s2->is8Bit());
  236. m_fibers[0].set(vm, this, s1);
  237. m_fibers[1].set(vm, this, s2);
  238. }
  239. void finishCreation(VM& vm, JSString* s1, JSString* s2, JSString* s3)
  240. {
  241. Base::finishCreation(vm);
  242. m_length = s1->length() + s2->length() + s3->length();
  243. setIs8Bit(s1->is8Bit() && s2->is8Bit() && s3->is8Bit());
  244. m_fibers[0].set(vm, this, s1);
  245. m_fibers[1].set(vm, this, s2);
  246. m_fibers[2].set(vm, this, s3);
  247. }
  248. void finishCreation(VM& vm)
  249. {
  250. JSString::finishCreation(vm);
  251. }
  252. void append(VM& vm, size_t index, JSString* jsString)
  253. {
  254. m_fibers[index].set(vm, this, jsString);
  255. m_length += jsString->m_length;
  256. RELEASE_ASSERT(static_cast<int32_t>(m_length) >= 0);
  257. setIs8Bit(is8Bit() && jsString->is8Bit());
  258. }
  259. static JSRopeString* createNull(VM& vm)
  260. {
  261. JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
  262. newString->finishCreation(vm);
  263. return newString;
  264. }
  265. public:
  266. static JSString* create(VM& vm, JSString* s1, JSString* s2)
  267. {
  268. JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
  269. newString->finishCreation(vm, s1, s2);
  270. return newString;
  271. }
  272. static JSString* create(VM& vm, JSString* s1, JSString* s2, JSString* s3)
  273. {
  274. JSRopeString* newString = new (NotNull, allocateCell<JSRopeString>(vm.heap)) JSRopeString(vm);
  275. newString->finishCreation(vm, s1, s2, s3);
  276. return newString;
  277. }
  278. void visitFibers(SlotVisitor&);
  279. static ptrdiff_t offsetOfFibers() { return OBJECT_OFFSETOF(JSRopeString, m_fibers); }
  280. static const unsigned s_maxInternalRopeLength = 3;
  281. private:
  282. friend JSValue jsString(ExecState*, Register*, unsigned);
  283. friend JSValue jsStringFromArguments(ExecState*, JSValue);
  284. JS_EXPORT_PRIVATE void resolveRope(ExecState*) const;
  285. void resolveRopeSlowCase8(LChar*) const;
  286. void resolveRopeSlowCase(UChar*) const;
  287. void outOfMemory(ExecState*) const;
  288. JSString* getIndexSlowCase(ExecState*, unsigned);
  289. mutable FixedArray<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers;
  290. };
  291. JSString* asString(JSValue);
  292. inline JSString* asString(JSValue value)
  293. {
  294. ASSERT(value.asCell()->isString());
  295. return jsCast<JSString*>(value.asCell());
  296. }
  297. inline JSString* jsEmptyString(VM* vm)
  298. {
  299. return vm->smallStrings.emptyString();
  300. }
  301. ALWAYS_INLINE JSString* jsSingleCharacterString(VM* vm, UChar c)
  302. {
  303. if (c <= maxSingleCharacterString)
  304. return vm->smallStrings.singleCharacterString(vm, c);
  305. return JSString::create(*vm, String(&c, 1).impl());
  306. }
  307. ALWAYS_INLINE JSString* jsSingleCharacterSubstring(ExecState* exec, const String& s, unsigned offset)
  308. {
  309. VM* vm = &exec->vm();
  310. ASSERT(offset < static_cast<unsigned>(s.length()));
  311. UChar c = s.characterAt(offset);
  312. if (c <= maxSingleCharacterString)
  313. return vm->smallStrings.singleCharacterString(vm, c);
  314. return JSString::create(*vm, StringImpl::create(s.impl(), offset, 1));
  315. }
  316. inline JSString* jsNontrivialString(VM* vm, const String& s)
  317. {
  318. ASSERT(s.length() > 1);
  319. return JSString::create(*vm, s.impl());
  320. }
  321. inline const String& JSString::value(ExecState* exec) const
  322. {
  323. if (isRope())
  324. static_cast<const JSRopeString*>(this)->resolveRope(exec);
  325. return m_value;
  326. }
  327. inline const String& JSString::tryGetValue() const
  328. {
  329. #if ENABLE(DETACHED_JIT) && BUILDING_DETACHED_JIT
  330. ASSERT(!isRope());
  331. if (isRope()) {
  332. __builtin_trap();
  333. }
  334. #else
  335. if (isRope())
  336. static_cast<const JSRopeString*>(this)->resolveRope(0);
  337. #endif
  338. return m_value;
  339. }
  340. inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
  341. {
  342. ASSERT(canGetIndex(i));
  343. if (isRope())
  344. return static_cast<JSRopeString*>(this)->getIndexSlowCase(exec, i);
  345. ASSERT(i < m_value.length());
  346. return jsSingleCharacterSubstring(exec, m_value, i);
  347. }
  348. inline JSString* jsString(VM* vm, const String& s)
  349. {
  350. int size = s.length();
  351. if (!size)
  352. return vm->smallStrings.emptyString();
  353. if (size == 1) {
  354. UChar c = s.characterAt(0);
  355. if (c <= maxSingleCharacterString)
  356. return vm->smallStrings.singleCharacterString(vm, c);
  357. }
  358. return JSString::create(*vm, s.impl());
  359. }
  360. inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
  361. {
  362. ASSERT(offset <= static_cast<unsigned>(s->length()));
  363. ASSERT(length <= static_cast<unsigned>(s->length()));
  364. ASSERT(offset + length <= static_cast<unsigned>(s->length()));
  365. VM* vm = &exec->vm();
  366. if (!length)
  367. return vm->smallStrings.emptyString();
  368. return jsSubstring(vm, s->value(exec), offset, length);
  369. }
  370. inline JSString* jsSubstring8(VM* vm, const String& s, unsigned offset, unsigned length)
  371. {
  372. ASSERT(offset <= static_cast<unsigned>(s.length()));
  373. ASSERT(length <= static_cast<unsigned>(s.length()));
  374. ASSERT(offset + length <= static_cast<unsigned>(s.length()));
  375. if (!length)
  376. return vm->smallStrings.emptyString();
  377. if (length == 1) {
  378. UChar c = s.characterAt(offset);
  379. if (c <= maxSingleCharacterString)
  380. return vm->smallStrings.singleCharacterString(vm, c);
  381. }
  382. return JSString::createHasOtherOwner(*vm, StringImpl::create8(s.impl(), offset, length));
  383. }
  384. inline JSString* jsSubstring(VM* vm, const String& s, unsigned offset, unsigned length)
  385. {
  386. ASSERT(offset <= static_cast<unsigned>(s.length()));
  387. ASSERT(length <= static_cast<unsigned>(s.length()));
  388. ASSERT(offset + length <= static_cast<unsigned>(s.length()));
  389. if (!length)
  390. return vm->smallStrings.emptyString();
  391. if (length == 1) {
  392. UChar c = s.characterAt(offset);
  393. if (c <= maxSingleCharacterString)
  394. return vm->smallStrings.singleCharacterString(vm, c);
  395. }
  396. return JSString::createHasOtherOwner(*vm, StringImpl::create(s.impl(), offset, length));
  397. }
  398. inline JSString* jsOwnedString(VM* vm, const String& s)
  399. {
  400. int size = s.length();
  401. if (!size)
  402. return vm->smallStrings.emptyString();
  403. if (size == 1) {
  404. UChar c = s.characterAt(0);
  405. if (c <= maxSingleCharacterString)
  406. return vm->smallStrings.singleCharacterString(vm, c);
  407. }
  408. return JSString::createHasOtherOwner(*vm, s.impl());
  409. }
  410. inline JSRopeString* jsStringBuilder(VM* vm)
  411. {
  412. return JSRopeString::createNull(*vm);
  413. }
  414. inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->vm()); }
  415. inline JSString* jsString(ExecState* exec, const String& s) { return jsString(&exec->vm(), s); }
  416. inline JSString* jsSingleCharacterString(ExecState* exec, UChar c) { return jsSingleCharacterString(&exec->vm(), c); }
  417. inline JSString* jsSubstring8(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring8(&exec->vm(), s, offset, length); }
  418. inline JSString* jsSubstring(ExecState* exec, const String& s, unsigned offset, unsigned length) { return jsSubstring(&exec->vm(), s, offset, length); }
  419. inline JSString* jsNontrivialString(ExecState* exec, const String& s) { return jsNontrivialString(&exec->vm(), s); }
  420. inline JSString* jsOwnedString(ExecState* exec, const String& s) { return jsOwnedString(&exec->vm(), s); }
  421. ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot)
  422. {
  423. if (propertyName == exec->propertyNames().length) {
  424. slot.setValue(jsNumber(m_length));
  425. return true;
  426. }
  427. unsigned i = propertyName.asIndex();
  428. if (i < m_length) {
  429. ASSERT(i != PropertyName::NotAnIndex); // No need for an explicit check, the above test would always fail!
  430. slot.setValue(getIndex(exec, i));
  431. return true;
  432. }
  433. return false;
  434. }
  435. ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
  436. {
  437. if (propertyName < m_length) {
  438. slot.setValue(getIndex(exec, propertyName));
  439. return true;
  440. }
  441. return false;
  442. }
  443. inline bool isJSString(JSValue v)
  444. {
  445. DEFINE_STATIC_sJSStringClassInfo;
  446. return v.isCell() && v.asCell()->classInfo() == sJSStringClassInfo;
  447. }
  448. // --- JSValue inlines ----------------------------
  449. inline bool JSValue::toBoolean(ExecState* exec) const
  450. {
  451. if (isInt32())
  452. return asInt32();
  453. if (isDouble())
  454. return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
  455. if (isCell())
  456. return asCell()->toBoolean(exec);
  457. return isTrue(); // false, null, and undefined all convert to false.
  458. }
  459. inline JSString* JSValue::toString(ExecState* exec) const
  460. {
  461. if (isString())
  462. return jsCast<JSString*>(asCell());
  463. return toStringSlowCase(exec);
  464. }
  465. inline String JSValue::toWTFString(ExecState* exec) const
  466. {
  467. if (isString())
  468. return static_cast<JSString*>(asCell())->value(exec);
  469. return toWTFStringSlowCase(exec);
  470. }
  471. ALWAYS_INLINE String inlineJSValueNotStringtoString(const JSValue& value, ExecState* exec)
  472. {
  473. VM& vm = exec->vm();
  474. if (value.isInt32())
  475. return vm.numericStrings.add(value.asInt32());
  476. if (value.isDouble())
  477. return vm.numericStrings.add(value.asDouble());
  478. if (value.isTrue())
  479. return vm.propertyNames->trueKeyword.string();
  480. if (value.isFalse())
  481. return vm.propertyNames->falseKeyword.string();
  482. if (value.isNull())
  483. return vm.propertyNames->nullKeyword.string();
  484. if (value.isUndefined())
  485. return vm.propertyNames->undefinedKeyword.string();
  486. return value.toString(exec)->value(exec);
  487. }
  488. ALWAYS_INLINE String JSValue::toWTFStringInline(ExecState* exec) const
  489. {
  490. if (isString())
  491. return static_cast<JSString*>(asCell())->value(exec);
  492. return inlineJSValueNotStringtoString(*this, exec);
  493. }
  494. } // namespace JSC
  495. #endif // JSString_h