Status: Assigned
Owner: [email protected]
CC: [email protected],  [email protected]
Labels: Type-Bug Priority-High

New issue 4255 by [email protected]: Let variables are inconsistently allocated, causing crash on OSR.
https://code.google.com/p/v8/issues/detail?id=4255

Consider following code:

// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation

'use strict';
{
  let x = function() {};
}


Depending on whether we compile lazily or not, we get the following scope analysis:

yangguo@yangguo:~/v8$ out/ia32.debug/d8 test.js --print-scopes --no-lazy
global { // (0, 1278)
  // scope has trivial outer context
  // strict mode scope
  // 2 stack slots
  // temporary vars:
  TEMPORARY .result;  // local[1]

  block { // (1247, 1275)
    // scope has trivial outer context
    // strict mode scope
    // local vars:
    LET x;  // local[0]

    function () { // (1267, 1272)
      // scope has trivial outer context
      // strict mode scope
      // local vars:
    }
  }
}

yangguo@yangguo:~/v8$ out/ia32.debug/d8 test.js --print-scopes --lazy
global { // (0, 1278)
  // scope has trivial outer context
  // strict mode scope
  // 1 stack slots
  // temporary vars:
  TEMPORARY .result;  // local[0]

  block { // (1247, 1275)
    // scope has trivial outer context
    // strict mode scope
    // 5 heap slots
    // local vars:
    LET x;  // context[4]

    function () { // (1267, 1272)
      // strict mode scope
      // local vars:
    }
  }
}


Note that we have a different number of stack slots depending on whether we compile lazily. This is because in Parser::ParseFunctionLiteral, if we parse lazily, we cannot predict whether a variable needs to be context allocated. To be safe, in case a variable is used in an inner context, we mark all outer scopes to force context allocate.

That is a problem for the debugger, since we replace unoptimized code without debug break slots with recompiled unoptimized code that contain debug break slots. Luckily, this does not happen up till now, because we have an exception for top-level code, and lazy compilation only affects functions defined on the top-level.

However, crankshaft also replaces on stack. Consider the following code:

// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation
// comments to trigger lazy compilation comments to trigger lazy compilation

'use strict';
{
  let x = function() {};
  for (var i = 0; i < 1000000; i++);
  print(x);
}


We crash right during compile for OSR:

#0 v8::internal::Map::instance_type (this=0xca05bbfd) at .././src/objects-inl.h:4175 #1 0x08c9c650 in v8::internal::TypeImpl<v8::internal::ZoneTypeConfig>::NowOf (value=0x2a939d19, region=0x9e349c4) at .././src/types-inl.h:46 #2 0x08cacbd0 in v8::internal::AstTyper::ObservedOnStack (this=0x9e3d428, value=0x2a939d19) at ../src/typing.cc:64 #3 0x08cad041 in v8::internal::AstTyper::ObserveTypesAtOsrEntry (this=0x9e3d428, stmt=0x9e3d054) at ../src/typing.cc:91 #4 0x08caedb0 in v8::internal::AstTyper::VisitForStatement (this=0x9e3d428, stmt=0x9e3d054) at ../src/typing.cc:291 #5 0x08dfc214 in v8::internal::ForStatement::Accept (this=0x9e3d054, v=0x9e3d428) at ../src/ast.cc:28 #6 0x08cad94c in v8::internal::AstTyper::Visit (this=0x9e3d428, node=0x9e3d054) at .././src/typing.h:30 #7 0x08cad8b1 in v8::internal::AstTyper::VisitStatements (this=0x9e3d428, stmts=0x9e3c534) at ../src/typing.cc:130 #8 0x08cad9fa in v8::internal::AstTyper::VisitBlock (this=0x9e3d428, stmt=0x9e3c518) at ../src/typing.cc:137 #9 0x08dfc004 in v8::internal::Block::Accept (this=0x9e3c518, v=0x9e3d428) at ../src/ast.cc:28 #10 0x08cad94c in v8::internal::AstTyper::Visit (this=0x9e3d428, node=0x9e3c518) at .././src/typing.h:30 #11 0x08cad8b1 in v8::internal::AstTyper::VisitStatements (this=0x9e3d428, stmts=0x9e3c438) at ../src/typing.cc:130 #12 0x08cacb0e in v8::internal::AstTyper::Run (info=0x9e34908) at ../src/typing.cc:45 #13 0x087c3418 in v8::internal::OptimizedCompileJob::CreateGraph (this=0xffffbcd8) at ../src/compiler.cc:451 #14 0x087c6258 in v8::internal::GetOptimizedCodeNow (info=0x9e34908) at ../src/compiler.cc:781 #15 0x087c6aa8 in v8::internal::Compiler::GetOptimizedCode (function=..., current_code=..., mode=v8::internal::Compiler::NOT_CONCURRENT, osr_ast_id=...)
    at ../src/compiler.cc:1525
#16 0x08f34413 in v8::internal::__RT_impl_Runtime_CompileForOnStackReplacement (args=..., isolate=0x9e09c50) at ../src/runtime/runtime-compiler.cc:262 #17 0x08f33b91 in v8::internal::Runtime_CompileForOnStackReplacement (args_length=1, args_object=0xffffc1cc, isolate=0x9e09c50)
    at ../src/runtime/runtime-compiler.cc:188
