Version 3.22.18

Add tool to visualize machine code/lithium.

Handle misaligned loads and stores in load elimination. Do not track misaligned loads and be conservative about invalidating misaligned stores. (issue 2934)

Performance and stability improvements on all platforms.

git-svn-id: http://v8.googlecode.com/svn/trunk@17310 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 304e913..fd1705c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2013-10-22: Version 3.22.18
+
+        Add tool to visualize machine code/lithium.
+
+        Handle misaligned loads and stores in load elimination. Do not track
+        misaligned loads and be conservative about invalidating misaligned
+        stores. (issue 2934)
+
+        Performance and stability improvements on all platforms.
+
+
 2013-10-21: Version 3.22.17
 
         Harmony: Implement Math.trunc and Math.sign. (issue 2938)
diff --git a/OWNERS b/OWNERS
index e69a7d5..450e9b2 100644
--- a/OWNERS
+++ b/OWNERS
@@ -2,6 +2,7 @@
 danno@chromium.org
 dslomov@chromium.org
 hpayer@chromium.org
+ishell@chromium.org
 jkummerow@chromium.org
 machenbach@chromium.org
 mstarzinger@chromium.org
diff --git a/src/arm/lithium-arm.cc b/src/arm/lithium-arm.cc
index ac1a03e..3fb07bc 100644
--- a/src/arm/lithium-arm.cc
+++ b/src/arm/lithium-arm.cc
@@ -656,7 +656,7 @@
 
 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 @@
     }
 #endif
 
-    instr->set_position(position_);
     if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
       instr = AssignPointerMap(instr);
     }
diff --git a/src/arm/lithium-arm.h b/src/arm/lithium-arm.h
index 0894652..6c036c7 100644
--- a/src/arm/lithium-arm.h
+++ b/src/arm/lithium-arm.h
@@ -215,7 +215,6 @@
       : environment_(NULL),
         hydrogen_value_(NULL),
         bit_field_(IsCallBits::encode(false)) {
-    set_position(RelocInfo::kNoPosition);
   }
 
   virtual ~LInstruction() {}
@@ -256,15 +255,6 @@
   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 @@
   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_;
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index d2fd70f..60e21b7 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -259,8 +259,9 @@
     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 @@
   // 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 @@
                            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(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::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 @@
   __ 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 @@
       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 @@
   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);
diff --git a/src/arm/lithium-codegen-arm.h b/src/arm/lithium-codegen-arm.h
index 47e854d..b893a9d 100644
--- a/src/arm/lithium-codegen-arm.h
+++ b/src/arm/lithium-codegen-arm.h
@@ -59,8 +59,7 @@
         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 @@
   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 @@
 
   Safepoint::Kind expected_safepoint_kind_;
 
-  int old_position_;
-
   class PushSafepointRegistersScope V8_FINAL BASE_EMBEDDED {
    public:
     PushSafepointRegistersScope(LCodeGen* codegen,
diff --git a/src/code-stubs-hydrogen.cc b/src/code-stubs-hydrogen.cc
index 091d4fb..3e91afc 100644
--- a/src/code-stubs-hydrogen.cc
+++ b/src/code-stubs-hydrogen.cc
@@ -146,14 +146,10 @@
   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);
 
-  HConstant* undefined_constant =
-      Add<HConstant>(isolate()->factory()->undefined_value());
-  graph()->set_undefined_constant(undefined_constant);
-
   for (int i = 0; i < param_count; ++i) {
     HParameter* param =
         Add<HParameter>(i, HParameter::REGISTER_PARAMETER);
@@ -207,8 +203,7 @@
   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 +840,7 @@
   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()) {
diff --git a/src/codegen.cc b/src/codegen.cc
index b15324c..7b2f81b 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -134,7 +134,9 @@
   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 @@
     } 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
 }
diff --git a/src/compiler.cc b/src/compiler.cc
index 6d09722..39524a9 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -313,6 +313,43 @@
 }
 
 
+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 @@
   // 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();
diff --git a/src/factory.cc b/src/factory.cc
index bb998a4..4927cac 100644
--- a/src/factory.cc
+++ b/src/factory.cc
@@ -538,15 +538,22 @@
 }
 
 
