Add tool to visualize machine code/lithium.
authordanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 21 Oct 2013 13:35:48 +0000 (13:35 +0000)
committerdanno@chromium.org <danno@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Mon, 21 Oct 2013 13:35:48 +0000 (13:35 +0000)
In the process:
- Add a command-line flag --opt-code-positions to track source position information throughout optimized code.
- Add a subclass of the hydrogen graph builder to ensure that the source position is properly set on the graph builder for all generated hydrogen code.
- Overhaul handling of source positions in hydrogen to ensure they are passed through to generated code consistently and in most cases transparently.

Originally reviewed in this CL: https://codereview.chromium.org/24957003/

Review URL: https://codereview.chromium.org/29123008

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@17295 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

29 files changed:
src/arm/lithium-arm.cc
src/arm/lithium-arm.h
src/arm/lithium-codegen-arm.cc
src/arm/lithium-codegen-arm.h
src/code-stubs-hydrogen.cc
src/codegen.cc
src/compiler.cc
src/flag-definitions.h
src/hydrogen-instructions.cc
src/hydrogen-instructions.h
src/hydrogen-osr.cc
src/hydrogen-representation-changes.cc
src/hydrogen.cc
src/hydrogen.h
src/ia32/lithium-codegen-ia32.cc
src/ia32/lithium-codegen-ia32.h
src/ia32/lithium-ia32.cc
src/ia32/lithium-ia32.h
src/lithium-codegen.cc
src/lithium-codegen.h
src/lithium.cc
src/lithium.h
src/x64/lithium-codegen-x64.cc
src/x64/lithium-codegen-x64.h
src/x64/lithium-x64.cc
src/x64/lithium-x64.h
tools/sodium/index.html [new file with mode: 0644]
tools/sodium/sodium.js [new file with mode: 0644]
tools/sodium/styles.css [new file with mode: 0755]

index ac1a03ed8487ec13d3835eedeaac259f0ea06589..3fb07bc2c1207b0d912c7784a673d9162c57bda5 100644 (file)
@@ -656,7 +656,7 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
 
 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
   ASSERT(!instr->HasPointerMap());
-  instr->set_pointer_map(new(zone()) LPointerMap(position_, zone()));
+  instr->set_pointer_map(new(zone()) LPointerMap(zone()));
   return instr;
 }
 
@@ -914,7 +914,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
     }
 #endif
 
-    instr->set_position(position_);
     if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
       instr = AssignPointerMap(instr);
     }
