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