-Handle<PropertyCell> Factory::NewPropertyCell(Handle<Object> value) {
-  AllowDeferredHandleDereference convert_to_cell;
+Handle<PropertyCell> Factory::NewPropertyCellWithHole() {
   CALL_HEAP_FUNCTION(
       isolate(),
-      isolate()->heap()->AllocatePropertyCell(*value),
+      isolate()->heap()->AllocatePropertyCell(),
       PropertyCell);
 }
 
 
+Handle<PropertyCell> Factory::NewPropertyCell(Handle<Object> value) {
+  AllowDeferredHandleDereference convert_to_cell;
+  Handle<PropertyCell> cell = NewPropertyCellWithHole();
+  PropertyCell::SetValueInferType(cell, value);
+  return cell;
+}
+
+
 Handle<AllocationSite> Factory::NewAllocationSite() {
   CALL_HEAP_FUNCTION(
       isolate(),
@@ -1052,14 +1059,79 @@
 }
 
 
-Handle<GlobalObject> Factory::NewGlobalObject(
-    Handle<JSFunction> constructor) {
-  CALL_HEAP_FUNCTION(isolate(),
-                     isolate()->heap()->AllocateGlobalObject(*constructor),
+// TODO(mstarzinger): Temporary wrapper until handlified.
+static Handle<NameDictionary> NameDictionaryAdd(Handle<NameDictionary> dict,
+                                                Handle<Name> name,
+                                                Handle<Object> value,
+                                                PropertyDetails details) {
+  CALL_HEAP_FUNCTION(dict->GetIsolate(),
+                     dict->Add(*name, *value, details),
+                     NameDictionary);
+}
+
+
+static Handle<GlobalObject> NewGlobalObjectFromMap(Isolate* isolate,
+                                                   Handle<Map> map) {
+  CALL_HEAP_FUNCTION(isolate,
+                     isolate->heap()->Allocate(*map, OLD_POINTER_SPACE),
                      GlobalObject);
 }
 
 
+Handle<GlobalObject> Factory::NewGlobalObject(Handle<JSFunction> constructor) {
+  ASSERT(constructor->has_initial_map());
+  Handle<Map> map(constructor->initial_map());
+  ASSERT(map->is_dictionary_map());
+
+  // Make sure no field properties are described in the initial map.
+  // This guarantees us that normalizing the properties does not
+  // require us to change property values to PropertyCells.
+  ASSERT(map->NextFreePropertyIndex() == 0);
+
+  // Make sure we don't have a ton of pre-allocated slots in the
+  // global objects. They will be unused once we normalize the object.
+  ASSERT(map->unused_property_fields() == 0);
+  ASSERT(map->inobject_properties() == 0);
+
+  // Initial size of the backing store to avoid resize of the storage during
+  // bootstrapping. The size differs between the JS global object ad the
+  // builtins object.
+  int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
+
+  // Allocate a dictionary object for backing storage.
+  int at_least_space_for = map->NumberOfOwnDescriptors() * 2 + initial_size;
+  Handle<NameDictionary> dictionary = NewNameDictionary(at_least_space_for);
+
+  // The global object might be created from an object template with accessors.
+  // Fill these accessors into the dictionary.
+  Handle<DescriptorArray> descs(map->instance_descriptors());
+  for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
+    PropertyDetails details = descs->GetDetails(i);
+    ASSERT(details.type() == CALLBACKS);  // Only accessors are expected.
+    PropertyDetails d = PropertyDetails(details.attributes(), CALLBACKS, i + 1);
+    Handle<Name> name(descs->GetKey(i));
+    Handle<Object> value(descs->GetCallbacksObject(i), isolate());
+    Handle<PropertyCell> cell = NewPropertyCell(value);
+    NameDictionaryAdd(dictionary, name, cell, d);
+  }
+
+  // Allocate the global object and initialize it with the backing store.
+  Handle<GlobalObject> global = NewGlobalObjectFromMap(isolate(), map);
+  isolate()->heap()->InitializeJSObjectFromMap(*global, *dictionary, *map);
+
+  // Create a new map for the global object.
+  Handle<Map> new_map = Map::CopyDropDescriptors(map);
+  new_map->set_dictionary_map(true);
+
+  // Set up the global object as a normalized object.
+  global->set_map(*new_map);
+  global->set_properties(*dictionary);
+
+  // Make sure result is a global object with properties in dictionary.
+  ASSERT(global->IsGlobalObject() && !global->HasFastProperties());
+  return global;
+}
+
 
 Handle<JSObject> Factory::NewJSObjectFromMap(Handle<Map> map,
                                              PretenureFlag pretenure,
diff --git a/src/factory.h b/src/factory.h
index b2b426d..68980c5 100644
--- a/src/factory.h
+++ b/src/factory.h
@@ -248,6 +248,8 @@
 
   Handle<Cell> NewCell(Handle<Object> value);
 
+  Handle<PropertyCell> NewPropertyCellWithHole();
+
   Handle<PropertyCell> NewPropertyCell(Handle<Object> value);
 
   Handle<AllocationSite> NewAllocationSite();
@@ -306,7 +308,7 @@
   Handle<JSObject> NewJSObject(Handle<JSFunction> constructor,
                                PretenureFlag pretenure = NOT_TENURED);
 
-  // Global objects are pretenured.
+  // Global objects are pretenured and initialized based on a constructor.
   Handle<GlobalObject> NewGlobalObject(Handle<JSFunction> constructor);
 
   // JS objects are pretenured when allocated by the bootstrapper and
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 45f0c72..30b46cf 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -837,8 +837,19 @@
             "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)
diff --git a/src/heap.cc b/src/heap.cc
index 83da35c..fd5504f 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -2963,7 +2963,7 @@
 }
 
 
-MaybeObject* Heap::AllocatePropertyCell(Object* value) {
+MaybeObject* Heap::AllocatePropertyCell() {
   Object* result;
   MaybeObject* maybe_result = AllocateRawPropertyCell();
   if (!maybe_result->ToObject(&result)) return maybe_result;
@@ -2973,10 +2973,8 @@
   PropertyCell* cell = PropertyCell::cast(result);
   cell->set_dependent_code(DependentCode::cast(empty_fixed_array()),
                            SKIP_WRITE_BARRIER);
-  cell->set_value(value);
+  cell->set_value(the_hole_value());
   cell->set_type(Type::None());
-  maybe_result = cell->SetValueInferType(value);
-  if (maybe_result->IsFailure()) return maybe_result;
   return result;
 }
 
@@ -4851,73 +4849,6 @@
 }
 
 
-MaybeObject* Heap::AllocateGlobalObject(JSFunction* constructor) {
-  ASSERT(constructor->has_initial_map());
-  Map* map = constructor->initial_map();
-  ASSERT(map->is_dictionary_map());
-
-  // Make sure no field properties are described in the initial map.
-  // This guarantees us that normalizing the properties does not
-  // require us to change property values to PropertyCells.
-  ASSERT(map->NextFreePropertyIndex() == 0);
-
-  // Make sure we don't have a ton of pre-allocated slots in the
-  // global objects. They will be unused once we normalize the object.
-  ASSERT(map->unused_property_fields() == 0);
-  ASSERT(map->inobject_properties() == 0);
-
-  // Initial size of the backing store to avoid resize of the storage during
-  // bootstrapping. The size differs between the JS global object ad the
-  // builtins object.
-  int initial_size = map->instance_type() == JS_GLOBAL_OBJECT_TYPE ? 64 : 512;
-
-  // Allocate a dictionary object for backing storage.
-  NameDictionary* dictionary;
-  MaybeObject* maybe_dictionary =
-      NameDictionary::Allocate(
-          this,
-          map->NumberOfOwnDescriptors() * 2 + initial_size);
-  if (!maybe_dictionary->To(&dictionary)) return maybe_dictionary;
-
-  // The global object might be created from an object template with accessors.
-  // Fill these accessors into the dictionary.
-  DescriptorArray* descs = map->instance_descriptors();
-  for (int i = 0; i < map->NumberOfOwnDescriptors(); i++) {
-    PropertyDetails details = descs->GetDetails(i);
-    ASSERT(details.type() == CALLBACKS);  // Only accessors are expected.
-    PropertyDetails d = PropertyDetails(details.attributes(), CALLBACKS, i + 1);
-    Object* value = descs->GetCallbacksObject(i);
-    MaybeObject* maybe_value = AllocatePropertyCell(value);
-    if (!maybe_value->ToObject(&value)) return maybe_value;
-
-    MaybeObject* maybe_added = dictionary->Add(descs->GetKey(i), value, d);
-    if (!maybe_added->To(&dictionary)) return maybe_added;
-  }
-
-  // Allocate the global object and initialize it with the backing store.
-  JSObject* global;
-  MaybeObject* maybe_global = Allocate(map, OLD_POINTER_SPACE);
-  if (!maybe_global->To(&global)) return maybe_global;
-
-  InitializeJSObjectFromMap(global, dictionary, map);
-
-  // Create a new map for the global object.
-  Map* new_map;
-  MaybeObject* maybe_map = map->CopyDropDescriptors();
-  if (!maybe_map->To(&new_map)) return maybe_map;
-  new_map->set_dictionary_map(true);
-
-  // Set up the global object as a normalized object.
-  global->set_map(new_map);
-  global->set_properties(dictionary);
-
-  // Make sure result is a global object with properties in dictionary.
-  ASSERT(global->IsGlobalObject());
-  ASSERT(!global->HasFastProperties());
-  return global;
-}
-
-
 MaybeObject* Heap::CopyJSObject(JSObject* source, AllocationSite* site) {
   // Never used to copy functions.  If functions need to be copied we
   // have to be careful to clear the literals array.
diff --git a/src/heap.h b/src/heap.h
index 2344488..0bd2c40 100644
--- a/src/heap.h
+++ b/src/heap.h
@@ -661,12 +661,6 @@
       int length,
       PretenureFlag pretenure = NOT_TENURED);
 
-  // Allocates and initializes a new global object based on a constructor.
-  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
-  // failed.
-  // Please note this does not perform a garbage collection.
-  MUST_USE_RESULT MaybeObject* AllocateGlobalObject(JSFunction* constructor);
-
   // Returns a deep copy of the JavaScript object.
   // Properties and elements are copied too.
   // Returns failure if allocation failed.
@@ -888,22 +882,6 @@
   // Please note this does not perform a garbage collection.
   MUST_USE_RESULT MaybeObject* AllocateSymbol();
 
-  // Allocate a tenured simple cell.
-  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
-  // failed.
-  // Please note this does not perform a garbage collection.
-  MUST_USE_RESULT MaybeObject* AllocateCell(Object* value);
-
-  // Allocate a tenured JS global property cell.
-  // Returns Failure::RetryAfterGC(requested_bytes, space) if the allocation
-  // failed.
-  // Please note this does not perform a garbage collection.
-  MUST_USE_RESULT MaybeObject* AllocatePropertyCell(Object* value);
-
-  // Allocate Box.
-  MUST_USE_RESULT MaybeObject* AllocateBox(Object* value,
-                                           PretenureFlag pretenure);
-
   // Allocate a tenured AllocationSite. It's payload is null
   MUST_USE_RESULT MaybeObject* AllocateAllocationSite();
 
@@ -2165,6 +2143,16 @@
   // Allocate empty fixed double array.
   MUST_USE_RESULT MaybeObject* AllocateEmptyFixedDoubleArray();
 
+  // Allocate a tenured simple cell.
+  MUST_USE_RESULT MaybeObject* AllocateCell(Object* value);
+
+  // Allocate a tenured JS global property cell initialized with the hole.
+  MUST_USE_RESULT MaybeObject* AllocatePropertyCell();
+
+  // Allocate Box.
+  MUST_USE_RESULT MaybeObject* AllocateBox(Object* value,
+                                           PretenureFlag pretenure);
+
   // Performs a minor collection in new generation.
   void Scavenge();
 
diff --git a/src/hydrogen-dce.cc b/src/hydrogen-dce.cc
index 3b64107..e101ee5 100644
--- a/src/hydrogen-dce.cc
+++ b/src/hydrogen-dce.cc
@@ -98,11 +98,7 @@
       HInstruction* instr = it.Current();
       if (!instr->CheckFlag(HValue::kIsLive)) {
         // Instruction has not been marked live, so remove it.
-        if (!instr->IsConstant() || instr->block()->block_id() != 0) {
-          // TODO(titzer): Some global constants in block 0 can be used
-          // again later, and can't currently be removed. Fix that.
-          instr->DeleteAndReplaceWith(NULL);
-        }
+        instr->DeleteAndReplaceWith(NULL);
       } else {
         // Clear the liveness flag to leave the graph clean for the next DCE.
         instr->ClearFlag(HValue::kIsLive);
diff --git a/src/hydrogen-instructions.cc b/src/hydrogen-instructions.cc
index 867fa50..6da6774 100644
--- a/src/hydrogen-instructions.cc
+++ b/src/hydrogen-instructions.cc
@@ -741,6 +741,10 @@
   next_ = next;
   previous_ = prev;
   SetBlock(next->block());
+  if (position() == RelocInfo::kNoPosition &&
+      next->position() != RelocInfo::kNoPosition) {
+    set_position(next->position());
+  }
 }
 
 
@@ -775,6 +779,10 @@
   if (block->last() == previous) {
     block->set_last(this);
   }
+  if (position() == RelocInfo::kNoPosition &&
+      previous->position() != RelocInfo::kNoPosition) {
+    set_position(previous->position());
+  }
 }
 
 
@@ -1592,6 +1600,11 @@
 }
 
 
+int HPhi::position() const {
+  return block()->first()->position();
+}
+
+
 Range* HPhi::InferRange(Zone* zone) {
   Representation r = representation();
   if (r.IsSmiOrInteger32()) {
@@ -2563,6 +2576,7 @@
   ASSERT(IsLinked());
   if (block()->graph()->has_osr() &&
       block()->graph()->IsStandardConstant(this)) {
+    // TODO(titzer): this seems like a hack that should be fixed by custom OSR.
     return true;
   }
   if (UseCount() == 0) return true;
diff --git a/src/hydrogen-instructions.h b/src/hydrogen-instructions.h
index 696d8b0..993f79c 100644
--- a/src/hydrogen-instructions.h
+++ b/src/hydrogen-instructions.h
@@ -638,6 +638,8 @@
         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 @@
   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());
@@ -1774,8 +1776,7 @@
  public:
   enum Kind { BIND, LOOKUP };
 
-  HEnvironmentMarker(Kind kind, int index)
-      : kind_(kind), index_(index), next_simulate_(NULL) { }
+  DECLARE_INSTRUCTION_FACTORY_P2(HEnvironmentMarker, Kind, int);
 
   Kind kind() { return kind_; }
   int index() { return index_; }
@@ -1802,6 +1803,9 @@
   DECLARE_CONCRETE_INSTRUCTION(EnvironmentMarker);
 
  private:
+  HEnvironmentMarker(Kind kind, int index)
+      : kind_(kind), index_(index), next_simulate_(NULL) { }
+
   Kind kind_;
   int index_;
   HSimulate* next_simulate_;
@@ -3147,6 +3151,8 @@
   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() {
diff --git a/src/hydrogen-load-elimination.cc b/src/hydrogen-load-elimination.cc
index f33ebe2..3337188 100644
--- a/src/hydrogen-load-elimination.cc
+++ b/src/hydrogen-load-elimination.cc
@@ -212,7 +212,7 @@
   // instruction is redundant. Otherwise, return {instr}.
   HValue* store(HStoreNamedField* instr) {
     int field = FieldOf(instr->access());
-    if (field < 0) return instr;
+    if (field < 0) return KillIfMisaligned(instr);
 
     HValue* object = instr->object()->ActualValue();
     HValue* value = instr->value();
@@ -250,6 +250,38 @@
     }
   }
 
+  // Kill all entries aliasing the given store.
+  void KillStore(HStoreNamedField* s) {
+    int field = FieldOf(s->access());
+    if (field >= 0) {
+      KillFieldInternal(s->object()->ActualValue(), field, s->value());
+    } else {
+      KillIfMisaligned(s);
+    }
+  }
+
+  // Kill multiple entries in the case of a misaligned store.
+  HValue* KillIfMisaligned(HStoreNamedField* instr) {
+    HObjectAccess access = instr->access();
+    if (access.IsInobject()) {
+      int offset = access.offset();
+      if ((offset % kPointerSize) != 0) {
+        // Kill the field containing the first word of the access.
+        HValue* object = instr->object()->ActualValue();
+        int field = offset / kPointerSize;
+        KillFieldInternal(object, field, NULL);
+
+        // Kill the next field in case of overlap.
+        int size = kPointerSize;
+        if (access.representation().IsByte()) size = 1;
+        else if (access.representation().IsInteger32()) size = 4;
+        int next_field = (offset + size - 1) / kPointerSize;
+        if (next_field != field) KillFieldInternal(object, next_field, NULL);
+      }
+    }
+    return instr;
+  }
+
   // Find an entry for the given object and field pair.
   HFieldApproximation* Find(HValue* object, int field) {
     // Search for a field approximation for this object.
@@ -347,7 +379,8 @@
   // Compute the field index for the given in-object offset; -1 if not tracked.
   int FieldOf(int offset) {
     if (offset >= kMaxTrackedFields * kPointerSize) return -1;
-    ASSERT((offset % kPointerSize) == 0);  // Assume aligned accesses.
+    // TODO(titzer): track misaligned loads in a separate list?
+    if ((offset % kPointerSize) != 0) return -1;  // Ignore misaligned accesses.
     return offset / kPointerSize;
   }
 
@@ -430,11 +463,7 @@
 
     // Kill non-agreeing fields for each store contained in these effects.
     for (int i = 0; i < stores_.length(); i++) {
-      HStoreNamedField* s = stores_[i];
-      int field = table->FieldOf(s->access());
-      if (field >= 0) {
-        table->KillFieldInternal(s->object()->ActualValue(), field, s->value());
-      }
+      table->KillStore(stores_[i]);
     }
   }
 
diff --git a/src/hydrogen-osr.cc b/src/hydrogen-osr.cc
index 3492deb..6e39df6 100644
--- a/src/hydrogen-osr.cc
+++ b/src/hydrogen-osr.cc
@@ -54,10 +54,10 @@
   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 @@
   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);
 
diff --git a/src/hydrogen-representation-changes.cc b/src/hydrogen-representation-changes.cc
index 9601137..d0c9b58 100644
--- a/src/hydrogen-representation-changes.cc
+++ b/src/hydrogen-representation-changes.cc
@@ -61,6 +61,11 @@
   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);