index 08946529aaf8b7a586d62beca506538c3a69bcce..6c036c7b5dd3204b1250736e4c5e770c699053d4 100644 (file)
@@ -215,7 +215,6 @@ class LInstruction : public ZoneObject {
       : environment_(NULL),
         hydrogen_value_(NULL),
         bit_field_(IsCallBits::encode(false)) {
-    set_position(RelocInfo::kNoPosition);
   }
 
   virtual ~LInstruction() {}
@@ -256,15 +255,6 @@ class LInstruction : public ZoneObject {
   LPointerMap* pointer_map() const { return pointer_map_.get(); }
   bool HasPointerMap() const { return pointer_map_.is_set(); }
 
-  // The 31 bits PositionBits is used to store the int position value. And the
-  // position value may be RelocInfo::kNoPosition (-1). The accessor always
-  // +1/-1 so that the encoded value of position in bit_field_ is always >= 0
-  // and can fit into the 31 bits PositionBits.
-  void set_position(int pos) {
-    bit_field_ = PositionBits::update(bit_field_, pos + 1);
-  }
-  int position() { return PositionBits::decode(bit_field_) - 1; }
-
   void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; }
   HValue* hydrogen_value() const { return hydrogen_value_; }
 
@@ -304,7 +294,6 @@ class LInstruction : public ZoneObject {
   virtual LOperand* TempAt(int i) = 0;
 
   class IsCallBits: public BitField<bool, 0, 1> {};
-  class PositionBits: public BitField<int, 1, 31> {};
 
   LEnvironment* environment_;
   SetOncePointer<LPointerMap> pointer_map_;
index d2fd70f0aa8f4f931ef30015e839299228d7b6e0..60e21b7de046cafed97c190f86813263de7dafef 100644 (file)
@@ -259,8 +259,9 @@ bool LCodeGen::GenerateDeferredCode() {
     for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
       LDeferredCode* code = deferred_[i];
 
-      int pos = instructions_->at(code->instruction_index())->position();
-      RecordAndUpdatePosition(pos);
+      HValue* value =
+          instructions_->at(code->instruction_index())->hydrogen_value();
+      RecordAndWritePosition(value->position());
 
       Comment(";;; <@%d,#%d> "
               "-------------------- Deferred %s --------------------",
@@ -685,8 +686,6 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
   // Block literal pool emission to ensure nop indicating no inlined smi code
   // is in the correct position.
   Assembler::BlockConstPoolScope block_const_pool(masm());
-  LPointerMap* pointers = instr->pointer_map();
-  RecordPosition(pointers->position());
   __ Call(code, mode, TypeFeedbackId::None(), al, storage_mode);
   RecordSafepointWithLazyDeopt(instr, safepoint_mode);
 
@@ -704,9 +703,6 @@ void LCodeGen::CallRuntime(const Runtime::Function* function,
                            LInstruction* instr,
                            SaveFPRegsMode save_doubles) {
   ASSERT(instr != NULL);
-  LPointerMap* pointers = instr->pointer_map();
-  ASSERT(pointers != NULL);
-  RecordPosition(pointers->position());
 
   __ CallRuntime(function, num_arguments, save_doubles);
 
@@ -964,7 +960,7 @@ void LCodeGen::RecordSafepoint(LPointerMap* pointers,
 
 
 void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
-  LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
+  LPointerMap empty_pointers(zone());
   RecordSafepoint(&empty_pointers, deopt_mode);
 }
 
@@ -986,17 +982,10 @@ void LCodeGen::RecordSafepointWithRegistersAndDoubles(
 }
 
 
-void LCodeGen::RecordPosition(int position) {
+void LCodeGen::RecordAndWritePosition(int position) {
   if (position == RelocInfo::kNoPosition) return;
   masm()->positions_recorder()->RecordPosition(position);
-}
-
-
-void LCodeGen::RecordAndUpdatePosition(int position) {
-  if (position >= 0 && position != old_position_) {
-    masm()->positions_recorder()->RecordPosition(position);
-    old_position_ = position;
-  }
+  masm()->positions_recorder()->WriteRecordedPositions();
 }
 
 
@@ -3507,7 +3496,6 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
   __ bind(&invoke);
   ASSERT(instr->HasPointerMap());
   LPointerMap* pointers = instr->pointer_map();
-  RecordPosition(pointers->position());
   SafepointGenerator safepoint_generator(
       this, pointers, Safepoint::kLazyDeopt);
   // The number of arguments is stored in receiver which is r0, as expected
@@ -3597,7 +3585,6 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
       dont_adapt_arguments || formal_parameter_count == arity;
 
   LPointerMap* pointers = instr->pointer_map();
-  RecordPosition(pointers->position());
 
   if (can_invoke_directly) {
     if (r1_state == R1_UNINITIALIZED) {
@@ -4009,7 +3996,6 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
   Handle<JSFunction> known_function = instr->hydrogen()->known_function();
   if (known_function.is_null()) {
     LPointerMap* pointers = instr->pointer_map();
-    RecordPosition(pointers->position());
     SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
     ParameterCount count(instr->arity());
     __ InvokeFunction(r1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
index 47e854d5a6f50d771734e313baa375f122cb592d..b893a9da7e96a8f66e4dcab1a330ca329310232a 100644 (file)
@@ -59,8 +59,7 @@ class LCodeGen: public LCodeGenBase {
         frame_is_built_(false),
         safepoints_(info->zone()),
         resolver_(this),
-        expected_safepoint_kind_(Safepoint::kSimple),
-        old_position_(RelocInfo::kNoPosition) {
+        expected_safepoint_kind_(Safepoint::kSimple) {
     PopulateDeoptimizationLiteralsWithInlinedFunctions();
   }
 
@@ -291,8 +290,8 @@ class LCodeGen: public LCodeGenBase {
   void RecordSafepointWithRegistersAndDoubles(LPointerMap* pointers,
                                               int arguments,
                                               Safepoint::DeoptMode mode);
-  void RecordPosition(int position);
-  void RecordAndUpdatePosition(int position) V8_OVERRIDE;
+
+  void RecordAndWritePosition(int position) V8_OVERRIDE;
 
   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
   void EmitGoto(int block);
@@ -381,8 +380,6 @@ class LCodeGen: public LCodeGenBase {
 
   Safepoint::Kind expected_safepoint_kind_;
 
-  int old_position_;
-
   class PushSafepointRegistersScope V8_FINAL BASE_EMBEDDED {
    public:
     PushSafepointRegistersScope(LCodeGen* codegen,
index 091d4fb1cae9b5aa53b4375fd4f5ac7555e1e568..de79976878dff84d8d4398d7f9692bc6cf364e89 100644 (file)
@@ -146,7 +146,7 @@ bool CodeStubGraphBuilderBase::BuildGraph() {
   int param_count = descriptor_->register_param_count_;
   HEnvironment* start_environment = graph()->start_environment();
   HBasicBlock* next_block = CreateBasicBlock(start_environment);
-  current_block()->Goto(next_block);
+  Goto(next_block);
   next_block->SetJoinId(BailoutId::StubEntry());
   set_current_block(next_block);
 
@@ -207,8 +207,7 @@ bool CodeStubGraphBuilderBase::BuildGraph() {
   if (current_block() != NULL) {
     HReturn* hreturn_instruction = New<HReturn>(return_value,
                                                 stack_pop_count);
-    current_block()->Finish(hreturn_instruction);
-    set_current_block(NULL);
+    FinishCurrentBlock(hreturn_instruction);
   }
   return true;
 }
@@ -845,7 +844,7 @@ HValue* CodeStubGraphBuilder<CompareNilICStub>::BuildCodeInitializedStub() {
   HIfContinuation continuation;
   Handle<Map> sentinel_map(isolate->heap()->meta_map());
   Handle<Type> type = stub->GetType(isolate, sentinel_map);
-  BuildCompareNil(GetParameter(0), type, RelocInfo::kNoPosition, &continuation);
+  BuildCompareNil(GetParameter(0), type, &continuation);
   IfBuilder if_nil(this, &continuation);
   if_nil.Then();
   if (continuation.IsFalseReachable()) {
index b15324c8cf0ba6f98a7a8fa481f58bc2de0606bb..7b2f81ba8ab0e3ea85595fd18ec6d3664904e71e 100644 (file)
@@ -134,7 +134,9 @@ void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) {
   if (print_code) {
     // Print the source code if available.
     FunctionLiteral* function = info->function();
-    if (code->kind() == Code::OPTIMIZED_FUNCTION) {
+    bool print_source = code->kind() == Code::OPTIMIZED_FUNCTION ||
+        code->kind() == Code::FUNCTION;
+    if (print_source) {
       Handle<Script> script = info->script();
       if (!script->IsUndefined() && !script->source()->IsUndefined()) {
         PrintF("--- Raw source ---\n");
@@ -162,12 +164,16 @@ void CodeGenerator::PrintCode(Handle<Code> code, CompilationInfo* info) {
     } else {
       PrintF("--- Code ---\n");
     }
+    if (print_source) {
+      PrintF("source_position = %d\n", function->start_position());
+    }
     if (info->IsStub()) {
       CodeStub::Major major_key = info->code_stub()->MajorKey();
       code->Disassemble(CodeStub::MajorName(major_key, false));
     } else {
       code->Disassemble(*function->debug_name()->ToCString());
     }
+    PrintF("--- End code ---\n");
   }
 #endif  // ENABLE_DISASSEMBLER
 }
index 6d09722035fc610f52b4ee3262164236038ace9f..39524a92f9f491cdac38721b71ce283debfad41b 100644 (file)
@@ -313,6 +313,43 @@ static bool MakeCrankshaftCode(CompilationInfo* info) {
 }
 
 
+class HOptimizedGraphBuilderWithPotisions: public HOptimizedGraphBuilder {
+ public:
+  explicit HOptimizedGraphBuilderWithPotisions(CompilationInfo* info)
+      : HOptimizedGraphBuilder(info) {
+  }
+
+#define DEF_VISIT(type)                                 \
+  virtual void Visit##type(type* node) V8_OVERRIDE {    \
+    if (node->position() != RelocInfo::kNoPosition) {   \
+      SetSourcePosition(node->position());              \
+    }                                                   \
+    HOptimizedGraphBuilder::Visit##type(node);          \
+  }
+  EXPRESSION_NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+
+#define DEF_VISIT(type)                                          \
+  virtual void Visit##type(type* node) V8_OVERRIDE {             \
+    if (node->position() != RelocInfo::kNoPosition) {            \
+      SetSourcePosition(node->position());                       \
+    }                                                            \
+    HOptimizedGraphBuilder::Visit##type(node);                   \
+  }
+  STATEMENT_NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+
+#define DEF_VISIT(type)                                            \
+  virtual void Visit##type(type* node) V8_OVERRIDE {               \
+    HOptimizedGraphBuilder::Visit##type(node);                     \
+  }
+  MODULE_NODE_LIST(DEF_VISIT)
+  DECLARATION_NODE_LIST(DEF_VISIT)
+  AUXILIARY_NODE_LIST(DEF_VISIT)
+#undef DEF_VISIT
+};
+
+
 RecompileJob::Status RecompileJob::CreateGraph() {
   ASSERT(isolate()->use_crankshaft());
   ASSERT(info()->IsOptimizing());
@@ -419,7 +456,9 @@ RecompileJob::Status RecompileJob::CreateGraph() {
   // Type-check the function.
   AstTyper::Run(info());
 
-  graph_builder_ = new(info()->zone()) HOptimizedGraphBuilder(info());
+  graph_builder_ = FLAG_emit_opt_code_positions
+      ? new(info()->zone()) HOptimizedGraphBuilderWithPotisions(info())
+      : new(info()->zone()) HOptimizedGraphBuilder(info());
 
   Timer t(this, &time_taken_to_create_graph_);
   graph_ = graph_builder_->CreateGraph();
index 45f0c7273dd8f4ec6b63951661b1194f2dbbb833..30b46cfe1fea3026c3807c50f9c53e7d340686bf 100644 (file)
@@ -837,8 +837,19 @@ DEFINE_bool(print_unopt_code, false, "print unoptimized code before "
             "printing optimized code based on it")
 DEFINE_bool(print_code_verbose, false, "print more information for code")
 DEFINE_bool(print_builtin_code, false, "print generated code for builtins")
+DEFINE_bool(emit_opt_code_positions,
+            false, "annotate optimize code with source code positions")
 
 #ifdef ENABLE_DISASSEMBLER
+DEFINE_bool(sodium, false, "print generated code output suitable for use with "
+            "the Sodium code viewer")
+
+DEFINE_implication(sodium, print_code_stubs)
+DEFINE_implication(sodium, print_code)
+DEFINE_implication(sodium, print_opt_code)
+DEFINE_implication(sodium, emit_opt_code_positions)
+DEFINE_implication(sodium, code_comments)
+
 DEFINE_bool(print_all_code, false, "enable all flags related to printing code")
 DEFINE_implication(print_all_code, print_code)
 DEFINE_implication(print_all_code, print_opt_code)
index 867fa50fca25aa30e5508edc5368d76b23c7a576..1613127e2febe7c80d0d99ceb9f4efac5bb821d8 100644 (file)
@@ -741,6 +741,10 @@ void HInstruction::InsertBefore(HInstruction* next) {
   next_ = next;
   previous_ = prev;
   SetBlock(next->block());
+  if (position() == RelocInfo::kNoPosition &&
+      next->position() != RelocInfo::kNoPosition) {
+    set_position(next->position());
+  }
 }
 
 
@@ -775,6 +779,10 @@ void HInstruction::InsertAfter(HInstruction* previous) {
   if (block->last() == previous) {
     block->set_last(this);
   }
+  if (position() == RelocInfo::kNoPosition &&
+      previous->position() != RelocInfo::kNoPosition) {
+    set_position(previous->position());
+  }
 }
 
 
@@ -1592,6 +1600,11 @@ Range* HConstant::InferRange(Zone* zone) {
 }
 
 
+int HPhi::position() const {
+  return block()->first()->position();
+}
+
+
 Range* HPhi::InferRange(Zone* zone) {
   Representation r = representation();
   if (r.IsSmiOrInteger32()) {
index 696d8b00f8635fd98943df65da87ae3af511a982..de8e19a5fd73f72331c249c881d0222b0318b16d 100644 (file)
@@ -638,6 +638,8 @@ class HValue : public ZoneObject {
         flags_(0) {}
   virtual ~HValue() {}
 
+  virtual int position() const { return RelocInfo::kNoPosition; }
+
   HBasicBlock* block() const { return block_; }
   void SetBlock(HBasicBlock* block);
   int LoopWeight() const;
@@ -1114,7 +1116,7 @@ class HInstruction : public HValue {
   void InsertAfter(HInstruction* previous);
 
   // The position is a write-once variable.
-  int position() const { return position_; }
+  virtual int position() const V8_OVERRIDE { return position_; }
   bool has_position() const { return position_ != RelocInfo::kNoPosition; }
   void set_position(int position) {
     ASSERT(!has_position());
@@ -3147,6 +3149,8 @@ class HPhi V8_FINAL : public HValue {
   bool IsReceiver() const { return merged_index_ == 0; }
   bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
 
+  virtual int position() const V8_OVERRIDE;
+
   int merged_index() const { return merged_index_; }
 
   InductionVariableData* induction_variable_data() {
index 3492debfcef498022d032c15275eaa25c391462d..6e39df6aa95accc3a70937f6d9201a528d65ed41 100644 (file)
@@ -54,10 +54,10 @@ HBasicBlock* HOsrBuilder::BuildOsrLoopEntry(IterationStatement* statement) {
   HValue* true_value = graph->GetConstantTrue();
   HBranch* test = builder_->New<HBranch>(true_value, ToBooleanStub::Types(),
                                          non_osr_entry, osr_entry_);
-  builder_->current_block()->Finish(test);
+  builder_->FinishCurrentBlock(test);
 
   HBasicBlock* loop_predecessor = graph->CreateBasicBlock();
-  non_osr_entry->Goto(loop_predecessor);
+  builder_->Goto(non_osr_entry, loop_predecessor);
 
   builder_->set_current_block(osr_entry_);
   osr_entry_->set_osr_entry();
@@ -97,7 +97,7 @@ HBasicBlock* HOsrBuilder::BuildOsrLoopEntry(IterationStatement* statement) {
   builder_->Add<HOsrEntry>(osr_entry_id);
   HContext* context = builder_->Add<HContext>();
   environment->BindContext(context);
-  builder_->current_block()->Goto(loop_predecessor);
+  builder_->Goto(loop_predecessor);
   loop_predecessor->SetJoinId(statement->EntryId());
   builder_->set_current_block(loop_predecessor);
 
index 960113782f847cb024c42d4184401f1e51f58fab..d0c9b58258b591b6ba9be80fb2619e6ad0562813 100644 (file)
@@ -61,6 +61,11 @@ void HRepresentationChangesPhase::InsertRepresentationChangeForUse(
   if (new_value == NULL) {
     new_value = new(graph()->zone()) HChange(
         value, to, is_truncating_to_smi, is_truncating_to_int);
+    if (use_value->position() != RelocInfo::kNoPosition) {
+      new_value->set_position(use_value->position());
+    } else {
+      ASSERT(!FLAG_emit_opt_code_positions || !graph()->info()->IsOptimizing());
+    }
   }
 
   new_value->InsertBefore(next);
index fbca58f0c6444161ca524c891ce0693eca1e236c..83d48b19f7b70e57a94ee962d2327bdb53b682b8 100644 (file)
@@ -140,16 +140,25 @@ void HBasicBlock::RemovePhi(HPhi* phi) {
 }
 
 
-void HBasicBlock::AddInstruction(HInstruction* instr) {
+void HBasicBlock::AddInstruction(HInstruction* instr, int position) {
   ASSERT(!IsStartBlock() || !IsFinished());
   ASSERT(!instr->IsLinked());
   ASSERT(!IsFinished());
 
+  if (position != RelocInfo::kNoPosition) {
+    instr->set_position(position);
+  }
   if (first_ == NULL) {
     ASSERT(last_environment() != NULL);
     ASSERT(!last_environment()->ast_id().IsNone());
     HBlockEntry* entry = new(zone()) HBlockEntry();
     entry->InitializeAsFirst(this);
+    if (position != RelocInfo::kNoPosition) {
+      entry->set_position(position);
+    } else {
+      ASSERT(!FLAG_emit_opt_code_positions ||
+             !graph()->info()->IsOptimizing());
+    }
     first_ = last_ = entry;
   }
   instr->InsertAfter(last_);
@@ -200,9 +209,9 @@ HSimulate* HBasicBlock::CreateSimulate(BailoutId ast_id,
 }
 
 
-void HBasicBlock::Finish(HControlInstruction* end) {
+void HBasicBlock::Finish(HControlInstruction* end, int position) {
   ASSERT(!IsFinished());
-  AddInstruction(end);
+  AddInstruction(end, position);
   end_ = end;
   for (HSuccessorIterator it(end); !it.Done(); it.Advance()) {
     it.Current()->RegisterPredecessor(this);
@@ -211,6 +220,7 @@ void HBasicBlock::Finish(HControlInstruction* end) {
 
 
 void HBasicBlock::Goto(HBasicBlock* block,
+                       int position,
                        FunctionState* state,
                        bool add_simulate) {
   bool drop_extra = state != NULL &&
@@ -219,18 +229,21 @@ void HBasicBlock::Goto(HBasicBlock* block,
   if (block->IsInlineReturnTarget()) {
     HEnvironment* env = last_environment();
     int argument_count = env->arguments_environment()->parameter_count();
-    AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count));
+    AddInstruction(new(zone())
+                   HLeaveInlined(state->entry(), argument_count),
+                   position);
     UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
   }
 
-  if (add_simulate) AddNewSimulate(BailoutId::None());
+  if (add_simulate) AddNewSimulate(BailoutId::None(), position);
   HGoto* instr = new(zone()) HGoto(block);
-  Finish(instr);
+  Finish(instr, position);
 }
 
 
 void HBasicBlock::AddLeaveInlined(HValue* return_value,
-                                  FunctionState* state) {
+                                  FunctionState* state,
+                                  int position) {
   HBasicBlock* target = state->function_return();
   bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN;
 
@@ -238,12 +251,13 @@ void HBasicBlock::AddLeaveInlined(HValue* return_value,
   ASSERT(return_value != NULL);
   HEnvironment* env = last_environment();
   int argument_count = env->arguments_environment()->parameter_count();
-  AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count));
+  AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count),
+                 position);
   UpdateEnvironment(last_environment()->DiscardInlined(drop_extra));
   last_environment()->Push(return_value);
-  AddNewSimulate(BailoutId::None());
+  AddNewSimulate(BailoutId::None(), position);
   HGoto* instr = new(zone()) HGoto(target);
-  Finish(instr);
+  Finish(instr, position);
 }
 
 
@@ -701,9 +715,8 @@ bool HGraph::IsStandardConstant(HConstant* constant) {
 }
 
 
-HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder, int position)
+HGraphBuilder::IfBuilder::IfBuilder(HGraphBuilder* builder)
     : builder_(builder),
-      position_(position),
       finished_(false),
       deopt_then_(false),
       deopt_else_(false),
@@ -726,7 +739,6 @@ HGraphBuilder::IfBuilder::IfBuilder(
     HGraphBuilder* builder,
     HIfContinuation* continuation)
     : builder_(builder),
-      position_(RelocInfo::kNoPosition),
       finished_(false),
       deopt_then_(false),
       deopt_else_(false),
@@ -742,8 +754,7 @@ HGraphBuilder::IfBuilder::IfBuilder(
       split_edge_merge_block_(NULL),
       merge_block_(NULL) {
   continuation->Continue(&first_true_block_,
-                         &first_false_block_,
-                         &position_);
+                         &first_false_block_);
 }
 
 
@@ -760,12 +771,12 @@ HControlInstruction* HGraphBuilder::IfBuilder::AddCompare(
       compare->SetSuccessorAt(0, first_true_block_);
       compare->SetSuccessorAt(1, split_edge);
     }
-    split_edge->GotoNoSimulate(split_edge_merge_block_);
+    builder_->GotoNoSimulate(split_edge, split_edge_merge_block_);
   } else {
     compare->SetSuccessorAt(0, first_true_block_);
     compare->SetSuccessorAt(1, first_false_block_);
   }
-  builder_->current_block()->Finish(compare);
+  builder_->FinishCurrentBlock(compare);
   needs_compare_ = false;
   return compare;
 }
@@ -778,7 +789,7 @@ void HGraphBuilder::IfBuilder::Or() {
   if (split_edge_merge_block_ == NULL) {
     split_edge_merge_block_ =
         builder_->CreateBasicBlock(env->Copy());
-    first_true_block_->GotoNoSimulate(split_edge_merge_block_);
+    builder_->GotoNoSimulate(first_true_block_, split_edge_merge_block_);
     first_true_block_ = split_edge_merge_block_;
   }
   builder_->set_current_block(first_false_block_);
@@ -792,7 +803,7 @@ void HGraphBuilder::IfBuilder::And() {
   HEnvironment* env = first_false_block_->last_environment();
   if (split_edge_merge_block_ == NULL) {
     split_edge_merge_block_ = builder_->CreateBasicBlock(env->Copy());
-    first_false_block_->GotoNoSimulate(split_edge_merge_block_);
+    builder_->GotoNoSimulate(first_false_block_, split_edge_merge_block_);
     first_false_block_ = split_edge_merge_block_;
   }
   builder_->set_current_block(first_true_block_);
@@ -810,7 +821,7 @@ void HGraphBuilder::IfBuilder::CaptureContinuation(
   HBasicBlock* false_block = did_else_ && (first_false_block_ != NULL)
       ? builder_->current_block()
       : first_false_block_;
-  continuation->Capture(true_block, false_block, position_);
+  continuation->Capture(true_block, false_block);
   captured_ = true;
   End();
 }
@@ -827,11 +838,11 @@ void HGraphBuilder::IfBuilder::JoinContinuation(HIfContinuation* continuation) {
       : first_false_block_;
   if (true_block != NULL && !true_block->IsFinished()) {
     ASSERT(continuation->IsTrueReachable());
-    true_block->GotoNoSimulate(continuation->true_branch());
+    builder_->GotoNoSimulate(true_block, continuation->true_branch());
   }
   if (false_block != NULL && !false_block->IsFinished()) {
     ASSERT(continuation->IsFalseReachable());
-    false_block->GotoNoSimulate(continuation->false_branch());
+    builder_->GotoNoSimulate(false_block, continuation->false_branch());
   }
   captured_ = true;
   End();
@@ -852,7 +863,7 @@ void HGraphBuilder::IfBuilder::Then() {
     boolean_type.Add(ToBooleanStub::BOOLEAN);
     HBranch* branch = builder()->New<HBranch>(
         constant_false, boolean_type, first_true_block_, first_false_block_);
-    builder_->current_block()->Finish(branch);
+    builder_->FinishCurrentBlock(branch);
   }
   builder_->set_current_block(first_true_block_);
 }
@@ -880,10 +891,9 @@ void HGraphBuilder::IfBuilder::Deopt(const char* reason) {
 
 
 void HGraphBuilder::IfBuilder::Return(HValue* value) {
-  HBasicBlock* block = builder_->current_block();
   HValue* parameter_count = builder_->graph()->GetConstantMinus1();
-  block->FinishExit(builder_->New<HReturn>(value, parameter_count));
-  builder_->set_current_block(NULL);
+  builder_->FinishExitCurrentBlock(
+      builder_->New<HReturn>(value, parameter_count));
   if (did_else_) {
     first_false_block_ = NULL;
   } else {
@@ -913,17 +923,17 @@ void HGraphBuilder::IfBuilder::End() {
       HBasicBlock* last_false_block = builder_->current_block();
       ASSERT(!last_false_block->IsFinished());
       if (deopt_then_) {
-        last_false_block->GotoNoSimulate(merge_block_);
+        builder_->GotoNoSimulate(last_false_block, merge_block_);
         builder_->PadEnvironmentForContinuation(last_true_block_,
                                                 merge_block_);
-        last_true_block_->GotoNoSimulate(merge_block_);
+        builder_->GotoNoSimulate(last_true_block_, merge_block_);
       } else {
-        last_true_block_->GotoNoSimulate(merge_block_);
+        builder_->GotoNoSimulate(last_true_block_, merge_block_);
         if (deopt_else_) {
           builder_->PadEnvironmentForContinuation(last_false_block,
                                                   merge_block_);
         }
-        last_false_block->GotoNoSimulate(merge_block_);
+        builder_->GotoNoSimulate(last_false_block, merge_block_);
       }
       builder_->set_current_block(merge_block_);
     }
@@ -971,7 +981,7 @@ HValue* HGraphBuilder::LoopBuilder::BeginBody(
   phi_ = header_block_->AddNewPhi(env->values()->length());
   phi_->AddInput(initial);
   env->Push(initial);
-  builder_->current_block()->GotoNoSimulate(header_block_);
+  builder_->GotoNoSimulate(header_block_);
 
   HEnvironment* body_env = env->Copy();
   HEnvironment* exit_env = env->Copy();
@@ -983,7 +993,7 @@ HValue* HGraphBuilder::LoopBuilder::BeginBody(
 
   builder_->set_current_block(header_block_);
   env->Pop();
-  builder_->current_block()->Finish(builder_->New<HCompareNumericAndBranch>(
+  builder_->FinishCurrentBlock(builder_->New<HCompareNumericAndBranch>(
           phi_, terminating, token, body_block_, exit_block_));
 
   builder_->set_current_block(body_block_);
@@ -1008,10 +1018,10 @@ void HGraphBuilder::LoopBuilder::Break() {
     // Its the first time we saw a break.
     HEnvironment* env = exit_block_->last_environment()->Copy();
     exit_trampoline_block_ = builder_->CreateBasicBlock(env);
-    exit_block_->GotoNoSimulate(exit_trampoline_block_);
+    builder_->GotoNoSimulate(exit_block_, exit_trampoline_block_);
   }
 
-  builder_->current_block()->GotoNoSimulate(exit_trampoline_block_);
+  builder_->GotoNoSimulate(exit_trampoline_block_);
 }
 
 
@@ -1031,7 +1041,7 @@ void HGraphBuilder::LoopBuilder::EndBody() {
   // Push the new increment value on the expression stack to merge into the phi.
   builder_->environment()->Push(increment_);
   HBasicBlock* last_block = builder_->current_block();
-  last_block->GotoNoSimulate(header_block_);
+  builder_->GotoNoSimulate(last_block, header_block_);
   header_block_->loop_information()->RegisterBackEdge(last_block);
 
   if (exit_trampoline_block_ != NULL) {
@@ -1056,7 +1066,9 @@ HGraph* HGraphBuilder::CreateGraph() {
 
 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
   ASSERT(current_block() != NULL);
-  current_block()->AddInstruction(instr);
+  ASSERT(!FLAG_emit_opt_code_positions ||
+         position_ != RelocInfo::kNoPosition || !info_->IsOptimizing());
+  current_block()->AddInstruction(instr, position_);
   if (graph()->IsInsideNoSideEffectsScope()) {
     instr->SetFlag(HValue::kHasNoObservableSideEffects);
   }
@@ -1064,6 +1076,26 @@ HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
 }
 
 
+void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) {
+  ASSERT(!FLAG_emit_opt_code_positions || !info_->IsOptimizing() ||
+         position_ != RelocInfo::kNoPosition);
+  current_block()->Finish(last, position_);
+  if (last->IsReturn() || last->IsAbnormalExit()) {
+    set_current_block(NULL);
+  }
+}
+
+
+void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) {
+  ASSERT(!FLAG_emit_opt_code_positions || !info_->IsOptimizing() ||
+         position_ != RelocInfo::kNoPosition);
+  current_block()->FinishExit(instruction, position_);
+  if (instruction->IsReturn() || instruction->IsAbnormalExit()) {
+    set_current_block(NULL);
+  }
+}
+
+
 void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) {
   if (FLAG_native_code_counters && counter->Enabled()) {
     HValue* reference = Add<HConstant>(ExternalReference(counter));
@@ -1112,9 +1144,9 @@ void HGraphBuilder::FinishExitWithHardDeoptimization(
   PadEnvironmentForContinuation(current_block(), continuation);
   Add<HDeoptimize>(reason, Deoptimizer::EAGER);
   if (graph()->IsInsideNoSideEffectsScope()) {
-    current_block()->GotoNoSimulate(continuation);
+    GotoNoSimulate(continuation);
   } else {
-    current_block()->Goto(continuation);
+    Goto(continuation);
   }
 }
 
@@ -1876,9 +1908,8 @@ HValue* HGraphBuilder::BuildCloneShallowArray(HValue* boilerplate,
 void HGraphBuilder::BuildCompareNil(
     HValue* value,
     Handle<Type> type,
-    int position,
     HIfContinuation* continuation) {
-  IfBuilder if_nil(this, position);
+  IfBuilder if_nil(this);
   bool some_case_handled = false;
   bool some_case_missing = false;
 
@@ -2146,6 +2177,9 @@ HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info)
   // to know it's the initial state.
   function_state_= &initial_function_state_;
   InitializeAstVisitor(info->isolate());
+  if (FLAG_emit_opt_code_positions) {
+    SetSourcePosition(info->shared_info()->start_position());
+  }
 }
 
 
@@ -2158,8 +2192,8 @@ HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first,
     return first;
   } else {
     HBasicBlock* join_block = graph()->CreateBasicBlock();
-    first->Goto(join_block);
-    second->Goto(join_block);
+    Goto(first, join_block);
+    Goto(second, join_block);
     join_block->SetJoinId(join_id);
     return join_block;
   }
@@ -2170,7 +2204,7 @@ HBasicBlock* HOptimizedGraphBuilder::JoinContinue(IterationStatement* statement,
                                                   HBasicBlock* exit_block,
                                                   HBasicBlock* continue_block) {
   if (continue_block != NULL) {
-    if (exit_block != NULL) exit_block->Goto(continue_block);
+    if (exit_block != NULL) Goto(exit_block, continue_block);
     continue_block->SetJoinId(statement->ContinueId());
     return continue_block;
   }
@@ -2183,10 +2217,10 @@ HBasicBlock* HOptimizedGraphBuilder::CreateLoop(IterationStatement* statement,
                                                 HBasicBlock* body_exit,
                                                 HBasicBlock* loop_successor,
                                                 HBasicBlock* break_block) {
-  if (body_exit != NULL) body_exit->Goto(loop_entry);
+  if (body_exit != NULL) Goto(body_exit, loop_entry);
   loop_entry->PostProcessLoopHeader(statement);
   if (break_block != NULL) {
-    if (loop_successor != NULL) loop_successor->Goto(break_block);
+    if (loop_successor != NULL) Goto(loop_successor, break_block);
     break_block->SetJoinId(statement->ExitId());
     return break_block;
   }
@@ -2197,7 +2231,7 @@ HBasicBlock* HOptimizedGraphBuilder::CreateLoop(IterationStatement* statement,
 // Build a new loop header block and set it as the current block.
 HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry() {
   HBasicBlock* loop_entry = CreateLoopHeaderBlock();
-  current_block()->Goto(loop_entry);
+  Goto(loop_entry);
   set_current_block(loop_entry);
   return loop_entry;
 }
@@ -2212,8 +2246,8 @@ HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry(
 }
 
 
-void HBasicBlock::FinishExit(HControlInstruction* instruction) {
-  Finish(instruction);
+void HBasicBlock::FinishExit(HControlInstruction* instruction, int position) {
+  Finish(instruction, position);
   ClearEnvironment();
 }
 
@@ -2761,7 +2795,7 @@ void EffectContext::ReturnControl(HControlInstruction* instr,
   HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
   instr->SetSuccessorAt(0, empty_true);
   instr->SetSuccessorAt(1, empty_false);
-  owner()->current_block()->Finish(instr);
+  owner()->FinishCurrentBlock(instr);
   HBasicBlock* join = owner()->CreateJoin(empty_true, empty_false, ast_id);
   owner()->set_current_block(join);
 }
@@ -2771,7 +2805,7 @@ void EffectContext::ReturnContinuation(HIfContinuation* continuation,
                                        BailoutId ast_id) {
   HBasicBlock* true_branch = NULL;
   HBasicBlock* false_branch = NULL;
-  continuation->Continue(&true_branch, &false_branch, NULL);
+  continuation->Continue(&true_branch, &false_branch);
   if (!continuation->IsTrueReachable()) {
     owner()->set_current_block(false_branch);
   } else if (!continuation->IsFalseReachable()) {
@@ -2805,7 +2839,7 @@ void ValueContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
   HBasicBlock* materialize_true = owner()->graph()->CreateBasicBlock();
   instr->SetSuccessorAt(0, materialize_true);
   instr->SetSuccessorAt(1, materialize_false);
-  owner()->current_block()->Finish(instr);
+  owner()->FinishCurrentBlock(instr);
   owner()->set_current_block(materialize_true);
   owner()->Push(owner()->graph()->GetConstantTrue());
   owner()->set_current_block(materialize_false);
@@ -2820,7 +2854,7 @@ void ValueContext::ReturnContinuation(HIfContinuation* continuation,
                                       BailoutId ast_id) {
   HBasicBlock* materialize_true = NULL;
   HBasicBlock* materialize_false = NULL;
-  continuation->Continue(&materialize_true, &materialize_false, NULL);
+  continuation->Continue(&materialize_true, &materialize_false);
   if (continuation->IsTrueReachable()) {
     owner()->set_current_block(materialize_true);
     owner()->Push(owner()->graph()->GetConstantTrue());
@@ -2860,9 +2894,9 @@ void TestContext::ReturnControl(HControlInstruction* instr, BailoutId ast_id) {
   HBasicBlock* empty_false = owner()->graph()->CreateBasicBlock();
   instr->SetSuccessorAt(0, empty_true);
   instr->SetSuccessorAt(1, empty_false);
-  owner()->current_block()->Finish(instr);
-  empty_true->Goto(if_true(), owner()->function_state());
-  empty_false->Goto(if_false(), owner()->function_state());
+  owner()->FinishCurrentBlock(instr);
+  owner()->Goto(empty_true, if_true(), owner()->function_state());
+  owner()->Goto(empty_false, if_false(), owner()->function_state());
   owner()->set_current_block(NULL);
 }
 
@@ -2871,12 +2905,12 @@ void TestContext::ReturnContinuation(HIfContinuation* continuation,
                                      BailoutId ast_id) {
   HBasicBlock* true_branch = NULL;
   HBasicBlock* false_branch = NULL;
-  continuation->Continue(&true_branch, &false_branch, NULL);
+  continuation->Continue(&true_branch, &false_branch);
   if (continuation->IsTrueReachable()) {
-    true_branch->Goto(if_true(), owner()->function_state());
+    owner()->Goto(true_branch, if_true(), owner()->function_state());
   }
   if (continuation->IsFalseReachable()) {
-    false_branch->Goto(if_false(), owner()->function_state());
+    owner()->Goto(false_branch, if_false(), owner()->function_state());
   }
   owner()->set_current_block(NULL);
 }
@@ -2894,11 +2928,11 @@ void TestContext::BuildBranch(HValue* value) {
   HBasicBlock* empty_true = builder->graph()->CreateBasicBlock();
   HBasicBlock* empty_false = builder->graph()->CreateBasicBlock();
   ToBooleanStub::Types expected(condition()->to_boolean_types());
-  builder->current_block()->Finish(builder->New<HBranch>(
+  builder->FinishCurrentBlock(builder->New<HBranch>(
           value, expected, empty_true, empty_false));
 
-  empty_true->Goto(if_true(), builder->function_state());
-  empty_false->Goto(if_false(), builder->function_state());
+  owner()->Goto(empty_true, if_true(), builder->function_state());
+  owner()->Goto(empty_false , if_false(), builder->function_state());
   builder->set_current_block(NULL);
 }
 
@@ -3015,7 +3049,7 @@ bool HOptimizedGraphBuilder::BuildGraph() {
   // not replayed by the Lithium translation.
   HEnvironment* initial_env = environment()->CopyWithoutHistory();
   HBasicBlock* body_entry = CreateBasicBlock(initial_env);
-  current_block()->Goto(body_entry);
+  Goto(body_entry);
   body_entry->SetJoinId(BailoutId::FunctionEntry());
   set_current_block(body_entry);
 
@@ -3258,7 +3292,7 @@ void HOptimizedGraphBuilder::VisitBlock(Block* stmt) {
   }
   HBasicBlock* break_block = break_info.break_block();
   if (break_block != NULL) {
-    if (current_block() != NULL) current_block()->Goto(break_block);
+    if (current_block() != NULL) Goto(break_block);
     break_block->SetJoinId(stmt->ExitId());
     set_current_block(break_block);
   }
@@ -3368,7 +3402,7 @@ void HOptimizedGraphBuilder::VisitContinueStatement(
   HBasicBlock* continue_block = break_scope()->Get(
       stmt->target(), BreakAndContinueScope::CONTINUE, &drop_extra);
   Drop(drop_extra);
-  current_block()->Goto(continue_block);
+  Goto(continue_block);
   set_current_block(NULL);
 }
 
@@ -3381,7 +3415,7 @@ void HOptimizedGraphBuilder::VisitBreakStatement(BreakStatement* stmt) {
   HBasicBlock* break_block = break_scope()->Get(
       stmt->target(), BreakAndContinueScope::BREAK, &drop_extra);
   Drop(drop_extra);
-  current_block()->Goto(break_block);
+  Goto(break_block);
   set_current_block(NULL);
 }
 
@@ -3404,10 +3438,10 @@ void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
     if (context->IsTest()) {
       TestContext* test = TestContext::cast(context);
       CHECK_ALIVE(VisitForEffect(stmt->expression()));
-      current_block()->Goto(test->if_true(), state);
+      Goto(test->if_true(), state);
     } else if (context->IsEffect()) {
       CHECK_ALIVE(VisitForEffect(stmt->expression()));
-      current_block()->Goto(function_return(), state);
+      Goto(function_return(), state);
     } else {
       ASSERT(context->IsValue());
       CHECK_ALIVE(VisitForValue(stmt->expression()));
@@ -3421,9 +3455,9 @@ void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
       HBasicBlock* not_spec_object = graph()->CreateBasicBlock();
       typecheck->SetSuccessorAt(0, if_spec_object);
       typecheck->SetSuccessorAt(1, not_spec_object);
-      current_block()->Finish(typecheck);
-      if_spec_object->AddLeaveInlined(return_value, state);
-      not_spec_object->AddLeaveInlined(receiver, state);
+      FinishCurrentBlock(typecheck);
+      AddLeaveInlined(if_spec_object, return_value, state);
+      AddLeaveInlined(not_spec_object, receiver, state);
     }
   } else if (state->inlining_kind() == SETTER_CALL_RETURN) {
     // Return from an inlined setter call. The returned value is never used, the
@@ -3433,11 +3467,11 @@ void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
       HValue* rhs = environment()->arguments_environment()->Lookup(1);
       context->ReturnValue(rhs);
     } else if (context->IsEffect()) {
-      current_block()->Goto(function_return(), state);
+      Goto(function_return(), state);
     } else {
       ASSERT(context->IsValue());
       HValue* rhs = environment()->arguments_environment()->Lookup(1);
-      current_block()->AddLeaveInlined(rhs, state);
+      AddLeaveInlined(rhs, state);
     }
   } else {
     // Return from a normal inlined function. Visit the subexpression in the
@@ -3447,11 +3481,11 @@ void HOptimizedGraphBuilder::VisitReturnStatement(ReturnStatement* stmt) {
       VisitForControl(stmt->expression(), test->if_true(), test->if_false());
     } else if (context->IsEffect()) {
       CHECK_ALIVE(VisitForEffect(stmt->expression()));
-      current_block()->Goto(function_return(), state);
+      Goto(function_return(), state);
     } else {
       ASSERT(context->IsValue());
       CHECK_ALIVE(VisitForValue(stmt->expression()));
-      current_block()->AddLeaveInlined(Pop(), state);
+      AddLeaveInlined(Pop(), state);
     }
   }
   set_current_block(NULL);
@@ -3499,7 +3533,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
     not_string_block = graph()->CreateBasicBlock();
     string_check = New<HIsStringAndBranch>(
         tag_value, first_test_block, not_string_block);
-    current_block()->Finish(string_check);
+    FinishCurrentBlock(string_check);
 
     set_current_block(first_test_block);
   }
@@ -3542,7 +3576,7 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
 
     compare->SetSuccessorAt(0, body_block);
     compare->SetSuccessorAt(1, next_test_block);
-    current_block()->Finish(compare);
+    FinishCurrentBlock(compare);
 
     set_current_block(next_test_block);
   }
@@ -3623,8 +3657,8 @@ void HOptimizedGraphBuilder::VisitSwitchStatement(SwitchStatement* stmt) {
                                  last_block,
                                  stmt->ExitId()));
   } else {
-    if (fall_through_block != NULL) fall_through_block->Goto(break_block);
-    if (last_block != NULL) last_block->Goto(break_block);
+    if (fall_through_block != NULL) Goto(fall_through_block, break_block);
+    if (last_block != NULL) Goto(last_block, break_block);
     break_block->SetJoinId(stmt->ExitId());
     set_current_block(break_block);
   }
@@ -3829,7 +3863,7 @@ void HOptimizedGraphBuilder::VisitForInStatement(ForInStatement* stmt) {
 
   compare_index->SetSuccessorAt(0, loop_body);
   compare_index->SetSuccessorAt(1, loop_successor);
-  current_block()->Finish(compare_index);
+  FinishCurrentBlock(compare_index);
 
   set_current_block(loop_successor);
   Drop(5);
@@ -4080,7 +4114,6 @@ void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) {
                                            global_object,
                                            variable->name(),
                                            ast_context()->is_for_typeof());
-        instr->set_position(expr->position());
         return ast_context()->ReturnInstruction(instr, expr->id());
       }
     }
@@ -4832,7 +4865,6 @@ HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic(
 
 
 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
-    int position,
     BailoutId ast_id,
     BailoutId return_id,
     HValue* object,
@@ -4853,7 +4885,7 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
       HBasicBlock* if_false = graph()->CreateBasicBlock();
       HCompareMap* compare = New<HCompareMap>(
           object, info.map(),  if_true, if_false);
-      current_block()->Finish(compare);
+      FinishCurrentBlock(compare);
 
       set_current_block(if_true);
 
@@ -4863,13 +4895,12 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
         if (HasStackOverflow()) return;
       } else {
         if (!load->IsLinked()) {
-          load->set_position(position);
           AddInstruction(load);
         }
         if (!ast_context()->IsEffect()) Push(load);
       }
 
-      if (current_block() != NULL) current_block()->Goto(join);
+      if (current_block() != NULL) Goto(join);
       set_current_block(if_false);
     }
   }
@@ -4886,12 +4917,11 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
   } else {
     HValue* context = environment()->context();
     HInstruction* load = new(zone()) HLoadNamedGeneric(context, object, name);
-    load->set_position(position);
     AddInstruction(load);
     if (!ast_context()->IsEffect()) Push(load);
 
     if (join != NULL) {
-      current_block()->Goto(join);
+      Goto(join);
     } else {
       Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
       if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop());
@@ -4907,7 +4937,6 @@ void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
 
 
 bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
-    int position,
     BailoutId assignment_id,
     HValue* object,
     HValue* value,
@@ -4957,7 +4986,6 @@ bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
           checked_object, name, value, types->at(count - 1), &lookup),
       true);
   if (!ast_context()->IsEffect()) Push(value);
-  store->set_position(position);
   AddInstruction(store);
   Add<HSimulate>(assignment_id);
   if (!ast_context()->IsEffect()) Drop(1);
@@ -4967,14 +4995,13 @@ bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
 
 
 void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
-    int position,
     BailoutId assignment_id,
     HValue* object,
     HValue* value,
     SmallMapList* types,
     Handle<String> name) {
   if (TryStorePolymorphicAsMonomorphic(
-          position, assignment_id, object, value, types, name)) {
+          assignment_id, object, value, types, name)) {
     return;
   }
 
@@ -4995,17 +5022,16 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
       HBasicBlock* if_true = graph()->CreateBasicBlock();
       HBasicBlock* if_false = graph()->CreateBasicBlock();
       HCompareMap* compare = New<HCompareMap>(object, map,  if_true, if_false);
-      current_block()->Finish(compare);
+      FinishCurrentBlock(compare);
 
       set_current_block(if_true);
       HInstruction* instr;
       CHECK_ALIVE(instr = BuildStoreNamedField(
           compare, name, value, map, &lookup));
-      instr->set_position(position);
       // Goto will add the HSimulate for the store.
       AddInstruction(instr);
       if (!ast_context()->IsEffect()) Push(value);
-      current_block()->Goto(join);
+      Goto(join);
 
       set_current_block(if_false);
     }
@@ -5018,14 +5044,13 @@ void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField(
     FinishExitWithHardDeoptimization("Unknown map in polymorphic store", join);
   } else {
     HInstruction* instr = BuildStoreNamedGeneric(object, name, value);
-    instr->set_position(position);
     AddInstruction(instr);
 
     if (join != NULL) {
       if (!ast_context()->IsEffect()) {
         Push(value);
       }
-      current_block()->Goto(join);
+      Goto(join);
     } else {
       // The HSimulate for the store should not see the stored value in
       // effect contexts (it is not materialized at expr->id() in the
@@ -5079,7 +5104,7 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
     HValue* key = environment()->ExpressionStackAt(1);
     HValue* object = environment()->ExpressionStackAt(2);
     bool has_side_effects = false;
-    HandleKeyedElementAccess(object, key, value, expr, expr->position(),
+    HandleKeyedElementAccess(object, key, value, expr,
                              true,  // is_store
                              &has_side_effects);
     Drop(3);
@@ -5128,15 +5153,13 @@ void HOptimizedGraphBuilder::BuildStore(Expression* expr,
     }
   } else if (types != NULL && types->length() > 1) {
     Drop(2);
-    return HandlePolymorphicStoreNamedField(
-        expr->position(), ast_id, object, value, types, name);
+    return HandlePolymorphicStoreNamedField(ast_id, object, value, types, name);
   } else {
     Drop(2);
     instr = BuildStoreNamedGeneric(object, name, value);
   }
 
   if (!ast_context()->IsEffect()) Push(value);
-  instr->set_position(expr->position());
   AddInstruction(instr);
   if (instr->HasObservableSideEffects()) {
     Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
@@ -5165,7 +5188,6 @@ void HOptimizedGraphBuilder::HandlePropertyAssignment(Assignment* expr) {
 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
     Variable* var,
     HValue* value,
-    int position,
     BailoutId ast_id) {
   LookupResult lookup(isolate());
   GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
@@ -5188,7 +5210,6 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
     }
     HInstruction* instr =
         Add<HStoreGlobalCell>(value, cell, lookup.GetPropertyDetails());
-    instr->set_position(position);
     if (instr->HasObservableSideEffects()) {
       Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
     }
@@ -5197,7 +5218,7 @@ void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
     HStoreGlobalGeneric* instr =
         Add<HStoreGlobalGeneric>(global_object, var->name(),
                                  value, function_strict_mode_flag());
-    instr->set_position(position);
+    USE(instr);
     ASSERT(instr->HasObservableSideEffects());
     Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
   }
@@ -5226,7 +5247,6 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
       case Variable::UNALLOCATED:
         HandleGlobalVariableAssignment(var,
                                        Top(),
-                                       expr->position(),
                                        expr->AssignmentId());
         break;
 
@@ -5294,7 +5314,7 @@ void HOptimizedGraphBuilder::HandleCompoundAssignment(Assignment* expr) {
       key = Top();
     }
 
-    CHECK_ALIVE(PushLoad(prop, object, key, expr->position()));
+    CHECK_ALIVE(PushLoad(prop, object, key));
 
     CHECK_ALIVE(VisitForValue(expr->value()));
     HValue* right = Pop();
@@ -5357,7 +5377,6 @@ void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) {
         CHECK_ALIVE(VisitForValue(expr->value()));
         HandleGlobalVariableAssignment(var,
                                        Top(),
-                                       expr->position(),
                                        expr->AssignmentId());
         return ast_context()->ReturnValue(Pop());
 
@@ -5456,16 +5475,15 @@ void HOptimizedGraphBuilder::VisitThrow(Throw* expr) {
   CHECK_ALIVE(VisitForValue(expr->exception()));
 
   HValue* value = environment()->Pop();
-  HThrow* instr = Add<HThrow>(value);
-  instr->set_position(expr->position());
+  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
+  Add<HThrow>(value);
   Add<HSimulate>(expr->id());
 
   // If the throw definitely exits the function, we can finish with a dummy
   // control flow at this point.  This is not the case if the throw is inside
   // an inlined function which may be replaced.
   if (call_context() == NULL) {
-    current_block()->FinishExit(new(zone()) HAbnormalExit);
-    set_current_block(NULL);
+    FinishExitCurrentBlock(new(zone()) HAbnormalExit);
   }
 }
 
@@ -5628,7 +5646,6 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
     HValue* key,
     HValue* val,
     SmallMapList* maps,
-    int position,
     bool is_store,
     KeyedAccessStoreMode store_mode,
     bool* has_side_effects) {
@@ -5640,9 +5657,6 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
         TryBuildConsolidatedElementLoad(object, key, val, maps);
     if (consolidated_load != NULL) {
       *has_side_effects |= consolidated_load->HasObservableSideEffects();
-      if (position != RelocInfo::kNoPosition) {
-        consolidated_load->set_position(position);
-      }
       return consolidated_load;
     }
   }
@@ -5699,7 +5713,6 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
           store_mode);
     }
     *has_side_effects |= instr->HasObservableSideEffects();
-    if (position != RelocInfo::kNoPosition) instr->set_position(position);
     return is_store ? NULL : instr;
   }
 
@@ -5713,7 +5726,7 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
     HBasicBlock* other_map = graph()->CreateBasicBlock();
     HCompareMap* mapcompare =
         New<HCompareMap>(object, map, this_map, other_map);
-    current_block()->Finish(mapcompare);
+    FinishCurrentBlock(mapcompare);
 
     set_current_block(this_map);
     HInstruction* access = NULL;
@@ -5736,12 +5749,11 @@ HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess(
     *has_side_effects |= access->HasObservableSideEffects();
     // The caller will use has_side_effects and add a correct Simulate.
     access->SetFlag(HValue::kHasNoObservableSideEffects);
-    if (position != RelocInfo::kNoPosition) access->set_position(position);
     if (!is_store) {
       Push(access);
     }
     NoObservableSideEffectsScope scope(this);
-    current_block()->GotoNoSimulate(join);
+    GotoNoSimulate(join);
     set_current_block(other_map);
   }
 
@@ -5759,7 +5771,6 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
     HValue* key,
     HValue* val,
     Expression* expr,
-    int position,
     bool is_store,
     bool* has_side_effects) {
   ASSERT(!expr->IsPropertyName());
@@ -5781,7 +5792,7 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
     }
   } else if (types != NULL && !types->is_empty()) {
     return HandlePolymorphicElementAccess(
-        obj, key, val, types, position, is_store,
+        obj, key, val, types, is_store,
         expr->GetStoreMode(), has_side_effects);
   } else {
     if (is_store) {
@@ -5799,7 +5810,6 @@ HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess(
     }
     AddInstruction(instr);
   }
-  if (position != RelocInfo::kNoPosition) instr->set_position(position);
   *has_side_effects = instr->HasObservableSideEffects();
   return instr;
 }
@@ -5898,12 +5908,11 @@ bool HOptimizedGraphBuilder::TryArgumentsAccess(Property* expr) {
 
 void HOptimizedGraphBuilder::PushLoad(Property* expr,
                                       HValue* object,
-                                      HValue* key,
-                                      int position) {
+                                      HValue* key) {
   ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED);
   Push(object);
   if (key != NULL) Push(key);
-  BuildLoad(expr, position, expr->LoadId());
+  BuildLoad(expr, expr->LoadId());
 }
 
 
@@ -5916,7 +5925,6 @@ static bool AreStringTypes(SmallMapList* types) {
 
 
 void HOptimizedGraphBuilder::BuildLoad(Property* expr,
-                                       int position,
                                        BailoutId ast_id) {
   HInstruction* instr = NULL;
   if (expr->IsStringAccess()) {
@@ -5945,7 +5953,7 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
       PropertyAccessInfo info(isolate(), types->first(), name);
       if (!info.CanLoadAsMonomorphic(types)) {
         return HandlePolymorphicLoadNamedField(
-            position, ast_id, expr->LoadId(), object, types, name);
+            ast_id, expr->LoadId(), object, types, name);
       }
 
       BuildCheckHeapObject(object);
@@ -5970,7 +5978,7 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
 
     bool has_side_effects = false;
     HValue* load = HandleKeyedElementAccess(
-        obj, key, NULL, expr, position,
+        obj, key, NULL, expr,
         false,  // is_store
         &has_side_effects);
     if (has_side_effects) {
@@ -5984,7 +5992,6 @@ void HOptimizedGraphBuilder::BuildLoad(Property* expr,
     }
     return ast_context()->ReturnValue(load);
   }
-  instr->set_position(position);
   return ast_context()->ReturnInstruction(instr, ast_id);
 }
 
@@ -6002,7 +6009,7 @@ void HOptimizedGraphBuilder::VisitProperty(Property* expr) {
     CHECK_ALIVE(VisitForValue(expr->key()));
   }
 
-  BuildLoad(expr, expr->position(), expr->id());
+  BuildLoad(expr, expr->id());
 }
 
 
@@ -6115,7 +6122,6 @@ bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic(
     int argument_count = expr->arguments()->length() + 1;  // Includes receiver.
     HCallConstantFunction* call =
       New<HCallConstantFunction>(expr->target(), argument_count);
-    call->set_position(expr->position());
     PreProcessCall(call);
     AddInstruction(call);
     if (!ast_context()->IsEffect()) Push(call);
@@ -6179,9 +6185,9 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
         HBasicBlock* empty_smi_block = graph()->CreateBasicBlock();
         HBasicBlock* not_smi_block = graph()->CreateBasicBlock();
         number_block = graph()->CreateBasicBlock();
-        current_block()->Finish(New<HIsSmiAndBranch>(
+        FinishCurrentBlock(New<HIsSmiAndBranch>(
                 receiver, empty_smi_block, not_smi_block));
-        empty_smi_block->Goto(number_block);
+        Goto(empty_smi_block, number_block);
         set_current_block(not_smi_block);
       } else {
         BuildCheckHeapObject(receiver);
@@ -6206,10 +6212,10 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
       expr->set_map_check();
     }
 
-    current_block()->Finish(compare);
+    FinishCurrentBlock(compare);
 
     if (expr->check_type() == NUMBER_CHECK) {
-      if_true->Goto(number_block);
+      Goto(if_true, number_block);
       if_true = number_block;
       number_block->SetJoinId(expr->id());
     }
@@ -6232,13 +6238,12 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
     } else {
       HCallConstantFunction* call =
           New<HCallConstantFunction>(expr->target(), argument_count);
-      call->set_position(expr->position());
       PreProcessCall(call);
       AddInstruction(call);
       if (!ast_context()->IsEffect()) Push(call);
     }
 
-    if (current_block() != NULL) current_block()->Goto(join);
+    if (current_block() != NULL) Goto(join);
     set_current_block(if_false);
   }
 
@@ -6254,13 +6259,12 @@ void HOptimizedGraphBuilder::HandlePolymorphicCallNamed(
     FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join);
   } else {
     HCallNamed* call = New<HCallNamed>(name, argument_count);
-    call->set_position(expr->position());
     PreProcessCall(call);
 
     if (join != NULL) {
       AddInstruction(call);
       if (!ast_context()->IsEffect()) Push(call);
-      current_block()->Goto(join);
+      Goto(join);
     } else {
       return ast_context()->ReturnInstruction(call, expr->id());
     }
@@ -6562,12 +6566,12 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
       // return value will always evaluate to true, in a value context the
       // return value is the newly allocated receiver.
       if (call_context()->IsTest()) {
-        current_block()->Goto(inlined_test_context()->if_true(), state);
+        Goto(inlined_test_context()->if_true(), state);
       } else if (call_context()->IsEffect()) {
-        current_block()->Goto(function_return(), state);
+        Goto(function_return(), state);
       } else {
         ASSERT(call_context()->IsValue());
-        current_block()->AddLeaveInlined(implicit_return_value, state);
+        AddLeaveInlined(implicit_return_value, state);
       }
     } else if (state->inlining_kind() == SETTER_CALL_RETURN) {
       // Falling off the end of an inlined setter call. The returned value is
@@ -6576,21 +6580,21 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
       if (call_context()->IsTest()) {
         inlined_test_context()->ReturnValue(implicit_return_value);
       } else if (call_context()->IsEffect()) {
-        current_block()->Goto(function_return(), state);
+        Goto(function_return(), state);
       } else {
         ASSERT(call_context()->IsValue());
-        current_block()->AddLeaveInlined(implicit_return_value, state);
+        AddLeaveInlined(implicit_return_value, state);
       }
     } else {
       // Falling off the end of a normal inlined function. This basically means
       // returning undefined.
       if (call_context()->IsTest()) {
-        current_block()->Goto(inlined_test_context()->if_false(), state);
+        Goto(inlined_test_context()->if_false(), state);
       } else if (call_context()->IsEffect()) {
-        current_block()->Goto(function_return(), state);
+        Goto(function_return(), state);
       } else {
         ASSERT(call_context()->IsValue());
-        current_block()->AddLeaveInlined(undefined, state);
+        AddLeaveInlined(undefined, state);
       }
     }
   }
@@ -6612,13 +6616,13 @@ bool HOptimizedGraphBuilder::TryInline(CallKind call_kind,
       entry->RegisterReturnTarget(if_true, zone());
       if_true->SetJoinId(ast_id);
       HBasicBlock* true_target = TestContext::cast(ast_context())->if_true();
-      if_true->Goto(true_target, function_state());
+      Goto(if_true, true_target, function_state());
     }
     if (if_false->HasPredecessor()) {
       entry->RegisterReturnTarget(if_false, zone());
       if_false->SetJoinId(ast_id);
       HBasicBlock* false_target = TestContext::cast(ast_context())->if_false();
-      if_false->Goto(false_target, function_state());
+      Goto(if_false, false_target, function_state());
     }
     set_current_block(NULL);
     return true;
@@ -6725,7 +6729,6 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr,
         Drop(1);  // Receiver.
         HInstruction* op =
             HUnaryMathOperation::New(zone(), context, argument, id);
-        op->set_position(expr->position());
         if (drop_extra) Drop(1);  // Optionally drop the function.
         ast_context()->ReturnInstruction(op, expr->id());
         return true;
@@ -6815,7 +6818,6 @@ bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall(
         Drop(1);  // Receiver.
         HInstruction* op =
             HUnaryMathOperation::New(zone(), context, argument, id);
-        op->set_position(expr->position());
         ast_context()->ReturnInstruction(op, expr->id());
         return true;
       }
@@ -6944,7 +6946,6 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
                                     wrapped_receiver,
                                     length,
                                     elements);
-    result->set_position(expr->position());
     ast_context()->ReturnInstruction(result, expr->id());
     return true;
   } else {
@@ -6982,7 +6983,6 @@ bool HOptimizedGraphBuilder::TryCallApply(Call* expr) {
         known_function,
         arguments_count);
     Drop(arguments_count);
-    call->set_position(expr->position());
     ast_context()->ReturnInstruction(call, expr->id());
     return true;
   }
@@ -7013,7 +7013,6 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
       CHECK_ALIVE(VisitArgumentList(expr->arguments()));
 
       call = New<HCallKeyed>(key, argument_count);
-      call->set_position(expr->position());
       Drop(argument_count + 1);  // 1 is the key.
       return ast_context()->ReturnInstruction(call, expr->id());
     }
@@ -7067,7 +7066,6 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
     } else {
       call = PreProcessCall(New<HCallNamed>(name, argument_count));
     }
-
   } else {
     VariableProxy* proxy = expr->expression()->AsVariableProxy();
     if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) {
@@ -7180,7 +7178,6 @@ void HOptimizedGraphBuilder::VisitCall(Call* expr) {
     }
   }
 
-  call->set_position(expr->position());
   return ast_context()->ReturnInstruction(call, expr->id());
 }
 
@@ -7198,6 +7195,7 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
   ASSERT(!HasStackOverflow());
   ASSERT(current_block() != NULL);
   ASSERT(current_block()->HasPredecessor());
+  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
   int argument_count = expr->arguments()->length() + 1;  // Plus constructor.
   Factory* factory = isolate()->factory();
 
@@ -7289,7 +7287,6 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
     environment()->SetExpressionStackAt(receiver_index, function);
     HInstruction* call =
       PreProcessCall(New<HCallNew>(function, argument_count));
-    call->set_position(expr->position());
     return ast_context()->ReturnInstruction(call, expr->id());
   } else {
     // The constructor function is both an operand to the instruction and an
@@ -7309,7 +7306,6 @@ void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) {
       call = New<HCallNew>(constructor, argument_count);
     }
     Drop(argument_count);
-    call->set_position(expr->position());
     return ast_context()->ReturnInstruction(call, expr->id());
   }
 }
@@ -7540,6 +7536,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
   ASSERT(!HasStackOverflow());
   ASSERT(current_block() != NULL);
   ASSERT(current_block()->HasPredecessor());
+  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
   Expression* target = expr->expression();
   VariableProxy* proxy = target->AsVariableProxy();
   Property* prop = target->AsProperty();
@@ -7572,7 +7569,6 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
       case Variable::UNALLOCATED:
         HandleGlobalVariableAssignment(var,
                                        after,
-                                       expr->position(),
                                        expr->AssignmentId());
         break;
 
@@ -7630,7 +7626,7 @@ void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) {
     key = Top();
   }
 
-  CHECK_ALIVE(PushLoad(prop, object, key, expr->position()));
+  CHECK_ALIVE(PushLoad(prop, object, key));
 
   after = BuildIncrement(returns_original_input, expr);
 
@@ -8057,7 +8053,7 @@ void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
     HBranch* test = is_logical_and
         ? New<HBranch>(left_value, expected, eval_right, empty_block)
         : New<HBranch>(left_value, expected, empty_block, eval_right);
-    current_block()->Finish(test);
+    FinishCurrentBlock(test);
 
     set_current_block(eval_right);
     Drop(1);  // Value of the left subexpression.
@@ -8114,10 +8110,10 @@ void HOptimizedGraphBuilder::VisitLogicalExpression(BinaryOperation* expr) {
 void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) {
   CHECK_ALIVE(VisitForValue(expr->left()));
   CHECK_ALIVE(VisitForValue(expr->right()));
+  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
   HValue* right = Pop();
   HValue* left = Pop();
   HInstruction* instr = BuildBinaryOperation(expr, left, right);
-  instr->set_position(expr->position());
   return ast_context()->ReturnInstruction(instr, expr->id());
 }
 
@@ -8126,9 +8122,9 @@ void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr,
                                                         Expression* sub_expr,
                                                         Handle<String> check) {
   CHECK_ALIVE(VisitForTypeOf(sub_expr));
+  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
   HValue* value = Pop();
   HTypeofIsAndBranch* instr = new(zone()) HTypeofIsAndBranch(value, check);
-  instr->set_position(expr->position());
   return ast_context()->ReturnControl(instr, expr->id());
 }
 
@@ -8150,6 +8146,8 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
   ASSERT(current_block() != NULL);
   ASSERT(current_block()->HasPredecessor());
 
+  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
+
   // Check for a few fast cases. The AST visiting behavior must be in sync
   // with the full codegen: We don't push both left and right values onto
   // the expression stack when one side is a special-case literal.
@@ -8174,7 +8172,6 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     Handle<String> rhs = Handle<String>::cast(literal->value());
     HClassOfTestAndBranch* instr =
         new(zone()) HClassOfTestAndBranch(value, rhs);
-    instr->set_position(expr->position());
     return ast_context()->ReturnControl(instr, expr->id());
   }
 
@@ -8196,7 +8193,6 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
   if (IsLiteralCompareBool(isolate(), left, op, right)) {
     HCompareObjectEqAndBranch* result =
         New<HCompareObjectEqAndBranch>(left, right);
-    result->set_position(expr->position());
     return ast_context()->ReturnControl(result, expr->id());
   }
 
@@ -8228,13 +8224,11 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     // assumed to stay the same for this instanceof.
     if (target.is_null()) {
       HInstanceOf* result = new(zone()) HInstanceOf(context, left, right);
-      result->set_position(expr->position());
       return ast_context()->ReturnInstruction(result, expr->id());
     } else {
       Add<HCheckValue>(right, target);
       HInstanceOfKnownGlobal* result =
         New<HInstanceOfKnownGlobal>(left, target);
-      result->set_position(expr->position());
       return ast_context()->ReturnInstruction(result, expr->id());
     }
 
@@ -8247,7 +8241,6 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     // TODO(olivf) InvokeFunction produces a check for the parameter count,
     // even though we are certain to pass the correct number of arguments here.
     HInstruction* result = New<HInvokeFunction>(function, 2);
-    result->set_position(expr->position());
     return ast_context()->ReturnInstruction(result, expr->id());
   }
 
@@ -8271,7 +8264,6 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
           AddCheckMap(right, map);
           HCompareObjectEqAndBranch* result =
               New<HCompareObjectEqAndBranch>(left, right);
-          result->set_position(expr->position());
           return ast_context()->ReturnControl(result, expr->id());
         } else {
           BuildCheckHeapObject(left);
@@ -8280,7 +8272,6 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
           AddInstruction(HCheckInstanceType::NewIsSpecObject(right, zone()));
           HCompareObjectEqAndBranch* result =
               New<HCompareObjectEqAndBranch>(left, right);
-          result->set_position(expr->position());
           return ast_context()->ReturnControl(result, expr->id());
         }
       }
@@ -8295,7 +8286,6 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     AddInstruction(HCheckInstanceType::NewIsInternalizedString(right, zone()));
     HCompareObjectEqAndBranch* result =
         New<HCompareObjectEqAndBranch>(left, right);
-    result->set_position(expr->position());
     return ast_context()->ReturnControl(result, expr->id());
   } else if (combined_type->Is(Type::String())) {
     BuildCheckHeapObject(left);
@@ -8304,7 +8294,6 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
     AddInstruction(HCheckInstanceType::NewIsString(right, zone()));
     HStringCompareAndBranch* result =
         New<HStringCompareAndBranch>(left, right, op);
-    result->set_position(expr->position());
     return ast_context()->ReturnControl(result, expr->id());
   } else {
     if (combined_rep.IsTagged() || combined_rep.IsNone()) {
@@ -8312,13 +8301,11 @@ void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) {
           new(zone()) HCompareGeneric(context, left, right, op);
       result->set_observed_input_representation(1, left_rep);
       result->set_observed_input_representation(2, right_rep);
-      result->set_position(expr->position());
       return ast_context()->ReturnInstruction(result, expr->id());
     } else {
       HCompareNumericAndBranch* result =
           New<HCompareNumericAndBranch>(left, right, op);
       result->set_observed_input_representation(left_rep, right_rep);
-      result->set_position(expr->position());
       return ast_context()->ReturnControl(result, expr->id());
     }
   }
@@ -8332,6 +8319,7 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
   ASSERT(current_block() != NULL);
   ASSERT(current_block()->HasPredecessor());
   ASSERT(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT);
+  if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
   CHECK_ALIVE(VisitForValue(sub_expr));
   HValue* value = Pop();
   if (expr->op() == Token::EQ_STRICT) {
@@ -8340,7 +8328,6 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
         : graph()->GetConstantUndefined();
     HCompareObjectEqAndBranch* instr =
         New<HCompareObjectEqAndBranch>(value, nil_constant);
-    instr->set_position(expr->position());
     return ast_context()->ReturnControl(instr, expr->id());
   } else {
     ASSERT_EQ(Token::EQ, expr->op());
@@ -8348,7 +8335,7 @@ void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr,
         ? handle(Type::Any(), isolate_)
         : expr->combined_type();
     HIfContinuation continuation;
-    BuildCompareNil(value, type, expr->position(), &continuation);
+    BuildCompareNil(value, type, &continuation);
     return ast_context()->ReturnContinuation(&continuation, expr->id());
   }
 }
@@ -8949,8 +8936,8 @@ void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
   HBasicBlock* if_smi = graph()->CreateBasicBlock();
   HBasicBlock* if_heap_object = graph()->CreateBasicBlock();
   HBasicBlock* join = graph()->CreateBasicBlock();
-  current_block()->Finish(New<HIsSmiAndBranch>(object, if_smi, if_heap_object));
-  if_smi->Goto(join);
+  FinishCurrentBlock(New<HIsSmiAndBranch>(object, if_smi, if_heap_object));
+  Goto(if_smi, join);
 
   // Check if object is a JSValue.
   set_current_block(if_heap_object);
@@ -8960,14 +8947,14 @@ void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) {
   HBasicBlock* not_js_value = graph()->CreateBasicBlock();
   typecheck->SetSuccessorAt(0, if_js_value);
   typecheck->SetSuccessorAt(1, not_js_value);
-  current_block()->Finish(typecheck);
-  not_js_value->Goto(join);
+  FinishCurrentBlock(typecheck);
+  Goto(not_js_value, join);
 
   // Create in-object property store to kValueOffset.
   set_current_block(if_js_value);
   Add<HStoreNamedField>(object,
       HObjectAccess::ForJSObjectOffset(JSValue::kValueOffset), value);
-  if_js_value->Goto(join);
+  Goto(if_js_value, join);
   join->SetJoinId(call->id());
   set_current_block(join);
   return ast_context()->ReturnValue(value);
@@ -9127,19 +9114,19 @@ void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) {
   HBasicBlock* join = graph()->CreateBasicBlock();
   typecheck->SetSuccessorAt(0, if_jsfunction);
   typecheck->SetSuccessorAt(1, if_nonfunction);
-  current_block()->Finish(typecheck);
+  FinishCurrentBlock(typecheck);
 
   set_current_block(if_jsfunction);
   HInstruction* invoke_result = Add<HInvokeFunction>(function, arg_count);
   Drop(arg_count);
   Push(invoke_result);
-  if_jsfunction->Goto(join);
+  Goto(if_jsfunction, join);
 
   set_current_block(if_nonfunction);
   HInstruction* call_result = Add<HCallFunction>(function, arg_count);
   Drop(arg_count);
   Push(call_result);
-  if_nonfunction->Goto(join);
+  Goto(if_nonfunction, join);
 
   set_current_block(join);
   join->SetJoinId(call->id());
index 4159602e44b7ad11c029bbfd0102780614abcd0c..b2568937f77a97c00b9996896b37b1819296fc39 100644 (file)
@@ -110,7 +110,7 @@ class HBasicBlock V8_FINAL : public ZoneObject {
   bool IsFinished() const { return end_ != NULL; }
   void AddPhi(HPhi* phi);
   void RemovePhi(HPhi* phi);
-  void AddInstruction(HInstruction* instr);
+  void AddInstruction(HInstruction* instr, int position);
   bool Dominates(HBasicBlock* other) const;
   int LoopNestingDepth() const;
 
@@ -133,30 +133,18 @@ class HBasicBlock V8_FINAL : public ZoneObject {
 
   void SetJoinId(BailoutId ast_id);
 
-  void Finish(HControlInstruction* last);
-  void FinishExit(HControlInstruction* instruction);
-  void Goto(HBasicBlock* block,
-            FunctionState* state = NULL,
-            bool add_simulate = true);
-  void GotoNoSimulate(HBasicBlock* block) {
-    Goto(block, NULL, false);
-  }
-
   int PredecessorIndexOf(HBasicBlock* predecessor) const;
   HPhi* AddNewPhi(int merged_index);
   HSimulate* AddNewSimulate(BailoutId ast_id,
+                            int position,
                             RemovableSimulate removable = FIXED_SIMULATE) {
     HSimulate* instr = CreateSimulate(ast_id, removable);
-    AddInstruction(instr);
+    AddInstruction(instr, position);
     return instr;
   }
   void AssignCommonDominator(HBasicBlock* other);
   void AssignLoopSuccessorDominators();
 
-  // Add the inlined function exit sequence, adding an HLeaveInlined
-  // instruction and updating the bailout environment.
-  void AddLeaveInlined(HValue* return_value, FunctionState* state);
-
   // If a target block is tagged as an inline function return, all
   // predecessors should contain the inlined exit sequence:
   //
@@ -191,14 +179,30 @@ class HBasicBlock V8_FINAL : public ZoneObject {
   void Verify();
 #endif
 
- private:
+ protected:
   friend class HGraphBuilder;
 
+  HSimulate* CreateSimulate(BailoutId ast_id, RemovableSimulate removable);
+  void Finish(HControlInstruction* last, int position);
+  void FinishExit(HControlInstruction* instruction, int position);
+  void Goto(HBasicBlock* block,
+            int position,
+            FunctionState* state = NULL,
+            bool add_simulate = true);
+  void GotoNoSimulate(HBasicBlock* block, int position) {
+    Goto(block, position, NULL, false);
+  }
+
+  // Add the inlined function exit sequence, adding an HLeaveInlined
+  // instruction and updating the bailout environment.
+  void AddLeaveInlined(HValue* return_value,
+                       FunctionState* state,
+                       int position);
+
+ private:
   void RegisterPredecessor(HBasicBlock* pred);
   void AddDominatedBlock(HBasicBlock* block);
 
-  HSimulate* CreateSimulate(BailoutId ast_id, RemovableSimulate removable);
-
   int block_id_;
   HGraph* graph_;
   ZoneList<HPhi*> phis_;
@@ -940,29 +944,24 @@ class HIfContinuation V8_FINAL {
  public:
   HIfContinuation() : continuation_captured_(false) {}
   HIfContinuation(HBasicBlock* true_branch,
-                  HBasicBlock* false_branch,
-                  int position = RelocInfo::kNoPosition)
+                  HBasicBlock* false_branch)
       : continuation_captured_(true), true_branch_(true_branch),
-        false_branch_(false_branch), position_(position) {}
+        false_branch_(false_branch) {}
   ~HIfContinuation() { ASSERT(!continuation_captured_); }
 
   void Capture(HBasicBlock* true_branch,
-               HBasicBlock* false_branch,
-               int position) {
+               HBasicBlock* false_branch) {
     ASSERT(!continuation_captured_);
     true_branch_ = true_branch;
     false_branch_ = false_branch;
-    position_ = position;
     continuation_captured_ = true;
   }
 
   void Continue(HBasicBlock** true_branch,
-                HBasicBlock** false_branch,
-                int* position) {
+                HBasicBlock** false_branch) {
     ASSERT(continuation_captured_);
     *true_branch = true_branch_;
     *false_branch = false_branch_;
-    if (position != NULL) *position = position_;
     continuation_captured_ = false;
   }
 
@@ -979,7 +978,6 @@ class HIfContinuation V8_FINAL {
   bool continuation_captured_;
   HBasicBlock* true_branch_;
   HBasicBlock* false_branch_;
-  int position_;
 };
 
 
@@ -988,7 +986,8 @@ class HGraphBuilder {
   explicit HGraphBuilder(CompilationInfo* info)
       : info_(info),
         graph_(NULL),
-        current_block_(NULL) {}
+        current_block_(NULL),
+        position_(RelocInfo::kNoPosition) {}
   virtual ~HGraphBuilder() {}
 
   HBasicBlock* current_block() const { return current_block_; }
@@ -1011,6 +1010,34 @@ class HGraphBuilder {
 
   // Adding instructions.
   HInstruction* AddInstruction(HInstruction* instr);
+  void FinishCurrentBlock(HControlInstruction* last);
+  void FinishExitCurrentBlock(HControlInstruction* instruction);
+
+  void Goto(HBasicBlock* from,
+            HBasicBlock* target,
+            FunctionState* state = NULL,
+            bool add_simulate = true) {
+    from->Goto(target, position_, state, add_simulate);
+  }
+  void Goto(HBasicBlock* target,
+            FunctionState* state = NULL,
+            bool add_simulate = true) {
+    Goto(current_block(), target, state, add_simulate);
+  }
+  void GotoNoSimulate(HBasicBlock* from, HBasicBlock* target) {
+    Goto(from, target, NULL, false);
+  }
+  void GotoNoSimulate(HBasicBlock* target) {
+    Goto(target, NULL, false);
+  }
+  void AddLeaveInlined(HBasicBlock* block,
+                       HValue* return_value,
+                       FunctionState* state) {
+    block->AddLeaveInlined(return_value, state, position_);
+  }
+  void AddLeaveInlined(HValue* return_value, FunctionState* state) {
+    return AddLeaveInlined(current_block(), return_value, state);
+  }
 
   template<class I>
   HInstruction* NewUncasted() { return I::New(zone(), context()); }
@@ -1205,6 +1232,8 @@ class HGraphBuilder {
 
   void AddSimulate(BailoutId id, RemovableSimulate removable = FIXED_SIMULATE);
 
+  int position() const { return position_; }
+
  protected:
   virtual bool BuildGraph() = 0;
 
@@ -1290,8 +1319,7 @@ class HGraphBuilder {
 
   class IfBuilder V8_FINAL {
    public:
-    explicit IfBuilder(HGraphBuilder* builder,
-                       int position = RelocInfo::kNoPosition);
+    explicit IfBuilder(HGraphBuilder* builder);
     IfBuilder(HGraphBuilder* builder,
               HIfContinuation* continuation);
 
@@ -1442,7 +1470,6 @@ class HGraphBuilder {
     HGraphBuilder* builder() const { return builder_; }
 
     HGraphBuilder* builder_;
-    int position_;
     bool finished_ : 1;
     bool deopt_then_ : 1;
     bool deopt_else_ : 1;
@@ -1603,7 +1630,6 @@ class HGraphBuilder {
   void BuildCompareNil(
       HValue* value,
       Handle<Type> type,
-      int position,
       HIfContinuation* continuation);
 
   HValue* BuildCreateAllocationMemento(HValue* previous_object,
@@ -1618,6 +1644,12 @@ class HGraphBuilder {
   HInstruction* BuildGetNativeContext();
   HInstruction* BuildGetArrayFunction();
 
+ protected:
+  void SetSourcePosition(int position) {
+    ASSERT(position != RelocInfo::kNoPosition);
+    position_ = position;
+  }
+
  private:
   HGraphBuilder();
 
@@ -1627,6 +1659,7 @@ class HGraphBuilder {
   CompilationInfo* info_;
   HGraph* graph_;
   HBasicBlock* current_block_;
+  int position_;
 };
 
 
@@ -1644,7 +1677,7 @@ inline HInstruction* HGraphBuilder::AddUncasted<HDeoptimize>(
   if (type == Deoptimizer::SOFT) {
     isolate()->counters()->soft_deopts_inserted()->Increment();
   }
-  current_block()->Finish(instr);
+  FinishCurrentBlock(instr);
   set_current_block(after_deopt_block);
   return instr;
 }
@@ -1678,7 +1711,7 @@ inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HValue* value) {
   int num_parameters = graph()->info()->num_parameters();
   HValue* params = AddUncasted<HConstant>(num_parameters);
   HReturn* return_instruction = New<HReturn>(value, params);
-  current_block()->FinishExit(return_instruction);
+  FinishExitCurrentBlock(return_instruction);
   return return_instruction;
 }
 
@@ -1712,8 +1745,7 @@ inline HInstruction* HGraphBuilder::NewUncasted<HContext>() {
 }
 
 
-class HOptimizedGraphBuilder V8_FINAL
-    : public HGraphBuilder, public AstVisitor {
+class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor {
  public:
   // A class encapsulating (lazily-allocated) break and continue blocks for
   // a breakable statement.  Separated from BreakAndContinueScope so that it
@@ -1800,7 +1832,7 @@ class HOptimizedGraphBuilder V8_FINAL
 
   DEFINE_AST_VISITOR_SUBCLASS_MEMBERS();
 
- private:
+ protected:
   // Type of a member function that generates inline code for a native function.
   typedef void (HOptimizedGraphBuilder::*InlineFunctionGenerator)
       (CallRuntime* call);
@@ -1970,6 +2002,7 @@ class HOptimizedGraphBuilder V8_FINAL
   AST_NODE_LIST(DECLARE_VISIT)
 #undef DECLARE_VISIT
 
+ private:
   // Helpers for flow graph construction.
   enum GlobalPropertyAccess {
     kUseCell,
@@ -2021,13 +2054,11 @@ class HOptimizedGraphBuilder V8_FINAL
 
   void HandleGlobalVariableAssignment(Variable* var,
                                       HValue* value,
-                                      int position,
                                       BailoutId ast_id);
 
   void HandlePropertyAssignment(Assignment* expr);
   void HandleCompoundAssignment(Assignment* expr);
-  void HandlePolymorphicLoadNamedField(int position,
-                                       BailoutId ast_id,
+  void HandlePolymorphicLoadNamedField(BailoutId ast_id,
                                        BailoutId return_id,
                                        HValue* object,
                                        SmallMapList* types,
@@ -2124,14 +2155,12 @@ class HOptimizedGraphBuilder V8_FINAL
                                      BailoutId return_id,
                                      bool can_inline_accessor = true);
 
-  void HandlePolymorphicStoreNamedField(int position,
-                                        BailoutId assignment_id,
+  void HandlePolymorphicStoreNamedField(BailoutId assignment_id,
                                         HValue* object,
                                         HValue* value,
                                         SmallMapList* types,
                                         Handle<String> name);
-  bool TryStorePolymorphicAsMonomorphic(int position,
-                                        BailoutId assignment_id,
+  bool TryStorePolymorphicAsMonomorphic(BailoutId assignment_id,
                                         HValue* object,
                                         HValue* value,
                                         SmallMapList* types,
@@ -2180,7 +2209,6 @@ class HOptimizedGraphBuilder V8_FINAL
                                          HValue* key,
                                          HValue* val,
                                          SmallMapList* maps,
-                                         int position,
                                          bool is_store,
                                          KeyedAccessStoreMode store_mode,
                                          bool* has_side_effects);
@@ -2189,7 +2217,6 @@ class HOptimizedGraphBuilder V8_FINAL
                                    HValue* key,
                                    HValue* val,
                                    Expression* expr,
-                                   int position,
                                    bool is_store,
                                    bool* has_side_effects);
 
@@ -2200,12 +2227,10 @@ class HOptimizedGraphBuilder V8_FINAL
   HCheckMaps* AddCheckMap(HValue* object, Handle<Map> map);
 
   void BuildLoad(Property* property,
-                 int position,
                  BailoutId ast_id);
   void PushLoad(Property* property,
                 HValue* object,
-                HValue* key,
-                int position);
+                HValue* key);
 
   void BuildStoreForEffect(Expression* expression,
                            Property* prop,
index 4b0a7b2e4e460e8f72a3cb30f376893c52964e7d..c231fe1151a912f5f17af597009ef918adbf7f20 100644 (file)
@@ -447,8 +447,9 @@ bool LCodeGen::GenerateDeferredCode() {
       X87Stack copy(code->x87_stack());
       x87_stack_ = copy;
 
-      int pos = instructions_->at(code->instruction_index())->position();
-      RecordAndUpdatePosition(pos);
+      HValue* value =
+          instructions_->at(code->instruction_index())->hydrogen_value();
+      RecordAndWritePosition(value->position());
 
       Comment(";;; <@%d,#%d> "
               "-------------------- Deferred %s --------------------",
@@ -935,8 +936,6 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
                                LInstruction* instr,
                                SafepointMode safepoint_mode) {
   ASSERT(instr != NULL);
-  LPointerMap* pointers = instr->pointer_map();
-  RecordPosition(pointers->position());
   __ call(code, mode);
   RecordSafepointWithLazyDeopt(instr, safepoint_mode);
 
@@ -962,8 +961,6 @@ void LCodeGen::CallRuntime(const Runtime::Function* fun,
                            SaveFPRegsMode save_doubles) {
   ASSERT(instr != NULL);
   ASSERT(instr->HasPointerMap());
-  LPointerMap* pointers = instr->pointer_map();
-  RecordPosition(pointers->position());
 
   __ CallRuntime(fun, argc, save_doubles);
 
@@ -1256,7 +1253,7 @@ void LCodeGen::RecordSafepoint(LPointerMap* pointers,
 
 
 void LCodeGen::RecordSafepoint(Safepoint::DeoptMode mode) {
-  LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
+  LPointerMap empty_pointers(zone());
   RecordSafepoint(&empty_pointers, mode);
 }
 
@@ -1268,17 +1265,10 @@ void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
 }
 
 
-void LCodeGen::RecordPosition(int position) {
+void LCodeGen::RecordAndWritePosition(int position) {
   if (position == RelocInfo::kNoPosition) return;
   masm()->positions_recorder()->RecordPosition(position);
-}
-
-
-void LCodeGen::RecordAndUpdatePosition(int position) {
-  if (position >= 0 && position != old_position_) {
-    masm()->positions_recorder()->RecordPosition(position);
-    old_position_ = position;
-  }
+  masm()->positions_recorder()->WriteRecordedPositions();
 }
 
 
@@ -3689,7 +3679,6 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
   __ bind(&invoke);
   ASSERT(instr->HasPointerMap());
   LPointerMap* pointers = instr->pointer_map();
-  RecordPosition(pointers->position());
   SafepointGenerator safepoint_generator(
       this, pointers, Safepoint::kLazyDeopt);
   ParameterCount actual(eax);
@@ -3774,9 +3763,6 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
   bool can_invoke_directly =
       dont_adapt_arguments || formal_parameter_count == arity;
 
-  LPointerMap* pointers = instr->pointer_map();
-  RecordPosition(pointers->position());
-
   if (can_invoke_directly) {
     if (edi_state == EDI_UNINITIALIZED) {
       __ LoadHeapObject(edi, function);
@@ -3801,6 +3787,7 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
     RecordSafepointWithLazyDeopt(instr, RECORD_SIMPLE_SAFEPOINT);
   } else {
     // We need to adapt arguments.
+    LPointerMap* pointers = instr->pointer_map();
     SafepointGenerator generator(
         this, pointers, Safepoint::kLazyDeopt);
     ParameterCount count(arity);
@@ -4269,7 +4256,6 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
   Handle<JSFunction> known_function = instr->hydrogen()->known_function();
   if (known_function.is_null()) {
     LPointerMap* pointers = instr->pointer_map();
-    RecordPosition(pointers->position());
     SafepointGenerator generator(
         this, pointers, Safepoint::kLazyDeopt);
     ParameterCount count(instr->arity());
index 54ea04e7b9636f3b39d6e158c9567e7cbb50b967..78bc69de918fc5d338cdeeda5db2fb8c28b7b0b0 100644 (file)
@@ -64,8 +64,7 @@ class LCodeGen: public LCodeGenBase {
         x87_stack_(assembler),
         safepoints_(info->zone()),
         resolver_(this),
-        expected_safepoint_kind_(Safepoint::kSimple),
-        old_position_(RelocInfo::kNoPosition) {
+        expected_safepoint_kind_(Safepoint::kSimple) {
     PopulateDeoptimizationLiteralsWithInlinedFunctions();
   }
 
@@ -308,9 +307,8 @@ class LCodeGen: public LCodeGenBase {
   void RecordSafepointWithRegisters(LPointerMap* pointers,
                                     int arguments,
                                     Safepoint::DeoptMode mode);
-  void RecordPosition(int position);
 
-  void RecordAndUpdatePosition(int position) V8_OVERRIDE;
+  void RecordAndWritePosition(int position) V8_OVERRIDE;
 
   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
   void EmitGoto(int block);
@@ -472,8 +470,6 @@ class LCodeGen: public LCodeGenBase {
 
   Safepoint::Kind expected_safepoint_kind_;
 
-  int old_position_;
-
   class PushSafepointRegistersScope V8_FINAL  BASE_EMBEDDED {
    public:
     explicit PushSafepointRegistersScope(LCodeGen* codegen)
index e9bdfd06e3ed00d0c962b090d21fac3f3f7cdf81..1c13e839fcadcbaee885eff59f06409cc4b7be52 100644 (file)
@@ -708,7 +708,7 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
 
 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
   ASSERT(!instr->HasPointerMap());
-  instr->set_pointer_map(new(zone()) LPointerMap(position_, zone()));
+  instr->set_pointer_map(new(zone()) LPointerMap(zone()));
   return instr;
 }
 
@@ -908,7 +908,6 @@ void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
 void LChunkBuilder::VisitInstruction(HInstruction* current) {
   HInstruction* old_current = current_instruction_;
   current_instruction_ = current;
-  if (current->has_position()) position_ = current->position();
 
   LInstruction* instr = NULL;
   if (current->CanReplaceWithDummyUses()) {
@@ -963,7 +962,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
     }
 #endif
 
-    instr->set_position(position_);
     if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
       instr = AssignPointerMap(instr);
     }
index f3f9efa681421994e10ec61dceb35b4d8dd84020..a016cfb036af81f7c69bdf946515d03a55450475 100644 (file)
@@ -214,7 +214,6 @@ class LInstruction : public ZoneObject {
       : environment_(NULL),
         hydrogen_value_(NULL),
         bit_field_(IsCallBits::encode(false)) {
-    set_position(RelocInfo::kNoPosition);
   }
 
   virtual ~LInstruction() {}
@@ -255,15 +254,6 @@ class LInstruction : public ZoneObject {
   LPointerMap* pointer_map() const { return pointer_map_.get(); }
   bool HasPointerMap() const { return pointer_map_.is_set(); }
 
-  // The 31 bits PositionBits is used to store the int position value. And the
-  // position value may be RelocInfo::kNoPosition (-1). The accessor always
-  // +1/-1 so that the encoded value of position in bit_field_ is always >= 0
-  // and can fit into the 31 bits PositionBits.
-  void set_position(int pos) {
-    bit_field_ = PositionBits::update(bit_field_, pos + 1);
-  }
-  int position() { return PositionBits::decode(bit_field_) - 1; }
-
   void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; }
   HValue* hydrogen_value() const { return hydrogen_value_; }
 
@@ -309,7 +299,6 @@ class LInstruction : public ZoneObject {
   virtual LOperand* TempAt(int i) = 0;
 
   class IsCallBits: public BitField<bool, 0, 1> {};
-  class PositionBits: public BitField<int, 1, 31> {};
 
   LEnvironment* environment_;
   SetOncePointer<LPointerMap> pointer_map_;
@@ -2750,7 +2739,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
         next_block_(NULL),
         argument_count_(0),
         allocator_(allocator),
-        position_(RelocInfo::kNoPosition),
         instruction_pending_deoptimization_environment_(NULL),
         pending_deoptimization_ast_id_(BailoutId::None()) { }
 
@@ -2908,7 +2896,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
   HBasicBlock* next_block_;
   int argument_count_;
   LAllocator* allocator_;
-  int position_;
   LInstruction* instruction_pending_deoptimization_environment_;
   BailoutId pending_deoptimization_ast_id_;
 
index 1917c338873f49d2b89daba7fb0e1489e1bbefd5..19ebe7e516bfe648fe7a131d2edec3fc3de8b777 100644 (file)
@@ -103,7 +103,13 @@ bool LCodeGenBase::GenerateBody() {
 
     GenerateBodyInstructionPre(instr);
 
-    RecordAndUpdatePosition(instr->position());
+    HValue* value = instr->hydrogen_value();
+    if (value->position() != RelocInfo::kNoPosition) {
+      ASSERT(!graph()->info()->IsOptimizing() ||
+             !FLAG_emit_opt_code_positions ||
+             value->position() != RelocInfo::kNoPosition);
+      RecordAndWritePosition(value->position());
+    }
 
     instr->CompileToNative(codegen);
 
index 8f2ccd5640011db478bc0b892c69e8c2ae863899..9caab8127dbe3e34cc3d2a164a6ec59f296fdee7 100644 (file)
@@ -62,7 +62,7 @@ class LCodeGenBase BASE_EMBEDDED {
   virtual void GenerateBodyInstructionPost(LInstruction* instr) {}
 
   virtual void EnsureSpaceForLazyDeopt(int space_needed) = 0;
-  virtual void RecordAndUpdatePosition(int position) = 0;
+  virtual void RecordAndWritePosition(int position) = 0;
 
   int GetNextEmittedBlock() const;
 
index 6a45d6c59d0e55d2076e539e61a5dcdbc802e4b7..1be4b0654bbba424980c629f611d33c212ee99f4 100644 (file)
@@ -229,7 +229,7 @@ void LPointerMap::PrintTo(StringStream* stream) {
     if (i != 0) stream->Add(";");
     pointer_operands_[i]->PrintTo(stream);
   }
-  stream->Add("} @%d", position());
+  stream->Add("}");
 }
 
 
index fd50ee8f8b9df0f20d5b5ac70682ca5d633b6177..4f84087835ae9a24dd33fccdcec8f1ff5b9f13ec 100644 (file)
@@ -476,10 +476,9 @@ class LParallelMove V8_FINAL : public ZoneObject {
 
 class LPointerMap V8_FINAL : public ZoneObject {
  public:
-  explicit LPointerMap(int position, Zone* zone)
+  explicit LPointerMap(Zone* zone)
       : pointer_operands_(8, zone),
         untagged_operands_(0, zone),
-        position_(position),
         lithium_position_(-1) { }
 
   const ZoneList<LOperand*>* GetNormalizedOperands() {
@@ -489,7 +488,6 @@ class LPointerMap V8_FINAL : public ZoneObject {
     untagged_operands_.Clear();
     return &pointer_operands_;
   }
-  int position() const { return position_; }
   int lithium_position() const { return lithium_position_; }
 
   void set_lithium_position(int pos) {
@@ -505,7 +503,6 @@ class LPointerMap V8_FINAL : public ZoneObject {
  private:
   ZoneList<LOperand*> pointer_operands_;
   ZoneList<LOperand*> untagged_operands_;
-  int position_;
   int lithium_position_;
 };
 
index 908d0acf826e72f23301d90ab114d30e6d7bd27e..c82ef8d81b3c9274672970b06642aea6884d29e6 100644 (file)
@@ -299,8 +299,9 @@ bool LCodeGen::GenerateDeferredCode() {
     for (int i = 0; !is_aborted() && i < deferred_.length(); i++) {
       LDeferredCode* code = deferred_[i];
 
-      int pos = instructions_->at(code->instruction_index())->position();
-      RecordAndUpdatePosition(pos);
+      HValue* value =
+          instructions_->at(code->instruction_index())->hydrogen_value();
+      RecordAndWritePosition(value->position());
 
       Comment(";;; <@%d,#%d> "
               "-------------------- Deferred %s --------------------",
@@ -563,8 +564,6 @@ void LCodeGen::CallCodeGeneric(Handle<Code> code,
                                int argc) {
   EnsureSpaceForLazyDeopt(Deoptimizer::patch_size() - masm()->CallSize(code));
   ASSERT(instr != NULL);
-  LPointerMap* pointers = instr->pointer_map();
-  RecordPosition(pointers->position());
   __ call(code, mode);
   RecordSafepointWithLazyDeopt(instr, safepoint_mode, argc);
 
@@ -590,8 +589,6 @@ void LCodeGen::CallRuntime(const Runtime::Function* function,
                            SaveFPRegsMode save_doubles) {
   ASSERT(instr != NULL);
   ASSERT(instr->HasPointerMap());
-  LPointerMap* pointers = instr->pointer_map();
-  RecordPosition(pointers->position());
 
   __ CallRuntime(function, num_arguments, save_doubles);
 
@@ -840,7 +837,7 @@ void LCodeGen::RecordSafepoint(LPointerMap* pointers,
 
 
 void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
-  LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
+  LPointerMap empty_pointers(zone());
   RecordSafepoint(&empty_pointers, deopt_mode);
 }
 
@@ -852,17 +849,10 @@ void LCodeGen::RecordSafepointWithRegisters(LPointerMap* pointers,
 }
 
 
-void LCodeGen::RecordPosition(int position) {
+void LCodeGen::RecordAndWritePosition(int position) {
   if (position == RelocInfo::kNoPosition) return;
   masm()->positions_recorder()->RecordPosition(position);
-}
-
-
-void LCodeGen::RecordAndUpdatePosition(int position) {
-  if (position >= 0 && position != old_position_) {
-    masm()->positions_recorder()->RecordPosition(position);
-    old_position_ = position;
-  }
+  masm()->positions_recorder()->WriteRecordedPositions();
 }
 
 
@@ -3176,7 +3166,6 @@ void LCodeGen::DoApplyArguments(LApplyArguments* instr) {
   __ bind(&invoke);
   ASSERT(instr->HasPointerMap());
   LPointerMap* pointers = instr->pointer_map();
-  RecordPosition(pointers->position());
   SafepointGenerator safepoint_generator(
       this, pointers, Safepoint::kLazyDeopt);
   ParameterCount actual(rax);
@@ -3250,7 +3239,6 @@ void LCodeGen::CallKnownFunction(Handle<JSFunction> function,
       dont_adapt_arguments || formal_parameter_count == arity;
 
   LPointerMap* pointers = instr->pointer_map();
-  RecordPosition(pointers->position());
 
   if (can_invoke_directly) {
     if (rdi_state == RDI_UNINITIALIZED) {
@@ -3736,7 +3724,6 @@ void LCodeGen::DoInvokeFunction(LInvokeFunction* instr) {
   Handle<JSFunction> known_function = instr->hydrogen()->known_function();
   if (known_function.is_null()) {
     LPointerMap* pointers = instr->pointer_map();
-    RecordPosition(pointers->position());
     SafepointGenerator generator(this, pointers, Safepoint::kLazyDeopt);
     ParameterCount count(instr->arity());
     __ InvokeFunction(rdi, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
index e6855637c1c1ba852093791d073eb1a0b57a39b0..f3f202a277ffa1b951cf498bb47096b7853581ee 100644 (file)
@@ -60,8 +60,7 @@ class LCodeGen: public LCodeGenBase {
         frame_is_built_(false),
         safepoints_(info->zone()),
         resolver_(this),
-        expected_safepoint_kind_(Safepoint::kSimple),
-        old_position_(RelocInfo::kNoPosition) {
+        expected_safepoint_kind_(Safepoint::kSimple) {
     PopulateDeoptimizationLiteralsWithInlinedFunctions();
   }
 
@@ -256,8 +255,7 @@ class LCodeGen: public LCodeGenBase {
   void RecordSafepointWithRegisters(LPointerMap* pointers,
                                     int arguments,
                                     Safepoint::DeoptMode mode);
-  void RecordPosition(int position);
-  void RecordAndUpdatePosition(int position) V8_OVERRIDE;
+  void RecordAndWritePosition(int position) V8_OVERRIDE;
 
   static Condition TokenToCondition(Token::Value op, bool is_unsigned);
   void EmitGoto(int block);
@@ -346,8 +344,6 @@ class LCodeGen: public LCodeGenBase {
 
   Safepoint::Kind expected_safepoint_kind_;
 
-  int old_position_;
-
   class PushSafepointRegistersScope V8_FINAL BASE_EMBEDDED {
    public:
     explicit PushSafepointRegistersScope(LCodeGen* codegen)
index 6e35237680b24a1df9903588b26c0f1c2a1d0b70..93a2eb7fcc3ff52c16d1fddddaabdb1e0b8be9e8 100644 (file)
@@ -665,7 +665,7 @@ LInstruction* LChunkBuilder::MarkAsCall(LInstruction* instr,
 
 LInstruction* LChunkBuilder::AssignPointerMap(LInstruction* instr) {
   ASSERT(!instr->HasPointerMap());
-  instr->set_pointer_map(new(zone()) LPointerMap(position_, zone()));
+  instr->set_pointer_map(new(zone()) LPointerMap(zone()));
   return instr;
 }
 
@@ -859,7 +859,6 @@ void LChunkBuilder::DoBasicBlock(HBasicBlock* block, HBasicBlock* next_block) {
 void LChunkBuilder::VisitInstruction(HInstruction* current) {
   HInstruction* old_current = current_instruction_;
   current_instruction_ = current;
-  if (current->has_position()) position_ = current->position();
 
   LInstruction* instr = NULL;
   if (current->CanReplaceWithDummyUses()) {
@@ -914,7 +913,6 @@ void LChunkBuilder::VisitInstruction(HInstruction* current) {
     }
 #endif
 
-    instr->set_position(position_);
     if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
       instr = AssignPointerMap(instr);
     }
index 0de9ea5ac8068ce8c31d955c699729bb475e2fe0..590f47af4a7d7d237d658a07dcf4891e54646cf9 100644 (file)
@@ -212,7 +212,6 @@ class LInstruction : public ZoneObject {
       : environment_(NULL),
         hydrogen_value_(NULL),
         bit_field_(IsCallBits::encode(false)) {
-    set_position(RelocInfo::kNoPosition);
   }
 
   virtual ~LInstruction() {}
@@ -253,15 +252,6 @@ class LInstruction : public ZoneObject {
   LPointerMap* pointer_map() const { return pointer_map_.get(); }
   bool HasPointerMap() const { return pointer_map_.is_set(); }
 
-  // The 31 bits PositionBits is used to store the int position value. And the
-  // position value may be RelocInfo::kNoPosition (-1). The accessor always
-  // +1/-1 so that the encoded value of position in bit_field_ is always >= 0
-  // and can fit into the 31 bits PositionBits.
-  void set_position(int pos) {
-    bit_field_ = PositionBits::update(bit_field_, pos + 1);
-  }
-  int position() { return PositionBits::decode(bit_field_) - 1; }
-
   void set_hydrogen_value(HValue* value) { hydrogen_value_ = value; }
   HValue* hydrogen_value() const { return hydrogen_value_; }
 
@@ -301,7 +291,6 @@ class LInstruction : public ZoneObject {
   virtual LOperand* TempAt(int i) = 0;
 
   class IsCallBits: public BitField<bool, 0, 1> {};
-  class PositionBits: public BitField<int, 1, 31> {};
 
   LEnvironment* environment_;
   SetOncePointer<LPointerMap> pointer_map_;
@@ -2551,7 +2540,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
         next_block_(NULL),
         argument_count_(0),
         allocator_(allocator),
-        position_(RelocInfo::kNoPosition),
         instruction_pending_deoptimization_environment_(NULL),
         pending_deoptimization_ast_id_(BailoutId::None()) { }
 
@@ -2704,7 +2692,6 @@ class LChunkBuilder V8_FINAL BASE_EMBEDDED {
   HBasicBlock* next_block_;
   int argument_count_;
   LAllocator* allocator_;
-  int position_;
   LInstruction* instruction_pending_deoptimization_environment_;
   BailoutId pending_deoptimization_ast_id_;
 
diff --git a/tools/sodium/index.html b/tools/sodium/index.html
new file mode 100644 (file)
index 0000000..cbfe499
--- /dev/null
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Sodium</title>
+    <meta charset="utf-8">
+    <link href="styles.css" rel="stylesheet" type="text/css">
+  </head>
+  <script src="https://google-code-prettify.googlecode.com/svn/loader/run_prettify.js"></script>
+  <script src="./sodium.js"></script>
+  <script type="text/javascript"></script>
+  <body>
+    <table style='top:5px; width:100%;'>
+      <tr><td id='table-header'>
+          <input type='file' id='log-file-id' />
+          <select id="kind-selector-id" onchange="Sodium.kindChangedHandler(this);"></select><br>
+          <select id="function-selector-id" onchange="Sodium.functionChangedHandler();"></select>
+      </td></tr>
+      <tr>
+      <table style='height:90%;'>
+      <tr>
+        <td id='asm-container'>
+          <div id='asm-text'></div>
+        </td>
+        <td id='source-container'>
+          <div id='source-text'><pre id='source-text-pre'/></div>
+        </td>
+      </tr>
+      </table>
+      </tr>
+    </table>
+    <script>
+      Sodium.buildFunctionKindSelector(document.getElementById('kind-selector-id'));
+      document.getElementById('log-file-id').addEventListener('change', Sodium.readLog, false);
+    </script>
+  </body>
+</html>
diff --git a/tools/sodium/sodium.js b/tools/sodium/sodium.js
new file mode 100644 (file)
index 0000000..44475a1
--- /dev/null
@@ -0,0 +1,409 @@
+// Copyright 2013 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+var Sodium = (function() {
+  "use strict";
+
+  var kinds = ["FUNCTION", "OPTIMIZED_FUNCTION", "STUB", "BUILTIN",
+               "LOAD_IC", "KEYED_LOAD_IC", "CALL_IC", "KEYED_CALL_IC",
+               "STORE_IC", "KEYED_STORE_IC", "BINARY_OP_IC", "COMPARE_IC",
+               "COMPARE_NIL_IC", "TO_BOOLEAN_IC"];
+  var kindsWithSource = {
+    'FUNCTION': true,
+    'OPTIMIZED_FUNCTION': true
+  };
+
+  var addressRegEx = "0x[0-9a-f]{8,16}";
+  var nameFinder = new RegExp("^name = (.+)$");
+  var kindFinder = new RegExp("^kind = (.+)$");
+  var firstPositionFinder = new RegExp("^source_position = (\\d+)$");
+  var separatorFilter = new RegExp("^--- (.)+ ---$");
+  var rawSourceFilter = new RegExp("^--- Raw source ---$");
+  var codeEndFinder = new RegExp("^--- End code ---$");
+  var whiteSpaceLineFinder = new RegExp("^\\W*$");
+  var instructionBeginFinder =
+    new RegExp("^Instructions\\W+\\(size = \\d+\\)");
+  var instructionFinder =
+    new RegExp("^\(" + addressRegEx + "\)\(\\W+\\d+\\W+.+\)");
+  var positionFinder =
+    new RegExp("^(" + addressRegEx + ")\\W+position\\W+\\((\\d+)\\)");
+  var addressFinder = new RegExp("\(" + addressRegEx + "\)");
+  var addressReplacer = new RegExp("\(" + addressRegEx + "\)", "gi");
+
+  var fileContent = "";
+  var selectedFunctionKind = "";
+  var currentFunctionKind = "";
+
+  var currentFunctionName = "";
+  var firstSourcePosition = 0;
+  var startAddress = "";
+  var readingSource = false;
+  var readingAsm = false;
+  var sourceBegin = -1;
+  var sourceEnd = -1;
+  var asmBegin = -1;
+  var asmEnd = -1;
+  var codeObjects = [];
+  var selectedAsm = null;
+  var selectedSource = null;
+  var selectedSourceClass = "";
+
+  function Code(name, kind, sourceBegin, sourceEnd, asmBegin, asmEnd,
+                firstSourcePosition, startAddress) {
+    this.name = name;
+    this.kind = kind;
+    this.sourceBegin = sourceBegin;
+    this.sourceEnd = sourceEnd;
+    this.asmBegin = asmBegin;
+    this.asmEnd = asmEnd;
+    this.firstSourcePosition = firstSourcePosition;
+    this.startAddress = startAddress;
+  }
+
+  function getCurrentCodeObject() {
+    var functionSelect = document.getElementById('function-selector-id');
+    return functionSelect.options[functionSelect.selectedIndex].codeObject;
+  }
+
+  function getCurrentSourceText() {
+    var code = getCurrentCodeObject();
+    if (code.sourceBegin == -1 || code.sourceEnd == -1) return "";
+    return fileContent.substring(code.sourceBegin, code.sourceEnd);
+  }
+
+  function getCurrentAsmText() {
+    var code = getCurrentCodeObject();
+    if (code.asmBegin == -1 || code.asmEnd == -1) return "";
+    return fileContent.substring(code.asmBegin, code.asmEnd);
+  }
+
+  function setKindByIndex(index) {
+    selectedFunctionKind = kinds[index];
+  }
+
+  function processLine(text, begin, end) {
+    var line = text.substring(begin, end);
+    if (readingSource) {
+      if (separatorFilter.exec(line) != null) {
+        readingSource = false;
+      } else {
+        if (sourceBegin == -1) {
+          sourceBegin = begin;
+        }
+        sourceEnd = end;
+      }
+    } else {
+      if (readingAsm) {
+        if (codeEndFinder.exec(line) != null) {
+          readingAsm = false;
+          asmEnd = begin;
+          var newCode =
+            new Code(currentFunctionName, currentFunctionKind,
+                     sourceBegin, sourceEnd, asmBegin, asmEnd,
+                     firstSourcePosition, startAddress);
+          codeObjects.push(newCode);
+          currentFunctionKind = null;
+        } else {
+          if (asmBegin == -1) {
+            matches = instructionBeginFinder.exec(line);
+            if (matches != null) {
+              asmBegin = begin;
+            }
+          }
+          if (startAddress == "") {
+            matches = instructionFinder.exec(line);
+            if (matches != null) {
+              startAddress = matches[1];
+            }
+          }
+        }
+      } else {
+        var matches = kindFinder.exec(line);
+        if (matches != null) {
+          currentFunctionKind = matches[1];
+          if (!kindsWithSource[currentFunctionKind]) {
+            sourceBegin = -1;
+            sourceEnd = -1;
+          }
+        } else if (currentFunctionKind != null) {
+          matches = nameFinder.exec(line);
+          if (matches != null) {
+            readingAsm = true;
+            asmBegin = -1;
+            currentFunctionName = matches[1];
+          }
+        } else if (rawSourceFilter.exec(line) != null) {
+          readingSource = true;
+          sourceBegin = -1;
+        } else {
+          var matches = firstPositionFinder.exec(line);
+          if (matches != null) {
+            firstSourcePosition = parseInt(matches[1]);
+          }
+        }
+      }
+    }
+  }
+
+  function processLines(source, size, processLine) {
+    var firstChar = 0;
+    for (var x = 0; x < size; x++) {
+      var curChar = source[x];
+      if (curChar == '\n' || curChar == '\r') {
+        processLine(source, firstChar, x);
+        firstChar = x + 1;
+      }
+    }
+    if (firstChar != size - 1) {
+      processLine(source, firstChar, size - 1);
+    }
+  }
+
+  function processFileContent() {
+    document.getElementById('source-text-pre').innerHTML = '';
+    sourceBegin = -1;
+    codeObjects = [];
+    processLines(fileContent, fileContent.length, processLine);
+    var functionSelectElement = document.getElementById('function-selector-id');
+    functionSelectElement.innerHTML = '';
+    var length = codeObjects.length;
+    for (var i = 0; i < codeObjects.length; ++i) {
+      var code = codeObjects[i];
+      if (code.kind == selectedFunctionKind) {
+        var optionElement = document.createElement("option");
+        optionElement.codeObject = code;
+        optionElement.text = code.name;
+        functionSelectElement.add(optionElement, null);
+      }
+    }
+  }
+
+  function asmClick(element) {
+    if (element == selectedAsm) return;
+    if (selectedAsm != null) {
+      selectedAsm.classList.remove('highlight-yellow');
+    }
+    selectedAsm = element;
+    selectedAsm.classList.add('highlight-yellow');
+
+    var pc = element.firstChild.innerText;
+    var sourceLine = null;
+    if (addressFinder.exec(pc) != null) {
+      var position = findSourcePosition(pc);
+      var line = findSourceLine(position);
+      sourceLine = document.getElementById('source-line-' + line);
+      var sourceLineTop = sourceLine.offsetTop;
+      makeSourcePosVisible(sourceLineTop);
+    }
+    if (selectedSource == sourceLine) return;
+    if (selectedSource != null) {
+      selectedSource.classList.remove('highlight-yellow');
+      selectedSource.classList.add(selectedSourceClass);
+    }
+    if (sourceLine != null) {
+      selectedSourceClass = sourceLine.classList[0];
+      sourceLine.classList.remove(selectedSourceClass);
+      sourceLine.classList.add('highlight-yellow');
+    }
+    selectedSource = sourceLine;
+  }
+
+  function makeContainerPosVisible(container, newTop) {
+    var height = container.offsetHeight;
+    var margin = Math.floor(height / 4);
+    if (newTop < container.scrollTop + margin) {
+      newTop -= margin;
+      if (newTop < 0) newTop = 0;
+      container.scrollTop = newTop;
+      return;
+    }
+    if (newTop > (container.scrollTop + 3 * margin)) {
+      newTop = newTop - 3 * margin;
+      container.scrollTop = newTop;
+    }
+  }
+
+  function makeAsmPosVisible(newTop) {
+    var asmContainer = document.getElementById('asm-container');
+    makeContainerPosVisible(asmContainer, newTop);
+  }
+
+  function makeSourcePosVisible(newTop) {
+    var sourceContainer = document.getElementById('source-container');
+    makeContainerPosVisible(sourceContainer, newTop);
+  }
+
+  function addressClick(element, event) {
+    event.stopPropagation();
+    var asmLineId = 'address-' + element.innerText;
+    var asmLineElement = document.getElementById(asmLineId);
+    if (asmLineElement != null) {
+      var asmLineTop = asmLineElement.parentNode.offsetTop;
+      makeAsmPosVisible(asmLineTop);
+      asmLineElement.classList.add('highlight-flash-blue');
+      window.setTimeout(function() {
+        asmLineElement.classList.remove('highlight-flash-blue');
+      }, 1500);
+    }
+  }
+
+  function prepareAsm(originalSource) {
+    var newSource = "";
+    var lineNumber = 1;
+    var functionProcessLine = function(text, begin, end) {
+      var currentLine = text.substring(begin, end);
+      var matches = instructionFinder.exec(currentLine);
+      var clickHandler = "";
+      if (matches != null) {
+        var restOfLine = matches[2];
+        restOfLine = restOfLine.replace(
+          addressReplacer,
+          '<span class="hover-underline" ' +
+            'onclick="Sodium.addressClick(this, event);">\$1</span>');
+        currentLine = '<span id="address-' + matches[1] + '" >' +
+          matches[1] + '</span>' + restOfLine;
+        clickHandler = 'onclick=\'Sodium.asmClick(this)\' ';
+      } else if (whiteSpaceLineFinder.exec(currentLine)) {
+        currentLine = "<br>";
+      }
+      newSource += '<pre style=\'margin-bottom: -12px;\' ' + clickHandler + '>' +
+        currentLine + '</pre>';
+      lineNumber++;
+    }
+    processLines(originalSource, originalSource.length, functionProcessLine);
+    return newSource;
+  }
+
+  function findSourcePosition(pcToSearch) {
+    var position = 0;
+    var distance = 0x7FFFFFFF;
+    var pcToSearchOffset = parseInt(pcToSearch);
+    var processOneLine = function(text, begin, end) {
+      var currentLine = text.substring(begin, end);
+      var matches = positionFinder.exec(currentLine);
+      if (matches != null) {
+        var pcOffset = parseInt(matches[1]);
+        if (pcOffset <= pcToSearchOffset) {
+          var dist =  pcToSearchOffset - pcOffset;
+          var pos = parseInt(matches[2]);
+          if ((dist < distance) || (dist == distance && pos > position)) {
+            position = pos;
+            distance = dist;
+          }
+        }
+      }
+    }
+    var asmText = getCurrentAsmText();
+    processLines(asmText, asmText.length, processOneLine);
+    var code = getCurrentCodeObject();
+    if (position == 0) return 0;
+    return position - code.firstSourcePosition;
+  }
+
+  function findSourceLine(position) {
+    if (position == 0) return 1;
+    var line = 0;
+    var processOneLine = function(text, begin, end) {
+      if (begin < position) {
+        line++;
+      }
+    }
+    var sourceText = getCurrentSourceText();
+    processLines(sourceText, sourceText.length, processOneLine);
+    return line;
+  }
+
+  function functionChangedHandler() {
+    var functionSelect = document.getElementById('function-selector-id');
+    var source = getCurrentSourceText();
+    var sourceDivElement = document.getElementById('source-text');
+    var code = getCurrentCodeObject();
+    var newHtml = "<pre class=\"prettyprint linenums\" id=\"source-text\">"
+      + 'function ' + code.name + source + "</pre>";
+    sourceDivElement.innerHTML = newHtml;
+    try {
+      // Wrap in try to work when offline.
+      PR.prettyPrint();
+    } catch (e) {
+    }
+    var sourceLineContainer = sourceDivElement.firstChild.firstChild;
+    var lineCount = sourceLineContainer.childElementCount;
+    var current = sourceLineContainer.firstChild;
+    for (var i = 1; i < lineCount; ++i) {
+      current.id = "source-line-" + i;
+      current = current.nextElementSibling;
+    }
+
+    var asm = getCurrentAsmText();
+    document.getElementById('asm-text').innerHTML = prepareAsm(asm);
+  }
+
+  function kindChangedHandler(element) {
+    setKindByIndex(element.selectedIndex);
+    processFileContent();
+    functionChangedHandler();
+  }
+
+  function readLog(evt) {
+    //Retrieve the first (and only!) File from the FileList object
+    var f = evt.target.files[0];
+    if (f) {
+      var r = new FileReader();
+      r.onload = function(e) {
+        var file = evt.target.files[0];
+        currentFunctionKind = "";
+        fileContent = e.target.result;
+        processFileContent();
+        functionChangedHandler();
+      }
+      r.readAsText(f);
+    } else {
+      alert("Failed to load file");
+    }
+  }
+
+  function buildFunctionKindSelector(kindSelectElement) {
+    for (var x = 0; x < kinds.length; ++x) {
+      var optionElement = document.createElement("option");
+      optionElement.value = x;
+      optionElement.text = kinds[x];
+      kindSelectElement.add(optionElement, null);
+    }
+    kindSelectElement.selectedIndex = 1;
+    setKindByIndex(1);
+  }
+
+  return {
+    buildFunctionKindSelector: buildFunctionKindSelector,
+    kindChangedHandler: kindChangedHandler,
+    functionChangedHandler: functionChangedHandler,
+    asmClick: asmClick,
+    addressClick: addressClick,
+    readLog: readLog
+  };
+
+})();
diff --git a/tools/sodium/styles.css b/tools/sodium/styles.css
new file mode 100755 (executable)
index 0000000..4f7d89e
--- /dev/null
@@ -0,0 +1,70 @@
+#table-header {
+       background-color: rgba(150, 150, 255, 0.4);
+}
+
+#asm-container {
+       background-color: rgba(200, 200, 255, 0.4);
+    position:absolute;
+    overflow:auto;
+    cursor:default;
+    width:50%;
+    height:92%;
+}
+
+#source-container {
+    position:absolute;
+    overflow:auto;
+    width:48%;
+    left:51%;
+    height:92%;
+}
+
+table {
+    border-collapse: collapse;
+}
+
+.hover-underline:hover {
+    text-decoration: underline;
+}
+
+.highlight-flash-blue {
+    -webkit-transition: all 1s ease;
+    background-color: rgba(50, 50, 245, 0.4);
+    border-radius: 10px;
+    -o-border-radius: 10px;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+}
+
+
+.highlight-green {
+    background-color: rgba(0, 255, 0, 0.4);
+    border-radius: 10px;
+    -o-border-radius: 10px;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+}
+
+.highlight-yellow {
+    background-color: rgba(255, 255, 0, 0.4);
+    border-radius: 10px;
+    -o-border-radius: 10px;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+}
+
+.highlight-gray {
+    background-color: rgba(128, 128, 128, 0.4);
+    border-radius: 10px;
+    -o-border-radius: 10px;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+}
+
+.highlight-red {
+    background-color: rgba(255, 0, 0, 0.4);
+    border-radius: 10px;
+    -o-border-radius: 10px;
+    -moz-border-radius: 10px;
+    -webkit-border-radius: 10px;
+}