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/v8/V8ScriptRunner.h"
28
29 #include "bindings/v8/V8Binding.h"
30 #include "bindings/v8/V8GCController.h"
31 #include "bindings/v8/V8RecursionScope.h"
32 #include "core/dom/ExecutionContext.h"
33 #include "core/fetch/CachedMetadata.h"
34 #include "core/fetch/ScriptResource.h"
35 #include "platform/TraceEvent.h"
36
37 namespace WebCore {
38
precompileScript(v8::Handle<v8::String> code,ScriptResource * resource)39 PassOwnPtr<v8::ScriptData> V8ScriptRunner::precompileScript(v8::Handle<v8::String> code, ScriptResource* resource)
40 {
41 TRACE_EVENT0("v8", "v8.compile");
42 TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Compile");
43 // A pseudo-randomly chosen ID used to store and retrieve V8 ScriptData from
44 // the ScriptResource. If the format changes, this ID should be changed too.
45 static const unsigned dataTypeID = 0xECC13BD7;
46
47 // Very small scripts are not worth the effort to preparse.
48 static const int minPreparseLength = 1024;
49
50 if (!resource || code->Length() < minPreparseLength)
51 return nullptr;
52
53 CachedMetadata* cachedMetadata = resource->cachedMetadata(dataTypeID);
54 if (cachedMetadata)
55 return adoptPtr(v8::ScriptData::New(cachedMetadata->data(), cachedMetadata->size()));
56
57 OwnPtr<v8::ScriptData> scriptData = adoptPtr(v8::ScriptData::PreCompile(code));
58 if (!scriptData)
59 return nullptr;
60
61 resource->setCachedMetadata(dataTypeID, scriptData->Data(), scriptData->Length());
62
63 return scriptData.release();
64 }
65
compileScript(v8::Handle<v8::String> code,const String & fileName,const TextPosition & scriptStartPosition,v8::ScriptData * scriptData,v8::Isolate * isolate,AccessControlStatus corsStatus)66 v8::Local<v8::Script> V8ScriptRunner::compileScript(v8::Handle<v8::String> code, const String& fileName, const TextPosition& scriptStartPosition, v8::ScriptData* scriptData, v8::Isolate* isolate, AccessControlStatus corsStatus)
67 {
68 TRACE_EVENT0("v8", "v8.compile");
69 TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Compile");
70 v8::Handle<v8::String> name = v8String(isolate, fileName);
71 v8::Handle<v8::Integer> line = v8::Integer::New(scriptStartPosition.m_line.zeroBasedInt(), isolate);
72 v8::Handle<v8::Integer> column = v8::Integer::New(scriptStartPosition.m_column.zeroBasedInt(), isolate);
73 v8::Handle<v8::Boolean> isSharedCrossOrigin = corsStatus == SharableCrossOrigin ? v8::True(isolate) : v8::False(isolate);
74 v8::ScriptOrigin origin(name, line, column, isSharedCrossOrigin);
75 return v8::Script::Compile(code, &origin, scriptData);
76 }
77
runCompiledScript(v8::Handle<v8::Script> script,ExecutionContext * context,v8::Isolate * isolate)78 v8::Local<v8::Value> V8ScriptRunner::runCompiledScript(v8::Handle<v8::Script> script, ExecutionContext* context, v8::Isolate* isolate)
79 {
80 TRACE_EVENT0("v8", "v8.run");
81 TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
82 if (script.IsEmpty())
83 return v8::Local<v8::Value>();
84
85 if (V8RecursionScope::recursionLevel() >= kMaxRecursionDepth)
86 return handleMaxRecursionDepthExceeded(isolate);
87
88 if (handleOutOfMemory())
89 return v8::Local<v8::Value>();
90
91 RELEASE_ASSERT(!context->isIteratingOverObservers());
92
93 // Run the script and keep track of the current recursion depth.
94 v8::Local<v8::Value> result;
95 {
96 V8RecursionScope recursionScope(context);
97 result = script->Run();
98 }
99
100 if (handleOutOfMemory())
101 ASSERT(result.IsEmpty());
102
103 if (result.IsEmpty())
104 return v8::Local<v8::Value>();
105
106 crashIfV8IsDead();
107 return result;
108 }
109
compileAndRunInternalScript(v8::Handle<v8::String> source,v8::Isolate * isolate,const String & fileName,const TextPosition & scriptStartPosition,v8::ScriptData * scriptData)110 v8::Local<v8::Value> V8ScriptRunner::compileAndRunInternalScript(v8::Handle<v8::String> source, v8::Isolate* isolate, const String& fileName, const TextPosition& scriptStartPosition, v8::ScriptData* scriptData)
111 {
112 TRACE_EVENT0("v8", "v8.run");
113 TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
114 v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(source, fileName, scriptStartPosition, scriptData, isolate);
115 if (script.IsEmpty())
116 return v8::Local<v8::Value>();
117
118 V8RecursionScope::MicrotaskSuppression recursionScope;
119 v8::Local<v8::Value> result = script->Run();
120 crashIfV8IsDead();
121 return result;
122 }
123
callFunction(v8::Handle<v8::Function> function,ExecutionContext * context,v8::Handle<v8::Value> receiver,int argc,v8::Handle<v8::Value> info[],v8::Isolate * isolate)124 v8::Local<v8::Value> V8ScriptRunner::callFunction(v8::Handle<v8::Function> function, ExecutionContext* context, v8::Handle<v8::Value> receiver, int argc, v8::Handle<v8::Value> info[], v8::Isolate* isolate)
125 {
126 TRACE_EVENT0("v8", "v8.callFunction");
127 TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
128
129 if (V8RecursionScope::recursionLevel() >= kMaxRecursionDepth)
130 return handleMaxRecursionDepthExceeded(isolate);
131
132 RELEASE_ASSERT(!context->isIteratingOverObservers());
133
134 V8RecursionScope recursionScope(context);
135 v8::Local<v8::Value> result = function->Call(receiver, argc, info);
136 crashIfV8IsDead();
137 return result;
138 }
139
callInternalFunction(v8::Handle<v8::Function> function,v8::Handle<v8::Value> receiver,int argc,v8::Handle<v8::Value> info[],v8::Isolate * isolate)140 v8::Local<v8::Value> V8ScriptRunner::callInternalFunction(v8::Handle<v8::Function> function, v8::Handle<v8::Value> receiver, int argc, v8::Handle<v8::Value> info[], v8::Isolate* isolate)
141 {
142 TRACE_EVENT0("v8", "v8.callFunction");
143 TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
144 V8RecursionScope::MicrotaskSuppression recursionScope;
145 v8::Local<v8::Value> result = function->Call(receiver, argc, info);
146 crashIfV8IsDead();
147 return result;
148 }
149
callAsFunction(v8::Handle<v8::Object> object,v8::Handle<v8::Value> receiver,int argc,v8::Handle<v8::Value> info[])150 v8::Local<v8::Value> V8ScriptRunner::callAsFunction(v8::Handle<v8::Object> object, v8::Handle<v8::Value> receiver, int argc, v8::Handle<v8::Value> info[])
151 {
152 TRACE_EVENT0("v8", "v8.callFunction");
153 TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
154
155 V8RecursionScope::MicrotaskSuppression recursionScope;
156 v8::Local<v8::Value> result = object->CallAsFunction(receiver, argc, info);
157 crashIfV8IsDead();
158 return result;
159 }
160
callAsConstructor(v8::Handle<v8::Object> object,int argc,v8::Handle<v8::Value> info[])161 v8::Local<v8::Value> V8ScriptRunner::callAsConstructor(v8::Handle<v8::Object> object, int argc, v8::Handle<v8::Value> info[])
162 {
163 TRACE_EVENT0("v8", "v8.callFunction");
164 TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
165
166 V8RecursionScope::MicrotaskSuppression recursionScope;
167 v8::Local<v8::Value> result = object->CallAsConstructor(argc, info);
168 crashIfV8IsDead();
169 return result;
170 }
171
instantiateObject(v8::Handle<v8::ObjectTemplate> objectTemplate)172 v8::Local<v8::Object> V8ScriptRunner::instantiateObject(v8::Handle<v8::ObjectTemplate> objectTemplate)
173 {
174 TRACE_EVENT0("v8", "v8.newInstance");
175 TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
176
177 V8RecursionScope::MicrotaskSuppression scope;
178 v8::Local<v8::Object> result = objectTemplate->NewInstance();
179 crashIfV8IsDead();
180 return result;
181 }
182
instantiateObject(v8::Handle<v8::Function> function,int argc,v8::Handle<v8::Value> argv[])183 v8::Local<v8::Object> V8ScriptRunner::instantiateObject(v8::Handle<v8::Function> function, int argc, v8::Handle<v8::Value> argv[])
184 {
185 TRACE_EVENT0("v8", "v8.newInstance");
186 TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
187
188 V8RecursionScope::MicrotaskSuppression scope;
189 v8::Local<v8::Object> result = function->NewInstance(argc, argv);
190 crashIfV8IsDead();
191 return result;
192 }
193
instantiateObjectInDocument(v8::Handle<v8::Function> function,ExecutionContext * context,int argc,v8::Handle<v8::Value> argv[])194 v8::Local<v8::Object> V8ScriptRunner::instantiateObjectInDocument(v8::Handle<v8::Function> function, ExecutionContext* context, int argc, v8::Handle<v8::Value> argv[])
195 {
196 TRACE_EVENT0("v8", "v8.newInstance");
197 TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
198 V8RecursionScope scope(context);
199 v8::Local<v8::Object> result = function->NewInstance(argc, argv);
200 crashIfV8IsDead();
201 return result;
202 }
203
204 } // namespace WebCore
205