blob: c0950456f9b82d88802caa7e1e1b913ffbc11f02 [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);
Ben Murdochc5610432016-08-08 18:44:38 +010022 DCHECK_EQ(1, args.length());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040023 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
Ben Murdochda12d292016-06-02 14:46:10 +010024
Emily Bernierd0a1eb72015-03-24 16:35:39 -040025#ifdef DEBUG
26 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
27 PrintF("[unoptimized: ");
28 function->PrintName();
29 PrintF("]\n");
30 }
31#endif
Ben Murdochda12d292016-06-02 14:46:10 +010032
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000033 StackLimitCheck check(isolate);
34 if (check.JsHasOverflowed(1 * KB)) return isolate->StackOverflow();
Ben Murdochda12d292016-06-02 14:46:10 +010035 if (!Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
36 return isolate->heap()->exception();
Emily Bernierd0a1eb72015-03-24 16:35:39 -040037 }
Ben Murdochda12d292016-06-02 14:46:10 +010038 DCHECK(function->is_compiled());
Emily Bernierd0a1eb72015-03-24 16:35:39 -040039 return function->code();
40}
41
Ben Murdochc5610432016-08-08 18:44:38 +010042RUNTIME_FUNCTION(Runtime_CompileBaseline) {
43 HandleScope scope(isolate);
44 DCHECK_EQ(1, args.length());
45 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
46 StackLimitCheck check(isolate);
47 if (check.JsHasOverflowed(1 * KB)) return isolate->StackOverflow();
48 if (!Compiler::CompileBaseline(function)) {
49 return isolate->heap()->exception();
50 }
51 DCHECK(function->is_compiled());
52 return function->code();
53}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000054
55RUNTIME_FUNCTION(Runtime_CompileOptimized_Concurrent) {
56 HandleScope scope(isolate);
Ben Murdochc5610432016-08-08 18:44:38 +010057 DCHECK_EQ(1, args.length());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000058 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
Ben Murdochda12d292016-06-02 14:46:10 +010059 StackLimitCheck check(isolate);
60 if (check.JsHasOverflowed(1 * KB)) return isolate->StackOverflow();
61 if (!Compiler::CompileOptimized(function, Compiler::CONCURRENT)) {
62 return isolate->heap()->exception();
63 }
64 DCHECK(function->is_compiled());
65 return function->code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000066}
67
68
69RUNTIME_FUNCTION(Runtime_CompileOptimized_NotConcurrent) {
70 HandleScope scope(isolate);
Ben Murdochc5610432016-08-08 18:44:38 +010071 DCHECK_EQ(1, args.length());
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000072 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
Ben Murdochda12d292016-06-02 14:46:10 +010073 StackLimitCheck check(isolate);
74 if (check.JsHasOverflowed(1 * KB)) return isolate->StackOverflow();
75 if (!Compiler::CompileOptimized(function, Compiler::NOT_CONCURRENT)) {
76 return isolate->heap()->exception();
77 }
78 DCHECK(function->is_compiled());
79 return function->code();
Ben Murdoch4a90d5f2016-03-22 12:00:34 +000080}
81
Emily Bernierd0a1eb72015-03-24 16:35:39 -040082
83RUNTIME_FUNCTION(Runtime_NotifyStubFailure) {
84 HandleScope scope(isolate);
85 DCHECK(args.length() == 0);
86 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
87 DCHECK(AllowHeapAllocation::IsAllowed());
88 delete deoptimizer;
89 return isolate->heap()->undefined_value();
90}
91
92
93class ActivationsFinder : public ThreadVisitor {
94 public:
95 Code* code_;
96 bool has_code_activations_;
97
98 explicit ActivationsFinder(Code* code)
99 : code_(code), has_code_activations_(false) {}
100
101 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
102 JavaScriptFrameIterator it(isolate, top);
103 VisitFrames(&it);
104 }
105
106 void VisitFrames(JavaScriptFrameIterator* it) {
107 for (; !it->done(); it->Advance()) {
108 JavaScriptFrame* frame = it->frame();
109 if (code_->contains(frame->pc())) has_code_activations_ = true;
110 }
111 }
112};
113
114
115RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
116 HandleScope scope(isolate);
117 DCHECK(args.length() == 1);
118 CONVERT_SMI_ARG_CHECKED(type_arg, 0);
119 Deoptimizer::BailoutType type =
120 static_cast<Deoptimizer::BailoutType>(type_arg);
121 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
122 DCHECK(AllowHeapAllocation::IsAllowed());
Ben Murdoch097c5b22016-05-18 11:27:45 +0100123 TimerEventScope<TimerEventDeoptimizeCode> timer(isolate);
124 TRACE_EVENT0("v8", "V8.DeoptimizeCode");
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400125
126 Handle<JSFunction> function = deoptimizer->function();
127 Handle<Code> optimized_code = deoptimizer->compiled_code();
128
129 DCHECK(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
130 DCHECK(type == deoptimizer->bailout_type());
131
132 // Make sure to materialize objects before causing any allocation.
133 JavaScriptFrameIterator it(isolate);
134 deoptimizer->MaterializeHeapObjects(&it);
135 delete deoptimizer;
136
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000137 // Ensure the context register is updated for materialized objects.
138 JavaScriptFrameIterator top_it(isolate);
139 JavaScriptFrame* top_frame = top_it.frame();
140 isolate->set_context(Context::cast(top_frame->context()));
141
142 if (type == Deoptimizer::LAZY) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400143 return isolate->heap()->undefined_value();
144 }
145
Ben Murdochda12d292016-06-02 14:46:10 +0100146 // Search for other activations of the same optimized code.
147 // At this point {it} is at the topmost frame of all the frames materialized
148 // by the deoptimizer. Note that this frame does not necessarily represent
149 // an activation of {function} because of potential inlined tail-calls.
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400150 ActivationsFinder activations_finder(*optimized_code);
151 activations_finder.VisitFrames(&it);
152 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
153
154 if (!activations_finder.has_code_activations_) {
155 if (function->code() == *optimized_code) {
156 if (FLAG_trace_deopt) {
157 PrintF("[removing optimized code for: ");
158 function->PrintName();
159 PrintF("]\n");
160 }
161 function->ReplaceCode(function->shared()->code());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400162 }
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000163 // Evict optimized code for this function from the cache so that it
164 // doesn't get used for new closures.
165 function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
166 "notify deoptimized");
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400167 } else {
168 // TODO(titzer): we should probably do DeoptimizeCodeList(code)
169 // unconditionally if the code is not already marked for deoptimization.
170 // If there is an index by shared function info, all the better.
171 Deoptimizer::DeoptimizeFunction(*function);
172 }
173
174 return isolate->heap()->undefined_value();
175}
176
177
178static bool IsSuitableForOnStackReplacement(Isolate* isolate,
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000179 Handle<JSFunction> function) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400180 // Keep track of whether we've succeeded in optimizing.
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000181 if (function->shared()->optimization_disabled()) return false;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400182 // If we are trying to do OSR when there are already optimized
183 // activations of the function, it means (a) the function is directly or
184 // indirectly recursive and (b) an optimized invocation has been
185 // deoptimized so that we are currently in an unoptimized activation.
186 // Check for optimized activations of this function.
187 for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
188 JavaScriptFrame* frame = it.frame();
189 if (frame->is_optimized() && frame->function() == *function) return false;
190 }
191
192 return true;
193}
194
195
196RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
197 HandleScope scope(isolate);
198 DCHECK(args.length() == 1);
199 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
200 Handle<Code> caller_code(function->shared()->code());
201
202 // We're not prepared to handle a function with arguments object.
203 DCHECK(!function->shared()->uses_arguments());
204
Ben Murdoch61f157c2016-09-16 13:49:30 +0100205 CHECK(FLAG_use_osr);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400206
207 // Passing the PC in the javascript frame from the caller directly is
208 // not GC safe, so we walk the stack to get it.
209 JavaScriptFrameIterator it(isolate);
210 JavaScriptFrame* frame = it.frame();
211 if (!caller_code->contains(frame->pc())) {
212 // Code on the stack may not be the code object referenced by the shared
213 // function info. It may have been replaced to include deoptimization data.
214 caller_code = Handle<Code>(frame->LookupCode());
215 }
216
217 uint32_t pc_offset =
218 static_cast<uint32_t>(frame->pc() - caller_code->instruction_start());
219
220#ifdef DEBUG
221 DCHECK_EQ(frame->function(), *function);
222 DCHECK_EQ(frame->LookupCode(), *caller_code);
223 DCHECK(caller_code->contains(frame->pc()));
224#endif // DEBUG
225
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400226 BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset);
227 DCHECK(!ast_id.IsNone());
228
Ben Murdoch097c5b22016-05-18 11:27:45 +0100229 MaybeHandle<Code> maybe_result;
Ben Murdochda12d292016-06-02 14:46:10 +0100230 if (IsSuitableForOnStackReplacement(isolate, function)) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400231 if (FLAG_trace_osr) {
232 PrintF("[OSR - Compiling: ");
233 function->PrintName();
234 PrintF(" at AST id %d]\n", ast_id.ToInt());
235 }
Ben Murdochda12d292016-06-02 14:46:10 +0100236 maybe_result = Compiler::GetOptimizedCodeForOSR(function, ast_id, frame);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400237 }
238
239 // Revert the patched back edge table, regardless of whether OSR succeeds.
240 BackEdgeTable::Revert(isolate, *caller_code);
241
242 // Check whether we ended up with usable optimized code.
Ben Murdoch097c5b22016-05-18 11:27:45 +0100243 Handle<Code> result;
244 if (maybe_result.ToHandle(&result) &&
245 result->kind() == Code::OPTIMIZED_FUNCTION) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400246 DeoptimizationInputData* data =
247 DeoptimizationInputData::cast(result->deoptimization_data());
248
249 if (data->OsrPcOffset()->value() >= 0) {
250 DCHECK(BailoutId(data->OsrAstId()->value()) == ast_id);
251 if (FLAG_trace_osr) {
252 PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n",
253 ast_id.ToInt(), data->OsrPcOffset()->value());
254 }
255 // TODO(titzer): this is a massive hack to make the deopt counts
256 // match. Fix heuristics for reenabling optimizations!
257 function->shared()->increment_deopt_count();
258
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000259 if (result->is_turbofanned()) {
260 // TurboFanned OSR code cannot be installed into the function.
261 // But the function is obviously hot, so optimize it next time.
262 function->ReplaceCode(
263 isolate->builtins()->builtin(Builtins::kCompileOptimized));
264 } else {
265 // Crankshafted OSR code can be installed into the function.
266 function->ReplaceCode(*result);
267 }
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400268 return *result;
269 }
270 }
271
272 // Failed.
273 if (FLAG_trace_osr) {
274 PrintF("[OSR - Failed: ");
275 function->PrintName();
276 PrintF(" at AST id %d]\n", ast_id.ToInt());
277 }
278
279 if (!function->IsOptimized()) {
280 function->ReplaceCode(function->shared()->code());
281 }
282 return NULL;
283}
284
285
286RUNTIME_FUNCTION(Runtime_TryInstallOptimizedCode) {
287 HandleScope scope(isolate);
288 DCHECK(args.length() == 1);
289 CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
290
291 // First check if this is a real stack overflow.
292 StackLimitCheck check(isolate);
293 if (check.JsHasOverflowed()) {
294 SealHandleScope shs(isolate);
295 return isolate->StackOverflow();
296 }
297
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000298 isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400299 return (function->IsOptimized()) ? function->code()
300 : function->shared()->code();
301}
302
303
304bool CodeGenerationFromStringsAllowed(Isolate* isolate,
305 Handle<Context> context) {
Ben Murdoch61f157c2016-09-16 13:49:30 +0100306 DCHECK(context->allow_code_gen_from_strings()->IsFalse(isolate));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400307 // Check with callback if set.
308 AllowCodeGenerationFromStringsCallback callback =
309 isolate->allow_code_gen_callback();
310 if (callback == NULL) {
311 // No callback set and code generation disallowed.
312 return false;
313 } else {
314 // Callback set. Let it decide if code generation is allowed.
315 VMState<EXTERNAL> state(isolate);
316 return callback(v8::Utils::ToLocal(context));
317 }
318}
319
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000320static Object* CompileGlobalEval(Isolate* isolate, Handle<String> source,
321 Handle<SharedFunctionInfo> outer_info,
322 LanguageMode language_mode,
Ben Murdochc5610432016-08-08 18:44:38 +0100323 int eval_scope_position, int eval_position) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400324 Handle<Context> context = Handle<Context>(isolate->context());
325 Handle<Context> native_context = Handle<Context>(context->native_context());
326
327 // Check if native context allows code generation from
328 // strings. Throw an exception if it doesn't.
Ben Murdoch61f157c2016-09-16 13:49:30 +0100329 if (native_context->allow_code_gen_from_strings()->IsFalse(isolate) &&
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400330 !CodeGenerationFromStringsAllowed(isolate, native_context)) {
331 Handle<Object> error_message =
332 native_context->ErrorMessageForCodeGenerationFromStrings();
333 Handle<Object> error;
334 MaybeHandle<Object> maybe_error = isolate->factory()->NewEvalError(
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000335 MessageTemplate::kCodeGenFromStrings, error_message);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400336 if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000337 return isolate->heap()->exception();
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400338 }
339
340 // Deal with a normal eval call with a string argument. Compile it
341 // and return the compiled function bound in the local context.
342 static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
343 Handle<JSFunction> compiled;
344 ASSIGN_RETURN_ON_EXCEPTION_VALUE(
Ben Murdochc5610432016-08-08 18:44:38 +0100345 isolate, compiled, Compiler::GetFunctionFromEval(
346 source, outer_info, context, language_mode,
347 restriction, eval_scope_position, eval_position),
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000348 isolate->heap()->exception());
349 return *compiled;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400350}
351
352
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000353RUNTIME_FUNCTION(Runtime_ResolvePossiblyDirectEval) {
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400354 HandleScope scope(isolate);
Ben Murdochc5610432016-08-08 18:44:38 +0100355 DCHECK(args.length() == 6);
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400356
357 Handle<Object> callee = args.at<Object>(0);
358
359 // If "eval" didn't refer to the original GlobalEval, it's not a
360 // direct call to eval.
361 // (And even if it is, but the first argument isn't a string, just let
362 // execution default to an indirect call to eval, which will also return
363 // the first argument without doing anything).
364 if (*callee != isolate->native_context()->global_eval_fun() ||
365 !args[1]->IsString()) {
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000366 return *callee;
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400367 }
368
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000369 DCHECK(args[3]->IsSmi());
370 DCHECK(is_valid_language_mode(args.smi_at(3)));
371 LanguageMode language_mode = static_cast<LanguageMode>(args.smi_at(3));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400372 DCHECK(args[4]->IsSmi());
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400373 Handle<SharedFunctionInfo> outer_info(args.at<JSFunction>(2)->shared(),
374 isolate);
375 return CompileGlobalEval(isolate, args.at<String>(1), outer_info,
Ben Murdochc5610432016-08-08 18:44:38 +0100376 language_mode, args.smi_at(4), args.smi_at(5));
Emily Bernierd0a1eb72015-03-24 16:35:39 -0400377}
Ben Murdoch4a90d5f2016-03-22 12:00:34 +0000378} // namespace internal
379} // namespace v8