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()) {
current_block_(NULL),
next_block_(NULL),
allocator_(allocator),
- position_(RelocInfo::kNoPosition),
instruction_pending_deoptimization_environment_(NULL),
pending_deoptimization_ast_id_(BailoutId::None()) { }
HBasicBlock* current_block_;
HBasicBlock* next_block_;
LAllocator* allocator_;
- int position_;
LInstruction* instruction_pending_deoptimization_environment_;
BailoutId pending_deoptimization_ast_id_;
HValue* value =
instructions_->at(code->instruction_index())->hydrogen_value();
- RecordAndWritePosition(value->position());
+ RecordAndWritePosition(
+ chunk()->graph()->SourcePositionToScriptPosition(value->position()));
Comment(";;; <@%d,#%d> "
"-------------------- Deferred %s --------------------",
translations_.CreateByteArray(isolate()->factory());
data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
+ data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
Handle<FixedArray> literals =
factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
function->debug_name()->ToCString().get(), tracing_scope.file());
}
PrintF(tracing_scope.file(), "--- Optimized code ---\n");
+ PrintF(tracing_scope.file(),
+ "optimization_id = %d\n", info->optimization_id());
} else {
PrintF(tracing_scope.file(), "--- Code ---\n");
}
script_(script),
osr_ast_id_(BailoutId::None()),
parameter_count_(0),
- this_has_uses_(true) {
+ this_has_uses_(true),
+ optimization_id_(-1) {
Initialize(script->GetIsolate(), BASE, zone);
}
script_(Handle<Script>(Script::cast(shared_info->script()))),
osr_ast_id_(BailoutId::None()),
parameter_count_(0),
- this_has_uses_(true) {
+ this_has_uses_(true),
+ optimization_id_(-1) {
Initialize(script_->GetIsolate(), BASE, zone);
}
context_(closure->context()),
osr_ast_id_(BailoutId::None()),
parameter_count_(0),
- this_has_uses_(true) {
+ this_has_uses_(true),
+ optimization_id_(-1) {
Initialize(script_->GetIsolate(), BASE, zone);
}
IsLazy::encode(true)),
osr_ast_id_(BailoutId::None()),
parameter_count_(0),
- this_has_uses_(true) {
+ this_has_uses_(true),
+ optimization_id_(-1) {
Initialize(isolate, STUB, zone);
code_stub_ = stub;
}
// Type-check the function.
AstTyper::Run(info());
- graph_builder_ = FLAG_emit_opt_code_positions
+ graph_builder_ = FLAG_hydrogen_track_positions
? new(info()->zone()) HOptimizedGraphBuilderWithPositions(info())
: new(info()->zone()) HOptimizedGraphBuilder(info());
SetMode(OPTIMIZE);
osr_ast_id_ = osr_ast_id;
unoptimized_code_ = unoptimized;
+ optimization_id_ = isolate()->NextOptimizationId();
}
void DisableOptimization();
return osr_ast_id_ == osr_ast_id && function.is_identical_to(closure_);
}
+ int optimization_id() const { return optimization_id_; }
+
protected:
CompilationInfo(Handle<Script> script,
Zone* zone);
Handle<Foreign> object_wrapper_;
+ int optimization_id_;
+
DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
};
LOG(isolate(), CodeDeoptEvent(compiled_code_));
}
ElapsedTimer timer;
+
+ // Determine basic deoptimization information. The optimized frame is
+ // described by the input data.
+ DeoptimizationInputData* input_data =
+ DeoptimizationInputData::cast(compiled_code_->deoptimization_data());
+
if (trace_scope_ != NULL) {
timer.Start();
PrintF(trace_scope_->file(),
reinterpret_cast<intptr_t>(function_));
PrintFunctionName();
PrintF(trace_scope_->file(),
- " @%d, FP to SP delta: %d]\n",
+ " (opt #%d) @%d, FP to SP delta: %d]\n",
+ input_data->OptimizationId()->value(),
bailout_id_,
fp_to_sp_delta_);
if (bailout_type_ == EAGER || bailout_type_ == SOFT) {
}
}
- // Determine basic deoptimization information. The optimized frame is
- // described by the input data.
- DeoptimizationInputData* input_data =
- DeoptimizationInputData::cast(compiled_code_->deoptimization_data());
BailoutId node_id = input_data->AstId(bailout_id_);
ByteArray* translations = input_data->TranslationByteArray();
unsigned translation_index =
DEFINE_string(redirect_code_traces_to, NULL,
"output deopt information and disassembly into the given file")
+DEFINE_bool(hydrogen_track_positions, false,
+ "track source code positions when building IR")
+
//
// Disassembler only flags
//
"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 "
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, hydrogen_track_positions)
DEFINE_implication(sodium, code_comments)
DEFINE_bool(print_all_code, false, "enable all flags related to printing code")
}
+void HSourcePosition::PrintTo(FILE* out) {
+ if (IsUnknown()) {
+ PrintF(out, "<?>");
+ } else {
+ if (FLAG_hydrogen_track_positions) {
+ PrintF(out, "<%d:%d>", inlining_id(), position());
+ } else {
+ PrintF(out, "<0:%d>", raw());
+ }
+ }
+}
+
+
void HInstruction::PrintTo(StringStream* stream) {
PrintMnemonicTo(stream);
PrintDataTo(stream);
next_ = next;
previous_ = prev;
SetBlock(next->block());
- if (position() == RelocInfo::kNoPosition &&
- next->position() != RelocInfo::kNoPosition) {
+ if (!has_position() && next->has_position()) {
set_position(next->position());
}
}
if (block->last() == previous) {
block->set_last(this);
}
- if (position() == RelocInfo::kNoPosition &&
- previous->position() != RelocInfo::kNoPosition) {
+ if (!has_position() && previous->has_position()) {
set_position(previous->position());
}
}
}
-int HPhi::position() const {
+HSourcePosition HPhi::position() const {
return block()->first()->position();
}
typedef EnumSet<GVNFlag, int32_t> GVNFlagSet;
+// This class encapsulates encoding and decoding of sources positions from
+// which hydrogen values originated.
+// When FLAG_track_hydrogen_positions is set this object encodes the
+// identifier of the inlining and absolute offset from the start of the
+// inlined function.
+// When the flag is not set we simply track absolute offset from the
+// script start.
+class HSourcePosition {
+ public:
+ HSourcePosition(const HSourcePosition& other) : value_(other.value_) { }
+
+ static HSourcePosition Unknown() {
+ return HSourcePosition(RelocInfo::kNoPosition);
+ }
+
+ bool IsUnknown() const { return value_ == RelocInfo::kNoPosition; }
+
+ int position() const { return PositionField::decode(value_); }
+ void set_position(int position) {
+ if (FLAG_hydrogen_track_positions) {
+ value_ = static_cast<int>(PositionField::update(value_, position));
+ } else {
+ value_ = position;
+ }
+ }
+
+ int inlining_id() const { return InliningIdField::decode(value_); }
+ void set_inlining_id(int inlining_id) {
+ if (FLAG_hydrogen_track_positions) {
+ value_ = static_cast<int>(InliningIdField::update(value_, inlining_id));
+ }
+ }
+
+ int raw() const { return value_; }
+
+ void PrintTo(FILE* f);
+
+ private:
+ typedef BitField<int, 0, 9> InliningIdField;
+
+ // Offset from the start of the inlined function.
+ typedef BitField<int, 9, 22> PositionField;
+
+ // On HPositionInfo can use this constructor.
+ explicit HSourcePosition(int value) : value_(value) { }
+
+ friend class HPositionInfo;
+
+ // If FLAG_hydrogen_track_positions is set contains bitfields InliningIdField
+ // and PositionField.
+ // Otherwise contains absolute offset from the script start.
+ int value_;
+};
+
+
class HValue : public ZoneObject {
public:
static const int kNoNumber = -1;
flags_(0) {}
virtual ~HValue() {}
- virtual int position() const { return RelocInfo::kNoPosition; }
- virtual int operand_position(int index) const { return position(); }
+ virtual HSourcePosition position() const {
+ return HSourcePosition::Unknown();
+ }
+ virtual HSourcePosition operand_position(int index) const {
+ return position();
+ }
HBasicBlock* block() const { return block_; }
void SetBlock(HBasicBlock* block);
// In the first case it contains intruction's position as a tagged value.
// In the second case it points to an array which contains instruction's
// position and operands' positions.
-// TODO(vegorov): what we really want to track here is a combination of
-// source position and a script id because cross script inlining can easily
-// result in optimized functions composed of several scripts.
class HPositionInfo {
public:
explicit HPositionInfo(int pos) : data_(TagPosition(pos)) { }
- int position() const {
+ HSourcePosition position() const {
if (has_operand_positions()) {
- return static_cast<int>(operand_positions()[kInstructionPosIndex]);
+ return operand_positions()[kInstructionPosIndex];
}
- return static_cast<int>(UntagPosition(data_));
+ return HSourcePosition(static_cast<int>(UntagPosition(data_)));
}
- void set_position(int pos) {
+ void set_position(HSourcePosition pos) {
if (has_operand_positions()) {
operand_positions()[kInstructionPosIndex] = pos;
} else {
- data_ = TagPosition(pos);
+ data_ = TagPosition(pos.raw());
}
}
}
const int length = kFirstOperandPosIndex + operand_count;
- intptr_t* positions =
- zone->NewArray<intptr_t>(length);
+ HSourcePosition* positions =
+ zone->NewArray<HSourcePosition>(length);
for (int i = 0; i < length; i++) {
- positions[i] = RelocInfo::kNoPosition;
+ positions[i] = HSourcePosition::Unknown();
}
- const int pos = position();
+ const HSourcePosition pos = position();
data_ = reinterpret_cast<intptr_t>(positions);
set_position(pos);
ASSERT(has_operand_positions());
}
- int operand_position(int idx) const {
+ HSourcePosition operand_position(int idx) const {
if (!has_operand_positions()) {
return position();
}
- return static_cast<int>(*operand_position_slot(idx));
+ return *operand_position_slot(idx);
}
- void set_operand_position(int idx, int pos) {
+ void set_operand_position(int idx, HSourcePosition pos) {
*operand_position_slot(idx) = pos;
}
static const intptr_t kInstructionPosIndex = 0;
static const intptr_t kFirstOperandPosIndex = 1;
- intptr_t* operand_position_slot(int idx) const {
+ HSourcePosition* operand_position_slot(int idx) const {
ASSERT(has_operand_positions());
return &(operand_positions()[kFirstOperandPosIndex + idx]);
}
return !IsTaggedPosition(data_);
}
- intptr_t* operand_positions() const {
+ HSourcePosition* operand_positions() const {
ASSERT(has_operand_positions());
- return reinterpret_cast<intptr_t*>(data_);
+ return reinterpret_cast<HSourcePosition*>(data_);
}
static const intptr_t kPositionTag = 1;
}
// The position is a write-once variable.
- virtual int position() const V8_OVERRIDE {
- return position_.position();
+ virtual HSourcePosition position() const V8_OVERRIDE {
+ return HSourcePosition(position_.position());
}
bool has_position() const {
- return position_.position() != RelocInfo::kNoPosition;
+ return !position().IsUnknown();
}
- void set_position(int position) {
+ void set_position(HSourcePosition position) {
ASSERT(!has_position());
- ASSERT(position != RelocInfo::kNoPosition);
+ ASSERT(!position.IsUnknown());
position_.set_position(position);
}
- virtual int operand_position(int index) const V8_OVERRIDE {
- const int pos = position_.operand_position(index);
- return (pos != RelocInfo::kNoPosition) ? pos : position();
+ virtual HSourcePosition operand_position(int index) const V8_OVERRIDE {
+ const HSourcePosition pos = position_.operand_position(index);
+ return pos.IsUnknown() ? position() : pos;
}
- void set_operand_position(Zone* zone, int index, int pos) {
+ void set_operand_position(Zone* zone, int index, HSourcePosition pos) {
ASSERT(0 <= index && index < OperandCount());
position_.ensure_storage_for_operand_positions(zone, OperandCount());
position_.set_operand_position(index, pos);
bool IsReceiver() const { return merged_index_ == 0; }
bool HasMergedIndex() const { return merged_index_ != kInvalidMergedIndex; }
- virtual int position() const V8_OVERRIDE;
+ virtual HSourcePosition position() const V8_OVERRIDE;
int merged_index() const { return merged_index_; }
return representation();
}
- void SetOperandPositions(Zone* zone, int left_pos, int right_pos) {
+ void SetOperandPositions(Zone* zone,
+ HSourcePosition left_pos,
+ HSourcePosition right_pos) {
set_operand_position(zone, 1, left_pos);
set_operand_position(zone, 2, right_pos);
}
}
virtual void PrintDataTo(StringStream* stream) V8_OVERRIDE;
- void SetOperandPositions(Zone* zone, int left_pos, int right_pos) {
+ void SetOperandPositions(Zone* zone,
+ HSourcePosition left_pos,
+ HSourcePosition right_pos) {
set_operand_position(zone, 0, left_pos);
set_operand_position(zone, 1, right_pos);
}
if (new_value == NULL) {
new_value = new(graph()->zone()) HChange(
value, to, is_truncating_to_smi, is_truncating_to_int);
- if (use_value->operand_position(use_index) != RelocInfo::kNoPosition) {
+ if (!use_value->operand_position(use_index).IsUnknown()) {
new_value->set_position(use_value->operand_position(use_index));
} else {
- ASSERT(!FLAG_emit_opt_code_positions || !graph()->info()->IsOptimizing());
+ ASSERT(!FLAG_hydrogen_track_positions ||
+ !graph()->info()->IsOptimizing());
}
}
}
-void HBasicBlock::AddInstruction(HInstruction* instr, int position) {
+void HBasicBlock::AddInstruction(HInstruction* instr,
+ HSourcePosition position) {
ASSERT(!IsStartBlock() || !IsFinished());
ASSERT(!instr->IsLinked());
ASSERT(!IsFinished());
- if (position != RelocInfo::kNoPosition) {
+ if (!position.IsUnknown()) {
instr->set_position(position);
}
if (first_ == NULL) {
ASSERT(!last_environment()->ast_id().IsNone());
HBlockEntry* entry = new(zone()) HBlockEntry();
entry->InitializeAsFirst(this);
- if (position != RelocInfo::kNoPosition) {
+ if (!position.IsUnknown()) {
entry->set_position(position);
} else {
- ASSERT(!FLAG_emit_opt_code_positions ||
+ ASSERT(!FLAG_hydrogen_track_positions ||
!graph()->info()->IsOptimizing());
}
first_ = last_ = entry;
}
-void HBasicBlock::Finish(HControlInstruction* end, int position) {
+void HBasicBlock::Finish(HControlInstruction* end, HSourcePosition position) {
ASSERT(!IsFinished());
AddInstruction(end, position);
end_ = end;
void HBasicBlock::Goto(HBasicBlock* block,
- int position,
+ HSourcePosition position,
FunctionState* state,
bool add_simulate) {
bool drop_extra = state != NULL &&
void HBasicBlock::AddLeaveInlined(HValue* return_value,
FunctionState* state,
- int position) {
+ HSourcePosition position) {
HBasicBlock* target = state->function_return();
bool drop_extra = state->inlining_kind() == NORMAL_RETURN;
while (current != NULL) {
if (current->deopt_ && current->block_ != NULL) {
current->block_->FinishExit(
- HAbnormalExit::New(builder_->zone(), NULL), RelocInfo::kNoPosition);
+ HAbnormalExit::New(builder_->zone(), NULL),
+ HSourcePosition::Unknown());
}
current = current->next_;
}
HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) {
ASSERT(current_block() != NULL);
- ASSERT(!FLAG_emit_opt_code_positions ||
- position_ != RelocInfo::kNoPosition || !info_->IsOptimizing());
- current_block()->AddInstruction(instr, position_);
+ ASSERT(!FLAG_hydrogen_track_positions ||
+ !position_.IsUnknown() ||
+ !info_->IsOptimizing());
+ current_block()->AddInstruction(instr, source_position());
if (graph()->IsInsideNoSideEffectsScope()) {
instr->SetFlag(HValue::kHasNoObservableSideEffects);
}
void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) {
- ASSERT(!FLAG_emit_opt_code_positions || !info_->IsOptimizing() ||
- position_ != RelocInfo::kNoPosition);
- current_block()->Finish(last, position_);
+ ASSERT(!FLAG_hydrogen_track_positions ||
+ !info_->IsOptimizing() ||
+ !position_.IsUnknown());
+ current_block()->Finish(last, source_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_);
+ ASSERT(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() ||
+ !position_.IsUnknown());
+ current_block()->FinishExit(instruction, source_position());
if (instruction->IsReturn() || instruction->IsAbnormalExit()) {
set_current_block(NULL);
}
RemovableSimulate removable) {
ASSERT(current_block() != NULL);
ASSERT(!graph()->IsInsideNoSideEffectsScope());
- current_block()->AddNewSimulate(id, position_, removable);
+ current_block()->AddNewSimulate(id, source_position(), removable);
}
HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info)
: HGraphBuilder(info),
function_state_(NULL),
- initial_function_state_(this, info, NORMAL_RETURN),
+ initial_function_state_(this, info, NORMAL_RETURN, 0),
ast_context_(NULL),
break_scope_(NULL),
inlined_count_(0),
// to know it's the initial state.
function_state_= &initial_function_state_;
InitializeAstVisitor(info->zone());
- if (FLAG_emit_opt_code_positions) {
+ if (FLAG_hydrogen_track_positions) {
SetSourcePosition(info->shared_info()->start_position());
}
}
}
-void HBasicBlock::FinishExit(HControlInstruction* instruction, int position) {
+void HBasicBlock::FinishExit(HControlInstruction* instruction,
+ HSourcePosition position) {
Finish(instruction, position);
ClearEnvironment();
}
type_change_checksum_(0),
maximum_environment_size_(0),
no_side_effects_scope_count_(0),
- disallow_adding_new_values_(false) {
+ disallow_adding_new_values_(false),
+ next_inline_id_(0),
+ inlined_functions_(5, info->zone()) {
if (info->IsStub()) {
HydrogenCodeStub* stub = info->code_stub();
CodeStubInterfaceDescriptor* descriptor =
start_environment_ =
new(zone_) HEnvironment(zone_, descriptor->environment_length());
} else {
+ TraceInlinedFunction(info->shared_info(), HSourcePosition::Unknown());
start_environment_ =
new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_);
}
}
+int HGraph::TraceInlinedFunction(
+ Handle<SharedFunctionInfo> shared,
+ HSourcePosition position) {
+ if (!FLAG_hydrogen_track_positions) {
+ return 0;
+ }
+
+ int id = 0;
+ for (; id < inlined_functions_.length(); id++) {
+ if (inlined_functions_[id].shared().is_identical_to(shared)) {
+ break;
+ }
+ }
+
+ if (id == inlined_functions_.length()) {
+ inlined_functions_.Add(InlinedFunctionInfo(shared), zone());
+
+ if (!shared->script()->IsUndefined()) {
+ Handle<Script> script(Script::cast(shared->script()));
+ if (!script->source()->IsUndefined()) {
+ CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
+ PrintF(tracing_scope.file(),
+ "--- FUNCTION SOURCE (%s) id{%d,%d} ---\n",
+ shared->DebugName()->ToCString().get(),
+ info()->optimization_id(),
+ id);
+
+ {
+ ConsStringIteratorOp op;
+ StringCharacterStream stream(String::cast(script->source()),
+ &op,
+ shared->start_position());
+ // fun->end_position() points to the last character in the stream. We
+ // need to compensate by adding one to calculate the length.
+ int source_len =
+ shared->end_position() - shared->start_position() + 1;
+ for (int i = 0; i < source_len; i++) {
+ if (stream.HasMore()) {
+ PrintF(tracing_scope.file(), "%c", stream.GetNext());
+ }
+ }
+ }
+
+ PrintF(tracing_scope.file(), "\n--- END ---\n");
+ }
+ }
+ }
+
+ int inline_id = next_inline_id_++;
+
+ if (inline_id != 0) {
+ CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer());
+ PrintF(tracing_scope.file(), "INLINE (%s) id{%d,%d} AS %d AT ",
+ shared->DebugName()->ToCString().get(),
+ info()->optimization_id(),
+ id,
+ inline_id);
+ position.PrintTo(tracing_scope.file());
+ PrintF(tracing_scope.file(), "\n");
+ }
+
+ return inline_id;
+}
+
+
+int HGraph::SourcePositionToScriptPosition(HSourcePosition pos) {
+ if (!FLAG_hydrogen_track_positions || pos.IsUnknown()) {
+ return pos.raw();
+ }
+
+ return inlined_functions_[pos.inlining_id()].start_position() +
+ pos.position();
+}
+
+
// Block ordering was implemented with two mutually recursive methods,
// HGraph::Postorder and HGraph::PostorderLoopBlocks.
// The recursion could lead to stack overflow so the algorithm has been
// a (possibly inlined) function.
FunctionState::FunctionState(HOptimizedGraphBuilder* owner,
CompilationInfo* info,
- InliningKind inlining_kind)
+ InliningKind inlining_kind,
+ int inlining_id)
: owner_(owner),
compilation_info_(info),
call_context_(NULL),
entry_(NULL),
arguments_object_(NULL),
arguments_elements_(NULL),
+ inlining_id_(inlining_id),
+ outer_source_position_(HSourcePosition::Unknown()),
outer_(owner->function_state()) {
if (outer_ != NULL) {
// State for an inline function.
// Push on the state stack.
owner->set_function_state(this);
+
+ if (FLAG_hydrogen_track_positions) {
+ outer_source_position_ = owner->source_position();
+ owner->EnterInlinedSource(
+ info->shared_info()->start_position(),
+ inlining_id);
+ owner->SetSourcePosition(info->shared_info()->start_position());
+ }
}
FunctionState::~FunctionState() {
delete test_context_;
owner_->set_function_state(outer_);
+
+ if (FLAG_hydrogen_track_positions) {
+ owner_->set_source_position(outer_source_position_);
+ owner_->EnterInlinedSource(
+ outer_->compilation_info()->shared_info()->start_position(),
+ outer_->inlining_id());
+ }
}
Type* combined_type = clause->compare_type();
HControlInstruction* compare = BuildCompareInstruction(
Token::EQ_STRICT, tag_value, label_value, tag_type, label_type,
- combined_type, stmt->tag()->position(), clause->label()->position(),
+ combined_type,
+ ScriptPositionToSourcePosition(stmt->tag()->position()),
+ ScriptPositionToSourcePosition(clause->label()->position()),
clause->id());
HBasicBlock* next_test_block = graph()->CreateBasicBlock();
CHECK_ALIVE(VisitForValue(expr->exception()));
HValue* value = environment()->Pop();
- if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
+ if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
Add<HPushArgument>(value);
Add<HCallRuntime>(isolate()->factory()->empty_string(),
Runtime::FunctionForId(Runtime::kThrow), 1);
HValue* implicit_return_value,
BailoutId ast_id,
BailoutId return_id,
- InliningKind inlining_kind) {
+ InliningKind inlining_kind,
+ HSourcePosition position) {
int nodes_added = InliningAstSize(target);
if (nodes_added == kNotInlinable) return false;
ASSERT(target_shared->has_deoptimization_support());
AstTyper::Run(&target_info);
+ int function_id = graph()->TraceInlinedFunction(target_shared, position);
+
// Save the pending call context. Set up new one for the inlined function.
// The function state is new-allocated because we need to delete it
// in two different places.
FunctionState* target_state = new FunctionState(
- this, &target_info, inlining_kind);
+ this, &target_info, inlining_kind, function_id);
HConstant* undefined = graph()->GetConstantUndefined();
NULL,
expr->id(),
expr->ReturnId(),
- NORMAL_RETURN);
+ NORMAL_RETURN,
+ ScriptPositionToSourcePosition(expr->position()));
}
implicit_return_value,
expr->id(),
expr->ReturnId(),
- CONSTRUCT_CALL_RETURN);
+ CONSTRUCT_CALL_RETURN,
+ ScriptPositionToSourcePosition(expr->position()));
}
NULL,
ast_id,
return_id,
- GETTER_CALL_RETURN);
+ GETTER_CALL_RETURN,
+ source_position());
}
1,
implicit_return_value,
id, assignment_id,
- SETTER_CALL_RETURN);
+ SETTER_CALL_RETURN,
+ source_position());
}
NULL,
expr->id(),
expr->ReturnId(),
- NORMAL_RETURN);
+ NORMAL_RETURN,
+ ScriptPositionToSourcePosition(expr->position()));
}
CHECK_ALIVE(PushLoad(prop, receiver, key));
HValue* function = Pop();
+ if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
+
// Push the function under the receiver.
environment()->SetExpressionStackAt(0, function);
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
+ if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
int argument_count = expr->arguments()->length() + 1; // Plus constructor.
Factory* factory = isolate()->factory();
ASSERT(!HasStackOverflow());
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
+ if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
Expression* target = expr->expression();
VariableProxy* proxy = target->AsVariableProxy();
Property* prop = target->AsProperty();
BuildBinaryOperation(expr, left, right,
ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE
: PUSH_BEFORE_SIMULATE);
- if (FLAG_emit_opt_code_positions && result->IsBinaryOperation()) {
+ if (FLAG_hydrogen_track_positions && result->IsBinaryOperation()) {
HBinaryOperation::cast(result)->SetOperandPositions(
- zone(), expr->left()->position(), expr->right()->position());
+ zone(),
+ ScriptPositionToSourcePosition(expr->left()->position()),
+ ScriptPositionToSourcePosition(expr->right()->position()));
}
return ast_context()->ReturnValue(result);
}
ASSERT(current_block() != NULL);
ASSERT(current_block()->HasPredecessor());
- if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
+ if (!FLAG_hydrogen_track_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
CHECK_ALIVE(VisitForValue(expr->left()));
CHECK_ALIVE(VisitForValue(expr->right()));
- if (FLAG_emit_opt_code_positions) SetSourcePosition(expr->position());
+ if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
HValue* right = Pop();
HValue* left = Pop();
HControlInstruction* compare = BuildCompareInstruction(
op, left, right, left_type, right_type, combined_type,
- expr->left()->position(), expr->right()->position(), expr->id());
+ ScriptPositionToSourcePosition(expr->left()->position()),
+ ScriptPositionToSourcePosition(expr->right()->position()),
+ expr->id());
if (compare == NULL) return; // Bailed out.
return ast_context()->ReturnControl(compare, expr->id());
}
Type* left_type,
Type* right_type,
Type* combined_type,
- int left_position,
- int right_position,
+ HSourcePosition left_position,
+ HSourcePosition right_position,
BailoutId bailout_id) {
// Cases handled below depend on collected type feedback. They should
// soft deoptimize when there is no type feedback.
AddCheckMap(operand_to_check, map);
HCompareObjectEqAndBranch* result =
New<HCompareObjectEqAndBranch>(left, right);
- if (FLAG_emit_opt_code_positions) {
+ if (FLAG_hydrogen_track_positions) {
result->set_operand_position(zone(), 0, left_position);
result->set_operand_position(zone(), 1, right_position);
}
HCompareNumericAndBranch* result =
New<HCompareNumericAndBranch>(left, right, op);
result->set_observed_input_representation(left_rep, right_rep);
- if (FLAG_emit_opt_code_positions) {
+ if (FLAG_hydrogen_track_positions) {
result->SetOperandPositions(zone(), left_position, right_position);
}
return result;
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());
+ if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position());
CHECK_ALIVE(VisitForValue(sub_expr));
HValue* value = Pop();
if (expr->op() == Token::EQ_STRICT) {
if (info->IsOptimizing()) {
Handle<String> name = info->function()->debug_name();
PrintStringProperty("name", name->ToCString().get());
- PrintStringProperty("method", name->ToCString().get());
+ PrintIndent();
+ trace_.Add("method \"%s:%d\"\n",
+ name->ToCString().get(),
+ info->optimization_id());
} else {
CodeStub::Major major_key = info->code_stub()->MajorKey();
PrintStringProperty("name", CodeStub::MajorName(major_key, false));
Tag HIR_tag(this, "HIR");
for (HInstructionIterator it(current); !it.Done(); it.Advance()) {
HInstruction* instruction = it.Current();
- int bci = FLAG_emit_opt_code_positions && instruction->has_position() ?
- instruction->position() : 0;
int uses = instruction->UseCount();
PrintIndent();
- trace_.Add("%d %d ", bci, uses);
+ trace_.Add("0 %d ", uses);
instruction->PrintNameTo(&trace_);
trace_.Add(" ");
instruction->PrintTo(&trace_);
+ if (FLAG_hydrogen_track_positions &&
+ instruction->has_position() &&
+ instruction->position().raw() != 0) {
+ const HSourcePosition pos = instruction->position();
+ trace_.Add(" pos:");
+ if (pos.inlining_id() != 0) {
+ trace_.Add("%d_", pos.inlining_id());
+ }
+ trace_.Add("%d", pos.position());
+ }
trace_.Add(" <|@\n");
}
}
bool IsFinished() const { return end_ != NULL; }
void AddPhi(HPhi* phi);
void RemovePhi(HPhi* phi);
- void AddInstruction(HInstruction* instr, int position);
+ void AddInstruction(HInstruction* instr, HSourcePosition position);
bool Dominates(HBasicBlock* other) const;
bool EqualToOrDominates(HBasicBlock* other) const;
int LoopNestingDepth() const;
int PredecessorIndexOf(HBasicBlock* predecessor) const;
HPhi* AddNewPhi(int merged_index);
HSimulate* AddNewSimulate(BailoutId ast_id,
- int position,
+ HSourcePosition position,
RemovableSimulate removable = FIXED_SIMULATE) {
HSimulate* instr = CreateSimulate(ast_id, removable);
AddInstruction(instr, position);
friend class HGraphBuilder;
HSimulate* CreateSimulate(BailoutId ast_id, RemovableSimulate removable);
- void Finish(HControlInstruction* last, int position);
- void FinishExit(HControlInstruction* instruction, int position);
+ void Finish(HControlInstruction* last, HSourcePosition position);
+ void FinishExit(HControlInstruction* instruction, HSourcePosition position);
void Goto(HBasicBlock* block,
- int position,
+ HSourcePosition position,
FunctionState* state = NULL,
bool add_simulate = true);
- void GotoNoSimulate(HBasicBlock* block, int position) {
+ void GotoNoSimulate(HBasicBlock* block, HSourcePosition position) {
Goto(block, position, NULL, false);
}
// instruction and updating the bailout environment.
void AddLeaveInlined(HValue* return_value,
FunctionState* state,
- int position);
+ HSourcePosition position);
private:
void RegisterPredecessor(HBasicBlock* pred);
void DecrementInNoSideEffectsScope() { no_side_effects_scope_count_--; }
bool IsInsideNoSideEffectsScope() { return no_side_effects_scope_count_ > 0; }
+ // If we are tracking source positions then this function assigns a unique
+ // identifier to each inlining and dumps function source if it was inlined
+ // for the first time during the current optimization.
+ int TraceInlinedFunction(Handle<SharedFunctionInfo> shared,
+ HSourcePosition position);
+
+ // Converts given HSourcePosition to the absolute offset from the start of
+ // the corresponding script.
+ int SourcePositionToScriptPosition(HSourcePosition position);
+
private:
HConstant* ReinsertConstantIfNecessary(HConstant* constant);
HConstant* GetConstant(SetOncePointer<HConstant>* pointer,
int no_side_effects_scope_count_;
bool disallow_adding_new_values_;
+ class InlinedFunctionInfo {
+ public:
+ explicit InlinedFunctionInfo(Handle<SharedFunctionInfo> shared)
+ : shared_(shared), start_position_(shared->start_position()) {
+ }
+
+ Handle<SharedFunctionInfo> shared() const { return shared_; }
+ int start_position() const { return start_position_; }
+
+ private:
+ Handle<SharedFunctionInfo> shared_;
+ int start_position_;
+ };
+
+ int next_inline_id_;
+ ZoneList<InlinedFunctionInfo> inlined_functions_;
+
DISALLOW_COPY_AND_ASSIGN(HGraph);
};
public:
FunctionState(HOptimizedGraphBuilder* owner,
CompilationInfo* info,
- InliningKind inlining_kind);
+ InliningKind inlining_kind,
+ int inlining_id);
~FunctionState();
CompilationInfo* compilation_info() { return compilation_info_; }
bool arguments_pushed() { return arguments_elements() != NULL; }
+ int inlining_id() const { return inlining_id_; }
+
private:
HOptimizedGraphBuilder* owner_;
HArgumentsObject* arguments_object_;
HArgumentsElements* arguments_elements_;
+ int inlining_id_;
+ HSourcePosition outer_source_position_;
+
FunctionState* outer_;
};
: info_(info),
graph_(NULL),
current_block_(NULL),
- position_(RelocInfo::kNoPosition) {}
+ position_(HSourcePosition::Unknown()),
+ start_position_(0) {}
virtual ~HGraphBuilder() {}
HBasicBlock* current_block() const { return current_block_; }
HBasicBlock* target,
FunctionState* state = NULL,
bool add_simulate = true) {
- from->Goto(target, position_, state, add_simulate);
+ from->Goto(target, source_position(), state, add_simulate);
}
void Goto(HBasicBlock* target,
FunctionState* state = NULL,
void AddLeaveInlined(HBasicBlock* block,
HValue* return_value,
FunctionState* state) {
- block->AddLeaveInlined(return_value, state, position_);
+ block->AddLeaveInlined(return_value, state, source_position());
}
void AddLeaveInlined(HValue* return_value, FunctionState* state) {
return AddLeaveInlined(current_block(), return_value, state);
void AddSimulate(BailoutId id, RemovableSimulate removable = FIXED_SIMULATE);
- int position() const { return position_; }
-
protected:
virtual bool BuildGraph() = 0;
protected:
void SetSourcePosition(int position) {
ASSERT(position != RelocInfo::kNoPosition);
+ position_.set_position(position - start_position_);
+ }
+
+ void EnterInlinedSource(int start_position, int id) {
+ if (FLAG_hydrogen_track_positions) {
+ start_position_ = start_position;
+ position_.set_inlining_id(id);
+ }
+ }
+
+ // Convert the given absolute offset from the start of the script to
+ // the HSourcePosition assuming that this position corresponds to the
+ // same function as current position_.
+ HSourcePosition ScriptPositionToSourcePosition(int position) {
+ HSourcePosition pos = position_;
+ pos.set_position(position - start_position_);
+ return pos;
+ }
+
+ HSourcePosition source_position() { return position_; }
+ void set_source_position(HSourcePosition position) {
position_ = position;
}
CompilationInfo* info_;
HGraph* graph_;
HBasicBlock* current_block_;
- int position_;
+ HSourcePosition position_;
+ int start_position_;
};
HValue* implicit_return_value,
BailoutId ast_id,
BailoutId return_id,
- InliningKind inlining_kind);
+ InliningKind inlining_kind,
+ HSourcePosition position);
bool TryInlineCall(Call* expr);
bool TryInlineConstruct(CallNew* expr, HValue* implicit_return_value);
Type* left_type,
Type* right_type,
Type* combined_type,
- int left_position,
- int right_position,
+ HSourcePosition left_position,
+ HSourcePosition right_position,
BailoutId bailout_id);
HInstruction* BuildStringCharCodeAt(HValue* string,
HValue* value =
instructions_->at(code->instruction_index())->hydrogen_value();
- RecordAndWritePosition(value->position());
+ RecordAndWritePosition(
+ chunk()->graph()->SourcePositionToScriptPosition(value->position()));
Comment(";;; <@%d,#%d> "
"-------------------- Deferred %s --------------------",
translations_.CreateByteArray(isolate()->factory());
data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
+ data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
Handle<FixedArray> literals =
factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
sweeper_thread_(NULL),
num_sweeper_threads_(0),
max_available_threads_(0),
- stress_deopt_count_(0) {
+ stress_deopt_count_(0),
+ next_optimization_id_(0) {
id_ = NoBarrier_AtomicIncrement(&isolate_counter_, 1);
TRACE_ISOLATE(constructor);
// Given an address occupied by a live code object, return that object.
Object* FindCodeObject(Address a);
+ int NextOptimizationId() {
+ int id = next_optimization_id_++;
+ if (!Smi::IsValid(next_optimization_id_)) {
+ next_optimization_id_ = 0;
+ }
+ return id;
+ }
+
private:
Isolate();
// Counts deopt points if deopt_every_n_times is enabled.
unsigned int stress_deopt_count_;
+ int next_optimization_id_;
+
friend class ExecutionAccess;
friend class HandleScopeImplementer;
friend class IsolateInitializer;
GenerateBodyInstructionPre(instr);
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());
+ if (!value->position().IsUnknown()) {
+ RecordAndWritePosition(
+ chunk()->graph()->SourcePositionToScriptPosition(value->position()));
}
instr->CompileToNative(codegen);
HValue* value =
instructions_->at(code->instruction_index())->hydrogen_value();
- RecordAndWritePosition(value->position());
+ RecordAndWritePosition(
+ chunk()->graph()->SourcePositionToScriptPosition(value->position()));
Comment(";;; <@%d,#%d> "
"-------------------- Deferred %s --------------------",
translations_.CreateByteArray(isolate()->factory());
data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
+ data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
Handle<FixedArray> literals =
factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);
static const int kLiteralArrayIndex = 2;
static const int kOsrAstIdIndex = 3;
static const int kOsrPcOffsetIndex = 4;
- static const int kFirstDeoptEntryIndex = 5;
+ static const int kOptimizationIdIndex = 5;
+ static const int kFirstDeoptEntryIndex = 6;
// Offsets of deopt entry elements relative to the start of the entry.
static const int kAstIdRawOffset = 0;
DEFINE_ELEMENT_ACCESSORS(LiteralArray, FixedArray)
DEFINE_ELEMENT_ACCESSORS(OsrAstId, Smi)
DEFINE_ELEMENT_ACCESSORS(OsrPcOffset, Smi)
+ DEFINE_ELEMENT_ACCESSORS(OptimizationId, Smi)
#undef DEFINE_ELEMENT_ACCESSORS
HValue* value =
instructions_->at(code->instruction_index())->hydrogen_value();
- RecordAndWritePosition(value->position());
+ RecordAndWritePosition(
+ chunk()->graph()->SourcePositionToScriptPosition(value->position()));
Comment(";;; <@%d,#%d> "
"-------------------- Deferred %s --------------------",
translations_.CreateByteArray(isolate()->factory());
data->SetTranslationByteArray(*translations);
data->SetInlinedFunctionCount(Smi::FromInt(inlined_function_count_));
+ data->SetOptimizationId(Smi::FromInt(info_->optimization_id()));
Handle<FixedArray> literals =
factory()->NewFixedArray(deoptimization_literals_.length(), TENURED);