blob: 263c4f9e7758f66cabaa126fa47e73b740dc6fbd [file] [log] [blame]
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001// 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
Ben Murdoch4a90d5f2016-03-22 12:00:34 +00005#include "src/runtime/runtime-utils.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -04006
7#include "src/arguments.h"
8#include "src/compiler.h"
9#include "src/deoptimizer.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000010#include "src/frames-inl.h"
11#include "src/full-codegen/full-codegen.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040012#include "src/isolate-inl.h"
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000013#include "src/messages.h"
Emily Bernierd0a1eb72015-03-24 16:35:39 -040014#include "src/v8threads.h"
15#include "src/vm-state-inl.h"
16
17namespace v8 {
18namespace internal {
19
20RUNTIME_FUNCTION(Runtime_CompileLazy) {
21 HandleScope scope(isolate);
22 DCHECK(args.length() == 1);
23 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
24#ifdef DEBUG
25 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
26 PrintF("[unoptimized: ");
27 function->PrintName();
28 PrintF("]\n");
29 }
30#endif
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000031 StackLimitCheck check(isolate);
32 if (check.JsHasOverflowed(1 * KB)) return isolate->StackOverflow();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040033
34 // Compile the target function.
35 DCHECK(function->shared()->allows_lazy_compilation());
36
37 Handle<Code> code;
38 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, code,
39 Compiler::GetLazyCode(function));
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000040 DCHECK(code->IsJavaScriptCode());
41
Emily Bernierd0a1eb72015-03-24 16:35:39 -040042 function->ReplaceCode(*code);
43 return *code;
44}
45
46
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000047namespace {
Emily Bernierd0a1eb72015-03-24 16:35:39 -040048
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000049Object* CompileOptimized(Isolate* isolate, Handle<JSFunction> function,
50 Compiler::ConcurrencyMode mode) {
51 StackLimitCheck check(isolate);
52 if (check.JsHasOverflowed(1 * KB)) return isolate->StackOverflow();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040053
Emily Bernierd0a1eb72015-03-24 16:35:39 -040054 Handle<Code> code;
Ben Murdoch097c5b22016-05-18 11:27:45 +010055 if (Compiler::GetOptimizedCode(function, mode).ToHandle(&code)) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000056 // Optimization succeeded, return optimized code.
Emily Bernierd0a1eb72015-03-24 16:35:39 -040057 function->ReplaceCode(*code);
58 } else {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000059 // Optimization failed, get unoptimized code.
60 if (isolate->has_pending_exception()) { // Possible stack overflow.
61 return isolate->heap()->exception();
62 }
63 code = Handle<Code>(function->shared()->code(), isolate);
64 if (code->kind() != Code::FUNCTION &&
65 code->kind() != Code::OPTIMIZED_FUNCTION) {
66 ASSIGN_RETURN_FAILURE_ON_EXCEPTION(
67 isolate, code, Compiler::GetUnoptimizedCode(function));
68 }
69 function->ReplaceCode(*code);
Emily Bernierd0a1eb72015-03-24 16:35:39 -040070 }
71
72 DCHECK(function->code()->kind() == Code::FUNCTION ||
73 function->code()->kind() == Code::OPTIMIZED_FUNCTION ||
Ben Murdoch097c5b22016-05-18 11:27:45 +010074 (function->code()->is_interpreter_entry_trampoline() &&
75 function->shared()->HasBytecodeArray()) ||
Emily Bernierd0a1eb72015-03-24 16:35:39 -040076 function->IsInOptimizationQueue());
77 return function->code();
78}
79
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000080} // namespace
81
82
83RUNTIME_FUNCTION(Runtime_CompileOptimized_Concurrent) {
84 HandleScope scope(isolate);
85 DCHECK(args.length() == 1);
86 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
87 return CompileOptimized(isolate, function, Compiler::CONCURRENT);
88}
89
90
91RUNTIME_FUNCTION(Runtime_CompileOptimized_NotConcurrent) {
92 HandleScope scope(isolate);
93 DCHECK(args.length() == 1);
94 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
95 return CompileOptimized(isolate, function, Compiler::NOT_CONCURRENT);
96}
97
Emily Bernierd0a1eb72015-03-24 16:35:39 -040098
99RUNTIME_FUNCTION(Runtime_NotifyStubFailure) {
100 HandleScope scope(isolate);
101 DCHECK(args.length() == 0);
102 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
103 DCHECK(AllowHeapAllocation::IsAllowed());
104 delete deoptimizer;
105 return isolate->heap()->undefined_value();
106}
107
108
109class ActivationsFinder : public ThreadVisitor {
110 public:
111 Code* code_;
112 bool has_code_activations_;
113
114 explicit ActivationsFinder(Code* code)
115 : code_(code), has_code_activations_(false) {}
116
117 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
118 JavaScriptFrameIterator it(isolate, top);
119 VisitFrames(&it);
120 }
121
122 void VisitFrames(JavaScriptFrameIterator* it) {
123 for (; !it->done(); it->Advance()) {
124 JavaScriptFrame* frame = it->frame();
125 if (code_->contains(frame->pc())) has_code_activations_ = true;
126 }
127 }
128};
129
130
131RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
132 HandleScope scope(isolate);
133 DCHECK(args.length() == 1);
134 CONVERT_SMI_ARG_CHECKED(type_arg, 0);
135 Deoptimizer::BailoutType type =
136 static_cast<Deoptimizer::BailoutType>(type_arg);
137 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
138 DCHECK(AllowHeapAllocation::IsAllowed());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100139 TimerEventScope<TimerEventDeoptimizeCode> timer(isolate);
140 TRACE_EVENT0("v8", "V8.DeoptimizeCode");
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400141
142 Handle<JSFunction> function = deoptimizer->function();
143 Handle<Code> optimized_code = deoptimizer->compiled_code();
144
145 DCHECK(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
146 DCHECK(type == deoptimizer->bailout_type());
147
148 // Make sure to materialize objects before causing any allocation.
149 JavaScriptFrameIterator it(isolate);
150 deoptimizer->MaterializeHeapObjects(&it);
151 delete deoptimizer;
152
153 JavaScriptFrame* frame = it.frame();
154 RUNTIME_ASSERT(frame->function()->IsJSFunction());
155 DCHECK(frame->function() == *function);
156
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000157 // Ensure the context register is updated for materialized objects.
158 JavaScriptFrameIterator top_it(isolate);
159 JavaScriptFrame* top_frame = top_it.frame();
160 isolate->set_context(Context::cast(top_frame->context()));
161
162 if (type == Deoptimizer::LAZY) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400163 return isolate->heap()->undefined_value();
164 }
165
166 // Search for other activations of the same function and code.
167 ActivationsFinder activations_finder(*optimized_code);
168 activations_finder.VisitFrames(&it);
169 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
170
171 if (!activations_finder.has_code_activations_) {
172 if (function->code() == *optimized_code) {
173 if (FLAG_trace_deopt) {
174 PrintF("[removing optimized code for: ");
175 function->PrintName();
176 PrintF("]\n");
177 }
178 function->ReplaceCode(function->shared()->code());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400179 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000180 // Evict optimized code for this function from the cache so that it
181 // doesn't get used for new closures.
182 function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
183 "notify deoptimized");
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400184 } else {
185 // TODO(titzer): we should probably do DeoptimizeCodeList(code)
186 // unconditionally if the code is not already marked for deoptimization.
187 // If there is an index by shared function info, all the better.
188 Deoptimizer::DeoptimizeFunction(*function);
189 }
190
191 return isolate->heap()->undefined_value();
192}
193
194
195static bool IsSuitableForOnStackReplacement(Isolate* isolate,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000196 Handle<JSFunction> function) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400197 // Keep track of whether we've succeeded in optimizing.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000198 if (function->shared()->optimization_disabled()) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400199 // If we are trying to do OSR when there are already optimized
200 // activations of the function, it means (a) the function is directly or
201 // indirectly recursive and (b) an optimized invocation has been
202 // deoptimized so that we are currently in an unoptimized activation.
203 // Check for optimized activations of this function.
204 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
205 JavaScriptFrame* frame = it.frame();
206 if (frame->is_optimized() && frame->function() == *function) return false;
207 }
208
209 return true;
210}
211
212
213RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
214 HandleScope scope(isolate);
215 DCHECK(args.length() == 1);
216 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
217 Handle<Code> caller_code(function->shared()->code());
218
219 // We're not prepared to handle a function with arguments object.
220 DCHECK(!function->shared()->uses_arguments());
221
222 RUNTIME_ASSERT(FLAG_use_osr);
223
224 // Passing the PC in the javascript frame from the caller directly is
225 // not GC safe, so we walk the stack to get it.
226 JavaScriptFrameIterator it(isolate);
227 JavaScriptFrame* frame = it.frame();
228 if (!caller_code->contains(frame->pc())) {
229 // Code on the stack may not be the code object referenced by the shared
230 // function info. It may have been replaced to include deoptimization data.
231 caller_code = Handle<Code>(frame->LookupCode());
232 }
233
234 uint32_t pc_offset =
235 static_cast<uint32_t>(frame->pc() - caller_code->instruction_start());
236
237#ifdef DEBUG
238 DCHECK_EQ(frame->function(), *function);
239 DCHECK_EQ(frame->LookupCode(), *caller_code);
240 DCHECK(caller_code->contains(frame->pc()));
241#endif // DEBUG
242
243
244 BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset);
245 DCHECK(!ast_id.IsNone());
246
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000247 // Disable concurrent OSR for asm.js, to enable frame specialization.
248 Compiler::ConcurrencyMode mode = (isolate->concurrent_osr_enabled() &&
249 !function->shared()->asm_function() &&
250 function->shared()->ast_node_count() > 512)
251 ? Compiler::CONCURRENT
252 : Compiler::NOT_CONCURRENT;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400253
254 OptimizedCompileJob* job = NULL;
255 if (mode == Compiler::CONCURRENT) {
256 // Gate the OSR entry with a stack check.
257 BackEdgeTable::AddStackCheck(caller_code, pc_offset);
258 // Poll already queued compilation jobs.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259 OptimizingCompileDispatcher* dispatcher =
260 isolate->optimizing_compile_dispatcher();
261 if (dispatcher->IsQueuedForOSR(function, ast_id)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400262 if (FLAG_trace_osr) {
263 PrintF("[OSR - Still waiting for queued: ");
264 function->PrintName();
265 PrintF(" at AST id %d]\n", ast_id.ToInt());
266 }
267 return NULL;
268 }
269
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000270 job = dispatcher->FindReadyOSRCandidate(function, ast_id);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400271 }
272
Ben Murdoch097c5b22016-05-18 11:27:45 +0100273 MaybeHandle<Code> maybe_result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400274 if (job != NULL) {
275 if (FLAG_trace_osr) {
276 PrintF("[OSR - Found ready: ");
277 function->PrintName();
278 PrintF(" at AST id %d]\n", ast_id.ToInt());
279 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100280 maybe_result = Compiler::GetConcurrentlyOptimizedCode(job);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000281 } else if (IsSuitableForOnStackReplacement(isolate, function)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400282 if (FLAG_trace_osr) {
283 PrintF("[OSR - Compiling: ");
284 function->PrintName();
285 PrintF(" at AST id %d]\n", ast_id.ToInt());
286 }
Ben Murdoch097c5b22016-05-18 11:27:45 +0100287 maybe_result = Compiler::GetOptimizedCode(
288 function, mode, ast_id,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000289 (mode == Compiler::NOT_CONCURRENT) ? frame : nullptr);
Ben Murdoch097c5b22016-05-18 11:27:45 +0100290 Handle<Code> result;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400291 if (maybe_result.ToHandle(&result) &&
292 result.is_identical_to(isolate->builtins()->InOptimizationQueue())) {
293 // Optimization is queued. Return to check later.
294 return NULL;
295 }
296 }
297
298 // Revert the patched back edge table, regardless of whether OSR succeeds.
299 BackEdgeTable::Revert(isolate, *caller_code);
300
301 // Check whether we ended up with usable optimized code.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100302 Handle<Code> result;
303 if (maybe_result.ToHandle(&result) &&
304 result->kind() == Code::OPTIMIZED_FUNCTION) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400305 DeoptimizationInputData* data =
306 DeoptimizationInputData::cast(result->deoptimization_data());
307
308 if (data->OsrPcOffset()->value() >= 0) {
309 DCHECK(BailoutId(data->OsrAstId()->value()) == ast_id);
310 if (FLAG_trace_osr) {
311 PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n",
312 ast_id.ToInt(), data->OsrPcOffset()->value());
313 }
314 // TODO(titzer): this is a massive hack to make the deopt counts
315 // match. Fix heuristics for reenabling optimizations!
316 function->shared()->increment_deopt_count();
317
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000318 if (result->is_turbofanned()) {
319 // TurboFanned OSR code cannot be installed into the function.
320 // But the function is obviously hot, so optimize it next time.
321 function->ReplaceCode(
322 isolate->builtins()->builtin(Builtins::kCompileOptimized));
323 } else {
324 // Crankshafted OSR code can be installed into the function.
325 function->ReplaceCode(*result);
326 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400327 return *result;
328 }
329 }
330
331 // Failed.
332 if (FLAG_trace_osr) {
333 PrintF("[OSR - Failed: ");
334 function->PrintName();
335 PrintF(" at AST id %d]\n", ast_id.ToInt());
336 }
337
338 if (!function->IsOptimized()) {
339 function->ReplaceCode(function->shared()->code());
340 }
341 return NULL;
342}
343
344
345RUNTIME_FUNCTION(Runtime_TryInstallOptimizedCode) {
346 HandleScope scope(isolate);
347 DCHECK(args.length() == 1);
348 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
349
350 // First check if this is a real stack overflow.
351 StackLimitCheck check(isolate);
352 if (check.JsHasOverflowed()) {
353 SealHandleScope shs(isolate);
354 return isolate->StackOverflow();
355 }
356
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000357 isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400358 return (function->IsOptimized()) ? function->code()
359 : function->shared()->code();
360}
361
362
363bool CodeGenerationFromStringsAllowed(Isolate* isolate,
364 Handle<Context> context) {
365 DCHECK(context->allow_code_gen_from_strings()->IsFalse());
366 // Check with callback if set.
367 AllowCodeGenerationFromStringsCallback callback =
368 isolate->allow_code_gen_callback();
369 if (callback == NULL) {
370 // No callback set and code generation disallowed.
371 return false;
372 } else {
373 // Callback set. Let it decide if code generation is allowed.
374 VMState<EXTERNAL> state(isolate);
375 return callback(v8::Utils::ToLocal(context));
376 }
377}
378
379
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000380static Object* CompileGlobalEval(Isolate* isolate, Handle<String> source,
381 Handle<SharedFunctionInfo> outer_info,
382 LanguageMode language_mode,
383 int scope_position) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400384 Handle<Context> context = Handle<Context>(isolate->context());
385 Handle<Context> native_context = Handle<Context>(context->native_context());
386
387 // Check if native context allows code generation from
388 // strings. Throw an exception if it doesn't.
389 if (native_context->allow_code_gen_from_strings()->IsFalse() &&
390 !CodeGenerationFromStringsAllowed(isolate, native_context)) {
391 Handle<Object> error_message =
392 native_context->ErrorMessageForCodeGenerationFromStrings();
393 Handle<Object> error;
394 MaybeHandle<Object> maybe_error = isolate->factory()->NewEvalError(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000395 MessageTemplate::kCodeGenFromStrings, error_message);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400396 if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000397 return isolate->heap()->exception();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400398 }
399
400 // Deal with a normal eval call with a string argument. Compile it
401 // and return the compiled function bound in the local context.
402 static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
403 Handle<JSFunction> compiled;
404 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
405 isolate, compiled,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000406 Compiler::GetFunctionFromEval(source, outer_info, context, language_mode,
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400407 restriction, scope_position),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000408 isolate->heap()->exception());
409 return *compiled;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400410}
411
412
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000413RUNTIME_FUNCTION(Runtime_ResolvePossiblyDirectEval) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400414 HandleScope scope(isolate);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000415 DCHECK(args.length() == 5);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400416
417 Handle<Object> callee = args.at<Object>(0);
418
419 // If "eval" didn't refer to the original GlobalEval, it's not a
420 // direct call to eval.
421 // (And even if it is, but the first argument isn't a string, just let
422 // execution default to an indirect call to eval, which will also return
423 // the first argument without doing anything).
424 if (*callee != isolate->native_context()->global_eval_fun() ||
425 !args[1]->IsString()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000426 return *callee;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400427 }
428
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000429 DCHECK(args[3]->IsSmi());
430 DCHECK(is_valid_language_mode(args.smi_at(3)));
431 LanguageMode language_mode = static_cast<LanguageMode>(args.smi_at(3));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400432 DCHECK(args[4]->IsSmi());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400433 Handle<SharedFunctionInfo> outer_info(args.at<JSFunction>(2)->shared(),
434 isolate);
435 return CompileGlobalEval(isolate, args.at<String>(1), outer_info,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000436 language_mode, args.smi_at(4));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400437}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000438} // namespace internal
439} // namespace v8