Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / bindings / core / v8 / V8ScriptRunner.cpp
1 /*
2  * Copyright (C) 2009 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "bindings/core/v8/V8ScriptRunner.h"
28
29 #include "bindings/core/v8/ScriptSourceCode.h"
30 #include "bindings/core/v8/ScriptStreamer.h"
31 #include "bindings/core/v8/V8Binding.h"
32 #include "bindings/core/v8/V8GCController.h"
33 #include "bindings/core/v8/V8RecursionScope.h"
34 #include "bindings/core/v8/V8ThrowException.h"
35 #include "core/dom/ExecutionContext.h"
36 #include "core/fetch/CachedMetadata.h"
37 #include "core/fetch/ScriptResource.h"
38 #include "platform/ScriptForbiddenScope.h"
39 #include "platform/TraceEvent.h"
40
41 namespace blink {
42
43 namespace {
44
45 // In order to make sure all pending messages to be processed in
46 // v8::Function::Call, we don't call handleMaxRecursionDepthExceeded
47 // directly. Instead, we create a v8::Function of
48 // throwStackOverflowException and call it.
49 void throwStackOverflowException(const v8::FunctionCallbackInfo<v8::Value>& info)
50 {
51     V8ThrowException::throwRangeError(info.GetIsolate(), "Maximum call stack size exceeded.");
52 }
53
54 v8::Local<v8::Value> throwStackOverflowExceptionIfNeeded(v8::Isolate* isolate)
55 {
56     if (V8PerIsolateData::from(isolate)->isHandlingRecursionLevelError()) {
57         // If we are already handling a recursion level error, we should
58         // not invoke v8::Function::Call.
59         return v8::Undefined(isolate);
60     }
61     V8PerIsolateData::from(isolate)->setIsHandlingRecursionLevelError(true);
62     v8::Local<v8::Value> result = v8::Function::New(isolate, throwStackOverflowException)->Call(v8::Undefined(isolate), 0, 0);
63     V8PerIsolateData::from(isolate)->setIsHandlingRecursionLevelError(false);
64     return result;
65 }
66
67 v8::Local<v8::Script> compileAndProduceCache(v8::Isolate* isolate, v8::Handle<v8::String> code, v8::ScriptOrigin origin, ScriptResource* resource, v8::ScriptCompiler::CompileOptions options, unsigned cacheTag, Resource::MetadataCacheType cacheType)
68 {
69     v8::ScriptCompiler::Source source(code, origin);
70     v8::Local<v8::Script> script = v8::ScriptCompiler::Compile(isolate, &source, options);
71     const v8::ScriptCompiler::CachedData* cachedData = source.GetCachedData();
72     if (resource && cachedData) {
73         resource->clearCachedMetadata();
74         resource->setCachedMetadata(
75             cacheTag,
76             reinterpret_cast<const char*>(cachedData->data),
77             cachedData->length,
78             cacheType);
79     }
80     return script;
81 }
82
83 v8::Local<v8::Script> compileAndConsumeCache(v8::Isolate* isolate, v8::Handle<v8::String> code, v8::ScriptOrigin origin, ScriptResource* resource, v8::ScriptCompiler::CompileOptions options, unsigned cacheTag)
84 {
85     // Consume existing cache data:
86     CachedMetadata* cachedMetadata = resource->cachedMetadata(cacheTag);
87     v8::ScriptCompiler::CachedData* cachedData = new v8::ScriptCompiler::CachedData(
88         reinterpret_cast<const uint8_t*>(cachedMetadata->data()),
89         cachedMetadata->size(),
90         v8::ScriptCompiler::CachedData::BufferNotOwned);
91     v8::ScriptCompiler::Source source(code, origin, cachedData);
92     return v8::ScriptCompiler::Compile(isolate, &source, options);
93 }
94
95 } // namespace
96
97 v8::Local<v8::Script> V8ScriptRunner::compileScript(const ScriptSourceCode& source, v8::Isolate* isolate, AccessControlStatus corsStatus, V8CacheOptions cacheOptions)
98 {
99     return compileScript(v8String(isolate, source.source()), source.url(), source.startPosition(), source.resource(), source.streamer(), isolate, corsStatus, cacheOptions);
100 }
101
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)
103 {
104     TRACE_EVENT1("v8", "v8.compile", "fileName", fileName.utf8());
105     TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Compile");
106
107     // NOTE: For compatibility with WebCore, ScriptSourceCode's line starts at
108     // 1, whereas v8 starts at 0.
109     v8::Handle<v8::String> name = v8String(isolate, fileName);
110     v8::Handle<v8::Integer> line = v8::Integer::New(isolate, scriptStartPosition.m_line.zeroBasedInt());
111     v8::Handle<v8::Integer> column = v8::Integer::New(isolate, scriptStartPosition.m_column.zeroBasedInt());
112     v8::Handle<v8::Boolean> isSharedCrossOrigin = corsStatus == SharableCrossOrigin ? v8::True(isolate) : v8::False(isolate);
113     v8::ScriptOrigin origin(name, line, column, isSharedCrossOrigin);
114
115     v8::Local<v8::Script> script;
116     unsigned cacheTag = 0;
117     if (streamer) {
118         // We don't stream scripts which don't have a Resource.
119         ASSERT(resource);
120         // Failed resources should never get this far.
121         ASSERT(!resource->errorOccurred());
122         ASSERT(streamer->isFinished());
123         ASSERT(!streamer->streamingSuppressed());
124         script = v8::ScriptCompiler::Compile(isolate, streamer->source(), code, origin);
125         // Whether to produce the cached data or not is decided when the
126         // streamer is started. Here we only need to get the data out.
127         const v8::ScriptCompiler::CachedData* newCachedData = streamer->source()->GetCachedData();
128         if (newCachedData) {
129             resource->clearCachedMetadata();
130             // Temporarily disable cached metadata for streaming; it's
131             // producing broken data. FIXME: enable it again.
132             // resource->setCachedMetadata(streamer->cachedDataType(), reinterpret_cast<const char*>(newCachedData->data), newCachedData->length);
133         }
134     } else if (!resource || !resource->url().protocolIsInHTTPFamily() || code->Length() < 1024) {
135         v8::ScriptCompiler::Source source(code, origin);
136         script = v8::ScriptCompiler::Compile(isolate, &source, v8::ScriptCompiler::kNoCompileOptions);
137     } else {
138         switch (cacheOptions) {
139         case V8CacheOptionsParse:
140             cacheTag = tagForParserCache();
141             script = resource->cachedMetadata(cacheTag)
142                 ? compileAndConsumeCache(isolate, code, origin, resource, v8::ScriptCompiler::kConsumeParserCache, cacheTag)
143                 : compileAndProduceCache(isolate, code, origin, resource, v8::ScriptCompiler::kProduceParserCache, cacheTag, Resource::SendToPlatform);
144             break;
145         case V8CacheOptionsCode:
146             cacheTag = tagForCodeCache();
147             script = resource->cachedMetadata(cacheTag)
148                 ? compileAndConsumeCache(isolate, code, origin, resource, v8::ScriptCompiler::kConsumeCodeCache, cacheTag)
149                 : compileAndProduceCache(isolate, code, origin, resource, v8::ScriptCompiler::kProduceCodeCache, cacheTag, Resource::SendToPlatform);
150             break;
151         case V8CacheOptionsOff:
152             // Previous behaviour was to always generate an in-memory parser
153             // cache. We emulate this here.
154             // FIXME: Determine whether this should get its own setting, so we
155             //        can also have a true 'off'.
156             cacheTag = tagForParserCache();
157             script = resource->cachedMetadata(cacheTag)
158                 ? compileAndConsumeCache(isolate, code, origin, resource, v8::ScriptCompiler::kConsumeParserCache, cacheTag)
159                 : compileAndProduceCache(isolate, code, origin, resource, v8::ScriptCompiler::kProduceParserCache, cacheTag, Resource::CacheLocally);
160             break;
161         }
162     }
163     return script;
164 }
165
166 v8::Local<v8::Value> V8ScriptRunner::runCompiledScript(v8::Isolate* isolate, v8::Handle<v8::Script> script, ExecutionContext* context)
167 {
168     if (script.IsEmpty())
169         return v8::Local<v8::Value>();
170     TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Execution");
171     TRACE_EVENT1("v8", "v8.run", "fileName", TRACE_STR_COPY(*v8::String::Utf8Value(script->GetUnboundScript()->GetScriptName())));
172
173     if (V8RecursionScope::recursionLevel(isolate) >= kMaxRecursionDepth)
174         return throwStackOverflowExceptionIfNeeded(isolate);
175
176     RELEASE_ASSERT(!context->isIteratingOverObservers());
177
178     // Run the script and keep track of the current recursion depth.
179     v8::Local<v8::Value> result;
180     {
181         if (ScriptForbiddenScope::isScriptForbidden())
182             return v8::Local<v8::Value>();
183         V8RecursionScope recursionScope(isolate);
184         result = script->Run();
185     }
186
187     if (result.IsEmpty())
188         return v8::Local<v8::Value>();
189
190     crashIfV8IsDead();
191     return result;
192 }
193
194 v8::Local<v8::Value> V8ScriptRunner::compileAndRunInternalScript(v8::Handle<v8::String> source, v8::Isolate* isolate, const String& fileName, const TextPosition& scriptStartPosition)
195 {
196     v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(source, fileName, scriptStartPosition, 0, 0, isolate);
197     if (script.IsEmpty())
198         return v8::Local<v8::Value>();
199
200     TRACE_EVENT0("v8", "v8.run");
201     TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Execution");
202     V8RecursionScope::MicrotaskSuppression recursionScope(isolate);
203     v8::Local<v8::Value> result = script->Run();
204     crashIfV8IsDead();
205     return result;
206 }
207
208 v8::Local<v8::Value> V8ScriptRunner::runCompiledInternalScript(v8::Isolate* isolate, v8::Handle<v8::Script> script)
209 {
210     TRACE_EVENT0("v8", "v8.run");
211     TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Execution");
212     V8RecursionScope::MicrotaskSuppression recursionScope(isolate);
213     v8::Local<v8::Value> result = script->Run();
214     crashIfV8IsDead();
215     return result;
216 }
217
218 v8::Local<v8::Value> V8ScriptRunner::callFunction(v8::Handle<v8::Function> function, ExecutionContext* context, v8::Handle<v8::Value> receiver, int argc, v8::Handle<v8::Value> args[], v8::Isolate* isolate)
219 {
220     TRACE_EVENT0("v8", "v8.callFunction");
221     TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Execution");
222
223     if (V8RecursionScope::recursionLevel(isolate) >= kMaxRecursionDepth)
224         return throwStackOverflowExceptionIfNeeded(isolate);
225
226     RELEASE_ASSERT(!context->isIteratingOverObservers());
227
228     if (ScriptForbiddenScope::isScriptForbidden())
229         return v8::Local<v8::Value>();
230     V8RecursionScope recursionScope(isolate);
231     v8::Local<v8::Value> result = function->Call(receiver, argc, args);
232     crashIfV8IsDead();
233     return result;
234 }
235
236 v8::Local<v8::Value> V8ScriptRunner::callInternalFunction(v8::Handle<v8::Function> function, v8::Handle<v8::Value> receiver, int argc, v8::Handle<v8::Value> args[], v8::Isolate* isolate)
237 {
238     TRACE_EVENT0("v8", "v8.callFunction");
239     TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Execution");
240     V8RecursionScope::MicrotaskSuppression recursionScope(isolate);
241     v8::Local<v8::Value> result = function->Call(receiver, argc, args);
242     crashIfV8IsDead();
243     return result;
244 }
245
246 v8::Local<v8::Value> V8ScriptRunner::callAsFunction(v8::Isolate* isolate, v8::Handle<v8::Object> object, v8::Handle<v8::Value> receiver, int argc, v8::Handle<v8::Value> args[])
247 {
248     TRACE_EVENT0("v8", "v8.callFunction");
249     TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Execution");
250
251     V8RecursionScope::MicrotaskSuppression recursionScope(isolate);
252     v8::Local<v8::Value> result = object->CallAsFunction(receiver, argc, args);
253     crashIfV8IsDead();
254     return result;
255 }
256
257 v8::Local<v8::Object> V8ScriptRunner::instantiateObject(v8::Isolate* isolate, v8::Handle<v8::ObjectTemplate> objectTemplate)
258 {
259     TRACE_EVENT0("v8", "v8.newInstance");
260     TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Execution");
261
262     V8RecursionScope::MicrotaskSuppression scope(isolate);
263     v8::Local<v8::Object> result = objectTemplate->NewInstance();
264     crashIfV8IsDead();
265     return result;
266 }
267
268 v8::Local<v8::Object> V8ScriptRunner::instantiateObject(v8::Isolate* isolate, v8::Handle<v8::Function> function, int argc, v8::Handle<v8::Value> argv[])
269 {
270     TRACE_EVENT0("v8", "v8.newInstance");
271     TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Execution");
272
273     V8RecursionScope::MicrotaskSuppression scope(isolate);
274     v8::Local<v8::Object> result = function->NewInstance(argc, argv);
275     crashIfV8IsDead();
276     return result;
277 }
278
279 v8::Local<v8::Object> V8ScriptRunner::instantiateObjectInDocument(v8::Isolate* isolate, v8::Handle<v8::Function> function, ExecutionContext* context, int argc, v8::Handle<v8::Value> argv[])
280 {
281     TRACE_EVENT0("v8", "v8.newInstance");
282     TRACE_EVENT_SCOPED_SAMPLING_STATE("v8", "V8Execution");
283     if (ScriptForbiddenScope::isScriptForbidden())
284         return v8::Local<v8::Object>();
285     V8RecursionScope scope(isolate);
286     v8::Local<v8::Object> result = function->NewInstance(argc, argv);
287     crashIfV8IsDead();
288     return result;
289 }
290
291 unsigned V8ScriptRunner::tagForParserCache()
292 {
293     return StringHash::hash(v8::V8::GetVersion()) * 2;
294 }
295
296 unsigned V8ScriptRunner::tagForCodeCache()
297 {
298     return StringHash::hash(v8::V8::GetVersion()) * 2 + 1;
299 }
300
301 } // namespace blink