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 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 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 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 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 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 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 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 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 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 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 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