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 19 matching lines...) Expand all Loading... |
30 #include "bindings/core/v8/ScriptStreamer.h" | 30 #include "bindings/core/v8/ScriptStreamer.h" |
31 #include "bindings/core/v8/V8Binding.h" | 31 #include "bindings/core/v8/V8Binding.h" |
32 #include "bindings/core/v8/V8GCController.h" | 32 #include "bindings/core/v8/V8GCController.h" |
33 #include "bindings/core/v8/V8RecursionScope.h" | 33 #include "bindings/core/v8/V8RecursionScope.h" |
34 #include "bindings/core/v8/V8ThrowException.h" | 34 #include "bindings/core/v8/V8ThrowException.h" |
35 #include "core/dom/ExecutionContext.h" | 35 #include "core/dom/ExecutionContext.h" |
36 #include "core/fetch/CachedMetadata.h" | 36 #include "core/fetch/CachedMetadata.h" |
37 #include "core/fetch/ScriptResource.h" | 37 #include "core/fetch/ScriptResource.h" |
38 #include "platform/ScriptForbiddenScope.h" | 38 #include "platform/ScriptForbiddenScope.h" |
39 #include "platform/TraceEvent.h" | 39 #include "platform/TraceEvent.h" |
40 #include "third_party/snappy/src/snappy.h" | |
41 | 40 |
42 namespace blink { | 41 namespace blink { |
43 | 42 |
44 namespace { | 43 namespace { |
45 | 44 |
46 // In order to make sure all pending messages to be processed in | 45 // In order to make sure all pending messages to be processed in |
47 // v8::Function::Call, we don't call handleMaxRecursionDepthExceeded | 46 // v8::Function::Call, we don't call handleMaxRecursionDepthExceeded |
48 // directly. Instead, we create a v8::Function of | 47 // directly. Instead, we create a v8::Function of |
49 // throwStackOverflowException and call it. | 48 // throwStackOverflowException and call it. |
50 void throwStackOverflowException(const v8::FunctionCallbackInfo<v8::Value>& info
) | 49 void throwStackOverflowException(const v8::FunctionCallbackInfo<v8::Value>& info
) |
51 { | 50 { |
52 V8ThrowException::throwRangeError(info.GetIsolate(), "Maximum call stack siz
e exceeded."); | 51 V8ThrowException::throwRangeError(info.GetIsolate(), "Maximum call stack siz
e exceeded."); |
53 } | 52 } |
54 | 53 |
55 v8::Local<v8::Value> throwStackOverflowExceptionIfNeeded(v8::Isolate* isolate) | 54 v8::Local<v8::Value> throwStackOverflowExceptionIfNeeded(v8::Isolate* isolate) |
56 { | 55 { |
57 if (V8PerIsolateData::from(isolate)->isHandlingRecursionLevelError()) { | 56 if (V8PerIsolateData::from(isolate)->isHandlingRecursionLevelError()) { |
58 // If we are already handling a recursion level error, we should | 57 // If we are already handling a recursion level error, we should |
59 // not invoke v8::Function::Call. | 58 // not invoke v8::Function::Call. |
60 return v8::Undefined(isolate); | 59 return v8::Undefined(isolate); |
61 } | 60 } |
62 V8PerIsolateData::from(isolate)->setIsHandlingRecursionLevelError(true); | 61 V8PerIsolateData::from(isolate)->setIsHandlingRecursionLevelError(true); |
63 v8::Local<v8::Value> result = v8::Function::New(isolate, throwStackOverflowE
xception)->Call(v8::Undefined(isolate), 0, 0); | 62 v8::Local<v8::Value> result = v8::Function::New(isolate, throwStackOverflowE
xception)->Call(v8::Undefined(isolate), 0, 0); |
64 V8PerIsolateData::from(isolate)->setIsHandlingRecursionLevelError(false); | 63 V8PerIsolateData::from(isolate)->setIsHandlingRecursionLevelError(false); |
65 return result; | 64 return result; |
66 } | 65 } |
67 | 66 |
68 void writeToCache(ScriptResource* resource, unsigned cacheTag, Resource::Metadat
aCacheType cacheType, const v8::ScriptCompiler::CachedData* cachedData, bool com
pressed) | 67 v8::Local<v8::Script> compileAndProduceCache(v8::Isolate* isolate, v8::Handle<v8
::String> code, v8::ScriptOrigin origin, ScriptResource* resource, v8::ScriptCom
piler::CompileOptions options, unsigned cacheTag, Resource::MetadataCacheType ca
cheType) |
69 { | |
70 const char* data = reinterpret_cast<const char*>(cachedData->data); | |
71 int length = cachedData->length; | |
72 std::string compressedOutput; | |
73 if (compressed) { | |
74 snappy::Compress(data, length, &compressedOutput); | |
75 data = compressedOutput.data(); | |
76 length = compressedOutput.length(); | |
77 } | |
78 resource->clearCachedMetadata(); | |
79 resource->setCachedMetadata( | |
80 cacheTag, | |
81 data, | |
82 length, | |
83 cacheType); | |
84 } | |
85 | |
86 v8::Local<v8::Script> compileAndProduceCache(v8::Isolate* isolate, v8::Handle<v8
::String> code, v8::ScriptOrigin origin, ScriptResource* resource, v8::ScriptCom
piler::CompileOptions options, unsigned cacheTag, Resource::MetadataCacheType ca
cheType, bool compressed) | |
87 { | 68 { |
88 v8::ScriptCompiler::Source source(code, origin); | 69 v8::ScriptCompiler::Source source(code, origin); |
89 v8::Local<v8::Script> script = v8::ScriptCompiler::Compile(isolate, &source,
options); | 70 v8::Local<v8::Script> script = v8::ScriptCompiler::Compile(isolate, &source,
options); |
90 const v8::ScriptCompiler::CachedData* cachedData = source.GetCachedData(); | 71 const v8::ScriptCompiler::CachedData* cachedData = source.GetCachedData(); |
91 if (resource && cachedData) | 72 if (resource && cachedData) { |
92 writeToCache(resource, cacheTag, cacheType, cachedData, compressed); | 73 resource->clearCachedMetadata(); |
| 74 resource->setCachedMetadata( |
| 75 cacheTag, |
| 76 reinterpret_cast<const char*>(cachedData->data), |
| 77 cachedData->length, |
| 78 cacheType); |
| 79 } |
93 return script; | 80 return script; |
94 } | 81 } |
95 | 82 |
96 v8::Local<v8::Script> compileAndConsumeCache(v8::Isolate* isolate, v8::Handle<v8
::String> code, v8::ScriptOrigin origin, ScriptResource* resource, v8::ScriptCom
piler::CompileOptions options, unsigned cacheTag, bool compressed) | 83 v8::Local<v8::Script> compileAndConsumeCache(v8::Isolate* isolate, v8::Handle<v8
::String> code, v8::ScriptOrigin origin, ScriptResource* resource, v8::ScriptCom
piler::CompileOptions options, unsigned cacheTag) |
97 { | 84 { |
98 // Consume existing cache data: | 85 // Consume existing cache data: |
99 CachedMetadata* cachedMetadata = resource->cachedMetadata(cacheTag); | 86 CachedMetadata* cachedMetadata = resource->cachedMetadata(cacheTag); |
100 const char* data = cachedMetadata->data(); | |
101 int length = cachedMetadata->size(); | |
102 std::string uncompressedOutput; | |
103 if (compressed) { | |
104 snappy::Uncompress(data, length, &uncompressedOutput); | |
105 data = uncompressedOutput.data(); | |
106 length = uncompressedOutput.length(); | |
107 } | |
108 v8::ScriptCompiler::CachedData* cachedData = new v8::ScriptCompiler::CachedD
ata( | 87 v8::ScriptCompiler::CachedData* cachedData = new v8::ScriptCompiler::CachedD
ata( |
109 reinterpret_cast<const uint8_t*>(data), | 88 reinterpret_cast<const uint8_t*>(cachedMetadata->data()), |
110 length, | 89 cachedMetadata->size(), |
111 v8::ScriptCompiler::CachedData::BufferNotOwned); | 90 v8::ScriptCompiler::CachedData::BufferNotOwned); |
112 v8::ScriptCompiler::Source source(code, origin, cachedData); | 91 v8::ScriptCompiler::Source source(code, origin, cachedData); |
113 return v8::ScriptCompiler::Compile(isolate, &source, options); | 92 return v8::ScriptCompiler::Compile(isolate, &source, options); |
114 } | 93 } |
115 | 94 |
116 } // namespace | 95 } // namespace |
117 | 96 |
118 v8::Local<v8::Script> V8ScriptRunner::compileScript(const ScriptSourceCode& sour
ce, v8::Isolate* isolate, AccessControlStatus corsStatus, V8CacheOptions cacheOp
tions) | 97 v8::Local<v8::Script> V8ScriptRunner::compileScript(const ScriptSourceCode& sour
ce, v8::Isolate* isolate, AccessControlStatus corsStatus, V8CacheOptions cacheOp
tions) |
119 { | 98 { |
120 return compileScript(v8String(isolate, source.source()), source.url(), sourc
e.startPosition(), source.resource(), source.streamer(), isolate, corsStatus, ca
cheOptions); | 99 return compileScript(v8String(isolate, source.source()), source.url(), sourc
e.startPosition(), source.resource(), source.streamer(), isolate, corsStatus, ca
cheOptions); |
121 } | 100 } |
122 | 101 |
123 v8::Local<v8::Script> V8ScriptRunner::compileScript(v8::Handle<v8::String> code,
const String& fileName, const TextPosition& scriptStartPosition, ScriptResource
* resource, ScriptStreamer* streamer, v8::Isolate* isolate, AccessControlStatus
corsStatus, V8CacheOptions cacheOptions) | 102 v8::Local<v8::Script> V8ScriptRunner::compileScript(v8::Handle<v8::String> code,
const String& fileName, const TextPosition& scriptStartPosition, ScriptResource
* resource, ScriptStreamer* streamer, v8::Isolate* isolate, AccessControlStatus
corsStatus, V8CacheOptions cacheOptions) |
124 { | 103 { |
125 TRACE_EVENT1("v8", "v8.compile", "fileName", fileName.utf8()); | 104 TRACE_EVENT1("v8", "v8.compile", "fileName", fileName.utf8()); |
126 TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Compile"); | 105 TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Compile"); |
127 | 106 |
128 // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at | 107 // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at |
129 // 1, whereas v8 starts at 0. | 108 // 1, whereas v8 starts at 0. |
130 v8::Handle<v8::String> name = v8String(isolate, fileName); | 109 v8::Handle<v8::String> name = v8String(isolate, fileName); |
131 v8::Handle<v8::Integer> line = v8::Integer::New(isolate, scriptStartPosition
.m_line.zeroBasedInt()); | 110 v8::Handle<v8::Integer> line = v8::Integer::New(isolate, scriptStartPosition
.m_line.zeroBasedInt()); |
132 v8::Handle<v8::Integer> column = v8::Integer::New(isolate, scriptStartPositi
on.m_column.zeroBasedInt()); | 111 v8::Handle<v8::Integer> column = v8::Integer::New(isolate, scriptStartPositi
on.m_column.zeroBasedInt()); |
133 v8::Handle<v8::Boolean> isSharedCrossOrigin = corsStatus == SharableCrossOri
gin ? v8::True(isolate) : v8::False(isolate); | 112 v8::Handle<v8::Boolean> isSharedCrossOrigin = corsStatus == SharableCrossOri
gin ? v8::True(isolate) : v8::False(isolate); |
134 v8::ScriptOrigin origin(name, line, column, isSharedCrossOrigin); | 113 v8::ScriptOrigin origin(name, line, column, isSharedCrossOrigin); |
135 | 114 |
136 v8::Local<v8::Script> script; | 115 v8::Local<v8::Script> script; |
137 unsigned cacheTag = 0; | 116 unsigned cacheTag = 0; |
138 bool compressed = cacheOptions == V8CacheOptionsCodeCompressed; | |
139 if (streamer) { | 117 if (streamer) { |
140 // We don't stream scripts which don't have a Resource. | 118 // We don't stream scripts which don't have a Resource. |
141 ASSERT(resource); | 119 ASSERT(resource); |
142 // Failed resources should never get this far. | 120 // Failed resources should never get this far. |
143 ASSERT(!resource->errorOccurred()); | 121 ASSERT(!resource->errorOccurred()); |
144 ASSERT(streamer->isFinished()); | 122 ASSERT(streamer->isFinished()); |
145 ASSERT(!streamer->streamingSuppressed()); | 123 ASSERT(!streamer->streamingSuppressed()); |
146 script = v8::ScriptCompiler::Compile(isolate, streamer->source(), code,
origin); | 124 script = v8::ScriptCompiler::Compile(isolate, streamer->source(), code,
origin); |
147 // Whether to produce the cached data or not is decided when the | 125 // Whether to produce the cached data or not is decided when the |
148 // streamer is started. Here we only need to get the data out. | 126 // streamer is started. Here we only need to get the data out. |
149 const v8::ScriptCompiler::CachedData* newCachedData = streamer->source()
->GetCachedData(); | 127 const v8::ScriptCompiler::CachedData* newCachedData = streamer->source()
->GetCachedData(); |
150 if (newCachedData) { | 128 if (newCachedData) { |
151 // TODO(yangguo,vogelheim): code cache should use Resource::SendToPl
atform. | 129 resource->clearCachedMetadata(); |
152 writeToCache(resource, streamer->cachedDataType(), Resource::CacheLo
cally, newCachedData, compressed); | 130 resource->setCachedMetadata(streamer->cachedDataType(), reinterpret_
cast<const char*>(newCachedData->data), newCachedData->length, Resource::CacheLo
cally); |
153 } | 131 } |
154 } else if (!resource || !resource->url().protocolIsInHTTPFamily() || code->L
ength() < 1024) { | 132 } else if (!resource || !resource->url().protocolIsInHTTPFamily() || code->L
ength() < 1024) { |
155 v8::ScriptCompiler::Source source(code, origin); | 133 v8::ScriptCompiler::Source source(code, origin); |
156 script = v8::ScriptCompiler::Compile(isolate, &source, v8::ScriptCompile
r::kNoCompileOptions); | 134 script = v8::ScriptCompiler::Compile(isolate, &source, v8::ScriptCompile
r::kNoCompileOptions); |
157 } else { | 135 } else { |
158 Resource::MetadataCacheType cacheType = Resource::CacheLocally; | |
159 v8::ScriptCompiler::CompileOptions consumeOption = v8::ScriptCompiler::k
ConsumeParserCache; | |
160 v8::ScriptCompiler::CompileOptions produceOption = v8::ScriptCompiler::k
ProduceParserCache; | |
161 switch (cacheOptions) { | 136 switch (cacheOptions) { |
162 case V8CacheOptionsOff: | |
163 // Use default. | |
164 cacheTag = tagForParserCache(); | |
165 break; | |
166 case V8CacheOptionsParse: | 137 case V8CacheOptionsParse: |
167 cacheTag = tagForParserCache(); | 138 cacheTag = tagForParserCache(); |
168 cacheType = Resource::SendToPlatform; | 139 script = resource->cachedMetadata(cacheTag) |
169 consumeOption = v8::ScriptCompiler::kConsumeParserCache; | 140 ? compileAndConsumeCache(isolate, code, origin, resource, v8::Sc
riptCompiler::kConsumeParserCache, cacheTag) |
170 produceOption = v8::ScriptCompiler::kProduceParserCache; | 141 : compileAndProduceCache(isolate, code, origin, resource, v8::Sc
riptCompiler::kProduceParserCache, cacheTag, Resource::SendToPlatform); |
171 break; | 142 break; |
172 case V8CacheOptionsCodeCompressed: | |
173 case V8CacheOptionsCode: | 143 case V8CacheOptionsCode: |
174 cacheTag = tagForCodeCache(); | 144 cacheTag = tagForCodeCache(); |
175 cacheType = Resource::SendToPlatform; | 145 script = resource->cachedMetadata(cacheTag) |
176 consumeOption = v8::ScriptCompiler::kConsumeCodeCache; | 146 ? compileAndConsumeCache(isolate, code, origin, resource, v8::Sc
riptCompiler::kConsumeCodeCache, cacheTag) |
177 produceOption = v8::ScriptCompiler::kProduceCodeCache; | 147 : compileAndProduceCache(isolate, code, origin, resource, v8::Sc
riptCompiler::kProduceCodeCache, cacheTag, Resource::SendToPlatform); |
| 148 break; |
| 149 case V8CacheOptionsOff: |
| 150 // Previous behaviour was to always generate an in-memory parser |
| 151 // cache. We emulate this here. |
| 152 // FIXME: Determine whether this should get its own setting, so we |
| 153 // can also have a true 'off'. |
| 154 cacheTag = tagForParserCache(); |
| 155 script = resource->cachedMetadata(cacheTag) |
| 156 ? compileAndConsumeCache(isolate, code, origin, resource, v8::Sc
riptCompiler::kConsumeParserCache, cacheTag) |
| 157 : compileAndProduceCache(isolate, code, origin, resource, v8::Sc
riptCompiler::kProduceParserCache, cacheTag, Resource::CacheLocally); |
178 break; | 158 break; |
179 } | 159 } |
180 script = resource->cachedMetadata(cacheTag) | |
181 ? compileAndConsumeCache(isolate, code, origin, resource, consumeOpt
ion, cacheTag, compressed) | |
182 : compileAndProduceCache(isolate, code, origin, resource, produceOpt
ion, cacheTag, cacheType, compressed); | |
183 } | 160 } |
184 return script; | 161 return script; |
185 } | 162 } |
186 | 163 |
187 v8::Local<v8::Value> V8ScriptRunner::runCompiledScript(v8::Isolate* isolate, v8:
:Handle<v8::Script> script, ExecutionContext* context) | 164 v8::Local<v8::Value> V8ScriptRunner::runCompiledScript(v8::Isolate* isolate, v8:
:Handle<v8::Script> script, ExecutionContext* context) |
188 { | 165 { |
189 if (script.IsEmpty()) | 166 if (script.IsEmpty()) |
190 return v8::Local<v8::Value>(); | 167 return v8::Local<v8::Value>(); |
191 TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Execution"); | 168 TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Execution"); |
192 TRACE_EVENT1("v8", "v8.run", "fileName", TRACE_STR_COPY(*v8::String::Utf8Val
ue(script->GetUnboundScript()->GetScriptName()))); | 169 TRACE_EVENT1("v8", "v8.run", "fileName", TRACE_STR_COPY(*v8::String::Utf8Val
ue(script->GetUnboundScript()->GetScriptName()))); |
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
313 { | 290 { |
314 return StringHash::hash(v8::V8::GetVersion()) * 2; | 291 return StringHash::hash(v8::V8::GetVersion()) * 2; |
315 } | 292 } |
316 | 293 |
317 unsigned V8ScriptRunner::tagForCodeCache() | 294 unsigned V8ScriptRunner::tagForCodeCache() |
318 { | 295 { |
319 return StringHash::hash(v8::V8::GetVersion()) * 2 + 1; | 296 return StringHash::hash(v8::V8::GetVersion()) * 2 + 1; |
320 } | 297 } |
321 | 298 |
322 } // namespace blink | 299 } // namespace blink |
OLD | NEW |