LCOV - code coverage report
Current view: top level - src/runtime - runtime-compiler.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 159 171 93.0 %
Date: 2017-04-26 Functions: 18 28 64.3 %

          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/runtime/runtime-utils.h"
       6             : 
       7             : #include "src/arguments.h"
       8             : #include "src/asmjs/asm-js.h"
       9             : #include "src/compiler-dispatcher/optimizing-compile-dispatcher.h"
      10             : #include "src/compiler.h"
      11             : #include "src/deoptimizer.h"
      12             : #include "src/frames-inl.h"
      13             : #include "src/full-codegen/full-codegen.h"
      14             : #include "src/isolate-inl.h"
      15             : #include "src/messages.h"
      16             : #include "src/v8threads.h"
      17             : #include "src/vm-state-inl.h"
      18             : 
      19             : namespace v8 {
      20             : namespace internal {
      21             : 
      22     2109021 : RUNTIME_FUNCTION(Runtime_CompileLazy) {
      23     1054511 :   HandleScope scope(isolate);
      24             :   DCHECK_EQ(1, args.length());
      25     2109022 :   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     1054511 :   StackLimitCheck check(isolate);
      36     1054511 :   if (check.JsHasOverflowed(1 * KB)) return isolate->StackOverflow();
      37     1053811 :   if (!Compiler::Compile(function, Compiler::KEEP_EXCEPTION)) {
      38        2560 :     return isolate->heap()->exception();
      39             :   }
      40             :   DCHECK(function->is_compiled());
      41     1051251 :   return function->code();
      42             : }
      43             : 
      44      250772 : RUNTIME_FUNCTION(Runtime_CompileOptimized_Concurrent) {
      45      125386 :   HandleScope scope(isolate);
      46             :   DCHECK_EQ(1, args.length());
      47      250772 :   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
      48      125386 :   StackLimitCheck check(isolate);
      49      125386 :   if (check.JsHasOverflowed(1 * KB)) return isolate->StackOverflow();
      50      125375 :   if (!Compiler::CompileOptimized(function, Compiler::CONCURRENT)) {
      51           0 :     return isolate->heap()->exception();
      52             :   }
      53             :   DCHECK(function->is_compiled());
      54      125375 :   return function->code();
      55             : }
      56             : 
      57             : 
      58     1093398 : RUNTIME_FUNCTION(Runtime_CompileOptimized_NotConcurrent) {
      59      546700 :   HandleScope scope(isolate);
      60             :   DCHECK_EQ(1, args.length());
      61     1093400 :   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
      62      546700 :   StackLimitCheck check(isolate);
      63      546700 :   if (check.JsHasOverflowed(1 * KB)) return isolate->StackOverflow();
      64      546319 :   if (!Compiler::CompileOptimized(function, Compiler::NOT_CONCURRENT)) {
      65           0 :     return isolate->heap()->exception();
      66             :   }
      67             :   DCHECK(function->is_compiled());
      68      546318 :   return function->code();
      69             : }
      70             : 
      71       14002 : RUNTIME_FUNCTION(Runtime_InstantiateAsmJs) {
      72        7001 :   HandleScope scope(isolate);
      73             :   DCHECK_EQ(args.length(), 4);
      74       14002 :   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
      75             : 
      76             :   Handle<JSReceiver> stdlib;
      77       14002 :   if (args[1]->IsJSReceiver()) {
      78        4757 :     stdlib = args.at<JSReceiver>(1);
      79             :   }
      80             :   Handle<JSObject> foreign;
      81       14002 :   if (args[2]->IsJSObject()) {
      82        2546 :     foreign = args.at<JSObject>(2);
      83             :   }
      84             :   Handle<JSArrayBuffer> memory;
      85       14002 :   if (args[3]->IsJSArrayBuffer()) {
      86        2273 :     memory = args.at<JSArrayBuffer>(3);
      87             :   }
      88       13995 :   if (function->shared()->HasAsmWasmData() &&
      89             :       AsmJs::IsStdlibValid(isolate, handle(function->shared()->asm_wasm_data()),
      90       13988 :                            stdlib)) {
      91             :     MaybeHandle<Object> result;
      92             :     result = AsmJs::InstantiateAsmWasm(
      93       12978 :         isolate, handle(function->shared()->asm_wasm_data()), memory, foreign);
      94        6489 :     if (!result.is_null()) {
      95             :       return *result.ToHandleChecked();
      96             :     }
      97             :   }
      98             :   // Remove wasm data, mark as broken for asm->wasm,
      99             :   // replace code with CompileLazy, and return a smi 0 to indicate failure.
     100         514 :   if (function->shared()->HasAsmWasmData()) {
     101         507 :     function->shared()->ClearAsmWasmData();
     102             :   }
     103         514 :   function->shared()->set_is_asm_wasm_broken(true);
     104             :   DCHECK(function->code() ==
     105             :          isolate->builtins()->builtin(Builtins::kInstantiateAsmJs));
     106        1028 :   function->ReplaceCode(isolate->builtins()->builtin(Builtins::kCompileLazy));
     107        1028 :   if (function->shared()->code() ==
     108         514 :       isolate->builtins()->builtin(Builtins::kInstantiateAsmJs)) {
     109             :     function->shared()->ReplaceCode(
     110         507 :         isolate->builtins()->builtin(Builtins::kCompileLazy));
     111             :   }
     112        7001 :   return Smi::kZero;
     113             : }
     114             : 
     115       53294 : RUNTIME_FUNCTION(Runtime_NotifyStubFailure) {
     116       26647 :   HandleScope scope(isolate);
     117             :   DCHECK_EQ(0, args.length());
     118       26647 :   Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
     119             :   DCHECK(AllowHeapAllocation::IsAllowed());
     120       26647 :   delete deoptimizer;
     121       26647 :   return isolate->heap()->undefined_value();
     122             : }
     123             : 
     124       50872 : class ActivationsFinder : public ThreadVisitor {
     125             :  public:
     126             :   Code* code_;
     127             :   bool has_code_activations_;
     128             : 
     129       25436 :   explicit ActivationsFinder(Code* code)
     130       25436 :       : code_(code), has_code_activations_(false) {}
     131             : 
     132           8 :   void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
     133           8 :     JavaScriptFrameIterator it(isolate, top);
     134           8 :     VisitFrames(&it);
     135           8 :   }
     136             : 
     137       25444 :   void VisitFrames(JavaScriptFrameIterator* it) {
     138      392760 :     for (; !it->done(); it->Advance()) {
     139             :       JavaScriptFrame* frame = it->frame();
     140      367316 :       if (code_->contains(frame->pc())) has_code_activations_ = true;
     141             :     }
     142       25444 :   }
     143             : };
     144             : 
     145             : 
     146      274596 : RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
     147      124580 :   HandleScope scope(isolate);
     148             :   DCHECK_EQ(1, args.length());
     149      249160 :   CONVERT_SMI_ARG_CHECKED(type_arg, 0);
     150             :   Deoptimizer::BailoutType type =
     151      124580 :       static_cast<Deoptimizer::BailoutType>(type_arg);
     152      249160 :   Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
     153             :   DCHECK(AllowHeapAllocation::IsAllowed());
     154      249160 :   TimerEventScope<TimerEventDeoptimizeCode> timer(isolate);
     155      249160 :   TRACE_EVENT0("v8", "V8.DeoptimizeCode");
     156             : 
     157      124580 :   Handle<JSFunction> function = deoptimizer->function();
     158      124580 :   Handle<Code> optimized_code = deoptimizer->compiled_code();
     159             : 
     160             :   DCHECK(optimized_code->kind() == Code::OPTIMIZED_FUNCTION);
     161             :   DCHECK(type == deoptimizer->bailout_type());
     162             :   DCHECK_NULL(isolate->context());
     163             : 
     164             :   // TODO(turbofan): For Crankshaft we restore the context before objects are
     165             :   // being materialized, because it never de-materializes the context but it
     166             :   // requires a context to materialize arguments objects. This is specific to
     167             :   // Crankshaft and can be removed once only TurboFan goes through here.
     168      124580 :   if (!optimized_code->is_turbofanned()) {
     169       16730 :     JavaScriptFrameIterator top_it(isolate);
     170       16730 :     JavaScriptFrame* top_frame = top_it.frame();
     171       16730 :     isolate->set_context(Context::cast(top_frame->context()));
     172             :   } else {
     173             :     // TODO(turbofan): We currently need the native context to materialize
     174             :     // the arguments object, but only to get to its map.
     175      107850 :     isolate->set_context(function->native_context());
     176             :   }
     177             : 
     178             :   // Make sure to materialize objects before causing any allocation.
     179      249160 :   JavaScriptFrameIterator it(isolate);
     180      124580 :   deoptimizer->MaterializeHeapObjects(&it);
     181      124580 :   delete deoptimizer;
     182             : 
     183             :   // Ensure the context register is updated for materialized objects.
     184      124580 :   if (optimized_code->is_turbofanned()) {
     185      107850 :     JavaScriptFrameIterator top_it(isolate);
     186      107850 :     JavaScriptFrame* top_frame = top_it.frame();
     187      107850 :     isolate->set_context(Context::cast(top_frame->context()));
     188             :   }
     189             : 
     190      124580 :   if (type == Deoptimizer::LAZY) {
     191       99144 :     return isolate->heap()->undefined_value();
     192             :   }
     193             : 
     194             :   // Search for other activations of the same optimized code.
     195             :   // At this point {it} is at the topmost frame of all the frames materialized
     196             :   // by the deoptimizer. Note that this frame does not necessarily represent
     197             :   // an activation of {function} because of potential inlined tail-calls.
     198       50872 :   ActivationsFinder activations_finder(*optimized_code);
     199       25436 :   activations_finder.VisitFrames(&it);
     200       25436 :   isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
     201             : 
     202       25436 :   if (!activations_finder.has_code_activations_) {
     203             :     Deoptimizer::UnlinkOptimizedCode(*optimized_code,
     204       50592 :                                      function->context()->native_context());
     205             : 
     206             :     // Evict optimized code for this function from the cache so that it
     207             :     // doesn't get used for new closures.
     208             :     function->shared()->EvictFromOptimizedCodeMap(*optimized_code,
     209       25296 :                                                   "notify deoptimized");
     210             :   } else {
     211             :     // TODO(titzer): we should probably do DeoptimizeCodeList(code)
     212             :     // unconditionally if the code is not already marked for deoptimization.
     213             :     // If there is an index by shared function info, all the better.
     214         140 :     Deoptimizer::DeoptimizeFunction(*function);
     215             :   }
     216             : 
     217      150016 :   return isolate->heap()->undefined_value();
     218             : }
     219             : 
     220             : 
     221        8477 : static bool IsSuitableForOnStackReplacement(Isolate* isolate,
     222             :                                             Handle<JSFunction> function) {
     223             :   // Keep track of whether we've succeeded in optimizing.
     224        8477 :   if (function->shared()->optimization_disabled()) return false;
     225             :   // If we are trying to do OSR when there are already optimized
     226             :   // activations of the function, it means (a) the function is directly or
     227             :   // indirectly recursive and (b) an optimized invocation has been
     228             :   // deoptimized so that we are currently in an unoptimized activation.
     229             :   // Check for optimized activations of this function.
     230       56634 :   for (JavaScriptFrameIterator it(isolate); !it.done(); it.Advance()) {
     231             :     JavaScriptFrame* frame = it.frame();
     232       40449 :     if (frame->is_optimized() && frame->function() == *function) return false;
     233             :   }
     234             : 
     235        8477 :   return true;
     236             : }
     237             : 
     238             : namespace {
     239             : 
     240        2641 : BailoutId DetermineEntryAndDisarmOSRForBaseline(JavaScriptFrame* frame) {
     241        2641 :   Handle<Code> caller_code(frame->function()->shared()->code());
     242             : 
     243             :   // Passing the PC in the JavaScript frame from the caller directly is
     244             :   // not GC safe, so we walk the stack to get it.
     245        5282 :   if (!caller_code->contains(frame->pc())) {
     246             :     // Code on the stack may not be the code object referenced by the shared
     247             :     // function info.  It may have been replaced to include deoptimization data.
     248             :     caller_code = Handle<Code>(frame->LookupCode());
     249             :   }
     250             : 
     251             :   DCHECK_EQ(frame->LookupCode(), *caller_code);
     252             :   DCHECK_EQ(Code::FUNCTION, caller_code->kind());
     253             :   DCHECK(caller_code->contains(frame->pc()));
     254             : 
     255             :   // Revert the patched back edge table, regardless of whether OSR succeeds.
     256        2641 :   BackEdgeTable::Revert(frame->isolate(), *caller_code);
     257             : 
     258             :   // Return a BailoutId representing an AST id of the {IterationStatement}.
     259             :   uint32_t pc_offset =
     260        5282 :       static_cast<uint32_t>(frame->pc() - caller_code->instruction_start());
     261        2641 :   return caller_code->TranslatePcOffsetToAstId(pc_offset);
     262             : }
     263             : 
     264        5836 : BailoutId DetermineEntryAndDisarmOSRForInterpreter(JavaScriptFrame* frame) {
     265             :   InterpretedFrame* iframe = reinterpret_cast<InterpretedFrame*>(frame);
     266             : 
     267             :   // Note that the bytecode array active on the stack might be different from
     268             :   // the one installed on the function (e.g. patched by debugger). This however
     269             :   // is fine because we guarantee the layout to be in sync, hence any BailoutId
     270             :   // representing the entry point will be valid for any copy of the bytecode.
     271        5836 :   Handle<BytecodeArray> bytecode(iframe->GetBytecodeArray());
     272             : 
     273             :   DCHECK(frame->LookupCode()->is_interpreter_trampoline_builtin());
     274             :   DCHECK(frame->function()->shared()->HasBytecodeArray());
     275             :   DCHECK(frame->is_interpreted());
     276             :   DCHECK(FLAG_ignition_osr);
     277             : 
     278             :   // Reset the OSR loop nesting depth to disarm back edges.
     279             :   bytecode->set_osr_loop_nesting_level(0);
     280             : 
     281             :   // Return a BailoutId representing the bytecode offset of the back branch.
     282        5836 :   return BailoutId(iframe->GetBytecodeOffset());
     283             : }
     284             : 
     285             : }  // namespace
     286             : 
     287       16954 : RUNTIME_FUNCTION(Runtime_CompileForOnStackReplacement) {
     288        8477 :   HandleScope scope(isolate);
     289             :   DCHECK_EQ(1, args.length());
     290       16954 :   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
     291             : 
     292             :   // We're not prepared to handle a function with arguments object.
     293             :   DCHECK(!function->shared()->uses_arguments());
     294             : 
     295             :   // Only reachable when OST is enabled.
     296        8477 :   CHECK(FLAG_use_osr);
     297             : 
     298             :   // Determine frame triggering OSR request.
     299       16954 :   JavaScriptFrameIterator it(isolate);
     300        8477 :   JavaScriptFrame* frame = it.frame();
     301             :   DCHECK_EQ(frame->function(), *function);
     302             : 
     303             :   // Determine the entry point for which this OSR request has been fired and
     304             :   // also disarm all back edges in the calling code to stop new requests.
     305        8477 :   BailoutId ast_id = frame->is_interpreted()
     306             :                          ? DetermineEntryAndDisarmOSRForInterpreter(frame)
     307        8477 :                          : DetermineEntryAndDisarmOSRForBaseline(frame);
     308             :   DCHECK(!ast_id.IsNone());
     309             : 
     310             :   MaybeHandle<Code> maybe_result;
     311        8477 :   if (IsSuitableForOnStackReplacement(isolate, function)) {
     312        8477 :     if (FLAG_trace_osr) {
     313           0 :       PrintF("[OSR - Compiling: ");
     314           0 :       function->PrintName();
     315           0 :       PrintF(" at AST id %d]\n", ast_id.ToInt());
     316             :     }
     317        8477 :     maybe_result = Compiler::GetOptimizedCodeForOSR(function, ast_id, frame);
     318             :   }
     319             : 
     320             :   // Check whether we ended up with usable optimized code.
     321             :   Handle<Code> result;
     322       16870 :   if (maybe_result.ToHandle(&result) &&
     323        8393 :       result->kind() == Code::OPTIMIZED_FUNCTION) {
     324             :     DeoptimizationInputData* data =
     325        8393 :         DeoptimizationInputData::cast(result->deoptimization_data());
     326             : 
     327        8393 :     if (data->OsrPcOffset()->value() >= 0) {
     328             :       DCHECK(BailoutId(data->OsrAstId()->value()) == ast_id);
     329        8393 :       if (FLAG_trace_osr) {
     330             :         PrintF("[OSR - Entry at AST id %d, offset %d in optimized code]\n",
     331           0 :                ast_id.ToInt(), data->OsrPcOffset()->value());
     332             :       }
     333             : 
     334        8393 :       if (result->is_turbofanned()) {
     335             :         // When we're waiting for concurrent optimization, set to compile on
     336             :         // the next call - otherwise we'd run unoptimized once more
     337             :         // and potentially compile for OSR another time as well.
     338        5903 :         if (function->IsMarkedForConcurrentOptimization()) {
     339        2158 :           if (FLAG_trace_osr) {
     340           0 :             PrintF("[OSR - Re-marking ");
     341           0 :             function->PrintName();
     342           0 :             PrintF(" for non-concurrent optimization]\n");
     343             :           }
     344             :           function->ReplaceCode(
     345        4316 :               isolate->builtins()->builtin(Builtins::kCompileOptimized));
     346             :         }
     347             :       } else {
     348             :         // Crankshafted OSR code can be installed into the function.
     349        2490 :         function->ReplaceCode(*result);
     350             :       }
     351             :       return *result;
     352             :     }
     353             :   }
     354             : 
     355             :   // Failed.
     356          84 :   if (FLAG_trace_osr) {
     357           0 :     PrintF("[OSR - Failed: ");
     358           0 :     function->PrintName();
     359           0 :     PrintF(" at AST id %d]\n", ast_id.ToInt());
     360             :   }
     361             : 
     362          84 :   if (!function->IsOptimized()) {
     363          84 :     function->ReplaceCode(function->shared()->code());
     364             :   }
     365        8477 :   return NULL;
     366             : }
     367             : 
     368             : 
     369       81713 : RUNTIME_FUNCTION(Runtime_TryInstallOptimizedCode) {
     370       27239 :   HandleScope scope(isolate);
     371             :   DCHECK_EQ(1, args.length());
     372       54478 :   CONVERT_ARG_HANDLE_CHECKED(JSFunction, function, 0);
     373             : 
     374             :   // First check if this is a real stack overflow.
     375       27239 :   StackLimitCheck check(isolate);
     376       27239 :   if (check.JsHasOverflowed()) {
     377             :     SealHandleScope shs(isolate);
     378           4 :     return isolate->StackOverflow();
     379             :   }
     380             : 
     381       27235 :   isolate->optimizing_compile_dispatcher()->InstallOptimizedFunctions();
     382       27235 :   return (function->IsOptimized()) ? function->code()
     383       27235 :                                    : function->shared()->code();
     384             : }
     385             : 
     386             : 
     387          27 : bool CodeGenerationFromStringsAllowed(Isolate* isolate,
     388             :                                       Handle<Context> context) {
     389             :   DCHECK(context->allow_code_gen_from_strings()->IsFalse(isolate));
     390             :   // Check with callback if set.
     391             :   AllowCodeGenerationFromStringsCallback callback =
     392             :       isolate->allow_code_gen_callback();
     393          27 :   if (callback == NULL) {
     394             :     // No callback set and code generation disallowed.
     395             :     return false;
     396             :   } else {
     397             :     // Callback set. Let it decide if code generation is allowed.
     398          20 :     VMState<EXTERNAL> state(isolate);
     399          20 :     return callback(v8::Utils::ToLocal(context));
     400             :   }
     401             : }
     402             : 
     403     3781156 : static Object* CompileGlobalEval(Isolate* isolate, Handle<String> source,
     404             :                                  Handle<SharedFunctionInfo> outer_info,
     405             :                                  LanguageMode language_mode,
     406             :                                  int eval_scope_position, int eval_position) {
     407             :   Handle<Context> context = Handle<Context>(isolate->context());
     408             :   Handle<Context> native_context = Handle<Context>(context->native_context());
     409             : 
     410             :   // Check if native context allows code generation from
     411             :   // strings. Throw an exception if it doesn't.
     412     3781183 :   if (native_context->allow_code_gen_from_strings()->IsFalse(isolate) &&
     413          27 :       !CodeGenerationFromStringsAllowed(isolate, native_context)) {
     414             :     Handle<Object> error_message =
     415          20 :         native_context->ErrorMessageForCodeGenerationFromStrings();
     416             :     Handle<Object> error;
     417             :     MaybeHandle<Object> maybe_error = isolate->factory()->NewEvalError(
     418          20 :         MessageTemplate::kCodeGenFromStrings, error_message);
     419          40 :     if (maybe_error.ToHandle(&error)) isolate->Throw(*error);
     420          20 :     return isolate->heap()->exception();
     421             :   }
     422             : 
     423             :   // Deal with a normal eval call with a string argument. Compile it
     424             :   // and return the compiled function bound in the local context.
     425             :   static const ParseRestriction restriction = NO_PARSE_RESTRICTION;
     426             :   Handle<JSFunction> compiled;
     427     7562272 :   ASSIGN_RETURN_ON_EXCEPTION_VALUE(
     428             :       isolate, compiled,
     429             :       Compiler::GetFunctionFromEval(source, outer_info, context, language_mode,
     430             :                                     restriction, kNoSourcePosition,
     431             :                                     eval_scope_position, eval_position),
     432             :       isolate->heap()->exception());
     433     3625028 :   return *compiled;
     434             : }
     435             : 
     436             : 
     437     7563588 : RUNTIME_FUNCTION(Runtime_ResolvePossiblyDirectEval) {
     438     3781794 :   HandleScope scope(isolate);
     439             :   DCHECK_EQ(6, args.length());
     440             : 
     441     3781794 :   Handle<Object> callee = args.at(0);
     442             : 
     443             :   // If "eval" didn't refer to the original GlobalEval, it's not a
     444             :   // direct call to eval.
     445             :   // (And even if it is, but the first argument isn't a string, just let
     446             :   // execution default to an indirect call to eval, which will also return
     447             :   // the first argument without doing anything).
     448    11345190 :   if (*callee != isolate->native_context()->global_eval_fun() ||
     449     3781602 :       !args[1]->IsString()) {
     450             :     return *callee;
     451             :   }
     452             : 
     453             :   DCHECK(args[3]->IsSmi());
     454             :   DCHECK(is_valid_language_mode(args.smi_at(3)));
     455     3781156 :   LanguageMode language_mode = static_cast<LanguageMode>(args.smi_at(3));
     456             :   DCHECK(args[4]->IsSmi());
     457             :   Handle<SharedFunctionInfo> outer_info(args.at<JSFunction>(2)->shared(),
     458    11343468 :                                         isolate);
     459             :   return CompileGlobalEval(isolate, args.at<String>(1), outer_info,
     460     3781156 :                            language_mode, args.smi_at(4), args.smi_at(5));
     461             : }
     462             : }  // namespace internal
     463             : }  // namespace v8

Generated by: LCOV version 1.10