diff --git a/src/hydrogen.cc b/src/hydrogen.cc
index fbca58f..73b23cb 100644
--- a/src/hydrogen.cc
+++ b/src/hydrogen.cc
@@ -140,16 +140,25 @@
 }
 
 
-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 @@
 }
 
 
-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::Goto(HBasicBlock* block,
+                       int position,
                        FunctionState* state,
                        bool add_simulate) {
   bool drop_extra = state != NULL &&
@@ -219,18 +229,21 @@
   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 @@
   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);
 }
 
 
@@ -634,10 +648,21 @@
     // Can't pass GetInvalidContext() to HConstant::New, because that will
     // recursively call GetConstant
     HConstant* constant = HConstant::New(zone(), NULL, value);
-    constant->InsertAfter(GetConstantUndefined());
+    constant->InsertAfter(entry_block()->first());
     pointer->set(constant);
+    return constant;
   }
-  return pointer->get();
+  return ReinsertConstantIfNecessary(pointer->get());
+}
+
+
+HConstant* HGraph::ReinsertConstantIfNecessary(HConstant* constant) {
+  if (!constant->IsLinked()) {
+    // The constant was removed from the graph. Reinsert.
+    constant->ClearFlag(HValue::kIsDead);
+    constant->InsertAfter(entry_block()->first());
+  }
+  return constant;
 }
 
 
@@ -667,13 +692,14 @@
         true,                                                                  \
         false,                                                                 \
         boolean_value);                                                        \
-    constant->InsertAfter(GetConstantUndefined());                             \
+    constant->InsertAfter(entry_block()->first());                             \
     constant_##name##_.set(constant);                                          \
   }                                                                            \
-  return constant_##name##_.get();                                             \
+  return ReinsertConstantIfNecessary(constant_##name##_.get());                \
 }
 
 
+DEFINE_GET_CONSTANT(Undefined, undefined, HType::Tagged(), false)
 DEFINE_GET_CONSTANT(True, true, HType::Boolean(), true)
 DEFINE_GET_CONSTANT(False, false, HType::Boolean(), false)
 DEFINE_GET_CONSTANT(Hole, the_hole, HType::Tagged(), false)
@@ -701,9 +727,8 @@
 }
 
 
-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 +751,6 @@
     HGraphBuilder* builder,
     HIfContinuation* continuation)
     : builder_(builder),
-      position_(RelocInfo::kNoPosition),
       finished_(false),
       deopt_then_(false),
       deopt_else_(false),
@@ -742,8 +766,7 @@
       split_edge_merge_block_(NULL),
       merge_block_(NULL) {
   continuation->Continue(&first_true_block_,
-                         &first_false_block_,
-                         &position_);
+                         &first_false_block_);
 }
 
 
@@ -760,12 +783,12 @@
       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 +801,7 @@
   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 +815,7 @@
   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 +833,7 @@
   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 +850,11 @@
       : 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 +875,7 @@
     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 +903,9 @@
 
 
 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 +935,17 @@
       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 +993,7 @@
   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 +1005,7 @@
 
   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 +1030,10 @@
     // 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 +1053,7 @@
   // 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 +1078,9 @@
 
 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 +1088,26 @@
 }
 
 
+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 +1156,9 @@
   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 +1920,8 @@
 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 +2189,9 @@
   // 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 +2204,8 @@
     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 +2216,7 @@
                                                   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 +2229,10 @@
                                                 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 +2243,7 @@
 // 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 +2258,8 @@
 }
 
 
-void HBasicBlock::FinishExit(HControlInstruction* instruction) {
-  Finish(instruction);
+void HBasicBlock::FinishExit(HControlInstruction* instruction, int position) {
+  Finish(instruction, position);
   ClearEnvironment();
 }
 
@@ -2761,7 +2807,7 @@
   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 +2817,7 @@
                                        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 +2851,7 @@
   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 +2866,7 @@
                                       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 +2906,9 @@
   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 +2917,12 @@
                                      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 +2940,11 @@
   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 +3061,7 @@
   // 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);
 
@@ -3199,10 +3245,6 @@
   HInstruction* context = Add<HContext>();
   environment()->BindContext(context);
 
-  HConstant* undefined_constant = HConstant::cast(Add<HConstant>(
-      isolate()->factory()->undefined_value()));
-  graph()->set_undefined_constant(undefined_constant);
-
   // Create an arguments object containing the initial parameters.  Set the
   // initial values of parameters including "this" having parameter index 0.
   ASSERT_EQ(scope->num_parameters() + 1, environment()->parameter_count());
@@ -3216,6 +3258,7 @@
   AddInstruction(arguments_object);
   graph()->SetArgumentsObject(arguments_object);
 
+  HConstant* undefined_constant = graph()->GetConstantUndefined();
   // Initialize specials and locals to undefined.
   for (int i = environment()->parameter_count() + 1;
        i < environment()->length();
@@ -3258,7 +3301,7 @@
   }
   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 +3411,7 @@
   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 +3424,7 @@
   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 +3447,10 @@
     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 +3464,9 @@
       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 +3476,11 @@
       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 +3490,11 @@
       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 +3542,7 @@
     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 +3585,7 @@
 
     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 +3666,8 @@
                                  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 +3872,7 @@
 
   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 +4123,6 @@
                                            global_object,
                                            variable->name(),
                                            ast_context()->is_for_typeof());
-        instr->set_position(expr->position());
         return ast_context()->ReturnInstruction(instr, expr->id());
       }
     }
@@ -4832,7 +4874,6 @@
 
 
 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField(
-    int position,
     BailoutId ast_id,
     BailoutId return_id,
     HValue* object,
@@ -4853,7 +4894,7 @@
       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 +4904,12 @@
         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 +4926,11 @@
   } 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 +4946,6 @@
 
 
 bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic(
-    int position,
     BailoutId assignment_id,
     HValue* object,
     HValue* value,
@@ -4957,7 +4995,6 @@
           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 +5004,13 @@
 
 
 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 +5031,16 @@
       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 +5053,13 @@
     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 +5113,7 @@
     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 +5162,13 @@
     }
   } 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 +5197,6 @@
 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment(
     Variable* var,
     HValue* value,
-    int position,
     BailoutId ast_id) {
   LookupResult lookup(isolate());
   GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true);
@@ -5188,7 +5219,6 @@
     }
     HInstruction* instr =
         Add<HStoreGlobalCell>(value, cell, lookup.GetPropertyDetails());
-    instr->set_position(position);
     if (instr->HasObservableSideEffects()) {
       Add<HSimulate>(ast_id, REMOVABLE_SIMULATE);
     }
@@ -5197,7 +5227,7 @@
     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 +5256,6 @@
       case Variable::UNALLOCATED:
         HandleGlobalVariableAssignment(var,
                                        Top(),
-                                       expr->position(),
                                        expr->AssignmentId());
         break;
 
@@ -5294,7 +5323,7 @@
       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 +5386,6 @@
         CHECK_ALIVE(VisitForValue(expr->value()));
         HandleGlobalVariableAssignment(var,
                                        Top(),
-                                       expr->position(),
                                        expr->AssignmentId());
         return ast_context()->ReturnValue(Pop());
 
@@ -5456,16 +5484,15 @@
   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 +5655,6 @@
     HValue* key,
     HValue* val,
     SmallMapList* maps,
-    int position,
     bool is_store,
     KeyedAccessStoreMode store_mode,
     bool* has_side_effects) {
@@ -5640,9 +5666,6 @@
         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 +5722,6 @@
           store_mode);
     }
     *has_side_effects |= instr->HasObservableSideEffects();
-    if (position != RelocInfo::kNoPosition) instr->set_position(position);
     return is_store ? NULL : instr;
   }
 
@@ -5713,7 +5735,7 @@
     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 +5758,11 @@
     *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 +5780,6 @@
     HValue* key,
     HValue* val,
     Expression* expr,
-    int position,
     bool is_store,
     bool* has_side_effects) {
   ASSERT(!expr->IsPropertyName());
@@ -5781,7 +5801,7 @@
     }
   } 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 +5819,6 @@
     }
     AddInstruction(instr);
   }
-  if (position != RelocInfo::kNoPosition) instr->set_position(position);
   *has_side_effects = instr->HasObservableSideEffects();
   return instr;
 }
@@ -5898,12 +5917,11 @@
 
 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 +5934,6 @@
 
 
 void HOptimizedGraphBuilder::BuildLoad(Property* expr,
-                                       int position,
                                        BailoutId ast_id) {
   HInstruction* instr = NULL;
   if (expr->IsStringAccess()) {
@@ -5945,7 +5962,7 @@
       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 +5987,7 @@
 
     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 +6001,6 @@
     }
     return ast_context()->ReturnValue(load);
   }
-  instr->set_position(position);
   return ast_context()->ReturnInstruction(instr, ast_id);
 }
 
