34 bool HEscapeAnalysisPhase::HasNoEscapingUses(HValue* value,
int size) {
35 for (HUseIterator it(value->uses()); !it.Done(); it.Advance()) {
36 HValue* use = it.value();
37 if (use->HasEscapingOperandAt(it.index())) {
38 if (FLAG_trace_escape_analysis) {
39 PrintF(
"#%d (%s) escapes through #%d (%s) @%d\n", value->id(),
40 value->Mnemonic(), use->id(), use->Mnemonic(), it.index());
44 if (use->HasOutOfBoundsAccess(size)) {
45 if (FLAG_trace_escape_analysis) {
46 PrintF(
"#%d (%s) out of bounds at #%d (%s) @%d\n", value->id(),
47 value->Mnemonic(), use->id(), use->Mnemonic(), it.index());
51 int redefined_index = use->RedefinedOperandIndex();
52 if (redefined_index == it.index() && !HasNoEscapingUses(use, size)) {
53 if (FLAG_trace_escape_analysis) {
54 PrintF(
"#%d (%s) escapes redefinition #%d (%s) @%d\n", value->id(),
55 value->Mnemonic(), use->id(), use->Mnemonic(), it.index());
64 void HEscapeAnalysisPhase::CollectCapturedValues() {
65 int block_count =
graph()->blocks()->length();
66 for (
int i = 0; i < block_count; ++i) {
67 HBasicBlock* block =
graph()->blocks()->at(i);
68 for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
69 HInstruction* instr = it.Current();
70 if (!instr->IsAllocate())
continue;
71 HAllocate* allocate = HAllocate::cast(instr);
72 if (!allocate->size()->IsInteger32Constant())
continue;
73 int size_in_bytes = allocate->size()->GetInteger32Constant();
74 if (HasNoEscapingUses(instr, size_in_bytes)) {
75 if (FLAG_trace_escape_analysis) {
76 PrintF(
"#%d (%s) is being captured\n", instr->id(),
79 captured_.Add(instr, zone());
86 HCapturedObject* HEscapeAnalysisPhase::NewState(HInstruction* previous) {
87 Zone* zone =
graph()->zone();
88 HCapturedObject* state =
89 new(zone) HCapturedObject(number_of_values_, number_of_objects_, zone);
90 state->InsertAfter(previous);
96 HCapturedObject* HEscapeAnalysisPhase::NewStateForAllocation(
97 HInstruction* previous) {
98 HConstant* undefined =
graph()->GetConstantUndefined();
99 HCapturedObject* state = NewState(previous);
100 for (
int index = 0; index < number_of_values_; index++) {
101 state->SetOperandAt(index, undefined);
108 HCapturedObject* HEscapeAnalysisPhase::NewStateForLoopHeader(
109 HInstruction* previous,
110 HCapturedObject* old_state) {
111 HBasicBlock* block = previous->block();
112 HCapturedObject* state = NewState(previous);
113 for (
int index = 0; index < number_of_values_; index++) {
114 HValue* operand = old_state->OperandAt(index);
115 HPhi* phi = NewPhiAndInsert(block, operand, index);
116 state->SetOperandAt(index, phi);
123 HCapturedObject* HEscapeAnalysisPhase::NewStateCopy(
124 HInstruction* previous,
125 HCapturedObject* old_state) {
126 HCapturedObject* state = NewState(previous);
127 for (
int index = 0; index < number_of_values_; index++) {
128 HValue* operand = old_state->OperandAt(index);
129 state->SetOperandAt(index, operand);
137 HPhi* HEscapeAnalysisPhase::NewPhiAndInsert(HBasicBlock* block,
138 HValue* incoming_value,
140 Zone* zone =
graph()->zone();
141 HPhi* phi =
new(zone) HPhi(HPhi::kInvalidMergedIndex, zone);
142 for (
int i = 0; i < block->predecessors()->length(); i++) {
143 phi->AddInput(incoming_value);
151 HValue* HEscapeAnalysisPhase::NewMapCheckAndInsert(HCapturedObject* state,
152 HCheckMaps* mapcheck) {
153 Zone* zone =
graph()->zone();
154 HValue* value = state->map_value();
157 HCheckValue*
check = HCheckValue::New(
158 zone,
NULL, value, mapcheck->first_map(),
false);
159 check->InsertBefore(mapcheck);
168 void HEscapeAnalysisPhase::AnalyzeDataFlow(HInstruction* allocate) {
169 HBasicBlock* allocate_block = allocate->block();
174 int start = allocate_block->block_id();
175 for (
int i = start; i <
graph()->blocks()->length(); i++) {
176 HBasicBlock* block =
graph()->blocks()->at(i);
177 HCapturedObject* state = StateAt(block);
180 if (!allocate_block->Dominates(block) && allocate_block != block)
continue;
181 if (FLAG_trace_escape_analysis) {
182 PrintF(
"Analyzing data-flow in B%d\n", block->block_id());
186 for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
187 HInstruction* instr = it.Current();
188 switch (instr->opcode()) {
189 case HValue::kAllocate: {
190 if (instr != allocate)
continue;
191 state = NewStateForAllocation(allocate);
194 case HValue::kLoadNamedField: {
195 HLoadNamedField* load = HLoadNamedField::cast(instr);
197 if (load->object() != allocate)
continue;
198 ASSERT(load->access().IsInobject());
199 HValue* replacement = state->OperandAt(index);
200 load->DeleteAndReplaceWith(replacement);
201 if (FLAG_trace_escape_analysis) {
202 PrintF(
"Replacing load #%d with #%d (%s)\n", instr->id(),
203 replacement->id(), replacement->Mnemonic());
207 case HValue::kStoreNamedField: {
208 HStoreNamedField* store = HStoreNamedField::cast(instr);
210 if (store->object() != allocate)
continue;
211 ASSERT(store->access().IsInobject());
212 state = NewStateCopy(store->previous(), state);
213 state->SetOperandAt(index, store->value());
214 if (store->has_transition()) {
215 state->SetOperandAt(0, store->transition());
217 if (store->HasObservableSideEffects()) {
218 state->ReuseSideEffectsFromStore(store);
220 store->DeleteAndReplaceWith(store->ActualValue());
221 if (FLAG_trace_escape_analysis) {
222 PrintF(
"Replacing store #%d%s\n", instr->id(),
223 store->has_transition() ?
" (with transition)" :
"");
227 case HValue::kArgumentsObject:
228 case HValue::kCapturedObject:
229 case HValue::kSimulate: {
230 for (
int i = 0; i < instr->OperandCount(); i++) {
231 if (instr->OperandAt(i) != allocate)
continue;
232 instr->SetOperandAt(i, state);
236 case HValue::kCheckHeapObject: {
237 HCheckHeapObject* check = HCheckHeapObject::cast(instr);
238 if (check->value() != allocate)
continue;
239 check->DeleteAndReplaceWith(check->ActualValue());
242 case HValue::kCheckMaps: {
243 HCheckMaps* mapcheck = HCheckMaps::cast(instr);
244 if (mapcheck->value() != allocate)
continue;
245 NewMapCheckAndInsert(state, mapcheck);
246 mapcheck->DeleteAndReplaceWith(mapcheck->ActualValue());
256 for (
int i = 0; i < block->end()->SuccessorCount(); i++) {
257 HBasicBlock* succ = block->end()->SuccessorAt(i);
258 if (!allocate_block->Dominates(succ))
continue;
259 if (succ->predecessors()->length() == 1) {
261 SetStateAt(succ, state);
262 }
else if (StateAt(succ) ==
NULL && succ->IsLoopHeader()) {
265 SetStateAt(succ, NewStateForLoopHeader(succ->first(), state));
266 }
else if (StateAt(succ) ==
NULL) {
269 SetStateAt(succ, NewStateCopy(succ->first(), state));
274 HCapturedObject* succ_state = StateAt(succ);
275 for (
int index = 0; index < number_of_values_; index++) {
276 HValue* operand = state->OperandAt(index);
277 HValue* succ_operand = succ_state->OperandAt(index);
278 if (succ_operand->IsPhi() && succ_operand->block() == succ) {
280 HPhi* phi = HPhi::cast(succ_operand);
281 phi->SetOperandAt(succ->PredecessorIndexOf(block), operand);
282 }
else if (succ_operand != operand) {
284 HPhi* phi = NewPhiAndInsert(succ, succ_operand, index);
285 phi->SetOperandAt(succ->PredecessorIndexOf(block), operand);
286 succ_state->SetOperandAt(index, phi);
294 ASSERT(allocate->HasNoUses());
295 allocate->DeleteAndReplaceWith(
NULL);
299 void HEscapeAnalysisPhase::PerformScalarReplacement() {
300 for (
int i = 0; i < captured_.length(); i++) {
301 HAllocate* allocate = HAllocate::cast(captured_.at(i));
304 int size_in_bytes = allocate->size()->GetInteger32Constant();
306 number_of_objects_++;
307 block_states_.Clear();
310 AnalyzeDataFlow(allocate);
312 cumulative_values_ += number_of_values_;
313 ASSERT(allocate->HasNoUses());
314 ASSERT(!allocate->IsLinked());
322 if (
graph()->has_osr())
return;
323 int max_fixpoint_iteration_count = FLAG_escape_analysis_iterations;
324 for (
int i = 0; i < max_fixpoint_iteration_count; i++) {
325 CollectCapturedValues();
326 if (captured_.is_empty())
break;
327 PerformScalarReplacement();
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
void PrintF(const char *format,...)
#define ASSERT(condition)
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object size
void check(i::Vector< const uint8_t > string)
Vector< T > AddBlock(T value, int count, AllocationPolicy allocator=AllocationPolicy())