Changeset 194017 in webkit
- Timestamp:
- Dec 13, 2015 12:03:24 PM (8 years ago)
- Location:
- trunk/Source
- Files:
-
- 31 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/API/JSScriptRef.cpp
r192937 r194017 47 47 } 48 48 49 virtual const String& source() const override 49 unsigned hash() const override 50 { 51 return m_source.impl()->hash(); 52 } 53 54 StringView source() const override 50 55 { 51 56 return m_source; -
trunk/Source/JavaScriptCore/ChangeLog
r194011 r194017 1 2015-12-13 Andreas Kling <akling@apple.com> 2 3 CachedScript could have a copy-free path for all-ASCII scripts. 4 <https://webkit.org/b/152203> 5 6 Reviewed by Antti Koivisto. 7 8 Make SourceProvider vend a StringView instead of a String. 9 This relaxes the promises that providers have to make about string lifetimes. 10 11 This means that on the WebCore side, CachedScript is free to cache a String 12 internally, while only ever exposing it as a temporary StringView. 13 14 A few extra copies (CPU, not memory) are introduced, none of them on hot paths. 15 16 * API/JSScriptRef.cpp: 17 * bytecode/CodeBlock.cpp: 18 (JSC::CodeBlock::sourceCodeForTools): 19 (JSC::CodeBlock::dumpSource): 20 * inspector/ScriptDebugServer.cpp: 21 (Inspector::ScriptDebugServer::dispatchDidParseSource): 22 (Inspector::ScriptDebugServer::dispatchFailedToParseSource): 23 * interpreter/Interpreter.cpp: 24 (JSC::Interpreter::execute): 25 * jsc.cpp: 26 (functionFindTypeForExpression): 27 (functionHasBasicBlockExecuted): 28 (functionBasicBlockExecutionCount): 29 * parser/Lexer.cpp: 30 (JSC::Lexer<T>::setCode): 31 * parser/Lexer.h: 32 (JSC::Lexer<LChar>::setCodeStart): 33 (JSC::Lexer<UChar>::setCodeStart): 34 * parser/Parser.h: 35 (JSC::Parser::getToken): 36 * parser/SourceCode.cpp: 37 (JSC::SourceCode::toUTF8): 38 * parser/SourceCode.h: 39 (JSC::SourceCode::hash): 40 (JSC::SourceCode::view): 41 (JSC::SourceCode::toString): Deleted. 42 * parser/SourceCodeKey.h: 43 (JSC::SourceCodeKey::SourceCodeKey): 44 (JSC::SourceCodeKey::string): 45 * parser/SourceProvider.h: 46 (JSC::SourceProvider::getRange): 47 * runtime/Completion.cpp: 48 (JSC::loadAndEvaluateModule): 49 (JSC::loadModule): 50 * runtime/ErrorInstance.cpp: 51 (JSC::appendSourceToError): 52 * runtime/FunctionPrototype.cpp: 53 (JSC::functionProtoFuncToString): 54 * tools/FunctionOverrides.cpp: 55 (JSC::initializeOverrideInfo): 56 (JSC::FunctionOverrides::initializeOverrideFor): 57 1 58 2015-12-12 Benjamin Poulain <benjamin@webkit.org> 2 59 -
trunk/Source/JavaScriptCore/bytecode/CodeBlock.cpp
r193974 r194017 197 197 return toCString( 198 198 "function ", 199 provider->source(). impl()->utf8ForRange(rangeStart, rangeEnd - rangeStart));199 provider->source().substring(rangeStart, rangeEnd - rangeStart).utf8()); 200 200 } 201 201 … … 555 555 if (executable->isFunctionExecutable()) { 556 556 FunctionExecutable* functionExecutable = reinterpret_cast<FunctionExecutable*>(executable); 557 String source = functionExecutable->source().provider()->getRange(557 StringView source = functionExecutable->source().provider()->getRange( 558 558 functionExecutable->parametersStartOffset(), 559 559 functionExecutable->typeProfilingEndOffset() + 1); // Type profiling end offset is the character before the '}'. … … 562 562 return; 563 563 } 564 out.print(executable->source(). toString());564 out.print(executable->source().view()); 565 565 } 566 566 -
trunk/Source/JavaScriptCore/inspector/ScriptDebugServer.cpp
r193426 r194017 200 200 ScriptDebugListener::Script script; 201 201 script.url = sourceProvider->url(); 202 script.source = sourceProvider->source() ;202 script.source = sourceProvider->source().toString(); 203 203 script.startLine = sourceProvider->startPosition().m_line.zeroBasedInt(); 204 204 script.startColumn = sourceProvider->startPosition().m_column.zeroBasedInt(); … … 232 232 { 233 233 String url = sourceProvider->url(); 234 const String& data = sourceProvider->source();234 String data = sourceProvider->source().toString(); 235 235 int firstLine = sourceProvider->startPosition().m_line.oneBasedInt(); 236 236 -
trunk/Source/JavaScriptCore/interpreter/Interpreter.cpp
r193939 r194017 850 850 Vector<JSONPData> JSONPData; 851 851 bool parseResult; 852 const String programSource = program->source().toString();852 StringView programSource = program->source().view(); 853 853 if (programSource.isNull()) 854 854 return jsUndefined(); -
trunk/Source/JavaScriptCore/jsc.cpp
r192693 r194017 1465 1465 RELEASE_ASSERT(exec->argument(1).isString()); 1466 1466 String substring = exec->argument(1).getString(exec); 1467 String sourceCodeText = executable->source(). toString();1467 String sourceCodeText = executable->source().view().toString(); 1468 1468 unsigned offset = static_cast<unsigned>(sourceCodeText.find(substring) + executable->source().startOffset()); 1469 1469 … … 1503 1503 RELEASE_ASSERT(exec->argument(1).isString()); 1504 1504 String substring = exec->argument(1).getString(exec); 1505 String sourceCodeText = executable->source(). toString();1505 String sourceCodeText = executable->source().view().toString(); 1506 1506 RELEASE_ASSERT(sourceCodeText.contains(substring)); 1507 1507 int offset = sourceCodeText.find(substring) + executable->source().startOffset(); … … 1521 1521 RELEASE_ASSERT(exec->argument(1).isString()); 1522 1522 String substring = exec->argument(1).getString(exec); 1523 String sourceCodeText = executable->source(). toString();1523 String sourceCodeText = executable->source().view().toString(); 1524 1524 RELEASE_ASSERT(sourceCodeText.contains(substring)); 1525 1525 int offset = sourceCodeText.find(substring) + executable->source().startOffset(); -
trunk/Source/JavaScriptCore/parser/Lexer.cpp
r192141 r194017 544 544 m_lastToken = -1; 545 545 546 const String&sourceString = source.provider()->source();546 StringView sourceString = source.provider()->source(); 547 547 548 548 if (!sourceString.isNull()) 549 setCodeStart(sourceString .impl());549 setCodeStart(sourceString); 550 550 else 551 551 m_codeStart = 0; -
trunk/Source/JavaScriptCore/parser/Lexer.h
r192141 r194017 140 140 ALWAYS_INLINE void setOffsetFromSourcePtr(const T* sourcePtr, unsigned lineStartOffset) { setOffset(offsetFromSourcePtr(sourcePtr), lineStartOffset); } 141 141 142 ALWAYS_INLINE void setCodeStart(const String Impl*);142 ALWAYS_INLINE void setCodeStart(const StringView&); 143 143 144 144 ALWAYS_INLINE const Identifier* makeIdentifier(const LChar* characters, size_t length); … … 290 290 291 291 template <> 292 ALWAYS_INLINE void Lexer<LChar>::setCodeStart(const String Impl*sourceString)293 { 294 ASSERT(sourceString ->is8Bit());295 m_codeStart = sourceString ->characters8();296 } 297 298 template <> 299 ALWAYS_INLINE void Lexer<UChar>::setCodeStart(const String Impl*sourceString)300 { 301 ASSERT(!sourceString ->is8Bit());302 m_codeStart = sourceString ->characters16();292 ALWAYS_INLINE void Lexer<LChar>::setCodeStart(const StringView& sourceString) 293 { 294 ASSERT(sourceString.is8Bit()); 295 m_codeStart = sourceString.characters8(); 296 } 297 298 template <> 299 ALWAYS_INLINE void Lexer<UChar>::setCodeStart(const StringView& sourceString) 300 { 301 ASSERT(!sourceString.is8Bit()); 302 m_codeStart = sourceString.characters16(); 303 303 } 304 304 -
trunk/Source/JavaScriptCore/parser/Parser.h
r192937 r194017 991 991 992 992 void printUnexpectedTokenText(WTF::PrintStream&); 993 ALWAYS_INLINE String getToken() {993 ALWAYS_INLINE StringView getToken() { 994 994 SourceProvider* sourceProvider = m_source->provider(); 995 995 return sourceProvider->getRange(tokenStart(), tokenEndPosition().offset); -
trunk/Source/JavaScriptCore/parser/SourceCode.cpp
r163844 r194017 37 37 return CString("", 0); 38 38 39 return m_provider->source(). impl()->utf8ForRange(m_startChar, m_endChar - m_startChar);39 return m_provider->source().substring(m_startChar, m_endChar - m_startChar).utf8(); 40 40 } 41 41 -
trunk/Source/JavaScriptCore/parser/SourceCode.h
r186959 r194017 80 80 bool isHashTableDeletedValue() const { return m_provider.isHashTableDeletedValue(); } 81 81 82 String toString() const 82 unsigned hash() const 83 { 84 ASSERT(m_provider); 85 return m_provider->hash(); 86 } 87 88 StringView view() const 83 89 { 84 90 if (!m_provider) 85 return String ();91 return StringView(); 86 92 return m_provider->getRange(m_startChar, m_endChar); 87 93 } -
trunk/Source/JavaScriptCore/parser/SourceCodeKey.h
r192937 r194017 46 46 , m_name(name) 47 47 , m_flags((static_cast<unsigned>(codeType) << 3) | (static_cast<unsigned>(builtinMode) << 2) | (static_cast<unsigned>(strictMode) << 1) | static_cast<unsigned>(thisTDZMode)) 48 , m_hash(s tring().impl()->hash())48 , m_hash(sourceCode.hash()) 49 49 { 50 50 } … … 65 65 // To save memory, we compute our string on demand. It's expected that source 66 66 // providers cache their strings to make this efficient. 67 String string() const { return m_sourceCode.toString(); }67 StringView string() const { return m_sourceCode.view(); } 68 68 69 69 bool operator==(const SourceCodeKey& other) const -
trunk/Source/JavaScriptCore/parser/SourceProvider.h
r191973 r194017 44 44 JS_EXPORT_PRIVATE virtual ~SourceProvider(); 45 45 46 virtual const String& source() const = 0; 47 String getRange(int start, int end) const 46 virtual unsigned hash() const = 0; 47 virtual StringView source() const = 0; 48 StringView getRange(int start, int end) const 48 49 { 49 return source().substring SharingImpl(start, end - start);50 return source().substring(start, end - start); 50 51 } 51 52 … … 87 88 return adoptRef(*new StringSourceProvider(source, url, startPosition)); 88 89 } 90 91 unsigned hash() const override 92 { 93 return m_source.impl()->hash(); 94 } 89 95 90 virtual const String&source() const override96 virtual StringView source() const override 91 97 { 92 98 return m_source; … … 111 117 } 112 118 113 virtual const String& source() const override 119 unsigned hash() const override 120 { 121 return m_source.impl()->hash(); 122 } 123 124 virtual StringView source() const override 114 125 { 115 126 return m_source; -
trunk/Source/JavaScriptCore/runtime/Completion.cpp
r192937 r194017 168 168 169 169 // Insert the given source code to the ModuleLoader registry as the fetched registry entry. 170 globalObject->moduleLoader()->provide(exec, key, ModuleLoaderObject::Status::Fetch, source. toString());170 globalObject->moduleLoader()->provide(exec, key, ModuleLoaderObject::Status::Fetch, source.view().toString()); 171 171 if (exec->hadException()) 172 172 return rejectPromise(exec, globalObject); … … 205 205 206 206 // Insert the given source code to the ModuleLoader registry as the fetched registry entry. 207 globalObject->moduleLoader()->provide(exec, key, ModuleLoaderObject::Status::Fetch, source. toString());207 globalObject->moduleLoader()->provide(exec, key, ModuleLoaderObject::Status::Fetch, source.view().toString()); 208 208 if (exec->hadException()) 209 209 return rejectPromise(exec, globalObject); -
trunk/Source/JavaScriptCore/runtime/ErrorInstance.cpp
r190555 r194017 61 61 int expressionStop = divotPoint + endOffset; 62 62 63 const String&sourceString = codeBlock->source()->source();63 StringView sourceString = codeBlock->source()->source(); 64 64 if (!expressionStop || expressionStart > static_cast<int>(sourceString.length())) 65 65 return; … … 72 72 String message = asString(jsMessage)->value(callFrame); 73 73 if (expressionStart < expressionStop) 74 message = appender(message, codeBlock->source()->getRange(expressionStart, expressionStop) 74 message = appender(message, codeBlock->source()->getRange(expressionStart, expressionStop).toString(), type, ErrorInstance::FoundExactSource); 75 75 else { 76 76 // No range information, so give a few characters of context. 77 const StringImpl* data = sourceString.impl();78 77 int dataLength = sourceString.length(); 79 78 int start = expressionStart; … … 81 80 // Get up to 20 characters of context to the left and right of the divot, clamping to the line. 82 81 // Then strip whitespace. 83 while (start > 0 && (expressionStart - start < 20) && (*data)[start - 1] != '\n')82 while (start > 0 && (expressionStart - start < 20) && sourceString[start - 1] != '\n') 84 83 start--; 85 while (start < (expressionStart - 1) && isStrWhiteSpace( (*data)[start]))84 while (start < (expressionStart - 1) && isStrWhiteSpace(sourceString[start])) 86 85 start++; 87 while (stop < dataLength && (stop - expressionStart < 20) && (*data)[stop] != '\n')86 while (stop < dataLength && (stop - expressionStart < 20) && sourceString[stop] != '\n') 88 87 stop++; 89 while (stop > expressionStart && isStrWhiteSpace( (*data)[stop - 1]))88 while (stop > expressionStart && isStrWhiteSpace(sourceString[stop - 1])) 90 89 stop--; 91 message = appender(message, codeBlock->source()->getRange(start, stop) , type, ErrorInstance::FoundApproximateSource);90 message = appender(message, codeBlock->source()->getRange(start, stop).toString(), type, ErrorInstance::FoundApproximateSource); 92 91 } 93 92 exception->putDirect(*vm, vm->propertyNames->message, jsString(vm, message)); -
trunk/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
r193974 r194017 93 93 String functionHeader = executable->isArrowFunction() ? "" : "function "; 94 94 95 String source = executable->source().provider()->getRange(95 StringView source = executable->source().provider()->getRange( 96 96 executable->parametersStartOffset(), 97 97 executable->parametersStartOffset() + executable->source().length()); -
trunk/Source/JavaScriptCore/tools/FunctionOverrides.cpp
r184325 r194017 107 107 static void initializeOverrideInfo(const SourceCode& origCode, const String& newBody, FunctionOverrides::OverrideInfo& info) 108 108 { 109 String origProviderStr = origCode.provider()->source() ;109 String origProviderStr = origCode.provider()->source().toString(); 110 110 unsigned origBraceStart = origCode.startOffset(); 111 111 unsigned origFunctionStart = origProviderStr.reverseFind("function", origBraceStart); … … 136 136 FunctionOverrides& overrides = FunctionOverrides::overrides(); 137 137 138 auto it = overrides.m_entries.find(origCode. toString());138 auto it = overrides.m_entries.find(origCode.view().toString()); 139 139 if (it == overrides.m_entries.end()) 140 140 return false; -
trunk/Source/WTF/wtf/PrintStream.cpp
r184828 r194017 52 52 { 53 53 out.printf("%s", string); 54 } 55 56 void printInternal(PrintStream& out, const StringView& string) 57 { 58 out.print(string.utf8()); 54 59 } 55 60 -
trunk/Source/WTF/wtf/PrintStream.h
r190076 r194017 41 41 class String; 42 42 class StringImpl; 43 class StringView; 43 44 class UniquedStringImpl; 44 45 … … 71 72 72 73 WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const char*); 74 WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const StringView&); 73 75 WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const CString&); 74 76 WTF_EXPORT_PRIVATE void printInternal(PrintStream&, const String&); -
trunk/Source/WebCore/ChangeLog
r194016 r194017 1 2015-12-13 Andreas Kling <akling@apple.com> 2 3 CachedScript could have a copy-free path for all-ASCII scripts. 4 <https://webkit.org/b/152203> 5 6 Reviewed by ANtti Koivisto. 7 8 Many (if not most) of script resources on the web contain nothing but ASCII characters. 9 Such resources, when streamed through a text decoder, will yield the exact same byte 10 sequence, except in anonymous heap memory instead of delicious file-backed pages. 11 12 Care is taken to ensure that the wrapper StringImpl is updated to target newly cached 13 resource data if an asynchronous caching notification comes in. 14 15 * loader/cache/CachedResource.cpp: 16 (WebCore::CachedResource::tryReplaceEncodedData): 17 * loader/cache/CachedResource.h: 18 (WebCore::CachedResource::didReplaceSharedBufferContents): 19 * loader/cache/CachedScript.cpp: 20 (WebCore::encodingMayBeAllASCII): 21 (WebCore::CachedScript::script): 22 (WebCore::CachedScript::didReplaceSharedBufferContents): 23 * loader/cache/CachedScript.h: 24 * platform/SharedBuffer.h: 25 * platform/cf/SharedBufferCF.cpp: 26 (WebCore::SharedBuffer::tryReplaceContentsWithPlatformBuffer): 27 1 28 2015-12-13 Zalan Bujtas <zalan@apple.com> 2 29 -
trunk/Source/WebCore/bindings/js/CachedScriptSourceProvider.h
r177733 r194017 45 45 } 46 46 47 const String& source() const { return m_cachedScript->script(); } 47 unsigned hash() const override { return m_cachedScript->scriptHash(); } 48 StringView source() const override { return m_cachedScript->script(); } 48 49 49 50 private: -
trunk/Source/WebCore/bindings/js/ScriptSourceCode.h
r156550 r194017 62 62 const JSC::SourceCode& jsSourceCode() const { return m_code; } 63 63 64 const String&source() const { return m_provider->source(); }64 StringView source() const { return m_provider->source(); } 65 65 66 66 int startLine() const { return m_code.firstLine(); } -
trunk/Source/WebCore/inspector/InspectorPageAgent.cpp
r192592 r194017 162 162 return !result->isNull(); 163 163 case CachedResource::Script: 164 *result = downcast<CachedScript>(*cachedResource).script() ;164 *result = downcast<CachedScript>(*cachedResource).script().toString(); 165 165 return true; 166 166 case CachedResource::RawResource: { -
trunk/Source/WebCore/loader/cache/CachedResource.cpp
r192995 r194017 788 788 return; 789 789 790 m_data->tryReplaceContentsWithPlatformBuffer(newBuffer); 791 } 792 793 #endif 794 795 } 790 if (m_data->tryReplaceContentsWithPlatformBuffer(newBuffer)) { 791 didReplaceSharedBufferContents(); 792 // FIXME: Should we call checkNotify() here to move already-decoded images to the new data source? 793 } 794 } 795 796 #endif 797 798 } -
trunk/Source/WebCore/loader/cache/CachedResource.h
r188468 r194017 268 268 void didAccessDecodedData(double timeStamp); 269 269 270 virtual void didReplaceSharedBufferContents() { } 271 270 272 // FIXME: Make the rest of these data members private and use functions in derived classes instead. 271 273 HashCountedSet<CachedResourceClient*> m_clients; -
trunk/Source/WebCore/loader/cache/CachedScript.cpp
r185057 r194017 70 70 } 71 71 72 const String& CachedScript::script() 72 static bool encodingMayBeAllASCII(const String& encoding) 73 { 74 return encoding == "UTF-8" || encoding == "ISO-8859-1" || encoding == "ASCII"; 75 } 76 77 StringView CachedScript::script() 73 78 { 74 79 if (!m_script && m_data) { 80 if (m_ASCIIOptimizationState == Unknown 81 && encodingMayBeAllASCII(encoding()) 82 && m_data->size() 83 && charactersAreAllASCII(reinterpret_cast<const LChar*>(m_data->data()), m_data->size())) { 84 85 m_script = StringImpl::createWithoutCopying(reinterpret_cast<const LChar*>(m_data->data()), m_data->size()); 86 m_ASCIIOptimizationState = DataAndDecodedStringHaveSameBytes; 87 88 // If the encoded and decoded data are the same, there is no decoded data cost! 89 setDecodedSize(0); 90 m_decodedDataDeletionTimer.stop(); 91 return m_script; 92 } 75 93 m_script = m_decoder->decodeAndFlush(m_data->data(), encodedSize()); 94 m_ASCIIOptimizationState = DataAndDecodedStringHaveDifferentBytes; 76 95 setDecodedSize(m_script.sizeInBytes()); 77 96 } 78 m_decodedDataDeletionTimer.restart(); 97 if (m_ASCIIOptimizationState == DataAndDecodedStringHaveDifferentBytes) 98 m_decodedDataDeletionTimer.restart(); 79 99 return m_script; 100 } 101 102 unsigned CachedScript::scriptHash() 103 { 104 script(); 105 return m_script.impl()->hash(); 106 } 107 108 void CachedScript::didReplaceSharedBufferContents() 109 { 110 // We receive this callback when the CachedResource's internal SharedBuffer has had its contents 111 // replaced by the memory-mapping-of-file-backed-resources optimization. If m_script is just a 112 // non-copying wrapper around the old SharedBuffer contents, we have to retarget it. 113 if (m_ASCIIOptimizationState == DataAndDecodedStringHaveSameBytes) 114 m_script = StringImpl::createWithoutCopying(reinterpret_cast<const LChar*>(m_data->data()), m_data->size()); 115 CachedResource::didReplaceSharedBufferContents(); 80 116 } 81 117 -
trunk/Source/WebCore/loader/cache/CachedScript.h
r175549 r194017 38 38 virtual ~CachedScript(); 39 39 40 const String& script(); 40 StringView script(); 41 unsigned scriptHash(); 41 42 42 43 String mimeType() const; … … 45 46 bool mimeTypeAllowedByNosniff() const; 46 47 #endif 48 49 void didReplaceSharedBufferContents() override; 47 50 48 51 private: … … 58 61 59 62 String m_script; 63 64 enum ASCIIResourceOptimizationState { Unknown, DataAndDecodedStringHaveSameBytes, DataAndDecodedStringHaveDifferentBytes }; 65 ASCIIResourceOptimizationState m_ASCIIOptimizationState { Unknown }; 66 60 67 RefPtr<TextResourceDecoder> m_decoder; 61 68 }; -
trunk/Source/WebCore/platform/SharedBuffer.h
r185273 r194017 120 120 WEBCORE_EXPORT unsigned getSomeData(const char*& data, unsigned position = 0) const; 121 121 122 voidtryReplaceContentsWithPlatformBuffer(SharedBuffer&);122 bool tryReplaceContentsWithPlatformBuffer(SharedBuffer&); 123 123 WEBCORE_EXPORT bool hasPlatformData() const; 124 124 -
trunk/Source/WebCore/platform/cf/SharedBufferCF.cpp
r185273 r194017 93 93 } 94 94 95 voidSharedBuffer::tryReplaceContentsWithPlatformBuffer(SharedBuffer& newContents)95 bool SharedBuffer::tryReplaceContentsWithPlatformBuffer(SharedBuffer& newContents) 96 96 { 97 97 if (!newContents.m_cfData) 98 return ;98 return false; 99 99 100 100 clear(); 101 101 m_cfData = newContents.m_cfData; 102 return true; 102 103 } 103 104 -
trunk/Source/WebCore/platform/soup/SharedBufferSoup.cpp
r184620 r194017 79 79 } 80 80 81 voidSharedBuffer::tryReplaceContentsWithPlatformBuffer(SharedBuffer& newContents)81 bool SharedBuffer::tryReplaceContentsWithPlatformBuffer(SharedBuffer& newContents) 82 82 { 83 83 if (!newContents.hasPlatformData()) 84 return ;84 return false; 85 85 86 86 clear(); 87 87 // FIXME: Use GRefPtr instead of GUniquePtr for the SoupBuffer. 88 88 m_soupBuffer.swap(newContents.m_soupBuffer); 89 return true; 89 90 } 90 91 -
trunk/Source/WebKit/mac/WebView/WebScriptDebugger.mm
r191887 r194017 52 52 static NSString *toNSString(SourceProvider* sourceProvider) 53 53 { 54 const String& sourceString = sourceProvider->source() ;54 const String& sourceString = sourceProvider->source().toString(); 55 55 if (sourceString.isEmpty()) 56 56 return nil;
Note: See TracChangeset
for help on using the changeset viewer.