@@ -6002,7 +6018,7 @@
     CHECK_ALIVE(VisitForValue(expr->key()));
   }
 
-  BuildLoad(expr, expr->position(), expr->id());
+  BuildLoad(expr, expr->id());
 }
 
 
@@ -6115,7 +6131,6 @@
     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 +6194,9 @@
         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 +6221,10 @@
       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 +6247,12 @@
     } 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 +6268,12 @@
     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 +6575,12 @@
       // 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 +6589,21 @@
       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 +6625,13 @@
       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 +6738,6 @@
         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 +6827,6 @@
         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 +6955,6 @@
                                     wrapped_receiver,
                                     length,
                                     elements);
-    result->set_position(expr->position());
     ast_context()->ReturnInstruction(result, expr->id());
     return true;
   } else {
@@ -6982,7 +6992,6 @@
         known_function,
         arguments_count);
     Drop(arguments_count);
-    call->set_position(expr->position());
     ast_context()->ReturnInstruction(call, expr->id());
     return true;
   }
@@ -7013,7 +7022,6 @@
       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 +7075,6 @@
     } 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 +7187,6 @@
     }
   }
 
-  call->set_position(expr->position());
   return ast_context()->ReturnInstruction(call, expr->id());
 }
 
@@ -7198,6 +7204,7 @@
   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 +7296,6 @@
     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 +7315,6 @@
       call = New<HCallNew>(constructor, argument_count);
     }
     Drop(argument_count);
-    call->set_position(expr->position());
     return ast_context()->ReturnInstruction(call, expr->id());
   }
 }
@@ -7540,6 +7545,7 @@
   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 +7578,6 @@
       case Variable::UNALLOCATED:
         HandleGlobalVariableAssignment(var,
                                        after,
-                                       expr->position(),
                                        expr->AssignmentId());
         break;
 
@@ -7630,7 +7635,7 @@
     key = Top();
   }
 
-  CHECK_ALIVE(PushLoad(prop, object, key, expr->position()));
+  CHECK_ALIVE(PushLoad(prop, object, key));
 
   after = BuildIncrement(returns_original_input, expr);
 
@@ -8057,7 +8062,7 @@
     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 +8119,10 @@
 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 +8131,9 @@
                                                         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 +8155,8 @@
   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 +8181,6 @@
     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 +8202,6 @@
   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 +8233,11 @@
     // 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 +8250,6 @@
     // 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 +8273,6 @@
           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 +8281,6 @@
           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 +8295,6 @@
     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 +8303,6 @@
     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 +8310,11 @@
           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 +8328,7 @@
   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 +8337,6 @@
         : 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 +8344,7 @@
         ? 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 +8945,8 @@
   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 +8956,14 @@
   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 +9123,19 @@
   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());
diff --git a/src/hydrogen.h b/src/hydrogen.h
index 4159602..e671692 100644
--- a/src/hydrogen.h
+++ b/src/hydrogen.h
@@ -110,7 +110,7 @@
   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 @@
 
   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 @@
   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_;
@@ -338,10 +342,7 @@
 
   void CollectPhis();
 
-  void set_undefined_constant(HConstant* constant) {
-    undefined_constant_.set(constant);
-  }
-  HConstant* GetConstantUndefined() const { return undefined_constant_.get(); }
+  HConstant* GetConstantUndefined();
   HConstant* GetConstant0();
   HConstant* GetConstant1();
   HConstant* GetConstantMinus1();
@@ -456,6 +457,7 @@
   bool IsInsideNoSideEffectsScope() { return no_side_effects_scope_count_ > 0; }
 
  private:
+  HConstant* ReinsertConstantIfNecessary(HConstant* constant);
   HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
                          int32_t integer_value);
 
@@ -475,7 +477,7 @@
   ZoneList<HValue*> values_;
   ZoneList<HPhi*>* phi_list_;
   ZoneList<HInstruction*>* uint32_instructions_;
-  SetOncePointer<HConstant> undefined_constant_;
+  SetOncePointer<HConstant> constant_undefined_;
   SetOncePointer<HConstant> constant_0_;
   SetOncePointer<HConstant> constant_1_;
   SetOncePointer<HConstant> constant_minus1_;
@@ -940,29 +942,24 @@
  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 +976,6 @@
   bool continuation_captured_;
   HBasicBlock* true_branch_;
   HBasicBlock* false_branch_;
-  int position_;
 };
 
 
@@ -988,7 +984,8 @@
   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 +1008,34 @@
 
   // 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 +1230,8 @@
 
   void AddSimulate(BailoutId id, RemovableSimulate removable = FIXED_SIMULATE);
 
+  int position() const { return position_; }
+
  protected:
   virtual bool BuildGraph() = 0;
 
@@ -1290,8 +1317,7 @@
 
   class IfBuilder V8_FINAL {
    public:
-    explicit IfBuilder(HGraphBuilder* builder,
-                       int position = RelocInfo::kNoPosition);
+    explicit IfBuilder(HGraphBuilder* builder);
     IfBuilder(HGraphBuilder* builder,
               HIfContinuation* continuation);
 
@@ -1442,7 +1468,6 @@
     HGraphBuilder* builder() const { return builder_; }
 
     HGraphBuilder* builder_;
-    int position_;
     bool finished_ : 1;
     bool deopt_then_ : 1;
     bool deopt_else_ : 1;
@@ -1603,7 +1628,6 @@
   void BuildCompareNil(
       HValue* value,
       Handle<Type> type,
-      int position,
       HIfContinuation* continuation);
 
   HValue* BuildCreateAllocationMemento(HValue* previous_object,
@@ -1618,6 +1642,12 @@
   HInstruction* BuildGetNativeContext();
   HInstruction* BuildGetArrayFunction();
 
+ protected:
+  void SetSourcePosition(int position) {
+    ASSERT(position != RelocInfo::kNoPosition);
+    position_ = position;
+  }
+
  private:
   HGraphBuilder();
 
@@ -1627,6 +1657,7 @@
   CompilationInfo* info_;
   HGraph* graph_;
   HBasicBlock* current_block_;
+  int position_;
 };
 
 
@@ -1644,7 +1675,7 @@
   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 +1709,7 @@
   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 +1743,7 @@
 }
 
 
-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 +1830,7 @@
 
   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);
@@ -1918,7 +1948,7 @@
     env->Bind(index, value);
     if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) {
       HEnvironmentMarker* bind =
-          new(zone()) HEnvironmentMarker(HEnvironmentMarker::BIND, index);
+          New<HEnvironmentMarker>(HEnvironmentMarker::BIND, index);
       AddInstruction(bind);
 #ifdef DEBUG
       bind->set_closure(env->closure());
@@ -1931,7 +1961,7 @@
     HValue* value = env->Lookup(index);
     if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) {
       HEnvironmentMarker* lookup =
-          new(zone()) HEnvironmentMarker(HEnvironmentMarker::LOOKUP, index);
+          New<HEnvironmentMarker>(HEnvironmentMarker::LOOKUP, index);
       AddInstruction(lookup);
 #ifdef DEBUG
       lookup->set_closure(env->closure());
@@ -1970,6 +2000,7 @@
   AST_NODE_LIST(DECLARE_VISIT)
 #undef DECLARE_VISIT
 
+ private:
   // Helpers for flow graph construction.
   enum GlobalPropertyAccess {
     kUseCell,
@@ -2021,13 +2052,11 @@
 
   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 +2153,12 @@
                                      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 +2207,6 @@
                                          HValue* key,
                                          HValue* val,
                                          SmallMapList* maps,
-                                         int position,
                                          bool is_store,
                                          KeyedAccessStoreMode store_mode,
                                          bool* has_side_effects);
@@ -2189,7 +2215,6 @@
                                    HValue* key,
                                    HValue* val,
                                    Expression* expr,
-                                   int position,
                                    bool is_store,
                                    bool* has_side_effects);
 
@@ -2200,12 +2225,10 @@
   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,
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 4b0a7b2..c231fe1 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -447,8 +447,9 @@
       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 @@
                                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 @@
                            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(Safepoint::DeoptMode mode) {
-  LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
+  LPointerMap empty_pointers(zone());
   RecordSafepoint(&empty_pointers, mode);
 }
 
@@ -1268,17 +1265,10 @@
 }
 
 
-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 @@
   __ 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 @@
   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 @@
     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 @@
   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());
diff --git a/src/ia32/lithium-codegen-ia32.h b/src/ia32/lithium-codegen-ia32.h
index 54ea04e..78bc69d 100644
--- a/src/ia32/lithium-codegen-ia32.h
+++ b/src/ia32/lithium-codegen-ia32.h
@@ -64,8 +64,7 @@
         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 @@
   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 @@
 
   Safepoint::Kind expected_safepoint_kind_;
 
-  int old_position_;
-
   class PushSafepointRegistersScope V8_FINAL  BASE_EMBEDDED {
    public:
     explicit PushSafepointRegistersScope(LCodeGen* codegen)
diff --git a/src/ia32/lithium-ia32.cc b/src/ia32/lithium-ia32.cc
index e9bdfd0..1c13e83 100644
--- a/src/ia32/lithium-ia32.cc
+++ b/src/ia32/lithium-ia32.cc
@@ -708,7 +708,7 @@
 
 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::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 @@
     }
 #endif
 
-    instr->set_position(position_);
     if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
       instr = AssignPointerMap(instr);
     }
diff --git a/src/ia32/lithium-ia32.h b/src/ia32/lithium-ia32.h
index f3f9efa..a016cfb 100644
--- a/src/ia32/lithium-ia32.h
+++ b/src/ia32/lithium-ia32.h
@@ -214,7 +214,6 @@
       : environment_(NULL),
         hydrogen_value_(NULL),
         bit_field_(IsCallBits::encode(false)) {
-    set_position(RelocInfo::kNoPosition);
   }
 
   virtual ~LInstruction() {}
@@ -255,15 +254,6 @@
   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 @@
   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 @@
         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 @@
   HBasicBlock* next_block_;
   int argument_count_;
   LAllocator* allocator_;
-  int position_;
   LInstruction* instruction_pending_deoptimization_environment_;
   BailoutId pending_deoptimization_ast_id_;
 
diff --git a/src/lithium-codegen.cc b/src/lithium-codegen.cc
index 1917c33..19ebe7e 100644
--- a/src/lithium-codegen.cc
+++ b/src/lithium-codegen.cc
@@ -103,7 +103,13 @@
 
     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);
 