#18 0x2a90d03c in ?? ()
#19 0x2a92e37e in ?? ()
#20 0x2a939d19 in ?? ()
#21 0x2a92be41 in ?? ()
#22 0x2a917fff in ?? ()
#23 0x08874426 in v8::internal::Invoke (is_construct=false, function=..., receiver=..., argc=0, args=0x0) at ../src/execution.cc:128 #24 0x08873a73 in v8::internal::Execution::Call (isolate=0x9e09c50, callable=..., receiver=..., argc=0, argv=0x0, convert_receiver=false)
    at ../src/execution.cc:179
#25 0x086c25d4 in v8::Script::Run (this=0x9e328e4, context=...) at ../src/api.cc:1687
#26 0x086cfc7b in v8::Script::Run (this=0x9e328e4) at ../src/api.cc:1700
#27 0x0868b1ee in v8::Shell::ExecuteString (isolate=0x9e09c50, source=..., name=..., print_result=false, report_exceptions=true,
    source_type=v8::Shell::SCRIPT) at ../src/d8.cc:349
#28 0x086964be in v8::SourceGroup::Execute (this=0x9e0800c, isolate=0x9e09c50) at ../src/d8.cc:1452 #29 0x08699460 in v8::Shell::RunMain (isolate=0x9e09c50, argc=3, argv=0xffffcb24) at ../src/d8.cc:1953 #30 0x0869a67c in v8::Shell::Main (argc=3, argv=0xffffcb24) at ../src/d8.cc:2392
#31 0x086a055b in main (argc=3, argv=0xffffcb24) at ../src/d8.cc:2435


What we do here is that we inspect the stack to make predictions on value types. However, the stack layout is different than we expect, and the object we are trying to get the map of is not an actual object.

If we skip AstTyper::ObserveTypesAtOsrEntry entirely to avoid running into this issue, we succeed with compilation. But trying to enter the compiled code, the deoptimizer fails:

#0  v8::base::OS::Abort () at ../src/base/platform/platform-posix.cc:229
#1 0x090e4522 in V8_Fatal (file=0x934873f <.L.str> "../src/deoptimizer.cc", line=1764, format=0x9334a40 <.L.str.949> "Check failed: %s.")
    at ../src/base/logging.cc:116
#2 0x08812727 in v8::internal::Deoptimizer::ComputeInputFrameSize (this=0x9e337d8) at ../src/deoptimizer.cc:1764 #3 0x0881238f in v8::internal::Deoptimizer::Deoptimizer (this=0x9e337d8, isolate=0x9e08c50, function=0x4480cbad, type=v8::internal::Deoptimizer::SOFT, bailout_id=4, from=0x42d3a4fd "\220\220\220\220\220f\220\003", fp_to_sp_delta=20, optimized_code=0x0) at ../src/deoptimizer.cc:587 #4 0x0880ec38 in v8::internal::Deoptimizer::New (function=0x4480cbad, type=v8::internal::Deoptimizer::SOFT, bailout_id=4, from=0x42d3a4fd "\220\220\220\220\220f\220\003", fp_to_sp_delta=20, isolate=0x9e08c50) at ../src/deoptimizer.cc:85
#5  0x4c40a2f8 in ?? ()
#6  0x42d2be41 in ?? ()
#7  0x42d17fff in ?? ()
#8 0x08874426 in v8::internal::Invoke (is_construct=false, function=..., receiver=..., argc=0, args=0x0) at ../src/execution.cc:128 #9 0x08873a73 in v8::internal::Execution::Call (isolate=0x9e08c50, callable=..., receiver=..., argc=0, argv=0x0, convert_receiver=false)
    at ../src/execution.cc:179
#10 0x086c25d4 in v8::Script::Run (this=0x9e318e4, context=...) at ../src/api.cc:1687
#11 0x086cfc7b in v8::Script::Run (this=0x9e318e4) at ../src/api.cc:1700
#12 0x0868b1ee in v8::Shell::ExecuteString (isolate=0x9e08c50, source=..., name=..., print_result=false, report_exceptions=true,
    source_type=v8::Shell::SCRIPT) at ../src/d8.cc:349
#13 0x086964be in v8::SourceGroup::Execute (this=0x9e0700c, isolate=0x9e08c50) at ../src/d8.cc:1452 #14 0x08699460 in v8::Shell::RunMain (isolate=0x9e08c50, argc=3, argv=0xffffcb24) at ../src/d8.cc:1953 #15 0x0869a67c in v8::Shell::Main (argc=3, argv=0xffffcb24) at ../src/d8.cc:2392
#16 0x086a055b in main (argc=3, argv=0xffffcb24) at ../src/d8.cc:2435


At this point I have no good idea how to fix this. Assuming that we only lazily compile for functions defined on top-level, we could always mark block scopes in the top-level function to force context allocation. Is there a better option?

--
You received this message because this project is configured to send all issue notifications to this address.
You may adjust your notification preferences at:
https://code.google.com/hosting/settings

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to