Line data Source code
1 : // Copyright 2014 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/arguments-inl.h"
6 : #include "src/asmjs/asm-js.h"
7 : #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
8 : #include "src/compiler.h"
9 : #include "src/deoptimizer.h"
10 : #include "src/frames-inl.h"
11 : #include "src/isolate-inl.h"
12 : #include "src/message-template.h"
13 : #include "src/objects/js-array-buffer-inl.h"
14 : #include "src/objects/js-array-inl.h"
15 : #include "src/runtime/runtime-utils.h"
16 : #include "src/v8threads.h"
17 : #include "src/vm-state-inl.h"
18 :
19 : namespace v8 {
20 : namespace internal {
21 :
22 1366069 : RUNTIME_FUNCTION(Runtime_CompileLazy) {
23 : HandleScope scope(isolate);
24 : DCHECK_EQ(1, args.length());
25 683034 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
26 :
27 : #ifdef DEBUG
28 : if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
29 : PrintF("[unoptimized: ");
30 : function->PrintName();
31 : PrintF("]\n");
32 : }
33 : #endif
34 :
35 : StackLimitCheck check(isolate);
36 683033 : if (check.JsHasOverflowed(kStackSpaceRequiredForCompilation * KB)) {
37 26647 : return isolate->StackOverflow();
38 : }
39 : IsCompiledScope is_compiled_scope;
40 656386 : if (!Compiler::Compile(function, Compiler::KEEP_EXCEPTION,
41 : &is_compiled_scope)) {
42 : return ReadOnlyRoots(isolate).exception();
43 : }
44 : DCHECK(function->is_compiled());
45 656363 : return function->code();
46 : }
47 :
48 16572 : RUNTIME_FUNCTION(Runtime_CompileOptimized_Concurrent) {
49 : HandleScope scope(isolate);
50 : DCHECK_EQ(1, args.length());
51 8286 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
52 : StackLimitCheck check(isolate);
53 8286 : if (check.JsHasOverflowed(kStackSpaceRequiredForCompilation * KB)) {
54 195 : return isolate->StackOverflow();
55 : }
56 8091 : if (!Compiler::CompileOptimized(function, ConcurrencyMode::kConcurrent)) {
57 : return ReadOnlyRoots(isolate).exception();
58 : }
59 : DCHECK(function->is_compiled());
60 8091 : return function->code();
61 : }
62 :
63 76 : RUNTIME_FUNCTION(Runtime_FunctionFirstExecution) {
64 : HandleScope scope(isolate);
65 : StackLimitCheck check(isolate);
66 : DCHECK_EQ(1, args.length());
67 :
68 38 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
69 : DCHECK_EQ(function->feedback_vector()->optimization_marker(),
70 : OptimizationMarker::kLogFirstExecution);
71 : DCHECK(FLAG_log_function_events);
72 : Handle<SharedFunctionInfo> sfi(function->shared(), isolate);
73 228 : LOG(isolate, FunctionEvent(
74 : "first-execution", Script::cast(sfi->script())->id(), 0,
75 : sfi->StartPosition(), sfi->EndPosition(), sfi->DebugName()));
76 38 : function->feedback_vector()->ClearOptimizationMarker();
77 : // Return the code to continue execution, we don't care at this point whether
78 : // this is for lazy compilation or has been eagerly complied.
79 : return function->code();
80 : }
81 :
82 654702 : RUNTIME_FUNCTION(Runtime_CompileOptimized_NotConcurrent) {
83 : HandleScope scope(isolate);
84 : DCHECK_EQ(1, args.length());
85 327351 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
86 : StackLimitCheck check(isolate);
87 327352 : if (check.JsHasOverflowed(kStackSpaceRequiredForCompilation * KB)) {
88 11177 : return isolate->StackOverflow();
89 : }
90 316175 : if (!Compiler::CompileOptimized(function, ConcurrencyMode::kNotConcurrent)) {
91 : return ReadOnlyRoots(isolate).exception();
92 : }
93 : DCHECK(function->is_compiled());
94 316176 : return function->code();
95 : }
96 :
97 234 : RUNTIME_FUNCTION(Runtime_EvictOptimizedCodeSlot) {
98 : SealHandleScope scope(isolate);
99 : DCHECK_EQ(1, args.length());
100 117 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
101 :
102 : DCHECK(function->shared()->is_compiled());
103 :
104 351 : function->feedback_vector()->EvictOptimizedCodeMarkedForDeoptimization(
105 117 : function->shared(), "Runtime_EvictOptimizedCodeSlot");
106 117 : return function->code();
107 : }
108 :
109 10046 : RUNTIME_FUNCTION(Runtime_InstantiateAsmJs) {
110 : HandleScope scope(isolate);
111 : DCHECK_EQ(args.length(), 4);
112 5023 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
113 :
114 : Handle<JSReceiver> stdlib;
115 5023 : if (args[1]->IsJSReceiver()) {
116 : stdlib = args.at<JSReceiver>(1);
117 : }
118 : Handle<JSReceiver> foreign;
119 5023 : if (args[2]->IsJSReceiver()) {
120 : foreign = args.at<JSReceiver>(2);
121 : }
122 : Handle<JSArrayBuffer> memory;
123 5023 : if (args[3]->IsJSArrayBuffer()) {
124 2188 : memory = args.at<JSArrayBuffer>(3);
125 : }
126 5023 : if (function->shared()->HasAsmWasmData()) {
127 : Handle<SharedFunctionInfo> shared(function->shared(), isolate);
128 : Handle<AsmWasmData> data(shared->asm_wasm_data(), isolate);
129 : MaybeHandle<Object> result = AsmJs::InstantiateAsmWasm(
130 5019 : isolate, shared, data, stdlib, foreign, memory);
131 5019 : if (!result.is_null()) {
132 : return *result.ToHandleChecked();
133 : }
134 : }
135 : // Remove wasm data, mark as broken for asm->wasm, replace function code with
136 : // UncompiledData, and return a smi 0 to indicate failure.
137 176 : if (function->shared()->HasAsmWasmData()) {
138 : SharedFunctionInfo::DiscardCompiled(isolate,
139 172 : handle(function->shared(), isolate));
140 : }
141 176 : function->shared()->set_is_asm_wasm_broken(true);
142 : DCHECK(function->code() ==
143 : isolate->builtins()->builtin(Builtins::kInstantiateAsmJs));
144 352 : function->set_code(isolate->builtins()->builtin(Builtins::kCompileLazy));
145 : return Smi::kZero;
146 : }
147 :
148 108478 : RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
149 : HandleScope scope(isolate);
150 : DCHECK_EQ(0, args.length());
151 54239 : Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
152 : DCHECK(deoptimizer->compiled_code()->kind() == Code::OPTIMIZED_FUNCTION);
153 : DCHECK(deoptimizer->compiled_code()->is_turbofanned());
154 : DCHECK(AllowHeapAllocation::IsAllowed());
155 : DCHECK(isolate->context().is_null());
156 :
157 : TimerEventScope<TimerEventDeoptimizeCode> timer(isolate);
158 162717 : TRACE_EVENT0("v8", "V8.DeoptimizeCode");
159 54239 : Handle<JSFunction> function = deoptimizer->function();
160 : DeoptimizeKind type = deoptimizer->deopt_kind();
161 :
162 : // TODO(turbofan): We currently need the native context to materialize
163 : // the arguments object, but only to get to its map.
164 108478 : isolate->set_context(deoptimizer->function()->native_context());
165 :
166 : // Make sure to materialize objects before causing any allocation.
167 54239 : deoptimizer->MaterializeHeapObjects();
168 54239 : delete deoptimizer;
169 :
170 : // Ensure the context register is updated for materialized objects.
171 54239 : JavaScriptFrameIterator top_it(isolate);
172 : JavaScriptFrame* top_frame = top_it.frame();
173 54239 : isolate->set_context(Context::cast(top_frame->context()));
174 :
175 : // Invalidate the underlying optimized code on non-lazy deopts.
176 54239 : if (type != DeoptimizeKind::kLazy) {
177 20701 : Deoptimizer::DeoptimizeFunction(*function);
178 : }
179 :
180 : return ReadOnlyRoots(isolate).undefined_value();
181 : }
182 :
183 :
184 11897 : static bool IsSuitableForOnStackReplacement(Isolate* isolate,
185 : Handle<JSFunction> function) {
186 : // Keep track of whether we've succeeded in optimizing.
187 11897 : if (function->shared()->optimization_disabled()) return false;
188 : // If we are trying to do OSR when there are already optimized
189 : // activations of the function, it means (a) the function is directly or
190 : // indirectly recursive and (b) an optimized invocation has been
191 : // deoptimized so that we are currently in an unoptimized activation.
192 : // Check for optimized activations of this function.
193 34290 : for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
194 : JavaScriptFrame* frame = it.frame();
195 45274 : if (frame->is_optimized() && frame->function() == *function) return false;
196 : }
197 :
198 11897 : return true;
199 : }
200 :
201 : namespace {
202 :
203 11897 : BailoutId DetermineEntryAndDisarmOSRForInterpreter(JavaScriptFrame* frame) {
204 : InterpretedFrame* iframe = reinterpret_cast<InterpretedFrame*>(frame);
205 :
206 : // Note that the bytecode array active on the stack might be different from
207 : // the one installed on the function (e.g. patched by debugger). This however
208 : // is fine because we guarantee the layout to be in sync, hence any BailoutId
209 : // representing the entry point will be valid for any copy of the bytecode.
210 11897 : Handle<BytecodeArray> bytecode(iframe->GetBytecodeArray(), iframe->isolate());
211 :
212 : DCHECK(frame->LookupCode()->is_interpreter_trampoline_builtin());
213 : DCHECK(frame->function()->shared()->HasBytecodeArray());
214 : DCHECK(frame->is_interpreted());
215 :
216 : // Reset the OSR loop nesting depth to disarm back edges.
217 : bytecode->set_osr_loop_nesting_level(0);
218 :
219 : // Return a BailoutId representing the bytecode offset of the back branch.
220 11897 : return BailoutId(iframe->GetBytecodeOffset());
221 : }
222 :
223 : } // namespace
224 :
225 23794 : RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
226 : HandleScope scope(isolate);
227 : DCHECK_EQ(1, args.length());
228 11897 : CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
229 :
230 : // Only reachable when OST is enabled.
231 11897 : CHECK(FLAG_use_osr);
232 :
233 : // Determine frame triggering OSR request.
234 11897 : JavaScriptFrameIterator it(isolate);
235 : JavaScriptFrame* frame = it.frame();
236 : DCHECK_EQ(frame->function(), *function);
237 : DCHECK(frame->is_interpreted());
238 :
239 : // Determine the entry point for which this OSR request has been fired and
240 : // also disarm all back edges in the calling code to stop new requests.
241 11897 : BailoutId ast_id = DetermineEntryAndDisarmOSRForInterpreter(frame);
242 : DCHECK(!ast_id.IsNone());
243 :
244 : MaybeHandle<Code> maybe_result;
245 11897 : if (IsSuitableForOnStackReplacement(isolate, function)) {
246 11897 : if (FLAG_trace_osr) {
247 0 : PrintF("[OSR - Compiling: ");
248 0 : function->PrintName();
249 0 : PrintF(" at AST id %d]\n", ast_id.ToInt());
250 : }
251 11897 : maybe_result = Compiler::GetOptimizedCodeForOSR(function, ast_id, frame);
252 : }
253 :
254 : // Check whether we ended up with usable optimized code.
255 : Handle<Code> result;
256 16512 : if (maybe_result.ToHandle(&result) &&
257 : result->kind() == Code::OPTIMIZED_FUNCTION) {
258 : DeoptimizationData data =
259 4615 : DeoptimizationData::cast(result->deoptimization_data());
260 :
261 9230 : if (data->OsrPcOffset()->value() >= 0) {
262 : DCHECK(BailoutId(data->OsrBytecodeOffset()->value()) == ast_id);
263 4615 : if (FLAG_trace_osr) {
264 : PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n",
265 0 : ast_id.ToInt(), data->OsrPcOffset()->value());
266 : }
267 :
268 : DCHECK(result->is_turbofanned());
269 4615 : if (!function->HasOptimizedCode()) {
270 : // If we're not already optimized, set to optimize non-concurrently on
271 : // the next call, otherwise we'd run unoptimized once more and
272 : // potentially compile for OSR again.
273 4440 : if (FLAG_trace_osr) {
274 0 : PrintF("[OSR - Re-marking ");
275 0 : function->PrintName();
276 0 : PrintF(" for non-concurrent optimization]\n");
277 : }
278 : function->SetOptimizationMarker(OptimizationMarker::kCompileOptimized);
279 : }
280 : return *result;
281 : }
282 : }
283 :
284 : // Failed.
285 7282 : if (FLAG_trace_osr) {
286 0 : PrintF("[OSR - Failed: ");
287 0 : function->PrintName();
288 0 : PrintF(" at AST id %d]\n", ast_id.ToInt());
289 : }
290 :
291 7282 : if (!function->IsOptimized()) {
292 14564 : function->set_code(function->shared()->GetCode());
293 : }
294 : return Object();
295 : }
296 :
297 2453791 : static Object CompileGlobalEval(Isolate* isolate, Handle<String> source,
298 : Handle<SharedFunctionInfo> outer_info,
299 : LanguageMode language_mode,
300 : int eval_scope_position, int eval_position) {
301 : Handle<Context> context(isolate->context(), isolate);
302 : Handle<Context> native_context(context->native_context(), isolate);
303 :
304 : // Check if native context allows code generation from
305 : // strings. Throw an exception if it doesn't.
306 4907633 : if (native_context->allow_code_gen_from_strings()->IsFalse(isolate) &&
307 51 : !Compiler::CodeGenerationFromStringsAllowed(isolate, native_context,
308 : source)) {
309 : Handle<Object> error_message =
310 40 : native_context->ErrorMessageForCodeGenerationFromStrings();
311 : Handle<Object> error;
312 : MaybeHandle<Object> maybe_error = isolate->factory()->NewEvalError(
313 40 : MessageTemplate::kCodeGenFromStrings, error_message);
314 80 : if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
315 40 : return ReadOnlyRoots(isolate).exception();
316 : }
317 :
318 : // Deal with a normal eval call with a string argument. Compile it
319 : // and return the compiled function bound in the local context.
320 : static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
321 : Handle<JSFunction> compiled;
322 5012879 : ASSIGN_RETURN_ON_EXCEPTION_VALUE(
323 : isolate, compiled,
324 : Compiler::GetFunctionFromEval(source, outer_info, context, language_mode,
325 : restriction, kNoSourcePosition,
326 : eval_scope_position, eval_position),
327 : ReadOnlyRoots(isolate).exception());
328 2348374 : return *compiled;
329 : }
330 :
331 4908356 : RUNTIME_FUNCTION(Runtime_ResolvePossiblyDirectEval) {
332 : HandleScope scope(isolate);
333 : DCHECK_EQ(6, args.length());
334 :
335 : Handle<Object> callee = args.at(0);
336 :
337 : // If "eval" didn't refer to the original GlobalEval, it's not a
338 : // direct call to eval.
339 : // (And even if it is, but the first argument isn't a string, just let
340 : // execution default to an indirect call to eval, which will also return
341 : // the first argument without doing anything).
342 9816595 : if (*callee != isolate->native_context()->global_eval_fun() ||
343 : !args[1]->IsString()) {
344 : return *callee;
345 : }
346 :
347 : DCHECK(args[3]->IsSmi());
348 : DCHECK(is_valid_language_mode(args.smi_at(3)));
349 2453791 : LanguageMode language_mode = static_cast<LanguageMode>(args.smi_at(3));
350 : DCHECK(args[4]->IsSmi());
351 : Handle<SharedFunctionInfo> outer_info(args.at<JSFunction>(2)->shared(),
352 : isolate);
353 : return CompileGlobalEval(isolate, args.at<String>(1), outer_info,
354 2453791 : language_mode, args.smi_at(4), args.smi_at(5));
355 : }
356 : } // namespace internal
357 122036 : } // namespace v8
|