diff --git a/src/lithium-codegen.h b/src/lithium-codegen.h
index 8f2ccd5..9caab81 100644
--- a/src/lithium-codegen.h
+++ b/src/lithium-codegen.h
@@ -62,7 +62,7 @@
   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;
 
diff --git a/src/lithium.cc b/src/lithium.cc
index 6a45d6c..1be4b06 100644
--- a/src/lithium.cc
+++ b/src/lithium.cc
@@ -229,7 +229,7 @@
     if (i != 0) stream->Add(";");
     pointer_operands_[i]->PrintTo(stream);
   }
-  stream->Add("} @%d", position());
+  stream->Add("}");
 }
 
 
diff --git a/src/lithium.h b/src/lithium.h
index fd50ee8..4f84087 100644
--- a/src/lithium.h
+++ b/src/lithium.h
@@ -476,10 +476,9 @@
 
 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 @@
     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 @@
  private:
   ZoneList<LOperand*> pointer_operands_;
   ZoneList<LOperand*> untagged_operands_;
-  int position_;
   int lithium_position_;
 };
 
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index af5f87d..4e19f1d 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -66,7 +66,8 @@
   static Register registers[] = { a0 };
   descriptor->register_param_count_ = 1;
   descriptor->register_params_ = registers;
-  descriptor->deoptimization_handler_ = NULL;
+  descriptor->deoptimization_handler_ =
+      Runtime::FunctionForId(Runtime::kNumberToString)->entry;
 }
 
 
@@ -546,23 +547,27 @@
       GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch);
   Register scratch3 =
       GetRegisterThatIsNotOneOf(input_reg, result_reg, scratch, scratch2);
-  DoubleRegister double_scratch = kLithiumScratchDouble.low();
-  DoubleRegister double_input = f12;
+  DoubleRegister double_scratch = kLithiumScratchDouble;
 
   __ Push(scratch, scratch2, scratch3);
 
-  __ ldc1(double_input, MemOperand(input_reg, double_offset));
-
   if (!skip_fastpath()) {
+    // Load double input.
+    __ ldc1(double_scratch, MemOperand(input_reg, double_offset));
+
     // Clear cumulative exception flags and save the FCSR.
     __ cfc1(scratch2, FCSR);
     __ ctc1(zero_reg, FCSR);
+
     // Try a conversion to a signed integer.
-    __ trunc_w_d(double_scratch, double_input);
+    __ Trunc_w_d(double_scratch, double_scratch);
+    // Move the converted value into the result register.
     __ mfc1(result_reg, double_scratch);
+
     // Retrieve and restore the FCSR.
     __ cfc1(scratch, FCSR);
     __ ctc1(scratch2, FCSR);
+
     // Check for overflow and NaNs.
     __ And(
         scratch, scratch,
@@ -575,7 +580,9 @@
   // Load the double value and perform a manual truncation.
   Register input_high = scratch2;
   Register input_low = scratch3;
-  __ Move(input_low, input_high, double_input);
+
+  __ lw(input_low, MemOperand(input_reg, double_offset));
+  __ lw(input_high, MemOperand(input_reg, double_offset + kIntSize));
 
   Label normal_exponent, restore_sign;
   // Extract the biased exponent in result.
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index 73ecf48..2c6e5a5 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -253,8 +253,9 @@
     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 --------------------",
@@ -656,8 +657,6 @@
                                SafepointMode safepoint_mode) {
   EnsureSpaceForLazyDeopt(Deoptimizer::patch_size());
   ASSERT(instr != NULL);
-  LPointerMap* pointers = instr->pointer_map();
-  RecordPosition(pointers->position());
   __ Call(code, mode);
   RecordSafepointWithLazyDeopt(instr, safepoint_mode);
 }
@@ -668,9 +667,6 @@
                            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);
 
@@ -937,7 +933,7 @@
 
 
 void LCodeGen::RecordSafepoint(Safepoint::DeoptMode deopt_mode) {
-  LPointerMap empty_pointers(RelocInfo::kNoPosition, zone());
+  LPointerMap empty_pointers(zone());
   RecordSafepoint(&empty_pointers, deopt_mode);
 }
 
@@ -959,17 +955,10 @@
 }
 
 
-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();
 }
 
 
@@ -3374,7 +3363,6 @@
   __ 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 a0, as expected
@@ -3463,7 +3451,6 @@
       dont_adapt_arguments || formal_parameter_count == arity;
 
   LPointerMap* pointers = instr->pointer_map();
-  RecordPosition(pointers->position());
 
   if (can_invoke_directly) {
     if (a1_state == A1_UNINITIALIZED) {
@@ -3921,7 +3908,6 @@
   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(a1, count, CALL_FUNCTION, generator, CALL_AS_METHOD);
diff --git a/src/mips/lithium-codegen-mips.h b/src/mips/lithium-codegen-mips.h
index e3d3a60..f643d02 100644
--- a/src/mips/lithium-codegen-mips.h
+++ b/src/mips/lithium-codegen-mips.h
@@ -58,8 +58,7 @@
         frame_is_built_(false),
         safepoints_(info->zone()),
         resolver_(this),
-        expected_safepoint_kind_(Safepoint::kSimple),
-        old_position_(RelocInfo::kNoPosition) {
+        expected_safepoint_kind_(Safepoint::kSimple) {
     PopulateDeoptimizationLiteralsWithInlinedFunctions();
   }
 
@@ -295,8 +294,8 @@
   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);
@@ -402,8 +401,6 @@
 
   Safepoint::Kind expected_safepoint_kind_;
 
-  int old_position_;
-
   class PushSafepointRegistersScope V8_FINAL  BASE_EMBEDDED {
    public:
     PushSafepointRegistersScope(LCodeGen* codegen,
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index b3cd74c..fb94bc3 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -661,7 +661,7 @@
 
 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;
 }
 
@@ -919,7 +919,6 @@
     }
 #endif
 
-    instr->set_position(position_);
     if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
       instr = AssignPointerMap(instr);
     }
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 68f1de9..301be8f 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -212,7 +212,6 @@
       : environment_(NULL),
         hydrogen_value_(NULL),
         bit_field_(IsCallBits::encode(false)) {
-    set_position(RelocInfo::kNoPosition);
   }
 
   virtual ~LInstruction() {}
@@ -253,15 +252,6 @@
   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 @@
   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_;
diff --git a/src/objects.cc b/src/objects.cc
index 743009f..aec412c 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -16310,8 +16310,8 @@
 }
 
 
