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
37namespace WebCore {
38
39PassOwnPtr<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
66v8::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
78v8::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
110v8::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
124v8::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
140v8::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
150v8::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
161v8::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
172v8::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
183v8::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
194v8::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