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/ScriptExecutionContext.h"
33#include "core/loader/CachedMetadata.h"
34#include "core/loader/cache/ScriptResource.h"
35#include "core/platform/chromium/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(fileName, isolate);
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() : v8::False();
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, ScriptExecutionContext* context)
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();
87
88    if (handleOutOfMemory())
89        return v8::Local<v8::Value>();
90
91    // Run the script and keep track of the current recursion depth.
92    v8::Local<v8::Value> result;
93    {
94        V8RecursionScope recursionScope(context);
95        result = script->Run();
96    }
97
98    if (handleOutOfMemory())
99        ASSERT(result.IsEmpty());
100
101    if (result.IsEmpty())
102        return v8::Local<v8::Value>();
103
104    crashIfV8IsDead();
105    return result;
106}
107
108v8::Local<v8::Value> V8ScriptRunner::compileAndRunInternalScript(v8::Handle<v8::String> source, v8::Isolate* isolate, const String& fileName, const TextPosition& scriptStartPosition, v8::ScriptData* scriptData)
109{
110    TRACE_EVENT0("v8", "v8.run");
111    TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
112    v8::Handle<v8::Script> script = V8ScriptRunner::compileScript(source, fileName, scriptStartPosition, scriptData, isolate);
113    if (script.IsEmpty())
114        return v8::Local<v8::Value>();
115
116    V8RecursionScope::MicrotaskSuppression recursionScope;
117    v8::Local<v8::Value> result = script->Run();
118    crashIfV8IsDead();
119    return result;
120}
121
122v8::Local<v8::Value> V8ScriptRunner::callFunction(v8::Handle<v8::Function> function, ScriptExecutionContext* context, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[])
123{
124    TRACE_EVENT0("v8", "v8.callFunction");
125    TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
126
127    if (V8RecursionScope::recursionLevel() >= kMaxRecursionDepth)
128        return handleMaxRecursionDepthExceeded();
129
130    V8RecursionScope recursionScope(context);
131    v8::Local<v8::Value> result = function->Call(receiver, argc, args);
132    crashIfV8IsDead();
133    return result;
134}
135
136v8::Local<v8::Value> V8ScriptRunner::callInternalFunction(v8::Handle<v8::Function> function, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[], v8::Isolate* isolate)
137{
138    TRACE_EVENT0("v8", "v8.callFunction");
139    TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
140    V8RecursionScope::MicrotaskSuppression recursionScope;
141    v8::Local<v8::Value> result = function->Call(receiver, argc, args);
142    crashIfV8IsDead();
143    return result;
144}
145
146v8::Local<v8::Value> V8ScriptRunner::callAsFunction(v8::Handle<v8::Object> object, v8::Handle<v8::Object> receiver, int argc, v8::Handle<v8::Value> args[])
147{
148    TRACE_EVENT0("v8", "v8.callFunction");
149    TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
150    V8RecursionScope::MicrotaskSuppression recursionScope;
151    v8::Local<v8::Value> result = object->CallAsFunction(receiver, argc, args);
152    crashIfV8IsDead();
153    return result;
154}
155
156v8::Local<v8::Value> V8ScriptRunner::callAsConstructor(v8::Handle<v8::Object> object, int argc, v8::Handle<v8::Value> args[])
157{
158    TRACE_EVENT0("v8", "v8.callFunction");
159    TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
160    V8RecursionScope::MicrotaskSuppression recursionScope;
161    v8::Local<v8::Value> result = object->CallAsConstructor(argc, args);
162    crashIfV8IsDead();
163    return result;
164}
165
166v8::Local<v8::Object> V8ScriptRunner::instantiateObject(v8::Handle<v8::ObjectTemplate> objectTemplate)
167{
168    TRACE_EVENT0("v8", "v8.newInstance");
169    TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
170    V8RecursionScope::MicrotaskSuppression scope;
171    v8::Local<v8::Object> result = objectTemplate->NewInstance();
172    crashIfV8IsDead();
173    return result;
174}
175
176v8::Local<v8::Object> V8ScriptRunner::instantiateObject(v8::Handle<v8::Function> function, int argc, v8::Handle<v8::Value> argv[])
177{
178    TRACE_EVENT0("v8", "v8.newInstance");
179    TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
180    V8RecursionScope::MicrotaskSuppression scope;
181    v8::Local<v8::Object> result = function->NewInstance(argc, argv);
182    crashIfV8IsDead();
183    return result;
184}
185
186v8::Local<v8::Object> V8ScriptRunner::instantiateObjectInDocument(v8::Handle<v8::Function> function, ScriptExecutionContext* context, int argc, v8::Handle<v8::Value> argv[])
187{
188    TRACE_EVENT0("v8", "v8.newInstance");
189    TRACE_EVENT_SCOPED_SAMPLING_STATE("V8", "Execution");
190    V8RecursionScope scope(context);
191    v8::Local<v8::Object> result = function->NewInstance(argc, argv);
192    crashIfV8IsDead();
193    return result;
194}
195
196} // namespace WebCore
197