-Type* PropertyCell::UpdateType(Handle<PropertyCell> cell,
-                               Handle<Object> value) {
+Type* PropertyCell::UpdatedType(Handle<PropertyCell> cell,
+                                Handle<Object> value) {
   Isolate* isolate = cell->GetIsolate();
   Handle<Type> old_type(cell->type(), isolate);
   // TODO(2803): Do not track ConsString as constant because they cannot be
@@ -16336,27 +16336,12 @@
 
 
 void PropertyCell::SetValueInferType(Handle<PropertyCell> cell,
-                                     Handle<Object> value,
-                                     WriteBarrierMode mode) {
-  CALL_HEAP_FUNCTION_VOID(cell->GetIsolate(),
-                          cell->SetValueInferType(*value, mode));
-}
-
-
-MaybeObject* PropertyCell::SetValueInferType(Object* value,
-                                             WriteBarrierMode ignored) {
-  set_value(value, ignored);
-  if (!Type::Any()->Is(type())) {
-    IdempotentPointerToHandleCodeTrampoline trampoline(GetIsolate());
-    MaybeObject* maybe_type = trampoline.CallWithReturnValue(
-        &PropertyCell::UpdateType,
-        Handle<PropertyCell>(this),
-        Handle<Object>(value, GetIsolate()));
-    Type* new_type = NULL;
-    if (!maybe_type->To(&new_type)) return maybe_type;
-    set_type(new_type);
+                                     Handle<Object> value) {
+  cell->set_value(*value);
+  if (!Type::Any()->Is(cell->type())) {
+    Type* new_type = UpdatedType(cell, value);
+    cell->set_type(new_type);
   }
-  return value;
 }
 
 
diff --git a/src/objects.h b/src/objects.h
index 8db2cee..165261b 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -9193,11 +9193,17 @@
   // a change of the type of the cell's contents, code dependent on the cell
   // will be deoptimized.
   static void SetValueInferType(Handle<PropertyCell> cell,
-                                Handle<Object> value,
-                                WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
-  MUST_USE_RESULT MaybeObject* SetValueInferType(
-      Object* value,
-      WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
+                                Handle<Object> value);
+
+  // Computes the new type of the cell's contents for the given value, but
+  // without actually modifying the 'type' field.
+  // TODO(mstarzinger): Return value should be handlified.
+  static Type* UpdatedType(Handle<PropertyCell> cell,
+                           Handle<Object> value);
+
+  void AddDependentCompilationInfo(CompilationInfo* info);
+
+  void AddDependentCode(Handle<Code> code);
 
   // Casting.
   static inline PropertyCell* cast(Object* obj);
@@ -9222,13 +9228,6 @@
                               kSize,
                               kSize> BodyDescriptor;
 
-  void AddDependentCompilationInfo(CompilationInfo* info);
-
-  void AddDependentCode(Handle<Code> code);
-
-  static Type* UpdateType(Handle<PropertyCell> cell,
-                          Handle<Object> value);
-
  private:
   DECL_ACCESSORS(type_raw, Object)
   DISALLOW_IMPLICIT_CONSTRUCTORS(PropertyCell);
diff --git a/src/stub-cache.cc b/src/stub-cache.cc
index 9a30173..bac274c 100644
--- a/src/stub-cache.cc
+++ b/src/stub-cache.cc
@@ -268,7 +268,7 @@
                                            Handle<Object> value,
                                            StrictModeFlag strict_mode) {
   Isolate* isolate = cell->GetIsolate();
-  Handle<Type> union_type(PropertyCell::UpdateType(cell, value), isolate);
+  Handle<Type> union_type(PropertyCell::UpdatedType(cell, value), isolate);
   bool is_constant = union_type->IsConstant();
   StoreGlobalStub stub(strict_mode, is_constant);
 
diff --git a/src/version.cc b/src/version.cc
index efcce67..ffa413b 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,7 +34,7 @@
 // system so their names cannot be changed without changing the scripts.
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     22
-#define BUILD_NUMBER      17
+#define BUILD_NUMBER      18
 #define PATCH_LEVEL       0
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index 908d0ac..c82ef8d 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -299,8 +299,9 @@
     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 @@
                                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 @@
                            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(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::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 @@
   __ 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 @@
       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 @@
   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);
diff --git a/src/x64/lithium-codegen-x64.h b/src/x64/lithium-codegen-x64.h
index e685563..f3f202a 100644
--- a/src/x64/lithium-codegen-x64.h
+++ b/src/x64/lithium-codegen-x64.h
@@ -60,8 +60,7 @@
         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 @@
   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 @@
 
   Safepoint::Kind expected_safepoint_kind_;
 
-  int old_position_;
-
   class PushSafepointRegistersScope V8_FINAL BASE_EMBEDDED {
    public:
     explicit PushSafepointRegistersScope(LCodeGen* codegen)
diff --git a/src/x64/lithium-x64.cc b/src/x64/lithium-x64.cc
index 6e35237..93a2eb7 100644
--- a/src/x64/lithium-x64.cc
+++ b/src/x64/lithium-x64.cc
@@ -665,7 +665,7 @@
 
 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::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 @@
     }
 #endif
 
-    instr->set_position(position_);
     if (FLAG_stress_pointer_maps && !instr->HasPointerMap()) {
       instr = AssignPointerMap(instr);
     }
diff --git a/src/x64/lithium-x64.h b/src/x64/lithium-x64.h
index 0de9ea5..590f47a 100644
--- a/src/x64/lithium-x64.h
+++ b/src/x64/lithium-x64.h
@@ -212,7 +212,6 @@
       : environment_(NULL),
         hydrogen_value_(NULL),
         bit_field_(IsCallBits::encode(false)) {
-    set_position(RelocInfo::kNoPosition);
   }
 
   virtual ~LInstruction() {}
@@ -253,15 +252,6 @@
   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 @@
   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 @@
         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 @@
   HBasicBlock* next_block_;
   int argument_count_;
   LAllocator* allocator_;
-  int position_;
   LInstruction* instruction_pending_deoptimization_environment_;
   BailoutId pending_deoptimization_ast_id_;
 
diff --git a/test/mjsunit/number-tostring-add.js b/test/mjsunit/number-tostring-add.js
new file mode 100644
index 0000000..41d3cbd
--- /dev/null
+++ b/test/mjsunit/number-tostring-add.js
@@ -0,0 +1,89 @@
+// 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.
+
+function add(a, b) {
+  return a + b;
+}
+
+function testToString(a, b) {
+  assertEquals(a, b.toString());
+  assertEquals(a, "" + b);
+  assertEquals(a, add("", b));
+  assertEquals("yes" + a, add("yes", b));
+}
+
+testToString("NaN", (NaN));
+testToString("Infinity", (1/0));
+testToString("-Infinity", (-1/0));
+testToString("0", (0));
+testToString("9", (9));
+testToString("90", (90));
+testToString("90.12", (90.12));
+testToString("0.1", (0.1));
+testToString("0.01", (0.01));
+testToString("0.0123", (0.0123));
+testToString("111111111111111110000", (111111111111111111111));
+testToString("1.1111111111111111e+21", (1111111111111111111111));
+testToString("1.1111111111111111e+22", (11111111111111111111111));
+testToString("0.00001", (0.00001));
+testToString("0.000001", (0.000001));
+testToString("1e-7", (0.0000001));
+testToString("1.2e-7", (0.00000012));
+testToString("1.23e-7", (0.000000123));
+testToString("1e-8", (0.00000001));
+testToString("1.2e-8", (0.000000012));
+testToString("1.23e-8", (0.0000000123));
+
+testToString("0", (-0));
+testToString("-9", (-9));
+testToString("-90", (-90));
+testToString("-90.12", (-90.12));
+testToString("-0.1", (-0.1));
+testToString("-0.01", (-0.01));
+testToString("-0.0123", (-0.0123));
+testToString("-111111111111111110000", (-111111111111111111111));
+testToString("-1.1111111111111111e+21", (-1111111111111111111111));
+testToString("-1.1111111111111111e+22", (-11111111111111111111111));
+testToString("-0.00001", (-0.00001));
+testToString("-0.000001", (-0.000001));
+testToString("-1e-7", (-0.0000001));
+testToString("-1.2e-7", (-0.00000012));
+testToString("-1.23e-7", (-0.000000123));
+testToString("-1e-8", (-0.00000001));
+testToString("-1.2e-8", (-0.000000012));
+testToString("-1.23e-8", (-0.0000000123));
+
+testToString("1000", (1000));
+testToString("0.00001", (0.00001));
+testToString("1000000000000000100", (1000000000000000128));
+testToString("1e+21", (1000000000000000012800));
+testToString("-1e+21", (-1000000000000000012800));
+testToString("1e-7", (0.0000001));
+testToString("-1e-7", (-0.0000001));
+testToString("1.0000000000000001e+21", (1000000000000000128000));
+testToString("0.000001", (0.000001));
+testToString("1e-7", (0.0000001));
diff --git a/test/mjsunit/number-tostring-func.js b/test/mjsunit/number-tostring-func.js
new file mode 100644
index 0000000..c64706e
--- /dev/null
+++ b/test/mjsunit/number-tostring-func.js
@@ -0,0 +1,367 @@
+// 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.
+
+// ----------------------------------------------------------------------
+// toString
+function testToString(a, b) {
+  assertEquals(a, b.toString());
+}
+
+function testToStringP(a, b, c) {
+  assertEquals(a, b.toString(c));
+}
+
+testToString("NaN", (NaN));
+testToString("Infinity", (1/0));
+testToString("-Infinity", (-1/0));
+testToString("0", (0));
+testToString("9", (9));
+testToString("90", (90));
+testToString("90.12", (90.12));
+testToString("0.1", (0.1));
+testToString("0.01", (0.01));
+testToString("0.0123", (0.0123));
+testToString("111111111111111110000", (111111111111111111111));
+testToString("1.1111111111111111e+21", (1111111111111111111111));
+testToString("1.1111111111111111e+22", (11111111111111111111111));
+testToString("0.00001", (0.00001));
+testToString("0.000001", (0.000001));
+testToString("1e-7", (0.0000001));
+testToString("1.2e-7", (0.00000012));
+testToString("1.23e-7", (0.000000123));
+testToString("1e-8", (0.00000001));
+testToString("1.2e-8", (0.000000012));
+testToString("1.23e-8", (0.0000000123));
+
+testToString("0", (-0));
+testToString("-9", (-9));
+testToString("-90", (-90));
+testToString("-90.12", (-90.12));
+testToString("-0.1", (-0.1));
+testToString("-0.01", (-0.01));
+testToString("-0.0123", (-0.0123));
+testToString("-111111111111111110000", (-111111111111111111111));
+testToString("-1.1111111111111111e+21", (-1111111111111111111111));
+testToString("-1.1111111111111111e+22", (-11111111111111111111111));
+testToString("-0.00001", (-0.00001));
+testToString("-0.000001", (-0.000001));
+testToString("-1e-7", (-0.0000001));
+testToString("-1.2e-7", (-0.00000012));
+testToString("-1.23e-7", (-0.000000123));
+testToString("-1e-8", (-0.00000001));
+testToString("-1.2e-8", (-0.000000012));
+testToString("-1.23e-8", (-0.0000000123));
+
+testToString("1000", (1000));
+testToString("0.00001", (0.00001));
+testToString("1000000000000000100", (1000000000000000128));
+testToString("1e+21", (1000000000000000012800));
+testToString("-1e+21", (-1000000000000000012800));
+testToString("1e-7", (0.0000001));
+testToString("-1e-7", (-0.0000001));
+testToString("1.0000000000000001e+21", (1000000000000000128000));
+testToString("0.000001", (0.000001));
+testToString("1e-7", (0.0000001));
+
+testToStringP("NaN", (NaN), 16);
+testToStringP("Infinity", (1/0), 16);
+testToStringP("-Infinity", (-1/0), 16);
+testToStringP("0", (0), 16);
+testToStringP("9", (9), 16);
+testToStringP("5a", (90), 16);
+testToStringP("5a.1eb851eb852", (90.12), 16);
+testToStringP("0.1999999999999a", (0.1), 16);
+testToStringP("0.028f5c28f5c28f6", (0.01), 16);
+testToStringP("0.032617c1bda511a", (0.0123), 16);
+testToStringP("605f9f6dd18bc8000", (111111111111111111111), 16);
+testToStringP("3c3bc3a4a2f75c0000", (1111111111111111111111), 16);
+testToStringP("25a55a46e5da9a00000", (11111111111111111111111), 16);
+testToStringP("0.0000a7c5ac471b4788", (0.00001), 16);
+testToStringP("0.000010c6f7a0b5ed8d", (0.000001), 16);
+testToStringP("0.000001ad7f29abcaf48", (0.0000001), 16);
+testToStringP("0.000002036565348d256", (0.00000012), 16);
+testToStringP("0.0000021047ee22aa466", (0.000000123), 16);
+testToStringP("0.0000002af31dc4611874", (0.00000001), 16);
+testToStringP("0.000000338a23b87483be", (0.000000012), 16);
+testToStringP("0.00000034d3fe36aaa0a2", (0.0000000123), 16);
+
+testToStringP("0", (-0), 16);
+testToStringP("-9", (-9), 16);
+testToStringP("-5a", (-90), 16);
+testToStringP("-5a.1eb851eb852", (-90.12), 16);
+testToStringP("-0.1999999999999a", (-0.1), 16);
+testToStringP("-0.028f5c28f5c28f6", (-0.01), 16);
+testToStringP("-0.032617c1bda511a", (-0.0123), 16);
+testToStringP("-605f9f6dd18bc8000", (-111111111111111111111), 16);
+testToStringP("-3c3bc3a4a2f75c0000", (-1111111111111111111111), 16);
+testToStringP("-25a55a46e5da9a00000", (-11111111111111111111111), 16);
+testToStringP("-0.0000a7c5ac471b4788", (-0.00001), 16);
+testToStringP("-0.000010c6f7a0b5ed8d", (-0.000001), 16);
+testToStringP("-0.000001ad7f29abcaf48", (-0.0000001), 16);
+testToStringP("-0.000002036565348d256", (-0.00000012), 16);
+testToStringP("-0.0000021047ee22aa466", (-0.000000123), 16);
+testToStringP("-0.0000002af31dc4611874", (-0.00000001), 16);
+testToStringP("-0.000000338a23b87483be", (-0.000000012), 16);
+testToStringP("-0.00000034d3fe36aaa0a2", (-0.0000000123), 16);
+
+testToString("4294967296", Math.pow(2,32));
+testToStringP("ffffffff", (Math.pow(2,32)-1), 16);
+testToStringP("11111111111111111111111111111111", (Math.pow(2,32)-1), 2);
+testToStringP("5yc1z", (10000007), 36);
+testToStringP("0", (0), 36);
+testToStringP("0", (0), 16);
+testToStringP("0", (0), 10);
+testToStringP("0", (0), 8);
+testToStringP("0", (0), 2);
+testToStringP("100000000000000000000000000000000", Math.pow(2,32), 2);
+testToStringP("100000000000000000000000000000001", (Math.pow(2,32) + 1), 2);
+testToStringP("100000000000080", (0x100000000000081), 16);
+testToStringP("1000000000000100", (-(-'0x1000000000000081')), 16);
+testToStringP("1000000000000000", (-(-'0x1000000000000080')), 16);
+testToStringP("1000000000000000", (-(-'0x100000000000007F')), 16);
+testToStringP("100000000000000000000000000000000000000000000000010000000", (0x100000000000081), 2);
+testToStringP("-11111111111111111111111111111111", (-(Math.pow(2,32)-1)), 2);
+testToStringP("-5yc1z", (-10000007), 36);
+testToStringP("-100000000000000000000000000000000", (-Math.pow(2,32)), 2);
+testToStringP("-100000000000000000000000000000001", (-(Math.pow(2,32) + 1)), 2);
+testToStringP("-100000000000080", (-0x100000000000081), 16);
+testToStringP("-100000000000000000000000000000000000000000000000010000000", (-0x100000000000081), 2);
+testToStringP("8.8", (8.5), 16);
+testToStringP("-8.8", (-8.5), 16);
+
+// ----------------------------------------------------------------------
+// toFixed
+function testToFixed(a, b, c) {
+  assertEquals(a, b.toFixed(c));
+}
+
+testToFixed("NaN", (NaN), (2));
+testToFixed("Infinity", (1/0), (2));
+testToFixed("-Infinity", (-1/0), (2));
+
+testToFixed("1.1111111111111111e+21", (1111111111111111111111), (8));
+testToFixed("0.1", (0.1), (1));
+testToFixed("0.10", (0.1), (2));
+testToFixed("0.100", (0.1), (3));
+testToFixed("0.01", (0.01), (2));
+testToFixed("0.010", (0.01), (3));
+testToFixed("0.0100", (0.01), (4));
+testToFixed("0.00", (0.001), (2));
+testToFixed("0.001", (0.001), (3));
+testToFixed("0.0010", (0.001), (4));
+testToFixed("1.0000", (1), (4));
+testToFixed("1.0", (1), (1));
+testToFixed("1", (1), (0));
+testToFixed("12", (12), (0));
+testToFixed("1", (1.1), (0));
+testToFixed("12", (12.1), (0));
+testToFixed("1", (1.12), (0));
+testToFixed("12", (12.12), (0));
+testToFixed("0.0000006", (0.0000006), (7));
+testToFixed("0.00000006", (0.00000006), (8));
+testToFixed("0.000000060", (0.00000006), (9));
+testToFixed("0.0000000600", (0.00000006), (10));
+testToFixed("0", (0), (0));
+testToFixed("0.0", (0), (1));
+testToFixed("0.00", (0), (2));
+
+testToFixed("-1.1111111111111111e+21", (-1111111111111111111111), (8));
+testToFixed("-0.1", (-0.1), (1));
+testToFixed("-0.10", (-0.1), (2));
+testToFixed("-0.100", (-0.1), (3));
+testToFixed("-0.01", (-0.01), (2));
+testToFixed("-0.010", (-0.01), (3));
+testToFixed("-0.0100", (-0.01), (4));
+testToFixed("-0.00", (-0.001), (2));
+testToFixed("-0.001", (-0.001), (3));
+testToFixed("-0.0010", (-0.001), (4));
+testToFixed("-1.0000", (-1), (4));
+testToFixed("-1.0", (-1), (1));
+testToFixed("-1", (-1), (0));
+testToFixed("-1", (-1.1), (0));
+testToFixed("-12", (-12.1), (0));
+testToFixed("-1", (-1.12), (0));
+testToFixed("-12", (-12.12), (0));
+testToFixed("-0.0000006", (-0.0000006), (7));
+testToFixed("-0.00000006", (-0.00000006), (8));
+testToFixed("-0.000000060", (-0.00000006), (9));
+testToFixed("-0.0000000600", (-0.00000006), (10));
+testToFixed("0", (-0), (0));
+testToFixed("0.0", (-0), (1));
+testToFixed("0.00", (-0), (2));
+
+testToFixed("0.00001", (0.00001), (5));
+testToFixed("0.00000000000000000010", (0.0000000000000000001), (20));
+testToFixed("0.00001000000000000", (0.00001), (17));
+testToFixed("1.00000000000000000", (1), (17));
+testToFixed("100000000000000128.0", (100000000000000128), (1));
+testToFixed("10000000000000128.00", (10000000000000128), (2));
+testToFixed("10000000000000128.00000000000000000000", (10000000000000128), (20));
+testToFixed("-42.000", (-42), (3));
+testToFixed("-0.00000000000000000010", (-0.0000000000000000001), (20));
+testToFixed("0.12312312312312299889", (0.123123123123123), (20));
+
+assertEquals("-1000000000000000128", (-1000000000000000128).toFixed());
+assertEquals("0", (0).toFixed());
+assertEquals("1000000000000000128", (1000000000000000128).toFixed());
+assertEquals("1000", (1000).toFixed());
+assertEquals("0", (0.00001).toFixed());
+// Test that we round up even when the last digit generated is even.
+// dtoa does not do this in its original form.
+assertEquals("1", 0.5.toFixed(0), "0.5.toFixed(0)");
+assertEquals("-1", (-0.5).toFixed(0), "(-0.5).toFixed(0)");
+assertEquals("1.3", 1.25.toFixed(1), "1.25.toFixed(1)");
+// This is bizare, but Spidermonkey and KJS behave the same.
+assertEquals("234.2040", (234.20405).toFixed(4), "234.2040.toFixed(4)");
+assertEquals("234.2041", (234.2040506).toFixed(4));
+
+// ----------------------------------------------------------------------
+// toExponential
+function testToExponential(a, b) {
+  assertEquals(a, b.toExponential());
+}
+
+function testToExponentialP(a, b, c) {
+  assertEquals(a, b.toExponential(c));
+}
+
+testToExponential("1e+0", (1));
+testToExponential("1.1e+1", (11));
+testToExponential("1.12e+2", (112));
+testToExponential("1e-1", (0.1));
+testToExponential("1.1e-1", (0.11));
+testToExponential("1.12e-1", (0.112));
+testToExponential("-1e+0", (-1));
+testToExponential("-1.1e+1", (-11));
+testToExponential("-1.12e+2", (-112));
+testToExponential("-1e-1", (-0.1));
+testToExponential("-1.1e-1", (-0.11));
+testToExponential("-1.12e-1", (-0.112));
+testToExponential("0e+0", (0));
+testToExponential("1.12356e-4", (0.000112356));
+testToExponential("-1.12356e-4", (-0.000112356));
+
+testToExponentialP("1e+0", (1), (0));
+testToExponentialP("1e+1", (11), (0));
+testToExponentialP("1e+2", (112), (0));
+testToExponentialP("1.0e+0", (1), (1));
+testToExponentialP("1.1e+1", (11), (1));
+testToExponentialP("1.1e+2", (112), (1));
+testToExponentialP("1.00e+0", (1), (2));
+testToExponentialP("1.10e+1", (11), (2));
+testToExponentialP("1.12e+2", (112), (2));
+testToExponentialP("1.000e+0", (1), (3));
+testToExponentialP("1.100e+1", (11), (3));
+testToExponentialP("1.120e+2", (112), (3));
+testToExponentialP("1e-1", (0.1), (0));
+testToExponentialP("1e-1", (0.11), (0));
+testToExponentialP("1e-1", (0.112), (0));
+testToExponentialP("1.0e-1", (0.1), (1));
+testToExponentialP("1.1e-1", (0.11), (1));
+testToExponentialP("1.1e-1", (0.112), (1));
+testToExponentialP("1.00e-1", (0.1), (2));
+testToExponentialP("1.10e-1", (0.11), (2));
+testToExponentialP("1.12e-1", (0.112), (2));
+testToExponentialP("1.000e-1", (0.1), (3));
+testToExponentialP("1.100e-1", (0.11), (3));
+testToExponentialP("1.120e-1", (0.112), (3));
+
+testToExponentialP("-1e+0", (-1), (0));
+testToExponentialP("-1e+1", (-11), (0));
+testToExponentialP("-1e+2", (-112), (0));
+testToExponentialP("-1.0e+0", (-1), (1));
+testToExponentialP("-1.1e+1", (-11), (1));
+testToExponentialP("-1.1e+2", (-112), (1));
+testToExponentialP("-1.00e+0", (-1), (2));
+testToExponentialP("-1.10e+1", (-11), (2));
+testToExponentialP("-1.12e+2", (-112), (2));
+testToExponentialP("-1.000e+0", (-1), (3));
+testToExponentialP("-1.100e+1", (-11), (3));
+testToExponentialP("-1.120e+2", (-112), (3));
+testToExponentialP("-1e-1", (-0.1), (0));
+testToExponentialP("-1e-1", (-0.11), (0));
+testToExponentialP("-1e-1", (-0.112), (0));
+testToExponentialP("-1.0e-1", (-0.1), (1));
+testToExponentialP("-1.1e-1", (-0.11), (1));
+testToExponentialP("-1.1e-1", (-0.112), (1));
+testToExponentialP("-1.00e-1", (-0.1), (2));
+testToExponentialP("-1.10e-1", (-0.11), (2));
+testToExponentialP("-1.12e-1", (-0.112), (2));
+testToExponentialP("-1.000e-1", (-0.1), (3));
+testToExponentialP("-1.100e-1", (-0.11), (3));
+testToExponentialP("-1.120e-1", (-0.112), (3));
+
+testToExponentialP("NaN", (NaN), (2));
+testToExponentialP("Infinity", (Infinity), (2));
+testToExponentialP("-Infinity", (-Infinity), (2));
+testToExponentialP("1e+0", (1), (0));
+testToExponentialP("0.00e+0", (0), (2));
+testToExponentialP("1e+1", (11.2356), (0));
+testToExponentialP("1.1236e+1", (11.2356), (4));
+testToExponentialP("1.1236e-4", (0.000112356), (4));
+testToExponentialP("-1.1236e-4", (-0.000112356), (4));
+
+// ----------------------------------------------------------------------
+// toPrecision
+function testToPrecision(a, b, c) {
+  assertEquals(a, b.toPrecision(c));
+}
+
+testToPrecision("NaN", (NaN), (1));
+testToPrecision("Infinity", (Infinity), (2));
+testToPrecision("-Infinity", (-Infinity), (2));
+testToPrecision("0.000555000000000000", (0.000555), (15));
+testToPrecision("5.55000000000000e-7", (0.000000555), (15));
+testToPrecision("-5.55000000000000e-7", (-0.000000555), (15));
+testToPrecision("1e+8", (123456789), (1));
+testToPrecision("123456789", (123456789), (9));
+testToPrecision("1.2345679e+8", (123456789), (8));
+testToPrecision("1.234568e+8", (123456789), (7));
+testToPrecision("-1.234568e+8", (-123456789), (7));
+testToPrecision("-1.2e-9", Number(-.0000000012345), (2));
+testToPrecision("-1.2e-8", Number(-.000000012345), (2));
+testToPrecision("-1.2e-7", Number(-.00000012345), (2));
+testToPrecision("-0.0000012", Number(-.0000012345), (2));
+testToPrecision("-0.000012", Number(-.000012345), (2));
+testToPrecision("-0.00012", Number(-.00012345), (2));
+testToPrecision("-0.0012", Number(-.0012345), (2));
+testToPrecision("-0.012", Number(-.012345), (2));
+testToPrecision("-0.12", Number(-.12345), (2));
+testToPrecision("-1.2", Number(-1.2345), (2));
+testToPrecision("-12", Number(-12.345), (2));
+testToPrecision("-1.2e+2", Number(-123.45), (2));
+testToPrecision("-1.2e+3", Number(-1234.5), (2));
+testToPrecision("-1.2e+4", Number(-12345), (2));
+testToPrecision("-1.235e+4", Number(-12345.67), (4));
+testToPrecision("-1.234e+4", Number(-12344.67), (4));
+// Test that we round up even when the last digit generated is even.
+// dtoa does not do this in its original form.
+assertEquals("1.3", 1.25.toPrecision(2), "1.25.toPrecision(2)");
+assertEquals("1.4", 1.35.toPrecision(2), "1.35.toPrecision(2)");
+
+
+
diff --git a/tools/sodium/index.html b/tools/sodium/index.html
new file mode 100644
index 0000000..cbfe499
--- /dev/null
+++ b/tools/sodium/index.html
@@ -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
index 0000000..44475a1
--- /dev/null
+++ b/tools/sodium/sodium.js
@@ -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
index 0000000..4f7d89e
--- /dev/null
+++ b/tools/sodium/styles.css
@@ -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;
+}
diff --git a/tools/test-push-to-trunk.sh b/tools/test-push-to-trunk.sh
new file mode 100755
index 0000000..6c201e4
--- /dev/null
+++ b/tools/test-push-to-trunk.sh
@@ -0,0 +1,246 @@
+#!/bin/bash
+# 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.
+
+# Tests the push-to-trunk.sh script. Needs to be run in V8 base dir:
+# ./tools/test-push-to-trunk.sh
+
+# TODO(machenbach): Check automatically if expectations match.
+# TODO(machenbach): Mock out version number retrieval.
+# TODO(machenbach): Allow multiple different test cases.
+# TODO(machenbach): Allow multi line mock output.
+# TODO(machenbach): Represent test expectations/mock output without an array
+# index increment.
+
+########## Stdin for push-to-trunk.sh
+
+# Confirm push to trunk commit ID
+INPUT[0]="Y"
+# Open editor
+INPUT[1]=""
+# Confirm increment version number
+INPUT[2]="Y"
+# Reviewer for V8 CL
+INPUT[3]="reviewer@chromium.org"
+# Enter LGTM for V8 CL
+INPUT[4]="LGTM"
+# Confirm checkout sanity
+INPUT[5]="Y"
+# Manually type in trunk revision
+INPUT[6]="12345"
+# Reviewer for Chromium CL
+INPUT[7]="reviewer@chromium.org"
+
+########## Expected commands and mock output
+
+EXP[0]="git status -s -uno"
+OUT[0]=""
+EXP[1]="git status -s -b -uno"
+OUT[1]="## some_branch"
+EXP[2]="git svn fetch"
+OUT[2]=""
+EXP[3]="git branch"
+OUT[3]="not the temp branch"
+EXP[4]="git checkout -b prepare-push-temporary-branch-created-by-script"
+OUT[4]=""
+EXP[5]="git branch"
+OUT[5]="not the branch"
+EXP[6]="git branch"
+OUT[6]="not the trunk branch"
+EXP[7]="git checkout -b prepare-push svn/bleeding_edge"
+OUT[7]=""
+EXP[8]="git log -1 --format=%H ChangeLog"
+OUT[8]="hash1"
+EXP[9]="git log -1 hash1"
+OUT[9]=""
+EXP[10]="git log hash1..HEAD --format=%H"
+OUT[10]="hash2"
+EXP[11]="git log -1 hash2 --format=\"%w(80,8,8)%s\""
+OUT[11]="Log line..."
+EXP[12]="git log -1 hash2 --format=\"%B\""
+OUT[12]="BUG=6789"
+EXP[13]="git log -1 hash2 --format=\"%w(80,8,8)(%an)\""
+OUT[13]="   (author@chromium.org)"
+EXP[14]="git commit -a -m \"Prepare push to trunk.  Now working on version 3.4.5.\""
+OUT[14]=""
+EXP[15]="git cl upload -r reviewer@chromium.org --send-mail"
+OUT[15]=""
+EXP[16]="git cl dcommit"
+OUT[16]=""
+EXP[17]="git svn fetch"
+OUT[17]=""
+EXP[18]="git checkout svn/bleeding_edge"
+OUT[18]=""
+EXP[19]="git log -1 --format=%H --grep=Prepare push to trunk.  Now working on version 3.4.5."
+OUT[19]="hash3"
+EXP[20]="git diff svn/trunk"
+OUT[20]="patch1"
+EXP[21]="git checkout -b trunk-push svn/trunk"
+OUT[21]=""
+EXP[22]="git apply --index --reject /tmp/v8-push-to-trunk-tempfile-patch"
+OUT[22]=""
+EXP[23]="git add src/version.cc"
+OUT[23]=""
+EXP[24]="git commit -F /tmp/v8-push-to-trunk-tempfile-commitmsg"
+OUT[24]=""
+EXP[25]="git svn dcommit"
+OUT[25]="r1234"
+EXP[26]="git svn tag 3.4.5 -m \"Tagging version 3.4.5\""
+OUT[26]=""
+EXP[27]="git status -s -uno"
+OUT[27]=""
+EXP[28]="git checkout master"
+OUT[28]=""
+EXP[29]="git pull"
+OUT[29]=""
+EXP[30]="git checkout -b v8-roll-12345"
+OUT[30]=""
+EXP[31]="git commit -am Update V8 to version 3.4.5."
+OUT[31]=""
+EXP[32]="git cl upload --send-mail"
+OUT[32]=""
+EXP[33]="git checkout -f some_branch"
+OUT[33]=""
+EXP[34]="git branch -D prepare-push-temporary-branch-created-by-script"
+OUT[34]=""
+EXP[35]="git branch -D prepare-push"
+OUT[35]=""
+EXP[36]="git branch -D trunk-push"
+OUT[36]=""
+
+########## Global temp files for test input/output
+
+export TEST_OUTPUT=$(mktemp)
+export INDEX=$(mktemp)
+export MOCK_OUTPUT=$(mktemp)
+export EXPECTED_COMMANDS=$(mktemp)
+
+########## Command index
+
+inc_index() {
+  local I="$(command cat $INDEX)"
+  let "I+=1"
+  echo "$I" > $INDEX
+  echo $I
+}
+
+echo "-1" > $INDEX
+export -f inc_index
+
+########## Mock output accessor
+
+get_mock_output() {
+  local I=$1
+  let "I+=1"
+  command sed "${I}q;d" $MOCK_OUTPUT
+}
+
+export -f get_mock_output
+
+for E in "${OUT[@]}"; do
+  echo $E
+done > $MOCK_OUTPUT
+
+########## Expected commands accessor
+
+get_expected_command() {
+  local I=$1
+  let "I+=1"
+  command sed "${I}q;d" $EXPECTED_COMMANDS
+}
+
+export -f get_expected_command
+
+for E in "${EXP[@]}"; do
+  echo $E
+done > $EXPECTED_COMMANDS
+
+########## Mock commands
+
+git() {
+  # All calls to git are mocked out. Expected calls and mock output are stored
+  # in the EXP/OUT arrays above.
+  local I=$(inc_index)
+  local OUT=$(get_mock_output $I)
+  local EXP=$(get_expected_command $I)
+  echo "#############################" >> $TEST_OUTPUT
+  echo "Com. Index:  $I" >> $TEST_OUTPUT
+  echo "Expected:    ${EXP}" >> $TEST_OUTPUT
+  echo "Actual:      git $@" >> $TEST_OUTPUT
+  echo "Mock Output: ${OUT}" >> $TEST_OUTPUT
+  echo "${OUT}"
+}
+
+mv() {
+  echo "#############################" >> $TEST_OUTPUT
+  echo "mv $@" >> $TEST_OUTPUT
+}
+
+sed() {
+  # Only calls to sed * -i * are mocked out.
+  echo "#############################" >> $TEST_OUTPUT
+  local arr=$@
+  if [[ "${arr[@]}" =~ "-i" || "${arr[${#arr[@]}-1]}" == "-i" ]]; then
+    echo "sed $@" >> $TEST_OUTPUT
+  else
+    echo "sed $@" >> $TEST_OUTPUT
+    command sed "$@"
+  fi
+}
+
+editor() {
+  echo "#############################" >> $TEST_OUTPUT
+  echo "editor $@" >> $TEST_OUTPUT
+}
+
+cd() {
+  echo "#############################" >> $TEST_OUTPUT
+  echo "cd $@" >> $TEST_OUTPUT
+}
+
+export -f git
+export -f mv
+export -f sed
+export -f cd
+export -f editor
+export EDITOR=editor
+
+########## Invoke script with test stdin
+
+for i in "${INPUT[@]}"; do 
+    echo $i
+done | tools/push-to-trunk.sh -c "path/to/chromium"
+
+echo "Collected output:"
+command cat $TEST_OUTPUT
+
+########## Clean up
+
+rm -rf $TEST_OUTPUT
+rm -rf $INDEX
+rm -rf $MOCK_OUTPUT
+rm -rf $EXPECTED_COMMANDS