| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2009 Google Inc. All rights reserved. | 2 * Copyright (C) 2009 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
| 8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
| 9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
| 10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
| (...skipping 135 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 146 v8::ScriptCompiler::CachedData* cachedData = new v8::ScriptCompiler::CachedD
ata( | 146 v8::ScriptCompiler::CachedData* cachedData = new v8::ScriptCompiler::CachedD
ata( |
| 147 reinterpret_cast<const uint8_t*>(data), length, v8::ScriptCompiler::Cach
edData::BufferNotOwned); | 147 reinterpret_cast<const uint8_t*>(data), length, v8::ScriptCompiler::Cach
edData::BufferNotOwned); |
| 148 v8::ScriptCompiler::Source source(code, origin, cachedData); | 148 v8::ScriptCompiler::Source source(code, origin, cachedData); |
| 149 v8::MaybeLocal<v8::Script> script = v8::ScriptCompiler::Compile(isolate->Get
CurrentContext(), &source, compileOptions); | 149 v8::MaybeLocal<v8::Script> script = v8::ScriptCompiler::Compile(isolate->Get
CurrentContext(), &source, compileOptions); |
| 150 if (cachedData->rejected) | 150 if (cachedData->rejected) |
| 151 cacheHandler->clearCachedMetadata(CachedMetadataHandler::SendToPlatform)
; | 151 cacheHandler->clearCachedMetadata(CachedMetadataHandler::SendToPlatform)
; |
| 152 return script; | 152 return script; |
| 153 } | 153 } |
| 154 | 154 |
| 155 // Compile a script, and produce a V8 cache for future use. | 155 // Compile a script, and produce a V8 cache for future use. |
| 156 v8::MaybeLocal<v8::Script> compileAndProduceCache(CachedMetadataHandler* cacheHa
ndler, unsigned tag, v8::ScriptCompiler::CompileOptions compileOptions, CachedMe
tadataHandler::CacheType cacheType, v8::Isolate* isolate, v8::Local<v8::String>
code, v8::ScriptOrigin origin) | 156 v8::MaybeLocal<v8::Script> compileAndProduceCache(CachedMetadataHandler* cacheHa
ndler, uint32_t tag, v8::ScriptCompiler::CompileOptions compileOptions, CachedMe
tadataHandler::CacheType cacheType, v8::Isolate* isolate, v8::Local<v8::String>
code, v8::ScriptOrigin origin) |
| 157 { | 157 { |
| 158 V8CompileHistogram histogramScope(V8CompileHistogram::Cacheable); | 158 V8CompileHistogram histogramScope(V8CompileHistogram::Cacheable); |
| 159 v8::ScriptCompiler::Source source(code, origin); | 159 v8::ScriptCompiler::Source source(code, origin); |
| 160 v8::MaybeLocal<v8::Script> script = v8::ScriptCompiler::Compile(isolate->Get
CurrentContext(), &source, compileOptions); | 160 v8::MaybeLocal<v8::Script> script = v8::ScriptCompiler::Compile(isolate->Get
CurrentContext(), &source, compileOptions); |
| 161 const v8::ScriptCompiler::CachedData* cachedData = source.GetCachedData(); | 161 const v8::ScriptCompiler::CachedData* cachedData = source.GetCachedData(); |
| 162 if (cachedData) { | 162 if (cachedData) { |
| 163 const char* data = reinterpret_cast<const char*>(cachedData->data); | 163 const char* data = reinterpret_cast<const char*>(cachedData->data); |
| 164 int length = cachedData->length; | 164 int length = cachedData->length; |
| 165 if (length > 1024) { | 165 if (length > 1024) { |
| 166 // Omit histogram samples for small cache data to avoid outliers. | 166 // Omit histogram samples for small cache data to avoid outliers. |
| 167 int cacheSizeRatio = static_cast<int>(100.0 * length / code->Length(
)); | 167 int cacheSizeRatio = static_cast<int>(100.0 * length / code->Length(
)); |
| 168 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, codeCacheSizeH
istogram, new CustomCountHistogram("V8.CodeCacheSizeRatio", 0, 10000, 50)); | 168 DEFINE_THREAD_SAFE_STATIC_LOCAL(CustomCountHistogram, codeCacheSizeH
istogram, new CustomCountHistogram("V8.CodeCacheSizeRatio", 0, 10000, 50)); |
| 169 codeCacheSizeHistogram.count(cacheSizeRatio); | 169 codeCacheSizeHistogram.count(cacheSizeRatio); |
| 170 } | 170 } |
| 171 cacheHandler->clearCachedMetadata(CachedMetadataHandler::CacheLocally); | 171 cacheHandler->clearCachedMetadata(CachedMetadataHandler::CacheLocally); |
| 172 cacheHandler->setCachedMetadata(tag, data, length, cacheType); | 172 cacheHandler->setCachedMetadata(tag, data, length, cacheType); |
| 173 } | 173 } |
| 174 return script; | 174 return script; |
| 175 } | 175 } |
| 176 | 176 |
| 177 // Compile a script, and consume or produce a V8 Cache, depending on whether the | 177 // Compile a script, and consume or produce a V8 Cache, depending on whether the |
| 178 // given resource already has cached data available. | 178 // given resource already has cached data available. |
| 179 v8::MaybeLocal<v8::Script> compileAndConsumeOrProduce(CachedMetadataHandler* cac
heHandler, unsigned tag, v8::ScriptCompiler::CompileOptions consumeOptions, v8::
ScriptCompiler::CompileOptions produceOptions, CachedMetadataHandler::CacheType
cacheType, v8::Isolate* isolate, v8::Local<v8::String> code, v8::ScriptOrigin or
igin) | 179 v8::MaybeLocal<v8::Script> compileAndConsumeOrProduce(CachedMetadataHandler* cac
heHandler, uint32_t tag, v8::ScriptCompiler::CompileOptions consumeOptions, v8::
ScriptCompiler::CompileOptions produceOptions, CachedMetadataHandler::CacheType
cacheType, v8::Isolate* isolate, v8::Local<v8::String> code, v8::ScriptOrigin or
igin) |
| 180 { | 180 { |
| 181 RefPtr<CachedMetadata> codeCache(cacheHandler->cachedMetadata(tag)); | 181 RefPtr<CachedMetadata> codeCache(cacheHandler->cachedMetadata(tag)); |
| 182 return codeCache.get() | 182 return codeCache.get() |
| 183 ? compileAndConsumeCache(cacheHandler, codeCache, consumeOptions, isolat
e, code, origin) | 183 ? compileAndConsumeCache(cacheHandler, codeCache, consumeOptions, isolat
e, code, origin) |
| 184 : compileAndProduceCache(cacheHandler, tag, produceOptions, cacheType, i
solate, code, origin); | 184 : compileAndProduceCache(cacheHandler, tag, produceOptions, cacheType, i
solate, code, origin); |
| 185 } | 185 } |
| 186 | 186 |
| 187 enum CacheTagKind { | 187 enum CacheTagKind { |
| 188 CacheTagParser = 0, | 188 CacheTagParser = 0, |
| 189 CacheTagCode = 1, | 189 CacheTagCode = 1, |
| 190 CacheTagTimeStamp = 3, | 190 CacheTagTimeStamp = 3, |
| 191 CacheTagLast | 191 CacheTagLast |
| 192 }; | 192 }; |
| 193 | 193 |
| 194 static const int kCacheTagKindSize = 2; | 194 static const int kCacheTagKindSize = 2; |
| 195 | 195 |
| 196 unsigned cacheTag(CacheTagKind kind, CachedMetadataHandler* cacheHandler) | 196 uint32_t cacheTag(CacheTagKind kind, CachedMetadataHandler* cacheHandler) |
| 197 { | 197 { |
| 198 static_assert((1 << kCacheTagKindSize) >= CacheTagLast, "CacheTagLast must b
e large enough"); | 198 static_assert((1 << kCacheTagKindSize) >= CacheTagLast, "CacheTagLast must b
e large enough"); |
| 199 | 199 |
| 200 static unsigned v8CacheDataVersion = v8::ScriptCompiler::CachedDataVersionTa
g() << kCacheTagKindSize; | 200 static uint32_t v8CacheDataVersion = v8::ScriptCompiler::CachedDataVersionTa
g() << kCacheTagKindSize; |
| 201 | 201 |
| 202 // A script can be (successfully) interpreted with different encodings, | 202 // A script can be (successfully) interpreted with different encodings, |
| 203 // depending on the page it appears in. The cache doesn't know anything | 203 // depending on the page it appears in. The cache doesn't know anything |
| 204 // about encodings, but the cached data is specific to one encoding. If we | 204 // about encodings, but the cached data is specific to one encoding. If we |
| 205 // later load the script from the cache and interpret it with a different | 205 // later load the script from the cache and interpret it with a different |
| 206 // encoding, the cached data is not valid for that encoding. | 206 // encoding, the cached data is not valid for that encoding. |
| 207 return (v8CacheDataVersion | kind) + StringHash::hash(cacheHandler->encoding
()); | 207 return (v8CacheDataVersion | kind) + StringHash::hash(cacheHandler->encoding
()); |
| 208 } | 208 } |
| 209 | 209 |
| 210 // Check previously stored timestamp. | 210 // Check previously stored timestamp. |
| 211 bool isResourceHotForCaching(CachedMetadataHandler* cacheHandler, int hotHours) | 211 bool isResourceHotForCaching(CachedMetadataHandler* cacheHandler, int hotHours) |
| 212 { | 212 { |
| 213 const double cacheWithinSeconds = hotHours * 60 * 60; | 213 const double cacheWithinSeconds = hotHours * 60 * 60; |
| 214 unsigned tag = cacheTag(CacheTagTimeStamp, cacheHandler); | 214 uint32_t tag = cacheTag(CacheTagTimeStamp, cacheHandler); |
| 215 RefPtr<CachedMetadata> cachedMetadata = cacheHandler->cachedMetadata(tag); | 215 RefPtr<CachedMetadata> cachedMetadata = cacheHandler->cachedMetadata(tag); |
| 216 if (!cachedMetadata) | 216 if (!cachedMetadata) |
| 217 return false; | 217 return false; |
| 218 double timeStamp; | 218 double timeStamp; |
| 219 const int size = sizeof(timeStamp); | 219 const int size = sizeof(timeStamp); |
| 220 ASSERT(cachedMetadata->size() == size); | 220 ASSERT(cachedMetadata->size() == size); |
| 221 memcpy(&timeStamp, cachedMetadata->data(), size); | 221 memcpy(&timeStamp, cachedMetadata->data(), size); |
| 222 return (WTF::currentTime() - timeStamp) < cacheWithinSeconds; | 222 return (WTF::currentTime() - timeStamp) < cacheWithinSeconds; |
| 223 } | 223 } |
| 224 | 224 |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 304 case V8CacheOptionsCode: | 304 case V8CacheOptionsCode: |
| 305 case V8CacheOptionsAlways: { | 305 case V8CacheOptionsAlways: { |
| 306 // Use code caching for recently seen resources. | 306 // Use code caching for recently seen resources. |
| 307 // Use compression depending on the cache option. | 307 // Use compression depending on the cache option. |
| 308 if (codeCache) | 308 if (codeCache) |
| 309 return bind(compileAndConsumeCache, wrapPersistent(cacheHandler), co
deCache, v8::ScriptCompiler::kConsumeCodeCache); | 309 return bind(compileAndConsumeCache, wrapPersistent(cacheHandler), co
deCache, v8::ScriptCompiler::kConsumeCodeCache); |
| 310 if (cacheOptions != V8CacheOptionsAlways && !isResourceHotForCaching(cac
heHandler, hotHours)) { | 310 if (cacheOptions != V8CacheOptionsAlways && !isResourceHotForCaching(cac
heHandler, hotHours)) { |
| 311 V8ScriptRunner::setCacheTimeStamp(cacheHandler); | 311 V8ScriptRunner::setCacheTimeStamp(cacheHandler); |
| 312 return bind(compileWithoutOptions, V8CompileHistogram::Cacheable); | 312 return bind(compileWithoutOptions, V8CompileHistogram::Cacheable); |
| 313 } | 313 } |
| 314 unsigned codeCacheTag = cacheTag(CacheTagCode, cacheHandler); | 314 uint32_t codeCacheTag = cacheTag(CacheTagCode, cacheHandler); |
| 315 return bind(compileAndProduceCache, wrapPersistent(cacheHandler), codeCa
cheTag, v8::ScriptCompiler::kProduceCodeCache, CachedMetadataHandler::SendToPlat
form); | 315 return bind(compileAndProduceCache, wrapPersistent(cacheHandler), codeCa
cheTag, v8::ScriptCompiler::kProduceCodeCache, CachedMetadataHandler::SendToPlat
form); |
| 316 break; | 316 break; |
| 317 } | 317 } |
| 318 | 318 |
| 319 case V8CacheOptionsNone: | 319 case V8CacheOptionsNone: |
| 320 // Shouldn't happen, as this is handled above. | 320 // Shouldn't happen, as this is handled above. |
| 321 // Case is here so that compiler can check all cases are handled. | 321 // Case is here so that compiler can check all cases are handled. |
| 322 ASSERT_NOT_REACHED(); | 322 ASSERT_NOT_REACHED(); |
| 323 break; | 323 break; |
| 324 } | 324 } |
| (...skipping 237 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 562 if (ScriptForbiddenScope::isScriptForbidden()) { | 562 if (ScriptForbiddenScope::isScriptForbidden()) { |
| 563 throwScriptForbiddenException(isolate); | 563 throwScriptForbiddenException(isolate); |
| 564 return v8::MaybeLocal<v8::Object>(); | 564 return v8::MaybeLocal<v8::Object>(); |
| 565 } | 565 } |
| 566 v8::MicrotasksScope microtasksScope(isolate, v8::MicrotasksScope::kRunMicrot
asks); | 566 v8::MicrotasksScope microtasksScope(isolate, v8::MicrotasksScope::kRunMicrot
asks); |
| 567 v8::MaybeLocal<v8::Object> result = function->NewInstance(isolate->GetCurren
tContext(), argc, argv); | 567 v8::MaybeLocal<v8::Object> result = function->NewInstance(isolate->GetCurren
tContext(), argc, argv); |
| 568 crashIfIsolateIsDead(isolate); | 568 crashIfIsolateIsDead(isolate); |
| 569 return result; | 569 return result; |
| 570 } | 570 } |
| 571 | 571 |
| 572 unsigned V8ScriptRunner::tagForParserCache(CachedMetadataHandler* cacheHandler) | 572 uint32_t V8ScriptRunner::tagForParserCache(CachedMetadataHandler* cacheHandler) |
| 573 { | 573 { |
| 574 return cacheTag(CacheTagParser, cacheHandler); | 574 return cacheTag(CacheTagParser, cacheHandler); |
| 575 } | 575 } |
| 576 | 576 |
| 577 unsigned V8ScriptRunner::tagForCodeCache(CachedMetadataHandler* cacheHandler) | 577 uint32_t V8ScriptRunner::tagForCodeCache(CachedMetadataHandler* cacheHandler) |
| 578 { | 578 { |
| 579 return cacheTag(CacheTagCode, cacheHandler); | 579 return cacheTag(CacheTagCode, cacheHandler); |
| 580 } | 580 } |
| 581 | 581 |
| 582 // Store a timestamp to the cache as hint. | 582 // Store a timestamp to the cache as hint. |
| 583 void V8ScriptRunner::setCacheTimeStamp(CachedMetadataHandler* cacheHandler) | 583 void V8ScriptRunner::setCacheTimeStamp(CachedMetadataHandler* cacheHandler) |
| 584 { | 584 { |
| 585 double now = WTF::currentTime(); | 585 double now = WTF::currentTime(); |
| 586 unsigned tag = cacheTag(CacheTagTimeStamp, cacheHandler); | 586 uint32_t tag = cacheTag(CacheTagTimeStamp, cacheHandler); |
| 587 cacheHandler->clearCachedMetadata(CachedMetadataHandler::CacheLocally); | 587 cacheHandler->clearCachedMetadata(CachedMetadataHandler::CacheLocally); |
| 588 cacheHandler->setCachedMetadata(tag, reinterpret_cast<char*>(&now), sizeof(n
ow), CachedMetadataHandler::SendToPlatform); | 588 cacheHandler->setCachedMetadata(tag, reinterpret_cast<char*>(&now), sizeof(n
ow), CachedMetadataHandler::SendToPlatform); |
| 589 } | 589 } |
| 590 | 590 |
| 591 void V8ScriptRunner::throwException(v8::Isolate* isolate, v8::Local<v8::Value> e
xception, const v8::ScriptOrigin& origin) | 591 void V8ScriptRunner::throwException(v8::Isolate* isolate, v8::Local<v8::Value> e
xception, const v8::ScriptOrigin& origin) |
| 592 { | 592 { |
| 593 // In order for the current TryCatch to catch this exception and | 593 // In order for the current TryCatch to catch this exception and |
| 594 // call MessageCallback when SetVerbose(true), create a v8::Function | 594 // call MessageCallback when SetVerbose(true), create a v8::Function |
| 595 // that calls isolate->throwException(). | 595 // that calls isolate->throwException(). |
| 596 // Unlike throwStackOverflowExceptionIfNeeded(), create a temporary Script | 596 // Unlike throwStackOverflowExceptionIfNeeded(), create a temporary Script |
| 597 // with the specified ScriptOrigin. When the exception was created but not | 597 // with the specified ScriptOrigin. When the exception was created but not |
| 598 // thrown yet, the ScriptOrigin of the thrower is set to the exception. | 598 // thrown yet, the ScriptOrigin of the thrower is set to the exception. |
| 599 // v8::Function::New() has empty ScriptOrigin, and thus the exception will | 599 // v8::Function::New() has empty ScriptOrigin, and thus the exception will |
| 600 // be "muted" (sanitized in our terminology) if CORS does not allow. | 600 // be "muted" (sanitized in our terminology) if CORS does not allow. |
| 601 // https://html.spec.whatwg.org/multipage/webappapis.html#report-the-error | 601 // https://html.spec.whatwg.org/multipage/webappapis.html#report-the-error |
| 602 // Avoid compile and run scripts when API is available: crbug.com/639739 | 602 // Avoid compile and run scripts when API is available: crbug.com/639739 |
| 603 v8::Local<v8::Script> script = compileWithoutOptions( | 603 v8::Local<v8::Script> script = compileWithoutOptions( |
| 604 V8CompileHistogram::Cacheability::Noncacheable, isolate, | 604 V8CompileHistogram::Cacheability::Noncacheable, isolate, |
| 605 v8AtomicString(isolate, "((e) => { throw e; })"), origin) | 605 v8AtomicString(isolate, "((e) => { throw e; })"), origin) |
| 606 .ToLocalChecked(); | 606 .ToLocalChecked(); |
| 607 v8::Local<v8::Function> thrower = runCompiledInternalScript(isolate, script) | 607 v8::Local<v8::Function> thrower = runCompiledInternalScript(isolate, script) |
| 608 .ToLocalChecked().As<v8::Function>(); | 608 .ToLocalChecked().As<v8::Function>(); |
| 609 v8::Local<v8::Value> args[] = { exception }; | 609 v8::Local<v8::Value> args[] = { exception }; |
| 610 callInternalFunction(thrower, thrower, WTF_ARRAY_LENGTH(args), args, isolate
); | 610 callInternalFunction(thrower, thrower, WTF_ARRAY_LENGTH(args), args, isolate
); |
| 611 } | 611 } |
| 612 | 612 |
| 613 } // namespace blink | 613 } // namespace blink |
| OLD | NEW |