Changeset 97827 in webkit
- Timestamp:
- Oct 18, 2011 7:54:29 PM (13 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 13 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/ChangeLog
r97826 r97827 1 2011-10-18 Geoffrey Garen <ggaren@apple.com> 2 3 Switched ropes from malloc memory to GC memory 4 https://bugs.webkit.org/show_bug.cgi?id=70364 5 6 Reviewed by Gavin Barraclough. 7 8 ~1% SunSpider speedup. Neutral elsewhere. Removes one cause for strings 9 having C++ destructors. 10 11 * heap/MarkStack.cpp: 12 (JSC::visitChildren): Call the JSString visitChildren function now, 13 since it's no longer a no-op. 14 15 * runtime/JSString.cpp: 16 (JSC::JSString::~JSString): Moved this destructor out of line because 17 it's called virtually, so there's no value to inlining. 18 19 (JSC::JSString::RopeBuilder::expand): Switched RopeBuilder to be a thin 20 initializing wrapper around JSString. JSString now represents ropes 21 directly, rather than relying on an underlying malloc object. 22 23 (JSC::JSString::visitChildren): Visit our rope fibers, since they're GC 24 objects now. 25 26 (JSC::JSString::resolveRope): 27 (JSC::JSString::resolveRopeSlowCase): 28 (JSC::JSString::outOfMemory): Updated for operating on JSStrings instead 29 of malloc objects. 30 31 (JSC::JSString::replaceCharacter): Removed optimizations for substringing 32 ropes and replacing subsections of ropes. We want to reimplement versions 33 of these optimizations in the future, but this patch already has good 34 performance without them. 35 36 * runtime/JSString.h: 37 (JSC::RopeBuilder::JSString): 38 (JSC::RopeBuilder::finishCreation): 39 (JSC::RopeBuilder::createNull): 40 (JSC::RopeBuilder::create): 41 (JSC::RopeBuilder::createHasOtherOwner): 42 (JSC::jsSingleCharacterString): 43 (JSC::jsSingleCharacterSubstring): 44 (JSC::jsNontrivialString): 45 (JSC::jsString): 46 (JSC::jsSubstring): 47 (JSC::jsOwnedString): Lots of mechanical changes here. The two important 48 things are: (1) The fibers in JSString::m_fibers are JSStrings now, not 49 malloc objects; (2) I simplified the JSString constructor interface to 50 only accept PassRefPtr<StringImpl>, instead of variations on that like 51 UString, reducing refcount churn. 52 53 * runtime/JSValue.h: 54 * runtime/JSValue.cpp: 55 (JSC::JSValue::toPrimitiveString): Updated this function to return a 56 JSString instead of a UString, since that's what clients want now. 57 58 * runtime/Operations.cpp: 59 (JSC::jsAddSlowCase): 60 * runtime/Operations.h: 61 (JSC::jsString): 62 * runtime/SmallStrings.cpp: 63 (JSC::SmallStrings::createEmptyString): Updated for interface changes above. 64 65 * runtime/StringConstructor.cpp: 66 (JSC::constructWithStringConstructor): 67 * runtime/StringObject.h: 68 (JSC::StringObject::create): Don't create a new JSString if we already 69 have a JSString. 70 71 * runtime/StringPrototype.cpp: 72 (JSC::stringProtoFuncConcat): Updated for interface changes above. 73 1 74 2011-10-18 Gavin Barraclough <barraclough@apple.com> 2 75 -
trunk/Source/JavaScriptCore/heap/MarkStack.cpp
r97644 r97827 103 103 ASSERT(Heap::isMarked(cell)); 104 104 105 if (cell->vptr() == jsStringVPtr) 105 if (cell->vptr() == jsStringVPtr) { 106 JSString::visitChildren(const_cast<JSCell*>(cell), visitor); 106 107 return; 108 } 107 109 108 110 if (cell->vptr() == jsFinalObjectVPtr) { -
trunk/Source/JavaScriptCore/runtime/CommonIdentifiers.h
r96146 r97827 75 75 macro(valueOf) \ 76 76 macro(writable) \ 77 macro(displayName) 77 macro(displayName) \ 78 macro(undefined) 78 79 79 80 #define JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(macro) \ -
trunk/Source/JavaScriptCore/runtime/JSString.cpp
r97537 r97827 37 37 const ClassInfo JSString::s_info = { "string", 0, 0, 0, CREATE_METHOD_TABLE(JSString) }; 38 38 39 void JSString::RopeBuilder::expand() 40 { 41 ASSERT(m_jsString->m_fiberCount == JSString::s_maxInternalRopeLength); 42 JSString* jsString = m_jsString; 43 m_jsString = jsStringBuilder(&m_globalData); 44 append(jsString); 45 } 46 47 JSString::~JSString() 48 { 49 ASSERT(vptr() == JSGlobalData::jsStringVPtr); 50 } 51 52 void JSString::visitChildren(JSCell* cell, SlotVisitor& visitor) 53 { 54 JSString* thisObject = static_cast<JSString*>(cell); 55 Base::visitChildren(thisObject, visitor); 56 for (size_t i = 0; i < thisObject->m_fiberCount; ++i) 57 visitor.append(&thisObject->m_fibers[i]); 58 } 59 39 60 void JSString::resolveRope(ExecState* exec) const 40 61 { … … 49 70 } 50 71 51 RopeImpl::Fiber currentFiber = m_fibers[0]; 52 53 if ((m_fiberCount > 2) || (RopeImpl::isRope(currentFiber)) 54 || ((m_fiberCount == 2) && (RopeImpl::isRope(m_fibers[1])))) { 55 resolveRopeSlowCase(exec, buffer); 56 return; 72 for (size_t i = 0; i < m_fiberCount; ++i) { 73 if (m_fibers[i]->isRope()) 74 return resolveRopeSlowCase(exec, buffer); 57 75 } 58 76 59 77 UChar* position = buffer; 60 StringImpl* string = static_cast<StringImpl*>(currentFiber); 61 unsigned length = string->length(); 62 StringImpl::copyChars(position, string->characters(), length); 63 64 if (m_fiberCount > 1) { 65 position += length; 66 currentFiber = m_fibers[1]; 67 string = static_cast<StringImpl*>(currentFiber); 68 length = string->length(); 78 for (size_t i = 0; i < m_fiberCount; ++i) { 79 StringImpl* string = m_fibers[i]->m_value.impl(); 80 unsigned length = string->length(); 69 81 StringImpl::copyChars(position, string->characters(), length); 70 82 position += length; 71 83 } 72 73 84 ASSERT((buffer + m_length) == position); 74 for (unsigned i = 0; i < m_fiberCount; ++i) { 75 RopeImpl::deref(m_fibers[i]); 76 m_fibers[i] = 0; 77 } 85 78 86 m_fiberCount = 0; 79 80 87 ASSERT(!isRope()); 81 88 } … … 97 104 UChar* position = buffer + m_length; 98 105 99 // Start with the current RopeImpl. 100 Vector<RopeImpl::Fiber, 32> workQueue; 101 RopeImpl::Fiber currentFiber; 106 Vector<JSString*, 32> workQueue; // These strings are kept alive by the parent rope, so using a Vector is OK. 107 JSString* currentFiber; 102 108 for (unsigned i = 0; i < (m_fiberCount - 1); ++i) 103 workQueue.append(m_fibers[i] );104 currentFiber = m_fibers[m_fiberCount - 1] ;109 workQueue.append(m_fibers[i].get()); 110 currentFiber = m_fibers[m_fiberCount - 1].get(); 105 111 while (true) { 106 if (RopeImpl::isRope(currentFiber)) { 107 RopeImpl* rope = static_cast<RopeImpl*>(currentFiber); 112 if (currentFiber->isRope()) { 108 113 // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber' 109 114 // (we will be working backwards over the rope). 110 unsigned fiberCountMinusOne = rope->fiberCount() - 1;115 unsigned fiberCountMinusOne = currentFiber->fiberCount() - 1; 111 116 for (unsigned i = 0; i < fiberCountMinusOne; ++i) 112 workQueue.append( rope->fibers()[i]);113 currentFiber = rope->fibers()[fiberCountMinusOne];117 workQueue.append(currentFiber->m_fibers[i].get()); 118 currentFiber = currentFiber->m_fibers[fiberCountMinusOne].get(); 114 119 } else { 115 StringImpl* string = static_cast<StringImpl*>(currentFiber );120 StringImpl* string = static_cast<StringImpl*>(currentFiber->m_value.impl()); 116 121 unsigned length = string->length(); 117 122 position -= length; 118 123 StringImpl::copyChars(position, string->characters(), length); 119 124 120 // Was this the last item in the work queue?121 125 if (workQueue.isEmpty()) { 122 // Create a string from the UChar buffer, clear the rope RefPtr.126 m_fiberCount = 0; 123 127 ASSERT(buffer == position); 124 for (unsigned i = 0; i < m_fiberCount; ++i) {125 RopeImpl::deref(m_fibers[i]);126 m_fibers[i] = 0;127 }128 m_fiberCount = 0;129 130 128 ASSERT(!isRope()); 131 129 return; 132 130 } 133 131 134 // No! - set the next item up to process.135 132 currentFiber = workQueue.last(); 136 133 workQueue.removeLast(); … … 141 138 void JSString::outOfMemory(ExecState* exec) const 142 139 { 143 for (unsigned i = 0; i < m_fiberCount; ++i) {144 RopeImpl::deref(m_fibers[i]);145 m_fibers[i] = 0;146 }147 140 m_fiberCount = 0; 148 141 ASSERT(!isRope()); … … 152 145 } 153 146 154 // This function construsts a substring out of a rope without flattening by reusing the existing fibers.155 // This can reduce memory usage substantially. Since traversing ropes is slow the function will revert156 // back to flattening if the rope turns out to be long.157 JSString* JSString::substringFromRope(ExecState* exec, unsigned substringStart, unsigned substringLength)158 {159 ASSERT(isRope());160 ASSERT(substringLength);161 162 JSGlobalData* globalData = &exec->globalData();163 164 UString substringFibers[3];165 166 unsigned fiberCount = 0;167 unsigned substringFiberCount = 0;168 unsigned substringEnd = substringStart + substringLength;169 unsigned fiberEnd = 0;170 171 RopeIterator end;172 for (RopeIterator it(m_fibers.data(), m_fiberCount); it != end; ++it) {173 ++fiberCount;174 StringImpl* fiberString = *it;175 unsigned fiberStart = fiberEnd;176 fiberEnd = fiberStart + fiberString->length();177 if (fiberEnd <= substringStart)178 continue;179 unsigned copyStart = std::max(substringStart, fiberStart);180 unsigned copyEnd = std::min(substringEnd, fiberEnd);181 if (copyStart == fiberStart && copyEnd == fiberEnd)182 substringFibers[substringFiberCount++] = UString(fiberString);183 else184 substringFibers[substringFiberCount++] = UString(StringImpl::create(fiberString, copyStart - fiberStart, copyEnd - copyStart));185 if (fiberEnd >= substringEnd)186 break;187 if (fiberCount > substringFromRopeCutoff || substringFiberCount >= 3) {188 // This turned out to be a really inefficient rope. Just flatten it.189 resolveRope(exec);190 return jsSubstring(&exec->globalData(), m_value, substringStart, substringLength);191 }192 }193 ASSERT(substringFiberCount && substringFiberCount <= 3);194 195 if (substringLength == 1) {196 ASSERT(substringFiberCount == 1);197 UChar c = substringFibers[0][0];198 if (c <= maxSingleCharacterString)199 return globalData->smallStrings.singleCharacterString(globalData, c);200 }201 if (substringFiberCount == 1)202 return JSString::create(*globalData, substringFibers[0]);203 if (substringFiberCount == 2)204 return JSString::create(*globalData, substringFibers[0], substringFibers[1]);205 return JSString::create(*globalData, substringFibers[0], substringFibers[1], substringFibers[2]);206 }207 208 147 JSValue JSString::replaceCharacter(ExecState* exec, UChar character, const UString& replacement) 209 148 { 210 if (!isRope()) { 211 size_t matchPosition = m_value.find(character); 212 if (matchPosition == notFound) 213 return JSValue(this); 214 return jsString(exec, m_value.substringSharingImpl(0, matchPosition), replacement, m_value.substringSharingImpl(matchPosition + 1)); 215 } 216 217 RopeIterator end; 218 219 // Count total fibers and find matching string. 220 size_t fiberCount = 0; 221 StringImpl* matchString = 0; 222 size_t matchPosition = notFound; 223 for (RopeIterator it(m_fibers.data(), m_fiberCount); it != end; ++it) { 224 ++fiberCount; 225 if (matchString) 226 continue; 227 228 StringImpl* string = *it; 229 matchPosition = string->find(character); 230 if (matchPosition == notFound) 231 continue; 232 matchString = string; 233 } 234 235 if (!matchString) 236 return this; 237 238 RopeBuilder builder(replacement.length() ? fiberCount + 2 : fiberCount + 1); 239 if (UNLIKELY(builder.isOutOfMemory())) 240 return throwOutOfMemoryError(exec); 241 242 for (RopeIterator it(m_fibers.data(), m_fiberCount); it != end; ++it) { 243 StringImpl* string = *it; 244 if (string != matchString) { 245 builder.append(UString(string)); 246 continue; 247 } 248 249 builder.append(UString(string).substringSharingImpl(0, matchPosition)); 250 if (replacement.length()) 251 builder.append(replacement); 252 builder.append(UString(string).substringSharingImpl(matchPosition + 1)); 253 matchString = 0; 254 } 255 256 JSGlobalData* globalData = &exec->globalData(); 257 return JSValue(JSString::create(*globalData, builder.release())); 149 size_t matchPosition = value(exec).find(character); 150 if (matchPosition == notFound) 151 return JSValue(this); 152 return jsString(exec, m_value.substringSharingImpl(0, matchPosition), replacement, value(exec).substringSharingImpl(matchPosition + 1)); 258 153 } 259 154 -
trunk/Source/JavaScriptCore/runtime/JSString.h
r97537 r97827 60 60 JSString* jsOwnedString(ExecState*, const UString&); 61 61 62 JSString* jsStringBuilder(JSGlobalData*); 63 62 64 class JS_EXPORTCLASS JSString : public JSCell { 63 65 public: … … 66 68 friend class SpecializedThunkJIT; 67 69 friend struct ThunkHelpers; 70 friend JSString* jsStringBuilder(JSGlobalData*); 68 71 69 72 typedef JSCell Base; … … 71 74 class RopeBuilder { 72 75 public: 73 RopeBuilder( unsigned fiberCount)74 : m_ index(0)75 , m_ rope(RopeImpl::tryCreateUninitialized(fiberCount))76 RopeBuilder(JSGlobalData& globalData) 77 : m_globalData(globalData) 78 , m_jsString(jsStringBuilder(&globalData)) 76 79 { 77 80 } 78 81 79 bool isOutOfMemory() { return !m_rope; }80 81 void append(RopeImpl::Fiber& fiber)82 {83 ASSERT(m_rope);84 m_rope->initializeFiber(m_index, fiber);85 }86 void append(const UString& string)87 {88 ASSERT(m_rope);89 m_rope->initializeFiber(m_index, string.impl());90 }91 82 void append(JSString* jsString) 92 83 { 93 if ( jsString->isRope()) {94 for (unsigned i = 0; i < jsString->m_fiberCount; ++i)95 append(jsString->m_fibers[i]);96 } else97 append(jsString->string());84 if (m_jsString->m_fiberCount == JSString::s_maxInternalRopeLength) 85 expand(); 86 m_jsString->m_fibers[m_jsString->m_fiberCount].set(m_globalData, m_jsString, jsString); 87 m_jsString->m_fiberCount += 1; 88 m_jsString->m_length += jsString->m_length; 98 89 } 99 90 100 PassRefPtr<RopeImpl>release()91 JSString* release() 101 92 { 102 ASSERT(m_index == m_rope->fiberCount()); 103 return m_rope.release(); 93 JSString* tmp = m_jsString; 94 m_jsString = 0; 95 return tmp; 104 96 } 105 97 106 unsigned length() { return m_ rope->length(); }98 unsigned length() { return m_jsString->m_length; } 107 99 108 100 private: 109 unsigned m_index; 110 RefPtr<RopeImpl> m_rope; 101 void expand(); 102 103 JSGlobalData& m_globalData; 104 JSString* m_jsString; 111 105 }; 112 106 113 class RopeIterator {114 public:115 RopeIterator() { }116 117 RopeIterator(RopeImpl::Fiber* fibers, size_t fiberCount)118 {119 ASSERT(fiberCount);120 m_workQueue.append(WorkItem(fibers, fiberCount));121 skipRopes();122 }123 124 RopeIterator& operator++()125 {126 WorkItem& item = m_workQueue.last();127 ASSERT(!RopeImpl::isRope(item.fibers[item.i]));128 if (++item.i == item.fiberCount)129 m_workQueue.removeLast();130 skipRopes();131 return *this;132 }133 134 StringImpl* operator*()135 {136 WorkItem& item = m_workQueue.last();137 RopeImpl::Fiber fiber = item.fibers[item.i];138 ASSERT(!RopeImpl::isRope(fiber));139 return static_cast<StringImpl*>(fiber);140 }141 142 bool operator!=(const RopeIterator& other) const143 {144 return m_workQueue != other.m_workQueue;145 }146 147 private:148 struct WorkItem {149 WorkItem(RopeImpl::Fiber* fibers, size_t fiberCount)150 : fibers(fibers)151 , fiberCount(fiberCount)152 , i(0)153 {154 }155 156 bool operator!=(const WorkItem& other) const157 {158 return fibers != other.fibers || fiberCount != other.fiberCount || i != other.i;159 }160 161 RopeImpl::Fiber* fibers;162 size_t fiberCount;163 size_t i;164 };165 166 void skipRopes()167 {168 if (m_workQueue.isEmpty())169 return;170 171 while (1) {172 WorkItem& item = m_workQueue.last();173 RopeImpl::Fiber fiber = item.fibers[item.i];174 if (!RopeImpl::isRope(fiber))175 break;176 RopeImpl* rope = static_cast<RopeImpl*>(fiber);177 if (++item.i == item.fiberCount)178 m_workQueue.removeLast();179 m_workQueue.append(WorkItem(rope->fibers(), rope->fiberCount()));180 }181 }182 183 Vector<WorkItem, 16> m_workQueue;184 };185 186 107 private: 187 ALWAYS_INLINE JSString(JSGlobalData& globalData, const UString&value)108 JSString(JSGlobalData& globalData, PassRefPtr<StringImpl> value) 188 109 : JSCell(globalData, globalData.stringStructure.get()) 189 , m_length(value.length())190 110 , m_value(value) 191 111 , m_fiberCount(0) … … 193 113 } 194 114 195 enum HasOtherOwnerType { HasOtherOwner }; 196 JSString(JSGlobalData& globalData, const UString& value, HasOtherOwnerType) 115 JSString(JSGlobalData& globalData) 197 116 : JSCell(globalData, globalData.stringStructure.get()) 198 , m_length(value.length())199 , m_value(value)200 117 , m_fiberCount(0) 201 118 { 202 119 } 203 JSString(JSGlobalData& globalData, PassRefPtr<StringImpl> value, HasOtherOwnerType) 204 : JSCell(globalData, globalData.stringStructure.get()) 205 , m_length(value->length()) 206 , m_value(value) 207 , m_fiberCount(0) 208 { 209 } 210 JSString(JSGlobalData& globalData, PassRefPtr<RopeImpl> rope) 211 : JSCell(globalData, globalData.stringStructure.get()) 212 , m_length(rope->length()) 213 , m_fiberCount(1) 214 { 215 } 216 // This constructor constructs a new string by concatenating s1 & s2. 217 // This should only be called with fiberCount <= 3. 218 JSString(JSGlobalData& globalData, unsigned fiberCount, JSString* s1, JSString* s2) 219 : JSCell(globalData, globalData.stringStructure.get()) 220 , m_length(s1->length() + s2->length()) 221 , m_fiberCount(fiberCount) 222 { 223 } 224 // This constructor constructs a new string by concatenating s1 & s2. 225 // This should only be called with fiberCount <= 3. 226 JSString(JSGlobalData& globalData, unsigned fiberCount, JSString* s1, const UString& u2) 227 : JSCell(globalData, globalData.stringStructure.get()) 228 , m_length(s1->length() + u2.length()) 229 , m_fiberCount(fiberCount) 230 { 231 } 232 // This constructor constructs a new string by concatenating s1 & s2. 233 // This should only be called with fiberCount <= 3. 234 JSString(JSGlobalData& globalData, unsigned fiberCount, const UString& u1, JSString* s2) 235 : JSCell(globalData, globalData.stringStructure.get()) 236 , m_length(u1.length() + s2->length()) 237 , m_fiberCount(fiberCount) 238 { 239 } 240 JSString(ExecState* exec) 241 : JSCell(exec->globalData(), exec->globalData().stringStructure.get()) 242 , m_length(0) 243 , m_fiberCount(s_maxInternalRopeLength) 244 { 245 } 246 247 // This constructor constructs a new string by concatenating u1 & u2. 248 JSString(JSGlobalData& globalData, const UString& u1, const UString& u2) 249 : JSCell(globalData, globalData.stringStructure.get()) 250 , m_length(u1.length() + u2.length()) 251 , m_fiberCount(2) 252 { 253 } 254 255 // This constructor constructs a new string by concatenating u1, u2 & u3. 256 JSString(JSGlobalData& globalData, const UString& u1, const UString& u2, const UString& u3) 257 : JSCell(globalData, globalData.stringStructure.get()) 258 , m_length(u1.length() + u2.length() + u3.length()) 259 , m_fiberCount(s_maxInternalRopeLength) 260 { 261 } 262 263 void finishCreation(JSGlobalData& globalData, const UString& value) 120 121 void finishCreation(JSGlobalData& globalData) 264 122 { 265 123 Base::finishCreation(globalData); 124 m_length = 0; 125 } 126 127 void finishCreation(JSGlobalData& globalData, size_t length) 128 { 266 129 ASSERT(!m_value.isNull()); 267 Heap::heap(this)->reportExtraMemoryCost(value.impl()->cost());268 }269 270 void finishCreation(JSGlobalData& globalData)271 {272 130 Base::finishCreation(globalData); 131 m_length = length; 132 } 133 134 void finishCreation(JSGlobalData& globalData, size_t length, size_t cost) 135 { 273 136 ASSERT(!m_value.isNull()); 274 }275 276 void finishCreation(JSGlobalData& globalData, PassRefPtr<RopeImpl> rope)277 {278 137 Base::finishCreation(globalData); 279 m_fibers[0] = rope.leakRef(); 280 } 281 282 void finishCreation(JSGlobalData& globalData, unsigned fiberCount, JSString* s1, JSString* s2) 138 m_length = length; 139 Heap::heap(this)->reportExtraMemoryCost(cost); 140 } 141 142 void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2) 283 143 { 284 144 Base::finishCreation(globalData); 285 ASSERT_UNUSED(fiberCount, fiberCount <= s_maxInternalRopeLength); 286 unsigned index = 0; 287 appendStringInCreate(index, s1); 288 appendStringInCreate(index, s2); 289 ASSERT(fiberCount == index); 290 } 291 292 void finishCreation(JSGlobalData& globalData, unsigned fiberCount, JSString* s1, const UString& u2) 145 m_length = s1->length() + s2->length(); 146 m_fiberCount = 2; 147 m_fibers[0].set(globalData, this, s1); 148 m_fibers[1].set(globalData, this, s2); 149 } 150 151 void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3) 293 152 { 294 153 Base::finishCreation(globalData); 295 ASSERT_UNUSED(fiberCount, fiberCount <= s_maxInternalRopeLength); 296 unsigned index = 0; 297 appendStringInCreate(index, s1); 298 appendStringInCreate(index, u2); 299 ASSERT(fiberCount == index); 300 } 301 302 void finishCreation(JSGlobalData& globalData, unsigned fiberCount, const UString& u1, JSString* s2) 303 { 304 Base::finishCreation(globalData); 305 ASSERT_UNUSED(fiberCount, fiberCount <= s_maxInternalRopeLength); 306 unsigned index = 0; 307 appendStringInCreate(index, u1); 308 appendStringInCreate(index, s2); 309 ASSERT(fiberCount == index); 310 } 311 312 // Fills in the new string by concatenating v1, v2 & v3. 313 // This should only be called with fiberCount <= 3 ... which since every 314 // value must require a fiberCount of at least one implies that the length 315 // for each value must be exactly 1! 316 void finishCreation(ExecState* exec, JSValue v1, JSValue v2, JSValue v3) 317 { 318 Base::finishCreation(exec->globalData()); 319 unsigned index = 0; 320 appendValueInCreateAndIncrementLength(exec, index, v1); 321 appendValueInCreateAndIncrementLength(exec, index, v2); 322 appendValueInCreateAndIncrementLength(exec, index, v3); 323 ASSERT(index == s_maxInternalRopeLength); 324 } 325 326 void finishCreation(JSGlobalData& globalData, const UString& u1, const UString& u2) 327 { 328 Base::finishCreation(globalData); 329 unsigned index = 0; 330 appendStringInCreate(index, u1); 331 appendStringInCreate(index, u2); 332 ASSERT(index <= s_maxInternalRopeLength); 333 } 334 335 void finishCreation(JSGlobalData& globalData, const UString& u1, const UString& u2, const UString& u3) 336 { 337 Base::finishCreation(globalData); 338 unsigned index = 0; 339 appendStringInCreate(index, u1); 340 appendStringInCreate(index, u2); 341 appendStringInCreate(index, u3); 342 ASSERT(index <= s_maxInternalRopeLength); 343 } 344 345 public: 346 static JSString* create(JSGlobalData& globalData, const UString& value) 347 { 348 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, value); 349 newString->finishCreation(globalData, value); 350 return newString; 351 } 352 static JSString* createHasOtherOwner(JSGlobalData& globalData, const UString& value) 353 { 354 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, value, HasOtherOwner); 355 newString->finishCreation(globalData, value); 356 return newString; 357 } 358 static JSString* createHasOtherOwner(JSGlobalData& globalData, PassRefPtr<StringImpl> value) 359 { 360 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, value, HasOtherOwner); 154 m_length = s1->length() + s2->length() + s3->length(); 155 m_fiberCount = 3; 156 m_fibers[0].set(globalData, this, s1); 157 m_fibers[1].set(globalData, this, s2); 158 m_fibers[2].set(globalData, this, s3); 159 } 160 161 static JSString* createNull(JSGlobalData& globalData) 162 { 163 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData); 361 164 newString->finishCreation(globalData); 362 165 return newString; 363 166 } 364 static JSString* create(JSGlobalData& globalData, PassRefPtr<RopeImpl> rope) 365 { 366 RefPtr<RopeImpl> tempRope = rope; 367 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, tempRope); 368 newString->finishCreation(globalData, tempRope); 167 168 public: 169 static JSString* create(JSGlobalData& globalData, PassRefPtr<StringImpl> value) 170 { 171 ASSERT(value); 172 size_t length = value->length(); 173 size_t cost = value->cost(); 174 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, value); 175 newString->finishCreation(globalData, length, cost); 369 176 return newString; 370 177 } 371 static JSString* create(JSGlobalData& globalData, unsigned fiberCount,JSString* s1, JSString* s2)372 { 373 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData , fiberCount, s1, s2);374 newString->finishCreation(globalData, fiberCount,s1, s2);178 static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2) 179 { 180 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData); 181 newString->finishCreation(globalData, s1, s2); 375 182 return newString; 376 183 } 377 static JSString* create(JSGlobalData& globalData, unsigned fiberCount, JSString* s1, const UString& u2)378 { 379 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData , fiberCount, s1, u2);380 newString->finishCreation(globalData, fiberCount, s1, u2);184 static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3) 185 { 186 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData); 187 newString->finishCreation(globalData, s1, s2, s3); 381 188 return newString; 382 189 } 383 static JSString* create(JSGlobalData& globalData, unsigned fiberCount, const UString& u1, JSString* s2) 384 { 385 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, fiberCount, u1, s2); 386 newString->finishCreation(globalData, fiberCount, u1, s2); 190 static JSString* createHasOtherOwner(JSGlobalData& globalData, PassRefPtr<StringImpl> value) 191 { 192 ASSERT(value); 193 size_t length = value->length(); 194 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, value); 195 newString->finishCreation(globalData, length); 387 196 return newString; 388 197 } 389 static JSString* create(ExecState* exec, JSValue v1, JSValue v2, JSValue v3) 390 { 391 JSString* newString = new (allocateCell<JSString>(*exec->heap())) JSString(exec); 392 newString->finishCreation(exec, v1, v2, v3); 393 return newString; 394 } 395 static JSString* create(JSGlobalData& globalData, const UString& u1, const UString& u2) 396 { 397 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, u1, u2); 398 newString->finishCreation(globalData, u1, u2); 399 return newString; 400 } 401 static JSString* create(JSGlobalData& globalData, const UString& u1, const UString& u2, const UString& u3) 402 { 403 JSString* newString = new (allocateCell<JSString>(globalData.heap)) JSString(globalData, u1, u2, u3); 404 newString->finishCreation(globalData, u1, u2, u3); 405 return newString; 406 } 407 408 ~JSString() 409 { 410 ASSERT(vptr() == JSGlobalData::jsStringVPtr); 411 for (unsigned i = 0; i < m_fiberCount; ++i) 412 RopeImpl::deref(m_fibers[i]); 413 } 198 199 virtual ~JSString(); 414 200 415 201 const UString& value(ExecState* exec) const … … 455 241 static const ClassInfo s_info; 456 242 243 static void visitChildren(JSCell*, SlotVisitor&); 244 457 245 private: 458 246 JSString(VPtrStealingHackType) … … 465 253 void resolveRopeSlowCase(ExecState*, UChar*) const; 466 254 void outOfMemory(ExecState*) const; 467 JSString* substringFromRope(ExecState*, unsigned offset, unsigned length);468 469 void appendStringInCreate(unsigned& index, const UString& string)470 {471 StringImpl* impl = string.impl();472 impl->ref();473 m_fibers[index++] = impl;474 Heap::heap(this)->reportExtraMemoryCost(string.impl()->cost());475 }476 477 void appendStringInCreate(unsigned& index, JSString* jsString)478 {479 if (jsString->isRope()) {480 for (unsigned i = 0; i < jsString->m_fiberCount; ++i) {481 RopeImpl::Fiber fiber = jsString->m_fibers[i];482 fiber->ref();483 m_fibers[index++] = fiber;484 }485 } else486 appendStringInCreate(index, jsString->string());487 }488 489 void appendValueInCreateAndIncrementLength(ExecState* exec, unsigned& index, JSValue v)490 {491 if (v.isString()) {492 ASSERT(v.asCell()->isString());493 JSString* s = static_cast<JSString*>(v.asCell());494 ASSERT(s->fiberCount() == 1);495 appendStringInCreate(index, s);496 m_length += s->length();497 } else {498 UString u(v.toString(exec));499 StringImpl* impl = u.impl();500 impl->ref();501 m_fibers[index++] = impl;502 m_length += u.length();503 }504 }505 255 506 256 virtual JSObject* toThisObject(ExecState*) const; … … 519 269 mutable UString m_value; 520 270 mutable unsigned m_fiberCount; 521 mutable FixedArray< RopeImpl::Fiber, s_maxInternalRopeLength> m_fibers;271 mutable FixedArray<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers; 522 272 523 273 bool isRope() const { return m_fiberCount; } … … 526 276 527 277 friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2); 528 friend JSValue jsString(ExecState* exec, const UString& u1, JSString* s2);529 friend JSValue jsString(ExecState* exec, JSString* s1, const UString& u2);530 278 friend JSValue jsString(ExecState* exec, Register* strings, unsigned count); 531 279 friend JSValue jsString(ExecState* exec, JSValue thisValue); … … 560 308 if (c <= maxSingleCharacterString) 561 309 return globalData->smallStrings.singleCharacterString(globalData, c); 562 return fixupVPtr(globalData, JSString::create(*globalData, UString(&c, 1) ));310 return fixupVPtr(globalData, JSString::create(*globalData, UString(&c, 1).impl())); 563 311 } 564 312 … … 570 318 if (c <= maxSingleCharacterString) 571 319 return globalData->smallStrings.singleCharacterString(globalData, c); 572 return fixupVPtr(globalData, JSString::create(*globalData, UString(StringImpl::create(s.impl(), offset, 1))));320 return fixupVPtr(globalData, JSString::create(*globalData, StringImpl::create(s.impl(), offset, 1))); 573 321 } 574 322 … … 578 326 ASSERT(s[0]); 579 327 ASSERT(s[1]); 580 return fixupVPtr(globalData, JSString::create(*globalData, s));328 return fixupVPtr(globalData, JSString::create(*globalData, UString(s).impl())); 581 329 } 582 330 … … 584 332 { 585 333 ASSERT(s.length() > 1); 586 return fixupVPtr(globalData, JSString::create(*globalData, s ));334 return fixupVPtr(globalData, JSString::create(*globalData, s.impl())); 587 335 } 588 336 … … 606 354 return globalData->smallStrings.singleCharacterString(globalData, c); 607 355 } 608 return fixupVPtr(globalData, JSString::create(*globalData, s ));356 return fixupVPtr(globalData, JSString::create(*globalData, s.impl())); 609 357 } 610 358 … … 617 365 if (!length) 618 366 return globalData->smallStrings.emptyString(globalData); 619 if (s->isRope()) 620 return s->substringFromRope(exec, offset, length); 621 return jsSubstring(globalData, s->m_value, offset, length); 367 return jsSubstring(globalData, s->value(exec), offset, length); 622 368 } 623 369 … … 634 380 return globalData->smallStrings.singleCharacterString(globalData, c); 635 381 } 636 return fixupVPtr(globalData, JSString::createHasOtherOwner(*globalData, UString(StringImpl::create(s.impl(), offset, length))));382 return fixupVPtr(globalData, JSString::createHasOtherOwner(*globalData, StringImpl::create(s.impl(), offset, length))); 637 383 } 638 384 … … 647 393 return globalData->smallStrings.singleCharacterString(globalData, c); 648 394 } 649 return fixupVPtr(globalData, JSString::createHasOtherOwner(*globalData, s)); 395 return fixupVPtr(globalData, JSString::createHasOtherOwner(*globalData, s.impl())); 396 } 397 398 inline JSString* jsStringBuilder(JSGlobalData* globalData) 399 { 400 return fixupVPtr(globalData, JSString::createNull(*globalData)); 650 401 } 651 402 … … 727 478 } 728 479 729 inline UString JSValue::toPrimitiveString(ExecState* exec) const730 {731 ASSERT(!isString());732 if (isInt32())733 return exec->globalData().numericStrings.add(asInt32());734 if (isDouble())735 return exec->globalData().numericStrings.add(asDouble());736 if (isTrue())737 return "true";738 if (isFalse())739 return "false";740 if (isNull())741 return "null";742 if (isUndefined())743 return "undefined";744 ASSERT(isCell());745 return asCell()->toPrimitive(exec, NoPreference).toString(exec);746 }747 748 480 } // namespace JSC 749 481 -
trunk/Source/JavaScriptCore/runtime/JSValue.cpp
r94996 r97827 205 205 } 206 206 207 JSString* JSValue::toPrimitiveString(ExecState* exec) const 208 { 209 if (isString()) 210 return static_cast<JSString*>(asCell()); 211 if (isInt32()) 212 return jsString(&exec->globalData(), exec->globalData().numericStrings.add(asInt32())); 213 if (isDouble()) 214 return jsString(&exec->globalData(), exec->globalData().numericStrings.add(asDouble())); 215 if (isTrue()) 216 return jsNontrivialString(exec, exec->propertyNames().trueKeyword.ustring()); 217 if (isFalse()) 218 return jsNontrivialString(exec, exec->propertyNames().falseKeyword.ustring()); 219 if (isNull()) 220 return jsNontrivialString(exec, exec->propertyNames().nullKeyword.ustring()); 221 if (isUndefined()) 222 return jsNontrivialString(exec, exec->propertyNames().undefined.ustring()); 223 224 ASSERT(isCell()); 225 JSValue v = asCell()->toPrimitive(exec, NoPreference); 226 if (v.isString()) 227 return static_cast<JSString*>(v.asCell()); 228 return jsString(&exec->globalData(), v.toString(exec)); 229 } 230 207 231 } // namespace JSC -
trunk/Source/JavaScriptCore/runtime/JSValue.h
r97675 r97827 192 192 double toNumber(ExecState*) const; 193 193 UString toString(ExecState*) const; 194 UStringtoPrimitiveString(ExecState*) const;194 JSString* toPrimitiveString(ExecState*) const; 195 195 JSObject* toObject(ExecState*) const; 196 196 JSObject* toObject(ExecState*, JSGlobalObject*) const; -
trunk/Source/JavaScriptCore/runtime/Operations.cpp
r97097 r97827 51 51 return p2.isString() 52 52 ? jsString(callFrame, asString(p1), asString(p2)) 53 : jsString(callFrame, asString(p1), p2.toString(callFrame));53 : jsString(callFrame, asString(p1), jsString(callFrame, p2.toString(callFrame))); 54 54 } 55 55 if (p2.isString()) 56 return jsString(callFrame, p1.toString(callFrame), asString(p2));56 return jsString(callFrame, jsString(callFrame, p1.toString(callFrame)), asString(p2)); 57 57 58 58 return jsNumber(p1.toNumber(callFrame) + p2.toNumber(callFrame)); -
trunk/Source/JavaScriptCore/runtime/Operations.h
r96673 r97827 37 37 ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2) 38 38 { 39 JSGlobalData& globalData = exec->globalData(); 40 39 41 unsigned length1 = s1->length(); 40 42 if (!length1) … … 46 48 return throwOutOfMemoryError(exec); 47 49 48 unsigned fiberCount = s1->fiberCount() + s2->fiberCount(); 50 return fixupVPtr(&globalData, JSString::create(globalData, s1, s2)); 51 } 52 53 ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2, const UString& u3) 54 { 49 55 JSGlobalData* globalData = &exec->globalData(); 50 56 51 if (fiberCount <= JSString::s_maxInternalRopeLength)52 return JSString::create(*globalData, fiberCount, s1, s2);53 54 JSString::RopeBuilder ropeBuilder(fiberCount);55 if (UNLIKELY(ropeBuilder.isOutOfMemory()))56 return throwOutOfMemoryError(exec);57 ropeBuilder.append(s1);58 ropeBuilder.append(s2);59 return JSString::create(*globalData, ropeBuilder.release());60 }61 62 ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, JSString* s2)63 {64 unsigned length1 = u1.length();65 if (!length1)66 return s2;67 unsigned length2 = s2->length();68 if (!length2)69 return jsString(exec, u1);70 if ((length1 + length2) < length1)71 return throwOutOfMemoryError(exec);72 73 unsigned fiberCount = 1 + s2->fiberCount();74 JSGlobalData* globalData = &exec->globalData();75 76 if (fiberCount <= JSString::s_maxInternalRopeLength)77 return JSString::create(*globalData, fiberCount, u1, s2);78 79 JSString::RopeBuilder ropeBuilder(fiberCount);80 if (UNLIKELY(ropeBuilder.isOutOfMemory()))81 return throwOutOfMemoryError(exec);82 ropeBuilder.append(u1);83 ropeBuilder.append(s2);84 return JSString::create(*globalData, ropeBuilder.release());85 }86 87 ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, const UString& u2)88 {89 unsigned length1 = s1->length();90 if (!length1)91 return jsString(exec, u2);92 unsigned length2 = u2.length();93 if (!length2)94 return s1;95 if ((length1 + length2) < length1)96 return throwOutOfMemoryError(exec);97 98 unsigned fiberCount = s1->fiberCount() + 1;99 JSGlobalData* globalData = &exec->globalData();100 101 if (fiberCount <= JSString::s_maxInternalRopeLength)102 return JSString::create(*globalData, fiberCount, s1, u2);103 104 JSString::RopeBuilder ropeBuilder(fiberCount);105 if (UNLIKELY(ropeBuilder.isOutOfMemory()))106 return throwOutOfMemoryError(exec);107 ropeBuilder.append(s1);108 ropeBuilder.append(u2);109 return JSString::create(*globalData, ropeBuilder.release());110 }111 112 ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2)113 {114 unsigned length1 = u1.length();115 if (!length1)116 return jsString(exec, u2);117 unsigned length2 = u2.length();118 if (!length2)119 return jsString(exec, u1);120 if ((length1 + length2) < length1)121 return throwOutOfMemoryError(exec);122 123 JSGlobalData* globalData = &exec->globalData();124 return JSString::create(*globalData, u1, u2);125 }126 127 ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2, const UString& u3)128 {129 57 unsigned length1 = u1.length(); 130 58 unsigned length2 = u2.length(); 131 59 unsigned length3 = u3.length(); 132 60 if (!length1) 133 return jsString(exec, u2, u3);61 return jsString(exec, jsString(globalData, u2), jsString(globalData, u3)); 134 62 if (!length2) 135 return jsString(exec, u1, u3);63 return jsString(exec, jsString(globalData, u1), jsString(globalData, u3)); 136 64 if (!length3) 137 return jsString(exec, u1, u2);65 return jsString(exec, jsString(globalData, u1), jsString(globalData, u2)); 138 66 139 67 if ((length1 + length2) < length1) … … 142 70 return throwOutOfMemoryError(exec); 143 71 72 return fixupVPtr(globalData, JSString::create(exec->globalData(), jsString(globalData, u1), jsString(globalData, u2), jsString(globalData, u3))); 73 } 74 75 ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count) 76 { 144 77 JSGlobalData* globalData = &exec->globalData(); 145 return JSString::create(*globalData, u1, u2, u3); 146 } 147 148 ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count) 149 { 150 ASSERT(count >= 3); 151 152 unsigned fiberCount = 0; 78 JSString::RopeBuilder ropeBuilder(*globalData); 79 80 unsigned oldLength = 0; 81 153 82 for (unsigned i = 0; i < count; ++i) { 154 83 JSValue v = strings[i].jsValue(); 155 if (LIKELY(v.isString())) 156 fiberCount += asString(v)->fiberCount(); 157 else 158 ++fiberCount; 159 } 160 161 JSGlobalData* globalData = &exec->globalData(); 162 if (fiberCount == 3) 163 return JSString::create(exec, strings[0].jsValue(), strings[1].jsValue(), strings[2].jsValue()); 164 165 JSString::RopeBuilder ropeBuilder(fiberCount); 166 if (UNLIKELY(ropeBuilder.isOutOfMemory())) 167 return throwOutOfMemoryError(exec); 168 169 unsigned length = 0; 170 bool overflow = false; 171 172 for (unsigned i = 0; i < count; ++i) { 173 JSValue v = strings[i].jsValue(); 174 if (LIKELY(v.isString())) 84 if (v.isString()) 175 85 ropeBuilder.append(asString(v)); 176 86 else 177 ropeBuilder.append(v.toString(exec)); 178 179 unsigned newLength = ropeBuilder.length(); 180 if (newLength < length) 181 overflow = true; 182 length = newLength; 183 } 184 185 if (overflow) 186 return throwOutOfMemoryError(exec); 187 188 return JSString::create(*globalData, ropeBuilder.release()); 87 ropeBuilder.append(jsString(globalData, v.toString(exec))); 88 89 if (ropeBuilder.length() < oldLength) // True for overflow 90 return throwOutOfMemoryError(exec); 91 } 92 93 return ropeBuilder.release(); 189 94 } 190 95 191 96 ALWAYS_INLINE JSValue jsString(ExecState* exec, JSValue thisValue) 192 97 { 193 unsigned fiberCount = 0; 194 if (LIKELY(thisValue.isString())) 195 fiberCount += asString(thisValue)->fiberCount(); 98 JSGlobalData* globalData = &exec->globalData(); 99 JSString::RopeBuilder ropeBuilder(*globalData); 100 101 if (thisValue.isString()) 102 ropeBuilder.append(asString(thisValue)); 196 103 else 197 ++fiberCount; 104 ropeBuilder.append(jsString(globalData, thisValue.toString(exec))); 105 106 unsigned oldLength = 0; 107 198 108 for (unsigned i = 0; i < exec->argumentCount(); ++i) { 199 109 JSValue v = exec->argument(i); 200 if (LIKELY(v.isString())) 201 fiberCount += asString(v)->fiberCount(); 202 else 203 ++fiberCount; 204 } 205 206 JSString::RopeBuilder ropeBuilder(fiberCount); 207 if (UNLIKELY(ropeBuilder.isOutOfMemory())) 208 return throwOutOfMemoryError(exec); 209 210 if (LIKELY(thisValue.isString())) 211 ropeBuilder.append(asString(thisValue)); 212 else 213 ropeBuilder.append(thisValue.toString(exec)); 214 215 unsigned length = 0; 216 bool overflow = false; 217 218 for (unsigned i = 0; i < exec->argumentCount(); ++i) { 219 JSValue v = exec->argument(i); 220 if (LIKELY(v.isString())) 110 if (v.isString()) 221 111 ropeBuilder.append(asString(v)); 222 112 else 223 ropeBuilder.append(v.toString(exec)); 224 225 unsigned newLength = ropeBuilder.length(); 226 if (newLength < length) 227 overflow = true; 228 length = newLength; 229 } 230 231 if (overflow) 232 return throwOutOfMemoryError(exec); 233 234 JSGlobalData* globalData = &exec->globalData(); 235 return JSString::create(*globalData, ropeBuilder.release()); 113 ropeBuilder.append(jsString(globalData, v.toString(exec))); 114 115 if (ropeBuilder.length() < oldLength) // True for overflow 116 return throwOutOfMemoryError(exec); 117 } 118 119 return ropeBuilder.release(); 236 120 } 237 121 -
trunk/Source/JavaScriptCore/runtime/SmallStrings.cpp
r91194 r97827 107 107 { 108 108 ASSERT(!m_emptyString); 109 m_emptyString = JSString::createHasOtherOwner(*globalData, "");109 m_emptyString = JSString::createHasOtherOwner(*globalData, UString("").impl()); 110 110 } 111 111 -
trunk/Source/JavaScriptCore/runtime/StringConstructor.cpp
r97537 r97827 99 99 if (!exec->argumentCount()) 100 100 return JSValue::encode(StringObject::create(exec, globalObject->stringObjectStructure())); 101 return JSValue::encode(StringObject::create(exec, globalObject->stringObjectStructure(), exec->argument(0).toString(exec))); 101 102 JSString* string = exec->argument(0).isString() 103 ? asString(exec->argument(0)) 104 : jsString(exec, exec->argument(0).toString(exec)); 105 return JSValue::encode(StringObject::create(exec, globalObject->stringObjectStructure(), string)); 102 106 } 103 107 -
trunk/Source/JavaScriptCore/runtime/StringObject.h
r97537 r97827 38 38 return object; 39 39 } 40 static StringObject* create(ExecState* exec, Structure* structure, const UString& str)40 static StringObject* create(ExecState* exec, Structure* structure, JSString* string) 41 41 { 42 JSString* string = jsString(exec, str);43 42 StringObject* object = new (allocateCell<StringObject>(*exec->heap())) StringObject(exec->globalData(), structure); 44 43 object->finishCreation(exec->globalData(), string); -
trunk/Source/JavaScriptCore/runtime/StringPrototype.cpp
r97680 r97827 638 638 return JSValue::encode(v.isString() 639 639 ? jsString(exec, asString(thisValue), asString(v)) 640 : jsString(exec, asString(thisValue), v.toString(exec)));640 : jsString(exec, asString(thisValue), jsString(&exec->globalData(), v.toString(exec)))); 641 641 } 642 642 if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
Note: See TracChangeset
for help on using the changeset viewer.