V8 Project
runtime-compiler.cc
Go to the documentation of this file.
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/v8.h"
6 
7 #include "src/arguments.h"
8 #include "src/compiler.h"
9 #include "src/deoptimizer.h"
10 #include "src/frames.h"
11 #include "src/full-codegen.h"
12 #include "src/isolate.h"
13 #include "src/isolate-inl.h"
14 #include "src/runtime/runtime.h"
16 #include "src/v8threads.h"
17 #include "src/vm-state.h"
18 #include "src/vm-state-inl.h"
19 
20 namespace v8 {
21 namespace internal {
22 
23 RUNTIME_FUNCTION(Runtime_CompileLazy) {
24  HandleScope scope(isolate);
25  DCHECK(args.length() == 1);
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  // Compile the target function.
36  DCHECK(function->shared()->allows_lazy_compilation());
37 
38  Handle<Code> code;
40  Compiler::GetLazyCode(function));
41  DCHECK(code->kind() == Code::FUNCTION ||
42  code->kind() == Code::OPTIMIZED_FUNCTION);
43  function->ReplaceCode(*code);
44  return *code;
45 }
46 
47 
48 RUNTIME_FUNCTION(Runtime_CompileOptimized) {
49  HandleScope scope(isolate);
50  DCHECK(args.length() == 2);
52  CONVERT_BOOLEAN_ARG_CHECKED(concurrent, 1);
53 
54  Handle<Code> unoptimized(function->shared()->code());
55  if (!isolate->use_crankshaft() ||
56  function->shared()->optimization_disabled() ||
57  isolate->DebuggerHasBreakPoints()) {
58  // If the function is not optimizable or debugger is active continue
59  // using the code from the full compiler.
60  if (FLAG_trace_opt) {
61  PrintF("[failed to optimize ");
62  function->PrintName();
63  PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
64  function->shared()->optimization_disabled() ? "F" : "T",
65  isolate->DebuggerHasBreakPoints() ? "T" : "F");
66  }
67  function->ReplaceCode(*unoptimized);
68  return function->code();
69  }
70 
73  Handle<Code> code;
74  if (Compiler::GetOptimizedCode(function, unoptimized, mode).ToHandle(&code)) {
75  function->ReplaceCode(*code);
76  } else {
77  function->ReplaceCode(function->shared()->code());
78  }
79 
80  DCHECK(function->code()->kind() == Code::FUNCTION ||
81  function->code()->kind() == Code::OPTIMIZED_FUNCTION ||
82  function->IsInOptimizationQueue());
83  return function->code();
84 }
85 
86 
87 RUNTIME_FUNCTION(Runtime_NotifyStubFailure) {
88  HandleScope scope(isolate);
89  DCHECK(args.length() == 0);
90  Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
91  DCHECK(AllowHeapAllocation::IsAllowed());
92  delete deoptimizer;
93  return isolate->heap()->undefined_value();
94 }
95 
96 
98  public:
101 
102  explicit ActivationsFinder(Code* code)
103  : code_(code), has_code_activations_(false) {}
104 
105  void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
106  JavaScriptFrameIterator it(isolate, top);
107  VisitFrames(&it);
108  }
109 
110  void VisitFrames(JavaScriptFrameIterator* it) {
111  for (; !it->done(); it->Advance()) {
112  JavaScriptFrame* frame = it->frame();
113  if (code_->contains(frame->pc())) has_code_activations_ = true;
114  }
115  }
116 };
117 
118 
119 RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
120  HandleScope scope(isolate);
121  DCHECK(args.length() == 1);
122  CONVERT_SMI_ARG_CHECKED(type_arg, 0);
124  static_cast<Deoptimizer::BailoutType>(type_arg);
125  Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
126  DCHECK(AllowHeapAllocation::IsAllowed());
127 
128  Handle<JSFunction> function = deoptimizer->function();
129  Handle<Code> optimized_code = deoptimizer->compiled_code();
130 
131  DCHECK(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
132  DCHECK(type == deoptimizer->bailout_type());
133 
134  // Make sure to materialize objects before causing any allocation.
135  JavaScriptFrameIterator it(isolate);
136  deoptimizer->MaterializeHeapObjects(&it);
137  delete deoptimizer;
138 
139  JavaScriptFrame* frame = it.frame();
140  RUNTIME_ASSERT(frame->function()->IsJSFunction());
141  DCHECK(frame->function() == *function);
142 
143  // Avoid doing too much work when running with --always-opt and keep
144  // the optimized code around.
145  if (FLAG_always_opt || type == Deoptimizer::LAZY) {
146  return isolate->heap()->undefined_value();
147  }
148 
149  // Search for other activations of the same function and code.
150  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());
162  // Evict optimized code for this function from the cache so that it
163  // doesn't get used for new closures.
164  function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
165  "notify deoptimized");
166  }
167  } 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.
172  }
173 
174  return isolate->heap()->undefined_value();
175 }
176 
177 
179  Handle<JSFunction> function,
180  Handle<Code> current_code) {
181  // Keep track of whether we've succeeded in optimizing.
182  if (!isolate->use_crankshaft() || !current_code->optimizable()) return false;
183  // If we are trying to do OSR when there are already optimized
184  // activations of the function, it means (a) the function is directly or
185  // indirectly recursive and (b) an optimized invocation has been
186  // deoptimized so that we are currently in an unoptimized activation.
187  // Check for optimized activations of this function.
188  for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
189  JavaScriptFrame* frame = it.frame();
190  if (frame->is_optimized() && frame->function() == *function) return false;
191  }
192 
193  return true;
194 }
195 
196 
197 RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
198  HandleScope scope(isolate);
199  DCHECK(args.length() == 1);
201  Handle<Code> caller_code(function->shared()->code());
202 
203  // We're not prepared to handle a function with arguments object.
204  DCHECK(!function->shared()->uses_arguments());
205 
206  RUNTIME_ASSERT(FLAG_use_osr);
207 
208  // Passing the PC in the javascript frame from the caller directly is
209  // not GC safe, so we walk the stack to get it.
210  JavaScriptFrameIterator it(isolate);
211  JavaScriptFrame* frame = it.frame();
212  if (!caller_code->contains(frame->pc())) {
213  // Code on the stack may not be the code object referenced by the shared
214  // function info. It may have been replaced to include deoptimization data.
215  caller_code = Handle<Code>(frame->LookupCode());
216  }
217 
218  uint32_t pc_offset =
219  static_cast<uint32_t>(frame->pc() - caller_code->instruction_start());
220 
221 #ifdef DEBUG
222  DCHECK_EQ(frame->function(), *function);
223  DCHECK_EQ(frame->LookupCode(), *caller_code);
224  DCHECK(caller_code->contains(frame->pc()));
225 #endif // DEBUG
226 
227 
228  BailoutId ast_id = caller_code->TranslatePcOffsetToAstId(pc_offset);
229  DCHECK(!ast_id.IsNone());
230 
232  isolate->concurrent_osr_enabled() &&
233  (function->shared()->ast_node_count() > 512)
236  Handle<Code> result = Handle<Code>::null();
237 
238  OptimizedCompileJob* job = NULL;
239  if (mode == Compiler::CONCURRENT) {
240  // Gate the OSR entry with a stack check.
241  BackEdgeTable::AddStackCheck(caller_code, pc_offset);
242  // Poll already queued compilation jobs.
243  OptimizingCompilerThread* thread = isolate->optimizing_compiler_thread();
244  if (thread->IsQueuedForOSR(function, ast_id)) {
245  if (FLAG_trace_osr) {
246  PrintF("[OSR - Still waiting for queued: ");
247  function->PrintName();
248  PrintF(" at AST id %d]\n", ast_id.ToInt());
249  }
250  return NULL;
251  }
252 
253  job = thread->FindReadyOSRCandidate(function, ast_id);
254  }
255 
256  if (job != NULL) {
257  if (FLAG_trace_osr) {
258  PrintF("[OSR - Found ready: ");
259  function->PrintName();
260  PrintF(" at AST id %d]\n", ast_id.ToInt());
261  }
263  } else if (IsSuitableForOnStackReplacement(isolate, function, caller_code)) {
264  if (FLAG_trace_osr) {
265  PrintF("[OSR - Compiling: ");
266  function->PrintName();
267  PrintF(" at AST id %d]\n", ast_id.ToInt());
268  }
269  MaybeHandle<Code> maybe_result =
270  Compiler::GetOptimizedCode(function, caller_code, mode, ast_id);
271  if (maybe_result.ToHandle(&result) &&
272  result.is_identical_to(isolate->builtins()->InOptimizationQueue())) {
273  // Optimization is queued. Return to check later.
274  return NULL;
275  }
276  }
277 
278  // Revert the patched back edge table, regardless of whether OSR succeeds.
279  BackEdgeTable::Revert(isolate, *caller_code);
280 
281  // Check whether we ended up with usable optimized code.
282  if (!result.is_null() && result->kind() == Code::OPTIMIZED_FUNCTION) {
284  DeoptimizationInputData::cast(result->deoptimization_data());
285 
286  if (data->OsrPcOffset()->value() >= 0) {
287  DCHECK(BailoutId(data->OsrAstId()->value()) == ast_id);
288  if (FLAG_trace_osr) {
289  PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n",
290  ast_id.ToInt(), data->OsrPcOffset()->value());
291  }
292  // TODO(titzer): this is a massive hack to make the deopt counts
293  // match. Fix heuristics for reenabling optimizations!
294  function->shared()->increment_deopt_count();
295 
296  // TODO(titzer): Do not install code into the function.
297  function->ReplaceCode(*result);
298  return *result;
299  }
300  }
301 
302  // Failed.
303  if (FLAG_trace_osr) {
304  PrintF("[OSR - Failed: ");
305  function->PrintName();
306  PrintF(" at AST id %d]\n", ast_id.ToInt());
307  }
308 
309  if (!function->IsOptimized()) {
310  function->ReplaceCode(function->shared()->code());
311  }
312  return NULL;
313 }
314 
315 
316 RUNTIME_FUNCTION(Runtime_TryInstallOptimizedCode) {
317  HandleScope scope(isolate);
318  DCHECK(args.length() == 1);
320 
321  // First check if this is a real stack overflow.
322  StackLimitCheck check(isolate);
323  if (check.JsHasOverflowed()) {
324  SealHandleScope shs(isolate);
325  return isolate->StackOverflow();
326  }
327 
328  isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
329  return (function->IsOptimized()) ? function->code()
330  : function->shared()->code();
331 }
332 
333 
335  Handle<Context> context) {
336  DCHECK(context->allow_code_gen_from_strings()->IsFalse());
337  // Check with callback if set.
339  isolate->allow_code_gen_callback();
340  if (callback == NULL) {
341  // No callback set and code generation disallowed.
342  return false;
343  } else {
344  // Callback set. Let it decide if code generation is allowed.
345  VMState<EXTERNAL> state(isolate);
346  return callback(v8::Utils::ToLocal(context));
347  }
348 }
349 
350 
351 RUNTIME_FUNCTION(Runtime_CompileString) {
352  HandleScope scope(isolate);
353  DCHECK(args.length() == 2);
355  CONVERT_BOOLEAN_ARG_CHECKED(function_literal_only, 1);
356 
357  // Extract native context.
358  Handle<Context> context(isolate->native_context());
359 
360  // Check if native context allows code generation from
361  // strings. Throw an exception if it doesn't.
362  if (context->allow_code_gen_from_strings()->IsFalse() &&
363  !CodeGenerationFromStringsAllowed(isolate, context)) {
364  Handle<Object> error_message =
365  context->ErrorMessageForCodeGenerationFromStrings();
367  isolate, NewEvalError("code_gen_from_strings",
368  HandleVector<Object>(&error_message, 1)));
369  }
370 
371  // Compile source string in the native context.
372  ParseRestriction restriction = function_literal_only
375  Handle<JSFunction> fun;
377  isolate, fun,
378  Compiler::GetFunctionFromEval(source, context, SLOPPY, restriction,
380  return *fun;
381 }
382 
383 
385  Handle<Object> receiver,
386  StrictMode strict_mode,
387  int scope_position) {
388  Handle<Context> context = Handle<Context>(isolate->context());
389  Handle<Context> native_context = Handle<Context>(context->native_context());
390 
391  // Check if native context allows code generation from
392  // strings. Throw an exception if it doesn't.
393  if (native_context->allow_code_gen_from_strings()->IsFalse() &&
394  !CodeGenerationFromStringsAllowed(isolate, native_context)) {
395  Handle<Object> error_message =
396  native_context->ErrorMessageForCodeGenerationFromStrings();
397  Handle<Object> error;
398  MaybeHandle<Object> maybe_error = isolate->factory()->NewEvalError(
399  "code_gen_from_strings", HandleVector<Object>(&error_message, 1));
400  if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
401  return MakePair(isolate->heap()->exception(), NULL);
402  }
403 
404  // Deal with a normal eval call with a string argument. Compile it
405  // and return the compiled function bound in the local context.
406  static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
407  Handle<JSFunction> compiled;
409  isolate, compiled,
410  Compiler::GetFunctionFromEval(source, context, strict_mode, restriction,
411  scope_position),
412  MakePair(isolate->heap()->exception(), NULL));
413  return MakePair(*compiled, *receiver);
414 }
415 
416 
417 RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ResolvePossiblyDirectEval) {
418  HandleScope scope(isolate);
419  DCHECK(args.length() == 5);
420 
421  Handle<Object> callee = args.at<Object>(0);
422 
423  // If "eval" didn't refer to the original GlobalEval, it's not a
424  // direct call to eval.
425  // (And even if it is, but the first argument isn't a string, just let
426  // execution default to an indirect call to eval, which will also return
427  // the first argument without doing anything).
428  if (*callee != isolate->native_context()->global_eval_fun() ||
429  !args[1]->IsString()) {
430  return MakePair(*callee, isolate->heap()->undefined_value());
431  }
432 
433  DCHECK(args[3]->IsSmi());
434  DCHECK(args.smi_at(3) == SLOPPY || args.smi_at(3) == STRICT);
435  StrictMode strict_mode = static_cast<StrictMode>(args.smi_at(3));
436  DCHECK(args[4]->IsSmi());
437  return CompileGlobalEval(isolate, args.at<String>(1), args.at<Object>(2),
438  strict_mode, args.smi_at(4));
439 }
440 }
441 } // namespace v8::internal
static Local< Context > ToLocal(v8::internal::Handle< v8::internal::Context > obj)
void VisitFrames(JavaScriptFrameIterator *it)
void VisitThread(Isolate *isolate, ThreadLocalTop *top)
static void Revert(Isolate *isolate, Code *unoptimized_code)
static void AddStackCheck(Handle< Code > code, uint32_t pc_offset)
bool IsNone() const
Definition: utils.h:966
int ToInt() const
Definition: utils.h:958
bool contains(byte *pc)
Definition: objects-inl.h:6211
static MUST_USE_RESULT MaybeHandle< JSFunction > GetFunctionFromEval(Handle< String > source, Handle< Context > context, StrictMode strict_mode, ParseRestriction restriction, int scope_position)
Definition: compiler.cc:1081
static MUST_USE_RESULT MaybeHandle< Code > GetOptimizedCode(Handle< JSFunction > function, Handle< Code > current_code, ConcurrencyMode mode, BailoutId osr_ast_id=BailoutId::None())
Definition: compiler.cc:1307
static MUST_USE_RESULT MaybeHandle< Code > GetLazyCode(Handle< JSFunction > function)
Definition: compiler.cc:821
static Handle< Code > GetConcurrentlyOptimizedCode(OptimizedCompileJob *job)
Definition: compiler.cc:1354
static Deoptimizer * Grab(Isolate *isolate)
Definition: deoptimizer.cc:111
void MaterializeHeapObjects(JavaScriptFrameIterator *it)
static void DeoptimizeFunction(JSFunction *function)
Definition: deoptimizer.cc:503
Handle< JSFunction > function() const
Definition: deoptimizer.h:149
Handle< Code > compiled_code() const
Definition: deoptimizer.h:150
BailoutType bailout_type() const
Definition: deoptimizer.h:151
bool is_null() const
Definition: handles.h:124
static Handle< T > null()
Definition: handles.h:123
Object * Throw(Object *exception, MessageLocation *location=NULL)
Definition: isolate.cc:832
Context * context()
Definition: isolate.h:548
bool use_crankshaft() const
Definition: isolate.cc:2174
Factory * factory()
Definition: isolate.h:982
JSFunction * function() const
Definition: frames-inl.h:265
bool IsQueuedForOSR(Handle< JSFunction > function, BailoutId osr_ast_id)
OptimizedCompileJob * FindReadyOSRCandidate(Handle< JSFunction > function, BailoutId osr_ast_id)
static const int kNoPosition
Definition: assembler.h:317
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long mode(MIPS only)") DEFINE_BOOL(enable_always_align_csp
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define ASSIGN_RETURN_FAILURE_ON_EXCEPTION(isolate, dst, call)
Definition: isolate.h:131
#define ASSIGN_RETURN_ON_EXCEPTION_VALUE(isolate, dst, call, value)
Definition: isolate.h:123
#define THROW_NEW_ERROR_RETURN_FAILURE(isolate, call)
Definition: isolate.h:146
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
RUNTIME_FUNCTION_RETURN_PAIR(Runtime_ResolvePossiblyDirectEval)
static ObjectPair CompileGlobalEval(Isolate *isolate, Handle< String > source, Handle< Object > receiver, StrictMode strict_mode, int scope_position)
uint64_t ObjectPair
static bool IsSuitableForOnStackReplacement(Isolate *isolate, Handle< JSFunction > function, Handle< Code > current_code)
void PrintF(const char *format,...)
Definition: utils.cc:80
bool CodeGenerationFromStringsAllowed(Isolate *isolate, Handle< Context > context)
@ ONLY_SINGLE_FUNCTION_LITERAL
Definition: compiler.h:23
@ NO_PARSE_RESTRICTION
Definition: compiler.h:22
static ObjectPair MakePair(Object *x, Object *y)
@ RUNTIME_FUNCTION
Definition: serialize.h:23
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20
bool(* AllowCodeGenerationFromStringsCallback)(Local< Context > context)
Callback to check if code generation from strings is allowed.
Definition: v8.h:4192
#define CONVERT_BOOLEAN_ARG_CHECKED(name, index)
Definition: runtime-utils.h:39
#define RUNTIME_ASSERT(value)
Definition: runtime-utils.h:12
#define CONVERT_ARG_HANDLE_CHECKED(Type, name, index)
Definition: runtime-utils.h:28
#define CONVERT_SMI_ARG_CHECKED(name, index)
Definition: runtime-utils.h:46