| OLD | NEW |
| (Empty) |
| 1 // Copyright 2012 the V8 project authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #ifndef V8_HYDROGEN_H_ | |
| 6 #define V8_HYDROGEN_H_ | |
| 7 | |
| 8 #include "src/accessors.h" | |
| 9 #include "src/allocation.h" | |
| 10 #include "src/ast.h" | |
| 11 #include "src/bailout-reason.h" | |
| 12 #include "src/compiler.h" | |
| 13 #include "src/hydrogen-instructions.h" | |
| 14 #include "src/scopes.h" | |
| 15 #include "src/zone.h" | |
| 16 | |
| 17 namespace v8 { | |
| 18 namespace internal { | |
| 19 | |
| 20 // Forward declarations. | |
| 21 class BitVector; | |
| 22 class FunctionState; | |
| 23 class HEnvironment; | |
| 24 class HGraph; | |
| 25 class HLoopInformation; | |
| 26 class HOsrBuilder; | |
| 27 class HTracer; | |
| 28 class LAllocator; | |
| 29 class LChunk; | |
| 30 class LiveRange; | |
| 31 | |
| 32 | |
| 33 class HBasicBlock final : public ZoneObject { | |
| 34 public: | |
| 35 explicit HBasicBlock(HGraph* graph); | |
| 36 ~HBasicBlock() { } | |
| 37 | |
| 38 // Simple accessors. | |
| 39 int block_id() const { return block_id_; } | |
| 40 void set_block_id(int id) { block_id_ = id; } | |
| 41 HGraph* graph() const { return graph_; } | |
| 42 Isolate* isolate() const; | |
| 43 const ZoneList<HPhi*>* phis() const { return &phis_; } | |
| 44 HInstruction* first() const { return first_; } | |
| 45 HInstruction* last() const { return last_; } | |
| 46 void set_last(HInstruction* instr) { last_ = instr; } | |
| 47 HControlInstruction* end() const { return end_; } | |
| 48 HLoopInformation* loop_information() const { return loop_information_; } | |
| 49 HLoopInformation* current_loop() const { | |
| 50 return IsLoopHeader() ? loop_information() | |
| 51 : (parent_loop_header() != NULL | |
| 52 ? parent_loop_header()->loop_information() : NULL); | |
| 53 } | |
| 54 const ZoneList<HBasicBlock*>* predecessors() const { return &predecessors_; } | |
| 55 bool HasPredecessor() const { return predecessors_.length() > 0; } | |
| 56 const ZoneList<HBasicBlock*>* dominated_blocks() const { | |
| 57 return &dominated_blocks_; | |
| 58 } | |
| 59 const ZoneList<int>* deleted_phis() const { | |
| 60 return &deleted_phis_; | |
| 61 } | |
| 62 void RecordDeletedPhi(int merge_index) { | |
| 63 deleted_phis_.Add(merge_index, zone()); | |
| 64 } | |
| 65 HBasicBlock* dominator() const { return dominator_; } | |
| 66 HEnvironment* last_environment() const { return last_environment_; } | |
| 67 int argument_count() const { return argument_count_; } | |
| 68 void set_argument_count(int count) { argument_count_ = count; } | |
| 69 int first_instruction_index() const { return first_instruction_index_; } | |
| 70 void set_first_instruction_index(int index) { | |
| 71 first_instruction_index_ = index; | |
| 72 } | |
| 73 int last_instruction_index() const { return last_instruction_index_; } | |
| 74 void set_last_instruction_index(int index) { | |
| 75 last_instruction_index_ = index; | |
| 76 } | |
| 77 bool is_osr_entry() { return is_osr_entry_; } | |
| 78 void set_osr_entry() { is_osr_entry_ = true; } | |
| 79 | |
| 80 void AttachLoopInformation(); | |
| 81 void DetachLoopInformation(); | |
| 82 bool IsLoopHeader() const { return loop_information() != NULL; } | |
| 83 bool IsStartBlock() const { return block_id() == 0; } | |
| 84 void PostProcessLoopHeader(IterationStatement* stmt); | |
| 85 | |
| 86 bool IsFinished() const { return end_ != NULL; } | |
| 87 void AddPhi(HPhi* phi); | |
| 88 void RemovePhi(HPhi* phi); | |
| 89 void AddInstruction(HInstruction* instr, SourcePosition position); | |
| 90 bool Dominates(HBasicBlock* other) const; | |
| 91 bool EqualToOrDominates(HBasicBlock* other) const; | |
| 92 int LoopNestingDepth() const; | |
| 93 | |
| 94 void SetInitialEnvironment(HEnvironment* env); | |
| 95 void ClearEnvironment() { | |
| 96 DCHECK(IsFinished()); | |
| 97 DCHECK(end()->SuccessorCount() == 0); | |
| 98 last_environment_ = NULL; | |
| 99 } | |
| 100 bool HasEnvironment() const { return last_environment_ != NULL; } | |
| 101 void UpdateEnvironment(HEnvironment* env); | |
| 102 HBasicBlock* parent_loop_header() const { return parent_loop_header_; } | |
| 103 | |
| 104 void set_parent_loop_header(HBasicBlock* block) { | |
| 105 DCHECK(parent_loop_header_ == NULL); | |
| 106 parent_loop_header_ = block; | |
| 107 } | |
| 108 | |
| 109 bool HasParentLoopHeader() const { return parent_loop_header_ != NULL; } | |
| 110 | |
| 111 void SetJoinId(BailoutId ast_id); | |
| 112 | |
| 113 int PredecessorIndexOf(HBasicBlock* predecessor) const; | |
| 114 HPhi* AddNewPhi(int merged_index); | |
| 115 HSimulate* AddNewSimulate(BailoutId ast_id, SourcePosition position, | |
| 116 RemovableSimulate removable = FIXED_SIMULATE) { | |
| 117 HSimulate* instr = CreateSimulate(ast_id, removable); | |
| 118 AddInstruction(instr, position); | |
| 119 return instr; | |
| 120 } | |
| 121 void AssignCommonDominator(HBasicBlock* other); | |
| 122 void AssignLoopSuccessorDominators(); | |
| 123 | |
| 124 // If a target block is tagged as an inline function return, all | |
| 125 // predecessors should contain the inlined exit sequence: | |
| 126 // | |
| 127 // LeaveInlined | |
| 128 // Simulate (caller's environment) | |
| 129 // Goto (target block) | |
| 130 bool IsInlineReturnTarget() const { return is_inline_return_target_; } | |
| 131 void MarkAsInlineReturnTarget(HBasicBlock* inlined_entry_block) { | |
| 132 is_inline_return_target_ = true; | |
| 133 inlined_entry_block_ = inlined_entry_block; | |
| 134 } | |
| 135 HBasicBlock* inlined_entry_block() { return inlined_entry_block_; } | |
| 136 | |
| 137 bool IsDeoptimizing() const { | |
| 138 return end() != NULL && end()->IsDeoptimize(); | |
| 139 } | |
| 140 | |
| 141 void MarkUnreachable(); | |
| 142 bool IsUnreachable() const { return !is_reachable_; } | |
| 143 bool IsReachable() const { return is_reachable_; } | |
| 144 | |
| 145 bool IsLoopSuccessorDominator() const { | |
| 146 return dominates_loop_successors_; | |
| 147 } | |
| 148 void MarkAsLoopSuccessorDominator() { | |
| 149 dominates_loop_successors_ = true; | |
| 150 } | |
| 151 | |
| 152 bool IsOrdered() const { return is_ordered_; } | |
| 153 void MarkAsOrdered() { is_ordered_ = true; } | |
| 154 | |
| 155 void MarkSuccEdgeUnreachable(int succ); | |
| 156 | |
| 157 inline Zone* zone() const; | |
| 158 | |
| 159 #ifdef DEBUG | |
| 160 void Verify(); | |
| 161 #endif | |
| 162 | |
| 163 protected: | |
| 164 friend class HGraphBuilder; | |
| 165 | |
| 166 HSimulate* CreateSimulate(BailoutId ast_id, RemovableSimulate removable); | |
| 167 void Finish(HControlInstruction* last, SourcePosition position); | |
| 168 void FinishExit(HControlInstruction* instruction, SourcePosition position); | |
| 169 void Goto(HBasicBlock* block, SourcePosition position, | |
| 170 FunctionState* state = NULL, bool add_simulate = true); | |
| 171 void GotoNoSimulate(HBasicBlock* block, SourcePosition position) { | |
| 172 Goto(block, position, NULL, false); | |
| 173 } | |
| 174 | |
| 175 // Add the inlined function exit sequence, adding an HLeaveInlined | |
| 176 // instruction and updating the bailout environment. | |
| 177 void AddLeaveInlined(HValue* return_value, FunctionState* state, | |
| 178 SourcePosition position); | |
| 179 | |
| 180 private: | |
| 181 void RegisterPredecessor(HBasicBlock* pred); | |
| 182 void AddDominatedBlock(HBasicBlock* block); | |
| 183 | |
| 184 int block_id_; | |
| 185 HGraph* graph_; | |
| 186 ZoneList<HPhi*> phis_; | |
| 187 HInstruction* first_; | |
| 188 HInstruction* last_; | |
| 189 HControlInstruction* end_; | |
| 190 HLoopInformation* loop_information_; | |
| 191 ZoneList<HBasicBlock*> predecessors_; | |
| 192 HBasicBlock* dominator_; | |
| 193 ZoneList<HBasicBlock*> dominated_blocks_; | |
| 194 HEnvironment* last_environment_; | |
| 195 // Outgoing parameter count at block exit, set during lithium translation. | |
| 196 int argument_count_; | |
| 197 // Instruction indices into the lithium code stream. | |
| 198 int first_instruction_index_; | |
| 199 int last_instruction_index_; | |
| 200 ZoneList<int> deleted_phis_; | |
| 201 HBasicBlock* parent_loop_header_; | |
| 202 // For blocks marked as inline return target: the block with HEnterInlined. | |
| 203 HBasicBlock* inlined_entry_block_; | |
| 204 bool is_inline_return_target_ : 1; | |
| 205 bool is_reachable_ : 1; | |
| 206 bool dominates_loop_successors_ : 1; | |
| 207 bool is_osr_entry_ : 1; | |
| 208 bool is_ordered_ : 1; | |
| 209 }; | |
| 210 | |
| 211 | |
| 212 std::ostream& operator<<(std::ostream& os, const HBasicBlock& b); | |
| 213 | |
| 214 | |
| 215 class HPredecessorIterator final BASE_EMBEDDED { | |
| 216 public: | |
| 217 explicit HPredecessorIterator(HBasicBlock* block) | |
| 218 : predecessor_list_(block->predecessors()), current_(0) { } | |
| 219 | |
| 220 bool Done() { return current_ >= predecessor_list_->length(); } | |
| 221 HBasicBlock* Current() { return predecessor_list_->at(current_); } | |
| 222 void Advance() { current_++; } | |
| 223 | |
| 224 private: | |
| 225 const ZoneList<HBasicBlock*>* predecessor_list_; | |
| 226 int current_; | |
| 227 }; | |
| 228 | |
| 229 | |
| 230 class HInstructionIterator final BASE_EMBEDDED { | |
| 231 public: | |
| 232 explicit HInstructionIterator(HBasicBlock* block) | |
| 233 : instr_(block->first()) { | |
| 234 next_ = Done() ? NULL : instr_->next(); | |
| 235 } | |
| 236 | |
| 237 inline bool Done() const { return instr_ == NULL; } | |
| 238 inline HInstruction* Current() { return instr_; } | |
| 239 inline void Advance() { | |
| 240 instr_ = next_; | |
| 241 next_ = Done() ? NULL : instr_->next(); | |
| 242 } | |
| 243 | |
| 244 private: | |
| 245 HInstruction* instr_; | |
| 246 HInstruction* next_; | |
| 247 }; | |
| 248 | |
| 249 | |
| 250 class HLoopInformation final : public ZoneObject { | |
| 251 public: | |
| 252 HLoopInformation(HBasicBlock* loop_header, Zone* zone) | |
| 253 : back_edges_(4, zone), | |
| 254 loop_header_(loop_header), | |
| 255 blocks_(8, zone), | |
| 256 stack_check_(NULL) { | |
| 257 blocks_.Add(loop_header, zone); | |
| 258 } | |
| 259 ~HLoopInformation() {} | |
| 260 | |
| 261 const ZoneList<HBasicBlock*>* back_edges() const { return &back_edges_; } | |
| 262 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; } | |
| 263 HBasicBlock* loop_header() const { return loop_header_; } | |
| 264 HBasicBlock* GetLastBackEdge() const; | |
| 265 void RegisterBackEdge(HBasicBlock* block); | |
| 266 | |
| 267 HStackCheck* stack_check() const { return stack_check_; } | |
| 268 void set_stack_check(HStackCheck* stack_check) { | |
| 269 stack_check_ = stack_check; | |
| 270 } | |
| 271 | |
| 272 bool IsNestedInThisLoop(HLoopInformation* other) { | |
| 273 while (other != NULL) { | |
| 274 if (other == this) { | |
| 275 return true; | |
| 276 } | |
| 277 other = other->parent_loop(); | |
| 278 } | |
| 279 return false; | |
| 280 } | |
| 281 HLoopInformation* parent_loop() { | |
| 282 HBasicBlock* parent_header = loop_header()->parent_loop_header(); | |
| 283 return parent_header != NULL ? parent_header->loop_information() : NULL; | |
| 284 } | |
| 285 | |
| 286 private: | |
| 287 void AddBlock(HBasicBlock* block); | |
| 288 | |
| 289 ZoneList<HBasicBlock*> back_edges_; | |
| 290 HBasicBlock* loop_header_; | |
| 291 ZoneList<HBasicBlock*> blocks_; | |
| 292 HStackCheck* stack_check_; | |
| 293 }; | |
| 294 | |
| 295 | |
| 296 class BoundsCheckTable; | |
| 297 class InductionVariableBlocksTable; | |
| 298 class HGraph final : public ZoneObject { | |
| 299 public: | |
| 300 explicit HGraph(CompilationInfo* info); | |
| 301 | |
| 302 Isolate* isolate() const { return isolate_; } | |
| 303 Zone* zone() const { return zone_; } | |
| 304 CompilationInfo* info() const { return info_; } | |
| 305 | |
| 306 const ZoneList<HBasicBlock*>* blocks() const { return &blocks_; } | |
| 307 const ZoneList<HPhi*>* phi_list() const { return phi_list_; } | |
| 308 HBasicBlock* entry_block() const { return entry_block_; } | |
| 309 HEnvironment* start_environment() const { return start_environment_; } | |
| 310 | |
| 311 void FinalizeUniqueness(); | |
| 312 void OrderBlocks(); | |
| 313 void AssignDominators(); | |
| 314 void RestoreActualValues(); | |
| 315 | |
| 316 // Returns false if there are phi-uses of the arguments-object | |
| 317 // which are not supported by the optimizing compiler. | |
| 318 bool CheckArgumentsPhiUses(); | |
| 319 | |
| 320 // Returns false if there are phi-uses of an uninitialized const | |
| 321 // which are not supported by the optimizing compiler. | |
| 322 bool CheckConstPhiUses(); | |
| 323 | |
| 324 void CollectPhis(); | |
| 325 | |
| 326 HConstant* GetConstantUndefined(); | |
| 327 HConstant* GetConstant0(); | |
| 328 HConstant* GetConstant1(); | |
| 329 HConstant* GetConstantMinus1(); | |
| 330 HConstant* GetConstantTrue(); | |
| 331 HConstant* GetConstantFalse(); | |
| 332 HConstant* GetConstantBool(bool value); | |
| 333 HConstant* GetConstantHole(); | |
| 334 HConstant* GetConstantNull(); | |
| 335 HConstant* GetInvalidContext(); | |
| 336 | |
| 337 bool IsConstantUndefined(HConstant* constant); | |
| 338 bool IsConstant0(HConstant* constant); | |
| 339 bool IsConstant1(HConstant* constant); | |
| 340 bool IsConstantMinus1(HConstant* constant); | |
| 341 bool IsConstantTrue(HConstant* constant); | |
| 342 bool IsConstantFalse(HConstant* constant); | |
| 343 bool IsConstantHole(HConstant* constant); | |
| 344 bool IsConstantNull(HConstant* constant); | |
| 345 bool IsStandardConstant(HConstant* constant); | |
| 346 | |
| 347 HBasicBlock* CreateBasicBlock(); | |
| 348 HArgumentsObject* GetArgumentsObject() const { | |
| 349 return arguments_object_.get(); | |
| 350 } | |
| 351 | |
| 352 void SetArgumentsObject(HArgumentsObject* object) { | |
| 353 arguments_object_.set(object); | |
| 354 } | |
| 355 | |
| 356 int GetMaximumValueID() const { return values_.length(); } | |
| 357 int GetNextBlockID() { return next_block_id_++; } | |
| 358 int GetNextValueID(HValue* value) { | |
| 359 DCHECK(!disallow_adding_new_values_); | |
| 360 values_.Add(value, zone()); | |
| 361 return values_.length() - 1; | |
| 362 } | |
| 363 HValue* LookupValue(int id) const { | |
| 364 if (id >= 0 && id < values_.length()) return values_[id]; | |
| 365 return NULL; | |
| 366 } | |
| 367 void DisallowAddingNewValues() { | |
| 368 disallow_adding_new_values_ = true; | |
| 369 } | |
| 370 | |
| 371 bool Optimize(BailoutReason* bailout_reason); | |
| 372 | |
| 373 #ifdef DEBUG | |
| 374 void Verify(bool do_full_verify) const; | |
| 375 #endif | |
| 376 | |
| 377 bool has_osr() { | |
| 378 return osr_ != NULL; | |
| 379 } | |
| 380 | |
| 381 void set_osr(HOsrBuilder* osr) { | |
| 382 osr_ = osr; | |
| 383 } | |
| 384 | |
| 385 HOsrBuilder* osr() { | |
| 386 return osr_; | |
| 387 } | |
| 388 | |
| 389 int update_type_change_checksum(int delta) { | |
| 390 type_change_checksum_ += delta; | |
| 391 return type_change_checksum_; | |
| 392 } | |
| 393 | |
| 394 void update_maximum_environment_size(int environment_size) { | |
| 395 if (environment_size > maximum_environment_size_) { | |
| 396 maximum_environment_size_ = environment_size; | |
| 397 } | |
| 398 } | |
| 399 int maximum_environment_size() { return maximum_environment_size_; } | |
| 400 | |
| 401 bool use_optimistic_licm() { | |
| 402 return use_optimistic_licm_; | |
| 403 } | |
| 404 | |
| 405 void set_use_optimistic_licm(bool value) { | |
| 406 use_optimistic_licm_ = value; | |
| 407 } | |
| 408 | |
| 409 void MarkRecursive() { is_recursive_ = true; } | |
| 410 bool is_recursive() const { return is_recursive_; } | |
| 411 | |
| 412 void MarkDependsOnEmptyArrayProtoElements() { | |
| 413 // Add map dependency if not already added. | |
| 414 if (depends_on_empty_array_proto_elements_) return; | |
| 415 info()->dependencies()->AssumePropertyCell( | |
| 416 isolate()->factory()->array_protector()); | |
| 417 depends_on_empty_array_proto_elements_ = true; | |
| 418 } | |
| 419 | |
| 420 bool depends_on_empty_array_proto_elements() { | |
| 421 return depends_on_empty_array_proto_elements_; | |
| 422 } | |
| 423 | |
| 424 bool has_uint32_instructions() { | |
| 425 DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty()); | |
| 426 return uint32_instructions_ != NULL; | |
| 427 } | |
| 428 | |
| 429 ZoneList<HInstruction*>* uint32_instructions() { | |
| 430 DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty()); | |
| 431 return uint32_instructions_; | |
| 432 } | |
| 433 | |
| 434 void RecordUint32Instruction(HInstruction* instr) { | |
| 435 DCHECK(uint32_instructions_ == NULL || !uint32_instructions_->is_empty()); | |
| 436 if (uint32_instructions_ == NULL) { | |
| 437 uint32_instructions_ = new(zone()) ZoneList<HInstruction*>(4, zone()); | |
| 438 } | |
| 439 uint32_instructions_->Add(instr, zone()); | |
| 440 } | |
| 441 | |
| 442 void IncrementInNoSideEffectsScope() { no_side_effects_scope_count_++; } | |
| 443 void DecrementInNoSideEffectsScope() { no_side_effects_scope_count_--; } | |
| 444 bool IsInsideNoSideEffectsScope() { return no_side_effects_scope_count_ > 0; } | |
| 445 | |
| 446 // If we are tracking source positions then this function assigns a unique | |
| 447 // identifier to each inlining and dumps function source if it was inlined | |
| 448 // for the first time during the current optimization. | |
| 449 int TraceInlinedFunction(Handle<SharedFunctionInfo> shared, | |
| 450 SourcePosition position); | |
| 451 | |
| 452 // Converts given SourcePosition to the absolute offset from the start of | |
| 453 // the corresponding script. | |
| 454 int SourcePositionToScriptPosition(SourcePosition position); | |
| 455 | |
| 456 private: | |
| 457 HConstant* ReinsertConstantIfNecessary(HConstant* constant); | |
| 458 HConstant* GetConstant(SetOncePointer<HConstant>* pointer, | |
| 459 int32_t integer_value); | |
| 460 | |
| 461 template<class Phase> | |
| 462 void Run() { | |
| 463 Phase phase(this); | |
| 464 phase.Run(); | |
| 465 } | |
| 466 | |
| 467 Isolate* isolate_; | |
| 468 int next_block_id_; | |
| 469 HBasicBlock* entry_block_; | |
| 470 HEnvironment* start_environment_; | |
| 471 ZoneList<HBasicBlock*> blocks_; | |
| 472 ZoneList<HValue*> values_; | |
| 473 ZoneList<HPhi*>* phi_list_; | |
| 474 ZoneList<HInstruction*>* uint32_instructions_; | |
| 475 SetOncePointer<HConstant> constant_undefined_; | |
| 476 SetOncePointer<HConstant> constant_0_; | |
| 477 SetOncePointer<HConstant> constant_1_; | |
| 478 SetOncePointer<HConstant> constant_minus1_; | |
| 479 SetOncePointer<HConstant> constant_true_; | |
| 480 SetOncePointer<HConstant> constant_false_; | |
| 481 SetOncePointer<HConstant> constant_the_hole_; | |
| 482 SetOncePointer<HConstant> constant_null_; | |
| 483 SetOncePointer<HConstant> constant_invalid_context_; | |
| 484 SetOncePointer<HArgumentsObject> arguments_object_; | |
| 485 | |
| 486 HOsrBuilder* osr_; | |
| 487 | |
| 488 CompilationInfo* info_; | |
| 489 Zone* zone_; | |
| 490 | |
| 491 bool is_recursive_; | |
| 492 bool use_optimistic_licm_; | |
| 493 bool depends_on_empty_array_proto_elements_; | |
| 494 int type_change_checksum_; | |
| 495 int maximum_environment_size_; | |
| 496 int no_side_effects_scope_count_; | |
| 497 bool disallow_adding_new_values_; | |
| 498 | |
| 499 DISALLOW_COPY_AND_ASSIGN(HGraph); | |
| 500 }; | |
| 501 | |
| 502 | |
| 503 Zone* HBasicBlock::zone() const { return graph_->zone(); } | |
| 504 | |
| 505 | |
| 506 // Type of stack frame an environment might refer to. | |
| 507 enum FrameType { | |
| 508 JS_FUNCTION, | |
| 509 JS_CONSTRUCT, | |
| 510 JS_GETTER, | |
| 511 JS_SETTER, | |
| 512 ARGUMENTS_ADAPTOR, | |
| 513 STUB | |
| 514 }; | |
| 515 | |
| 516 | |
| 517 class HEnvironment final : public ZoneObject { | |
| 518 public: | |
| 519 HEnvironment(HEnvironment* outer, | |
| 520 Scope* scope, | |
| 521 Handle<JSFunction> closure, | |
| 522 Zone* zone); | |
| 523 | |
| 524 HEnvironment(Zone* zone, int parameter_count); | |
| 525 | |
| 526 HEnvironment* arguments_environment() { | |
| 527 return outer()->frame_type() == ARGUMENTS_ADAPTOR ? outer() : this; | |
| 528 } | |
| 529 | |
| 530 // Simple accessors. | |
| 531 Handle<JSFunction> closure() const { return closure_; } | |
| 532 const ZoneList<HValue*>* values() const { return &values_; } | |
| 533 const GrowableBitVector* assigned_variables() const { | |
| 534 return &assigned_variables_; | |
| 535 } | |
| 536 FrameType frame_type() const { return frame_type_; } | |
| 537 int parameter_count() const { return parameter_count_; } | |
| 538 int specials_count() const { return specials_count_; } | |
| 539 int local_count() const { return local_count_; } | |
| 540 HEnvironment* outer() const { return outer_; } | |
| 541 int pop_count() const { return pop_count_; } | |
| 542 int push_count() const { return push_count_; } | |
| 543 | |
| 544 BailoutId ast_id() const { return ast_id_; } | |
| 545 void set_ast_id(BailoutId id) { ast_id_ = id; } | |
| 546 | |
| 547 HEnterInlined* entry() const { return entry_; } | |
| 548 void set_entry(HEnterInlined* entry) { entry_ = entry; } | |
| 549 | |
| 550 int length() const { return values_.length(); } | |
| 551 | |
| 552 int first_expression_index() const { | |
| 553 return parameter_count() + specials_count() + local_count(); | |
| 554 } | |
| 555 | |
| 556 int first_local_index() const { | |
| 557 return parameter_count() + specials_count(); | |
| 558 } | |
| 559 | |
| 560 void Bind(Variable* variable, HValue* value) { | |
| 561 Bind(IndexFor(variable), value); | |
| 562 } | |
| 563 | |
| 564 void Bind(int index, HValue* value); | |
| 565 | |
| 566 void BindContext(HValue* value) { | |
| 567 Bind(parameter_count(), value); | |
| 568 } | |
| 569 | |
| 570 HValue* Lookup(Variable* variable) const { | |
| 571 return Lookup(IndexFor(variable)); | |
| 572 } | |
| 573 | |
| 574 HValue* Lookup(int index) const { | |
| 575 HValue* result = values_[index]; | |
| 576 DCHECK(result != NULL); | |
| 577 return result; | |
| 578 } | |
| 579 | |
| 580 HValue* context() const { | |
| 581 // Return first special. | |
| 582 return Lookup(parameter_count()); | |
| 583 } | |
| 584 | |
| 585 void Push(HValue* value) { | |
| 586 DCHECK(value != NULL); | |
| 587 ++push_count_; | |
| 588 values_.Add(value, zone()); | |
| 589 } | |
| 590 | |
| 591 HValue* Pop() { | |
| 592 DCHECK(!ExpressionStackIsEmpty()); | |
| 593 if (push_count_ > 0) { | |
| 594 --push_count_; | |
| 595 } else { | |
| 596 ++pop_count_; | |
| 597 } | |
| 598 return values_.RemoveLast(); | |
| 599 } | |
| 600 | |
| 601 void Drop(int count); | |
| 602 | |
| 603 HValue* Top() const { return ExpressionStackAt(0); } | |
| 604 | |
| 605 bool ExpressionStackIsEmpty() const; | |
| 606 | |
| 607 HValue* ExpressionStackAt(int index_from_top) const { | |
| 608 int index = length() - index_from_top - 1; | |
| 609 DCHECK(HasExpressionAt(index)); | |
| 610 return values_[index]; | |
| 611 } | |
| 612 | |
| 613 void SetExpressionStackAt(int index_from_top, HValue* value); | |
| 614 HValue* RemoveExpressionStackAt(int index_from_top); | |
| 615 | |
| 616 void Print() const; | |
| 617 | |
| 618 HEnvironment* Copy() const; | |
| 619 HEnvironment* CopyWithoutHistory() const; | |
| 620 HEnvironment* CopyAsLoopHeader(HBasicBlock* block) const; | |
| 621 | |
| 622 // Create an "inlined version" of this environment, where the original | |
| 623 // environment is the outer environment but the top expression stack | |
| 624 // elements are moved to an inner environment as parameters. | |
| 625 HEnvironment* CopyForInlining(Handle<JSFunction> target, | |
| 626 int arguments, | |
| 627 FunctionLiteral* function, | |
| 628 HConstant* undefined, | |
| 629 InliningKind inlining_kind) const; | |
| 630 | |
| 631 HEnvironment* DiscardInlined(bool drop_extra) { | |
| 632 HEnvironment* outer = outer_; | |
| 633 while (outer->frame_type() != JS_FUNCTION) outer = outer->outer_; | |
| 634 if (drop_extra) outer->Drop(1); | |
| 635 return outer; | |
| 636 } | |
| 637 | |
| 638 void AddIncomingEdge(HBasicBlock* block, HEnvironment* other); | |
| 639 | |
| 640 void ClearHistory() { | |
| 641 pop_count_ = 0; | |
| 642 push_count_ = 0; | |
| 643 assigned_variables_.Clear(); | |
| 644 } | |
| 645 | |
| 646 void SetValueAt(int index, HValue* value) { | |
| 647 DCHECK(index < length()); | |
| 648 values_[index] = value; | |
| 649 } | |
| 650 | |
| 651 // Map a variable to an environment index. Parameter indices are shifted | |
| 652 // by 1 (receiver is parameter index -1 but environment index 0). | |
| 653 // Stack-allocated local indices are shifted by the number of parameters. | |
| 654 int IndexFor(Variable* variable) const { | |
| 655 DCHECK(variable->IsStackAllocated()); | |
| 656 int shift = variable->IsParameter() | |
| 657 ? 1 | |
| 658 : parameter_count_ + specials_count_; | |
| 659 return variable->index() + shift; | |
| 660 } | |
| 661 | |
| 662 bool is_local_index(int i) const { | |
| 663 return i >= first_local_index() && i < first_expression_index(); | |
| 664 } | |
| 665 | |
| 666 bool is_parameter_index(int i) const { | |
| 667 return i >= 0 && i < parameter_count(); | |
| 668 } | |
| 669 | |
| 670 bool is_special_index(int i) const { | |
| 671 return i >= parameter_count() && i < parameter_count() + specials_count(); | |
| 672 } | |
| 673 | |
| 674 Zone* zone() const { return zone_; } | |
| 675 | |
| 676 private: | |
| 677 HEnvironment(const HEnvironment* other, Zone* zone); | |
| 678 | |
| 679 HEnvironment(HEnvironment* outer, | |
| 680 Handle<JSFunction> closure, | |
| 681 FrameType frame_type, | |
| 682 int arguments, | |
| 683 Zone* zone); | |
| 684 | |
| 685 // Create an artificial stub environment (e.g. for argument adaptor or | |
| 686 // constructor stub). | |
| 687 HEnvironment* CreateStubEnvironment(HEnvironment* outer, | |
| 688 Handle<JSFunction> target, | |
| 689 FrameType frame_type, | |
| 690 int arguments) const; | |
| 691 | |
| 692 // True if index is included in the expression stack part of the environment. | |
| 693 bool HasExpressionAt(int index) const; | |
| 694 | |
| 695 void Initialize(int parameter_count, int local_count, int stack_height); | |
| 696 void Initialize(const HEnvironment* other); | |
| 697 | |
| 698 Handle<JSFunction> closure_; | |
| 699 // Value array [parameters] [specials] [locals] [temporaries]. | |
| 700 ZoneList<HValue*> values_; | |
| 701 GrowableBitVector assigned_variables_; | |
| 702 FrameType frame_type_; | |
| 703 int parameter_count_; | |
| 704 int specials_count_; | |
| 705 int local_count_; | |
| 706 HEnvironment* outer_; | |
| 707 HEnterInlined* entry_; | |
| 708 int pop_count_; | |
| 709 int push_count_; | |
| 710 BailoutId ast_id_; | |
| 711 Zone* zone_; | |
| 712 }; | |
| 713 | |
| 714 | |
| 715 std::ostream& operator<<(std::ostream& os, const HEnvironment& env); | |
| 716 | |
| 717 | |
| 718 class HOptimizedGraphBuilder; | |
| 719 | |
| 720 enum ArgumentsAllowedFlag { | |
| 721 ARGUMENTS_NOT_ALLOWED, | |
| 722 ARGUMENTS_ALLOWED, | |
| 723 ARGUMENTS_FAKED | |
| 724 }; | |
| 725 | |
| 726 | |
| 727 class HIfContinuation; | |
| 728 | |
| 729 // This class is not BASE_EMBEDDED because our inlining implementation uses | |
| 730 // new and delete. | |
| 731 class AstContext { | |
| 732 public: | |
| 733 bool IsEffect() const { return kind_ == Expression::kEffect; } | |
| 734 bool IsValue() const { return kind_ == Expression::kValue; } | |
| 735 bool IsTest() const { return kind_ == Expression::kTest; } | |
| 736 | |
| 737 // 'Fill' this context with a hydrogen value. The value is assumed to | |
| 738 // have already been inserted in the instruction stream (or not need to | |
| 739 // be, e.g., HPhi). Call this function in tail position in the Visit | |
| 740 // functions for expressions. | |
| 741 virtual void ReturnValue(HValue* value) = 0; | |
| 742 | |
| 743 // Add a hydrogen instruction to the instruction stream (recording an | |
| 744 // environment simulation if necessary) and then fill this context with | |
| 745 // the instruction as value. | |
| 746 virtual void ReturnInstruction(HInstruction* instr, BailoutId ast_id) = 0; | |
| 747 | |
| 748 // Finishes the current basic block and materialize a boolean for | |
| 749 // value context, nothing for effect, generate a branch for test context. | |
| 750 // Call this function in tail position in the Visit functions for | |
| 751 // expressions. | |
| 752 virtual void ReturnControl(HControlInstruction* instr, BailoutId ast_id) = 0; | |
| 753 | |
| 754 // Finishes the current basic block and materialize a boolean for | |
| 755 // value context, nothing for effect, generate a branch for test context. | |
| 756 // Call this function in tail position in the Visit functions for | |
| 757 // expressions that use an IfBuilder. | |
| 758 virtual void ReturnContinuation(HIfContinuation* continuation, | |
| 759 BailoutId ast_id) = 0; | |
| 760 | |
| 761 void set_typeof_mode(TypeofMode typeof_mode) { typeof_mode_ = typeof_mode; } | |
| 762 TypeofMode typeof_mode() { return typeof_mode_; } | |
| 763 | |
| 764 protected: | |
| 765 AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind); | |
| 766 virtual ~AstContext(); | |
| 767 | |
| 768 HOptimizedGraphBuilder* owner() const { return owner_; } | |
| 769 | |
| 770 inline Zone* zone() const; | |
| 771 | |
| 772 // We want to be able to assert, in a context-specific way, that the stack | |
| 773 // height makes sense when the context is filled. | |
| 774 #ifdef DEBUG | |
| 775 int original_length_; | |
| 776 #endif | |
| 777 | |
| 778 private: | |
| 779 HOptimizedGraphBuilder* owner_; | |
| 780 Expression::Context kind_; | |
| 781 AstContext* outer_; | |
| 782 TypeofMode typeof_mode_; | |
| 783 }; | |
| 784 | |
| 785 | |
| 786 class EffectContext final : public AstContext { | |
| 787 public: | |
| 788 explicit EffectContext(HOptimizedGraphBuilder* owner) | |
| 789 : AstContext(owner, Expression::kEffect) { | |
| 790 } | |
| 791 virtual ~EffectContext(); | |
| 792 | |
| 793 void ReturnValue(HValue* value) override; | |
| 794 virtual void ReturnInstruction(HInstruction* instr, | |
| 795 BailoutId ast_id) override; | |
| 796 virtual void ReturnControl(HControlInstruction* instr, | |
| 797 BailoutId ast_id) override; | |
| 798 virtual void ReturnContinuation(HIfContinuation* continuation, | |
| 799 BailoutId ast_id) override; | |
| 800 }; | |
| 801 | |
| 802 | |
| 803 class ValueContext final : public AstContext { | |
| 804 public: | |
| 805 ValueContext(HOptimizedGraphBuilder* owner, ArgumentsAllowedFlag flag) | |
| 806 : AstContext(owner, Expression::kValue), flag_(flag) { | |
| 807 } | |
| 808 virtual ~ValueContext(); | |
| 809 | |
| 810 void ReturnValue(HValue* value) override; | |
| 811 virtual void ReturnInstruction(HInstruction* instr, | |
| 812 BailoutId ast_id) override; | |
| 813 virtual void ReturnControl(HControlInstruction* instr, | |
| 814 BailoutId ast_id) override; | |
| 815 virtual void ReturnContinuation(HIfContinuation* continuation, | |
| 816 BailoutId ast_id) override; | |
| 817 | |
| 818 bool arguments_allowed() { return flag_ == ARGUMENTS_ALLOWED; } | |
| 819 | |
| 820 private: | |
| 821 ArgumentsAllowedFlag flag_; | |
| 822 }; | |
| 823 | |
| 824 | |
| 825 class TestContext final : public AstContext { | |
| 826 public: | |
| 827 TestContext(HOptimizedGraphBuilder* owner, | |
| 828 Expression* condition, | |
| 829 HBasicBlock* if_true, | |
| 830 HBasicBlock* if_false) | |
| 831 : AstContext(owner, Expression::kTest), | |
| 832 condition_(condition), | |
| 833 if_true_(if_true), | |
| 834 if_false_(if_false) { | |
| 835 } | |
| 836 | |
| 837 void ReturnValue(HValue* value) override; | |
| 838 virtual void ReturnInstruction(HInstruction* instr, | |
| 839 BailoutId ast_id) override; | |
| 840 virtual void ReturnControl(HControlInstruction* instr, | |
| 841 BailoutId ast_id) override; | |
| 842 virtual void ReturnContinuation(HIfContinuation* continuation, | |
| 843 BailoutId ast_id) override; | |
| 844 | |
| 845 static TestContext* cast(AstContext* context) { | |
| 846 DCHECK(context->IsTest()); | |
| 847 return reinterpret_cast<TestContext*>(context); | |
| 848 } | |
| 849 | |
| 850 Expression* condition() const { return condition_; } | |
| 851 HBasicBlock* if_true() const { return if_true_; } | |
| 852 HBasicBlock* if_false() const { return if_false_; } | |
| 853 | |
| 854 private: | |
| 855 // Build the shared core part of the translation unpacking a value into | |
| 856 // control flow. | |
| 857 void BuildBranch(HValue* value); | |
| 858 | |
| 859 Expression* condition_; | |
| 860 HBasicBlock* if_true_; | |
| 861 HBasicBlock* if_false_; | |
| 862 }; | |
| 863 | |
| 864 | |
| 865 class FunctionState final { | |
| 866 public: | |
| 867 FunctionState(HOptimizedGraphBuilder* owner, | |
| 868 CompilationInfo* info, | |
| 869 InliningKind inlining_kind, | |
| 870 int inlining_id); | |
| 871 ~FunctionState(); | |
| 872 | |
| 873 CompilationInfo* compilation_info() { return compilation_info_; } | |
| 874 AstContext* call_context() { return call_context_; } | |
| 875 InliningKind inlining_kind() const { return inlining_kind_; } | |
| 876 HBasicBlock* function_return() { return function_return_; } | |
| 877 TestContext* test_context() { return test_context_; } | |
| 878 void ClearInlinedTestContext() { | |
| 879 delete test_context_; | |
| 880 test_context_ = NULL; | |
| 881 } | |
| 882 | |
| 883 FunctionState* outer() { return outer_; } | |
| 884 | |
| 885 HEnterInlined* entry() { return entry_; } | |
| 886 void set_entry(HEnterInlined* entry) { entry_ = entry; } | |
| 887 | |
| 888 HArgumentsObject* arguments_object() { return arguments_object_; } | |
| 889 void set_arguments_object(HArgumentsObject* arguments_object) { | |
| 890 arguments_object_ = arguments_object; | |
| 891 } | |
| 892 | |
| 893 HArgumentsElements* arguments_elements() { return arguments_elements_; } | |
| 894 void set_arguments_elements(HArgumentsElements* arguments_elements) { | |
| 895 arguments_elements_ = arguments_elements; | |
| 896 } | |
| 897 | |
| 898 bool arguments_pushed() { return arguments_elements() != NULL; } | |
| 899 | |
| 900 int inlining_id() const { return inlining_id_; } | |
| 901 | |
| 902 private: | |
| 903 HOptimizedGraphBuilder* owner_; | |
| 904 | |
| 905 CompilationInfo* compilation_info_; | |
| 906 | |
| 907 // During function inlining, expression context of the call being | |
| 908 // inlined. NULL when not inlining. | |
| 909 AstContext* call_context_; | |
| 910 | |
| 911 // The kind of call which is currently being inlined. | |
| 912 InliningKind inlining_kind_; | |
| 913 | |
| 914 // When inlining in an effect or value context, this is the return block. | |
| 915 // It is NULL otherwise. When inlining in a test context, there are a | |
| 916 // pair of return blocks in the context. When not inlining, there is no | |
| 917 // local return point. | |
| 918 HBasicBlock* function_return_; | |
| 919 | |
| 920 // When inlining a call in a test context, a context containing a pair of | |
| 921 // return blocks. NULL in all other cases. | |
| 922 TestContext* test_context_; | |
| 923 | |
| 924 // When inlining HEnterInlined instruction corresponding to the function | |
| 925 // entry. | |
| 926 HEnterInlined* entry_; | |
| 927 | |
| 928 HArgumentsObject* arguments_object_; | |
| 929 HArgumentsElements* arguments_elements_; | |
| 930 | |
| 931 int inlining_id_; | |
| 932 SourcePosition outer_source_position_; | |
| 933 | |
| 934 FunctionState* outer_; | |
| 935 }; | |
| 936 | |
| 937 | |
| 938 class HIfContinuation final { | |
| 939 public: | |
| 940 HIfContinuation() | |
| 941 : continuation_captured_(false), | |
| 942 true_branch_(NULL), | |
| 943 false_branch_(NULL) {} | |
| 944 HIfContinuation(HBasicBlock* true_branch, | |
| 945 HBasicBlock* false_branch) | |
| 946 : continuation_captured_(true), true_branch_(true_branch), | |
| 947 false_branch_(false_branch) {} | |
| 948 ~HIfContinuation() { DCHECK(!continuation_captured_); } | |
| 949 | |
| 950 void Capture(HBasicBlock* true_branch, | |
| 951 HBasicBlock* false_branch) { | |
| 952 DCHECK(!continuation_captured_); | |
| 953 true_branch_ = true_branch; | |
| 954 false_branch_ = false_branch; | |
| 955 continuation_captured_ = true; | |
| 956 } | |
| 957 | |
| 958 void Continue(HBasicBlock** true_branch, | |
| 959 HBasicBlock** false_branch) { | |
| 960 DCHECK(continuation_captured_); | |
| 961 *true_branch = true_branch_; | |
| 962 *false_branch = false_branch_; | |
| 963 continuation_captured_ = false; | |
| 964 } | |
| 965 | |
| 966 bool IsTrueReachable() { return true_branch_ != NULL; } | |
| 967 bool IsFalseReachable() { return false_branch_ != NULL; } | |
| 968 bool TrueAndFalseReachable() { | |
| 969 return IsTrueReachable() || IsFalseReachable(); | |
| 970 } | |
| 971 | |
| 972 HBasicBlock* true_branch() const { return true_branch_; } | |
| 973 HBasicBlock* false_branch() const { return false_branch_; } | |
| 974 | |
| 975 private: | |
| 976 bool continuation_captured_; | |
| 977 HBasicBlock* true_branch_; | |
| 978 HBasicBlock* false_branch_; | |
| 979 }; | |
| 980 | |
| 981 | |
| 982 class HAllocationMode final BASE_EMBEDDED { | |
| 983 public: | |
| 984 explicit HAllocationMode(Handle<AllocationSite> feedback_site) | |
| 985 : current_site_(NULL), feedback_site_(feedback_site), | |
| 986 pretenure_flag_(NOT_TENURED) {} | |
| 987 explicit HAllocationMode(HValue* current_site) | |
| 988 : current_site_(current_site), pretenure_flag_(NOT_TENURED) {} | |
| 989 explicit HAllocationMode(PretenureFlag pretenure_flag) | |
| 990 : current_site_(NULL), pretenure_flag_(pretenure_flag) {} | |
| 991 HAllocationMode() | |
| 992 : current_site_(NULL), pretenure_flag_(NOT_TENURED) {} | |
| 993 | |
| 994 HValue* current_site() const { return current_site_; } | |
| 995 Handle<AllocationSite> feedback_site() const { return feedback_site_; } | |
| 996 | |
| 997 bool CreateAllocationMementos() const WARN_UNUSED_RESULT { | |
| 998 return current_site() != NULL; | |
| 999 } | |
| 1000 | |
| 1001 PretenureFlag GetPretenureMode() const WARN_UNUSED_RESULT { | |
| 1002 if (!feedback_site().is_null()) return feedback_site()->GetPretenureMode(); | |
| 1003 return pretenure_flag_; | |
| 1004 } | |
| 1005 | |
| 1006 private: | |
| 1007 HValue* current_site_; | |
| 1008 Handle<AllocationSite> feedback_site_; | |
| 1009 PretenureFlag pretenure_flag_; | |
| 1010 }; | |
| 1011 | |
| 1012 | |
| 1013 class HGraphBuilder { | |
| 1014 public: | |
| 1015 explicit HGraphBuilder(CompilationInfo* info) | |
| 1016 : info_(info), | |
| 1017 graph_(NULL), | |
| 1018 current_block_(NULL), | |
| 1019 scope_(info->scope()), | |
| 1020 position_(SourcePosition::Unknown()), | |
| 1021 start_position_(0) {} | |
| 1022 virtual ~HGraphBuilder() {} | |
| 1023 | |
| 1024 Scope* scope() const { return scope_; } | |
| 1025 void set_scope(Scope* scope) { scope_ = scope; } | |
| 1026 | |
| 1027 HBasicBlock* current_block() const { return current_block_; } | |
| 1028 void set_current_block(HBasicBlock* block) { current_block_ = block; } | |
| 1029 HEnvironment* environment() const { | |
| 1030 return current_block()->last_environment(); | |
| 1031 } | |
| 1032 Zone* zone() const { return info_->zone(); } | |
| 1033 HGraph* graph() const { return graph_; } | |
| 1034 Isolate* isolate() const { return graph_->isolate(); } | |
| 1035 CompilationInfo* top_info() { return info_; } | |
| 1036 | |
| 1037 HGraph* CreateGraph(); | |
| 1038 | |
| 1039 // Bailout environment manipulation. | |
| 1040 void Push(HValue* value) { environment()->Push(value); } | |
| 1041 HValue* Pop() { return environment()->Pop(); } | |
| 1042 | |
| 1043 virtual HValue* context() = 0; | |
| 1044 | |
| 1045 // Adding instructions. | |
| 1046 HInstruction* AddInstruction(HInstruction* instr); | |
| 1047 void FinishCurrentBlock(HControlInstruction* last); | |
| 1048 void FinishExitCurrentBlock(HControlInstruction* instruction); | |
| 1049 | |
| 1050 void Goto(HBasicBlock* from, | |
| 1051 HBasicBlock* target, | |
| 1052 FunctionState* state = NULL, | |
| 1053 bool add_simulate = true) { | |
| 1054 from->Goto(target, source_position(), state, add_simulate); | |
| 1055 } | |
| 1056 void Goto(HBasicBlock* target, | |
| 1057 FunctionState* state = NULL, | |
| 1058 bool add_simulate = true) { | |
| 1059 Goto(current_block(), target, state, add_simulate); | |
| 1060 } | |
| 1061 void GotoNoSimulate(HBasicBlock* from, HBasicBlock* target) { | |
| 1062 Goto(from, target, NULL, false); | |
| 1063 } | |
| 1064 void GotoNoSimulate(HBasicBlock* target) { | |
| 1065 Goto(target, NULL, false); | |
| 1066 } | |
| 1067 void AddLeaveInlined(HBasicBlock* block, | |
| 1068 HValue* return_value, | |
| 1069 FunctionState* state) { | |
| 1070 block->AddLeaveInlined(return_value, state, source_position()); | |
| 1071 } | |
| 1072 void AddLeaveInlined(HValue* return_value, FunctionState* state) { | |
| 1073 return AddLeaveInlined(current_block(), return_value, state); | |
| 1074 } | |
| 1075 | |
| 1076 template <class I> | |
| 1077 HInstruction* NewUncasted() { | |
| 1078 return I::New(isolate(), zone(), context()); | |
| 1079 } | |
| 1080 | |
| 1081 template <class I> | |
| 1082 I* New() { | |
| 1083 return I::New(isolate(), zone(), context()); | |
| 1084 } | |
| 1085 | |
| 1086 template<class I> | |
| 1087 HInstruction* AddUncasted() { return AddInstruction(NewUncasted<I>());} | |
| 1088 | |
| 1089 template<class I> | |
| 1090 I* Add() { return AddInstructionTyped(New<I>());} | |
| 1091 | |
| 1092 template<class I, class P1> | |
| 1093 HInstruction* NewUncasted(P1 p1) { | |
| 1094 return I::New(isolate(), zone(), context(), p1); | |
| 1095 } | |
| 1096 | |
| 1097 template <class I, class P1> | |
| 1098 I* New(P1 p1) { | |
| 1099 return I::New(isolate(), zone(), context(), p1); | |
| 1100 } | |
| 1101 | |
| 1102 template<class I, class P1> | |
| 1103 HInstruction* AddUncasted(P1 p1) { | |
| 1104 HInstruction* result = AddInstruction(NewUncasted<I>(p1)); | |
| 1105 // Specializations must have their parameters properly casted | |
| 1106 // to avoid landing here. | |
| 1107 DCHECK(!result->IsReturn() && !result->IsSimulate() && | |
| 1108 !result->IsDeoptimize()); | |
| 1109 return result; | |
| 1110 } | |
| 1111 | |
| 1112 template<class I, class P1> | |
| 1113 I* Add(P1 p1) { | |
| 1114 I* result = AddInstructionTyped(New<I>(p1)); | |
| 1115 // Specializations must have their parameters properly casted | |
| 1116 // to avoid landing here. | |
| 1117 DCHECK(!result->IsReturn() && !result->IsSimulate() && | |
| 1118 !result->IsDeoptimize()); | |
| 1119 return result; | |
| 1120 } | |
| 1121 | |
| 1122 template<class I, class P1, class P2> | |
| 1123 HInstruction* NewUncasted(P1 p1, P2 p2) { | |
| 1124 return I::New(isolate(), zone(), context(), p1, p2); | |
| 1125 } | |
| 1126 | |
| 1127 template<class I, class P1, class P2> | |
| 1128 I* New(P1 p1, P2 p2) { | |
| 1129 return I::New(isolate(), zone(), context(), p1, p2); | |
| 1130 } | |
| 1131 | |
| 1132 template<class I, class P1, class P2> | |
| 1133 HInstruction* AddUncasted(P1 p1, P2 p2) { | |
| 1134 HInstruction* result = AddInstruction(NewUncasted<I>(p1, p2)); | |
| 1135 // Specializations must have their parameters properly casted | |
| 1136 // to avoid landing here. | |
| 1137 DCHECK(!result->IsSimulate()); | |
| 1138 return result; | |
| 1139 } | |
| 1140 | |
| 1141 template<class I, class P1, class P2> | |
| 1142 I* Add(P1 p1, P2 p2) { | |
| 1143 I* result = AddInstructionTyped(New<I>(p1, p2)); | |
| 1144 // Specializations must have their parameters properly casted | |
| 1145 // to avoid landing here. | |
| 1146 DCHECK(!result->IsSimulate()); | |
| 1147 return result; | |
| 1148 } | |
| 1149 | |
| 1150 template<class I, class P1, class P2, class P3> | |
| 1151 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3) { | |
| 1152 return I::New(isolate(), zone(), context(), p1, p2, p3); | |
| 1153 } | |
| 1154 | |
| 1155 template<class I, class P1, class P2, class P3> | |
| 1156 I* New(P1 p1, P2 p2, P3 p3) { | |
| 1157 return I::New(isolate(), zone(), context(), p1, p2, p3); | |
| 1158 } | |
| 1159 | |
| 1160 template<class I, class P1, class P2, class P3> | |
| 1161 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3) { | |
| 1162 return AddInstruction(NewUncasted<I>(p1, p2, p3)); | |
| 1163 } | |
| 1164 | |
| 1165 template<class I, class P1, class P2, class P3> | |
| 1166 I* Add(P1 p1, P2 p2, P3 p3) { | |
| 1167 return AddInstructionTyped(New<I>(p1, p2, p3)); | |
| 1168 } | |
| 1169 | |
| 1170 template<class I, class P1, class P2, class P3, class P4> | |
| 1171 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4) { | |
| 1172 return I::New(isolate(), zone(), context(), p1, p2, p3, p4); | |
| 1173 } | |
| 1174 | |
| 1175 template<class I, class P1, class P2, class P3, class P4> | |
| 1176 I* New(P1 p1, P2 p2, P3 p3, P4 p4) { | |
| 1177 return I::New(isolate(), zone(), context(), p1, p2, p3, p4); | |
| 1178 } | |
| 1179 | |
| 1180 template<class I, class P1, class P2, class P3, class P4> | |
| 1181 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4) { | |
| 1182 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4)); | |
| 1183 } | |
| 1184 | |
| 1185 template<class I, class P1, class P2, class P3, class P4> | |
| 1186 I* Add(P1 p1, P2 p2, P3 p3, P4 p4) { | |
| 1187 return AddInstructionTyped(New<I>(p1, p2, p3, p4)); | |
| 1188 } | |
| 1189 | |
| 1190 template<class I, class P1, class P2, class P3, class P4, class P5> | |
| 1191 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { | |
| 1192 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5); | |
| 1193 } | |
| 1194 | |
| 1195 template<class I, class P1, class P2, class P3, class P4, class P5> | |
| 1196 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { | |
| 1197 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5); | |
| 1198 } | |
| 1199 | |
| 1200 template<class I, class P1, class P2, class P3, class P4, class P5> | |
| 1201 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { | |
| 1202 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5)); | |
| 1203 } | |
| 1204 | |
| 1205 template<class I, class P1, class P2, class P3, class P4, class P5> | |
| 1206 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { | |
| 1207 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5)); | |
| 1208 } | |
| 1209 | |
| 1210 template<class I, class P1, class P2, class P3, class P4, class P5, class P6> | |
| 1211 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { | |
| 1212 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6); | |
| 1213 } | |
| 1214 | |
| 1215 template<class I, class P1, class P2, class P3, class P4, class P5, class P6> | |
| 1216 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { | |
| 1217 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6); | |
| 1218 } | |
| 1219 | |
| 1220 template<class I, class P1, class P2, class P3, class P4, class P5, class P6> | |
| 1221 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { | |
| 1222 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6)); | |
| 1223 } | |
| 1224 | |
| 1225 template<class I, class P1, class P2, class P3, class P4, class P5, class P6> | |
| 1226 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6) { | |
| 1227 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6)); | |
| 1228 } | |
| 1229 | |
| 1230 template<class I, class P1, class P2, class P3, class P4, | |
| 1231 class P5, class P6, class P7> | |
| 1232 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { | |
| 1233 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7); | |
| 1234 } | |
| 1235 | |
| 1236 template<class I, class P1, class P2, class P3, class P4, | |
| 1237 class P5, class P6, class P7> | |
| 1238 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { | |
| 1239 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7); | |
| 1240 } | |
| 1241 | |
| 1242 template<class I, class P1, class P2, class P3, | |
| 1243 class P4, class P5, class P6, class P7> | |
| 1244 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { | |
| 1245 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7)); | |
| 1246 } | |
| 1247 | |
| 1248 template<class I, class P1, class P2, class P3, | |
| 1249 class P4, class P5, class P6, class P7> | |
| 1250 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7) { | |
| 1251 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7)); | |
| 1252 } | |
| 1253 | |
| 1254 template<class I, class P1, class P2, class P3, class P4, | |
| 1255 class P5, class P6, class P7, class P8> | |
| 1256 HInstruction* NewUncasted(P1 p1, P2 p2, P3 p3, P4 p4, | |
| 1257 P5 p5, P6 p6, P7 p7, P8 p8) { | |
| 1258 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8); | |
| 1259 } | |
| 1260 | |
| 1261 template<class I, class P1, class P2, class P3, class P4, | |
| 1262 class P5, class P6, class P7, class P8> | |
| 1263 I* New(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) { | |
| 1264 return I::New(isolate(), zone(), context(), p1, p2, p3, p4, p5, p6, p7, p8); | |
| 1265 } | |
| 1266 | |
| 1267 template<class I, class P1, class P2, class P3, class P4, | |
| 1268 class P5, class P6, class P7, class P8> | |
| 1269 HInstruction* AddUncasted(P1 p1, P2 p2, P3 p3, P4 p4, | |
| 1270 P5 p5, P6 p6, P7 p7, P8 p8) { | |
| 1271 return AddInstruction(NewUncasted<I>(p1, p2, p3, p4, p5, p6, p7, p8)); | |
| 1272 } | |
| 1273 | |
| 1274 template<class I, class P1, class P2, class P3, class P4, | |
| 1275 class P5, class P6, class P7, class P8> | |
| 1276 I* Add(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5, P6 p6, P7 p7, P8 p8) { | |
| 1277 return AddInstructionTyped(New<I>(p1, p2, p3, p4, p5, p6, p7, p8)); | |
| 1278 } | |
| 1279 | |
| 1280 void AddSimulate(BailoutId id, RemovableSimulate removable = FIXED_SIMULATE); | |
| 1281 | |
| 1282 // When initializing arrays, we'll unfold the loop if the number of elements | |
| 1283 // is known at compile time and is <= kElementLoopUnrollThreshold. | |
| 1284 static const int kElementLoopUnrollThreshold = 8; | |
| 1285 | |
| 1286 protected: | |
| 1287 virtual bool BuildGraph() = 0; | |
| 1288 | |
| 1289 HBasicBlock* CreateBasicBlock(HEnvironment* env); | |
| 1290 HBasicBlock* CreateLoopHeaderBlock(); | |
| 1291 | |
| 1292 template <class BitFieldClass> | |
| 1293 HValue* BuildDecodeField(HValue* encoded_field) { | |
| 1294 HValue* mask_value = Add<HConstant>(static_cast<int>(BitFieldClass::kMask)); | |
| 1295 HValue* masked_field = | |
| 1296 AddUncasted<HBitwise>(Token::BIT_AND, encoded_field, mask_value); | |
| 1297 return AddUncasted<HShr>(masked_field, | |
| 1298 Add<HConstant>(static_cast<int>(BitFieldClass::kShift))); | |
| 1299 } | |
| 1300 | |
| 1301 HValue* BuildGetElementsKind(HValue* object); | |
| 1302 | |
| 1303 HValue* BuildCheckHeapObject(HValue* object); | |
| 1304 HValue* BuildCheckString(HValue* string); | |
| 1305 HValue* BuildWrapReceiver(HValue* object, HValue* function); | |
| 1306 | |
| 1307 // Building common constructs | |
| 1308 HValue* BuildCheckForCapacityGrow(HValue* object, | |
| 1309 HValue* elements, | |
| 1310 ElementsKind kind, | |
| 1311 HValue* length, | |
| 1312 HValue* key, | |
| 1313 bool is_js_array, | |
| 1314 PropertyAccessType access_type); | |
| 1315 | |
| 1316 HValue* BuildCheckAndGrowElementsCapacity(HValue* object, HValue* elements, | |
| 1317 ElementsKind kind, HValue* length, | |
| 1318 HValue* capacity, HValue* key); | |
| 1319 | |
| 1320 HValue* BuildCopyElementsOnWrite(HValue* object, | |
| 1321 HValue* elements, | |
| 1322 ElementsKind kind, | |
| 1323 HValue* length); | |
| 1324 | |
| 1325 void BuildTransitionElementsKind(HValue* object, | |
| 1326 HValue* map, | |
| 1327 ElementsKind from_kind, | |
| 1328 ElementsKind to_kind, | |
| 1329 bool is_jsarray); | |
| 1330 | |
| 1331 HValue* BuildNumberToString(HValue* object, Type* type); | |
| 1332 HValue* BuildToObject(HValue* receiver); | |
| 1333 | |
| 1334 void BuildJSObjectCheck(HValue* receiver, | |
| 1335 int bit_field_mask); | |
| 1336 | |
| 1337 // Checks a key value that's being used for a keyed element access context. If | |
| 1338 // the key is a index, i.e. a smi or a number in a unique string with a cached | |
| 1339 // numeric value, the "true" of the continuation is joined. Otherwise, | |
| 1340 // if the key is a name or a unique string, the "false" of the continuation is | |
| 1341 // joined. Otherwise, a deoptimization is triggered. In both paths of the | |
| 1342 // continuation, the key is pushed on the top of the environment. | |
| 1343 void BuildKeyedIndexCheck(HValue* key, | |
| 1344 HIfContinuation* join_continuation); | |
| 1345 | |
| 1346 // Checks the properties of an object if they are in dictionary case, in which | |
| 1347 // case "true" of continuation is taken, otherwise the "false" | |
| 1348 void BuildTestForDictionaryProperties(HValue* object, | |
| 1349 HIfContinuation* continuation); | |
| 1350 | |
| 1351 void BuildNonGlobalObjectCheck(HValue* receiver); | |
| 1352 | |
| 1353 HValue* BuildKeyedLookupCacheHash(HValue* object, | |
| 1354 HValue* key); | |
| 1355 | |
| 1356 HValue* BuildUncheckedDictionaryElementLoad(HValue* receiver, | |
| 1357 HValue* elements, HValue* key, | |
| 1358 HValue* hash, | |
| 1359 LanguageMode language_mode); | |
| 1360 | |
| 1361 // ES6 section 7.4.7 CreateIterResultObject ( value, done ) | |
| 1362 HValue* BuildCreateIterResultObject(HValue* value, HValue* done); | |
| 1363 | |
| 1364 HValue* BuildRegExpConstructResult(HValue* length, | |
| 1365 HValue* index, | |
| 1366 HValue* input); | |
| 1367 | |
| 1368 // Allocates a new object according with the given allocation properties. | |
| 1369 HAllocate* BuildAllocate(HValue* object_size, | |
| 1370 HType type, | |
| 1371 InstanceType instance_type, | |
| 1372 HAllocationMode allocation_mode); | |
| 1373 // Computes the sum of two string lengths, taking care of overflow handling. | |
| 1374 HValue* BuildAddStringLengths(HValue* left_length, HValue* right_length); | |
| 1375 // Creates a cons string using the two input strings. | |
| 1376 HValue* BuildCreateConsString(HValue* length, | |
| 1377 HValue* left, | |
| 1378 HValue* right, | |
| 1379 HAllocationMode allocation_mode); | |
| 1380 // Copies characters from one sequential string to another. | |
| 1381 void BuildCopySeqStringChars(HValue* src, | |
| 1382 HValue* src_offset, | |
| 1383 String::Encoding src_encoding, | |
| 1384 HValue* dst, | |
| 1385 HValue* dst_offset, | |
| 1386 String::Encoding dst_encoding, | |
| 1387 HValue* length); | |
| 1388 | |
| 1389 // Align an object size to object alignment boundary | |
| 1390 HValue* BuildObjectSizeAlignment(HValue* unaligned_size, int header_size); | |
| 1391 | |
| 1392 // Both operands are non-empty strings. | |
| 1393 HValue* BuildUncheckedStringAdd(HValue* left, | |
| 1394 HValue* right, | |
| 1395 HAllocationMode allocation_mode); | |
| 1396 // Add two strings using allocation mode, validating type feedback. | |
| 1397 HValue* BuildStringAdd(HValue* left, | |
| 1398 HValue* right, | |
| 1399 HAllocationMode allocation_mode); | |
| 1400 | |
| 1401 HInstruction* BuildUncheckedMonomorphicElementAccess( | |
| 1402 HValue* checked_object, | |
| 1403 HValue* key, | |
| 1404 HValue* val, | |
| 1405 bool is_js_array, | |
| 1406 ElementsKind elements_kind, | |
| 1407 PropertyAccessType access_type, | |
| 1408 LoadKeyedHoleMode load_mode, | |
| 1409 KeyedAccessStoreMode store_mode); | |
| 1410 | |
| 1411 HInstruction* AddElementAccess( | |
| 1412 HValue* elements, | |
| 1413 HValue* checked_key, | |
| 1414 HValue* val, | |
| 1415 HValue* dependency, | |
| 1416 ElementsKind elements_kind, | |
| 1417 PropertyAccessType access_type, | |
| 1418 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE); | |
| 1419 | |
| 1420 HInstruction* AddLoadStringInstanceType(HValue* string); | |
| 1421 HInstruction* AddLoadStringLength(HValue* string); | |
| 1422 HInstruction* BuildLoadStringLength(HValue* string); | |
| 1423 HStoreNamedField* AddStoreMapConstant(HValue* object, Handle<Map> map) { | |
| 1424 return Add<HStoreNamedField>(object, HObjectAccess::ForMap(), | |
| 1425 Add<HConstant>(map)); | |
| 1426 } | |
| 1427 HLoadNamedField* AddLoadMap(HValue* object, | |
| 1428 HValue* dependency = NULL); | |
| 1429 HLoadNamedField* AddLoadElements(HValue* object, | |
| 1430 HValue* dependency = NULL); | |
| 1431 | |
| 1432 bool MatchRotateRight(HValue* left, | |
| 1433 HValue* right, | |
| 1434 HValue** operand, | |
| 1435 HValue** shift_amount); | |
| 1436 | |
| 1437 HValue* BuildBinaryOperation(Token::Value op, HValue* left, HValue* right, | |
| 1438 Type* left_type, Type* right_type, | |
| 1439 Type* result_type, Maybe<int> fixed_right_arg, | |
| 1440 HAllocationMode allocation_mode, | |
| 1441 Strength strength, | |
| 1442 BailoutId opt_id = BailoutId::None()); | |
| 1443 | |
| 1444 HLoadNamedField* AddLoadFixedArrayLength(HValue *object, | |
| 1445 HValue *dependency = NULL); | |
| 1446 | |
| 1447 HLoadNamedField* AddLoadArrayLength(HValue *object, | |
| 1448 ElementsKind kind, | |
| 1449 HValue *dependency = NULL); | |
| 1450 | |
| 1451 HValue* AddLoadJSBuiltin(int context_index); | |
| 1452 | |
| 1453 HValue* EnforceNumberType(HValue* number, Type* expected); | |
| 1454 HValue* TruncateToNumber(HValue* value, Type** expected); | |
| 1455 | |
| 1456 void FinishExitWithHardDeoptimization(Deoptimizer::DeoptReason reason); | |
| 1457 | |
| 1458 void AddIncrementCounter(StatsCounter* counter); | |
| 1459 | |
| 1460 class IfBuilder final { | |
| 1461 public: | |
| 1462 // If using this constructor, Initialize() must be called explicitly! | |
| 1463 IfBuilder(); | |
| 1464 | |
| 1465 explicit IfBuilder(HGraphBuilder* builder); | |
| 1466 IfBuilder(HGraphBuilder* builder, | |
| 1467 HIfContinuation* continuation); | |
| 1468 | |
| 1469 ~IfBuilder() { | |
| 1470 if (!finished_) End(); | |
| 1471 } | |
| 1472 | |
| 1473 void Initialize(HGraphBuilder* builder); | |
| 1474 | |
| 1475 template<class Condition> | |
| 1476 Condition* If(HValue *p) { | |
| 1477 Condition* compare = builder()->New<Condition>(p); | |
| 1478 AddCompare(compare); | |
| 1479 return compare; | |
| 1480 } | |
| 1481 | |
| 1482 template<class Condition, class P2> | |
| 1483 Condition* If(HValue* p1, P2 p2) { | |
| 1484 Condition* compare = builder()->New<Condition>(p1, p2); | |
| 1485 AddCompare(compare); | |
| 1486 return compare; | |
| 1487 } | |
| 1488 | |
| 1489 template<class Condition, class P2, class P3> | |
| 1490 Condition* If(HValue* p1, P2 p2, P3 p3) { | |
| 1491 Condition* compare = builder()->New<Condition>(p1, p2, p3); | |
| 1492 AddCompare(compare); | |
| 1493 return compare; | |
| 1494 } | |
| 1495 | |
| 1496 template<class Condition> | |
| 1497 Condition* IfNot(HValue* p) { | |
| 1498 Condition* compare = If<Condition>(p); | |
| 1499 compare->Not(); | |
| 1500 return compare; | |
| 1501 } | |
| 1502 | |
| 1503 template<class Condition, class P2> | |
| 1504 Condition* IfNot(HValue* p1, P2 p2) { | |
| 1505 Condition* compare = If<Condition>(p1, p2); | |
| 1506 compare->Not(); | |
| 1507 return compare; | |
| 1508 } | |
| 1509 | |
| 1510 template<class Condition, class P2, class P3> | |
| 1511 Condition* IfNot(HValue* p1, P2 p2, P3 p3) { | |
| 1512 Condition* compare = If<Condition>(p1, p2, p3); | |
| 1513 compare->Not(); | |
| 1514 return compare; | |
| 1515 } | |
| 1516 | |
| 1517 template<class Condition> | |
| 1518 Condition* OrIf(HValue *p) { | |
| 1519 Or(); | |
| 1520 return If<Condition>(p); | |
| 1521 } | |
| 1522 | |
| 1523 template<class Condition, class P2> | |
| 1524 Condition* OrIf(HValue* p1, P2 p2) { | |
| 1525 Or(); | |
| 1526 return If<Condition>(p1, p2); | |
| 1527 } | |
| 1528 | |
| 1529 template<class Condition, class P2, class P3> | |
| 1530 Condition* OrIf(HValue* p1, P2 p2, P3 p3) { | |
| 1531 Or(); | |
| 1532 return If<Condition>(p1, p2, p3); | |
| 1533 } | |
| 1534 | |
| 1535 template<class Condition> | |
| 1536 Condition* AndIf(HValue *p) { | |
| 1537 And(); | |
| 1538 return If<Condition>(p); | |
| 1539 } | |
| 1540 | |
| 1541 template<class Condition, class P2> | |
| 1542 Condition* AndIf(HValue* p1, P2 p2) { | |
| 1543 And(); | |
| 1544 return If<Condition>(p1, p2); | |
| 1545 } | |
| 1546 | |
| 1547 template<class Condition, class P2, class P3> | |
| 1548 Condition* AndIf(HValue* p1, P2 p2, P3 p3) { | |
| 1549 And(); | |
| 1550 return If<Condition>(p1, p2, p3); | |
| 1551 } | |
| 1552 | |
| 1553 void Or(); | |
| 1554 void And(); | |
| 1555 | |
| 1556 // Captures the current state of this IfBuilder in the specified | |
| 1557 // continuation and ends this IfBuilder. | |
| 1558 void CaptureContinuation(HIfContinuation* continuation); | |
| 1559 | |
| 1560 // Joins the specified continuation from this IfBuilder and ends this | |
| 1561 // IfBuilder. This appends a Goto instruction from the true branch of | |
| 1562 // this IfBuilder to the true branch of the continuation unless the | |
| 1563 // true branch of this IfBuilder is already finished. And vice versa | |
| 1564 // for the false branch. | |
| 1565 // | |
| 1566 // The basic idea is as follows: You have several nested IfBuilder's | |
| 1567 // that you want to join based on two possible outcomes (i.e. success | |
| 1568 // and failure, or whatever). You can do this easily using this method | |
| 1569 // now, for example: | |
| 1570 // | |
| 1571 // HIfContinuation cont(graph()->CreateBasicBlock(), | |
| 1572 // graph()->CreateBasicBlock()); | |
| 1573 // ... | |
| 1574 // IfBuilder if_whatever(this); | |
| 1575 // if_whatever.If<Condition>(arg); | |
| 1576 // if_whatever.Then(); | |
| 1577 // ... | |
| 1578 // if_whatever.Else(); | |
| 1579 // ... | |
| 1580 // if_whatever.JoinContinuation(&cont); | |
| 1581 // ... | |
| 1582 // IfBuilder if_something(this); | |
| 1583 // if_something.If<Condition>(arg1, arg2); | |
| 1584 // if_something.Then(); | |
| 1585 // ... | |
| 1586 // if_something.Else(); | |
| 1587 // ... | |
| 1588 // if_something.JoinContinuation(&cont); | |
| 1589 // ... | |
| 1590 // IfBuilder if_finally(this, &cont); | |
| 1591 // if_finally.Then(); | |
| 1592 // // continues after then code of if_whatever or if_something. | |
| 1593 // ... | |
| 1594 // if_finally.Else(); | |
| 1595 // // continues after else code of if_whatever or if_something. | |
| 1596 // ... | |
| 1597 // if_finally.End(); | |
| 1598 void JoinContinuation(HIfContinuation* continuation); | |
| 1599 | |
| 1600 void Then(); | |
| 1601 void Else(); | |
| 1602 void End(); | |
| 1603 void EndUnreachable(); | |
| 1604 | |
| 1605 void Deopt(Deoptimizer::DeoptReason reason); | |
| 1606 void ThenDeopt(Deoptimizer::DeoptReason reason) { | |
| 1607 Then(); | |
| 1608 Deopt(reason); | |
| 1609 } | |
| 1610 void ElseDeopt(Deoptimizer::DeoptReason reason) { | |
| 1611 Else(); | |
| 1612 Deopt(reason); | |
| 1613 } | |
| 1614 | |
| 1615 void Return(HValue* value); | |
| 1616 | |
| 1617 private: | |
| 1618 void InitializeDontCreateBlocks(HGraphBuilder* builder); | |
| 1619 | |
| 1620 HControlInstruction* AddCompare(HControlInstruction* compare); | |
| 1621 | |
| 1622 HGraphBuilder* builder() const { | |
| 1623 DCHECK(builder_ != NULL); // Have you called "Initialize"? | |
| 1624 return builder_; | |
| 1625 } | |
| 1626 | |
| 1627 void AddMergeAtJoinBlock(bool deopt); | |
| 1628 | |
| 1629 void Finish(); | |
| 1630 void Finish(HBasicBlock** then_continuation, | |
| 1631 HBasicBlock** else_continuation); | |
| 1632 | |
| 1633 class MergeAtJoinBlock : public ZoneObject { | |
| 1634 public: | |
| 1635 MergeAtJoinBlock(HBasicBlock* block, | |
| 1636 bool deopt, | |
| 1637 MergeAtJoinBlock* next) | |
| 1638 : block_(block), | |
| 1639 deopt_(deopt), | |
| 1640 next_(next) {} | |
| 1641 HBasicBlock* block_; | |
| 1642 bool deopt_; | |
| 1643 MergeAtJoinBlock* next_; | |
| 1644 }; | |
| 1645 | |
| 1646 HGraphBuilder* builder_; | |
| 1647 bool finished_ : 1; | |
| 1648 bool did_then_ : 1; | |
| 1649 bool did_else_ : 1; | |
| 1650 bool did_else_if_ : 1; | |
| 1651 bool did_and_ : 1; | |
| 1652 bool did_or_ : 1; | |
| 1653 bool captured_ : 1; | |
| 1654 bool needs_compare_ : 1; | |
| 1655 bool pending_merge_block_ : 1; | |
| 1656 HBasicBlock* first_true_block_; | |
| 1657 HBasicBlock* first_false_block_; | |
| 1658 HBasicBlock* split_edge_merge_block_; | |
| 1659 MergeAtJoinBlock* merge_at_join_blocks_; | |
| 1660 int normal_merge_at_join_block_count_; | |
| 1661 int deopt_merge_at_join_block_count_; | |
| 1662 }; | |
| 1663 | |
| 1664 class LoopBuilder final { | |
| 1665 public: | |
| 1666 enum Direction { | |
| 1667 kPreIncrement, | |
| 1668 kPostIncrement, | |
| 1669 kPreDecrement, | |
| 1670 kPostDecrement, | |
| 1671 kWhileTrue | |
| 1672 }; | |
| 1673 | |
| 1674 explicit LoopBuilder(HGraphBuilder* builder); // while (true) {...} | |
| 1675 LoopBuilder(HGraphBuilder* builder, | |
| 1676 HValue* context, | |
| 1677 Direction direction); | |
| 1678 LoopBuilder(HGraphBuilder* builder, | |
| 1679 HValue* context, | |
| 1680 Direction direction, | |
| 1681 HValue* increment_amount); | |
| 1682 | |
| 1683 ~LoopBuilder() { | |
| 1684 DCHECK(finished_); | |
| 1685 } | |
| 1686 | |
| 1687 HValue* BeginBody( | |
| 1688 HValue* initial, | |
| 1689 HValue* terminating, | |
| 1690 Token::Value token); | |
| 1691 | |
| 1692 void BeginBody(int drop_count); | |
| 1693 | |
| 1694 void Break(); | |
| 1695 | |
| 1696 void EndBody(); | |
| 1697 | |
| 1698 private: | |
| 1699 void Initialize(HGraphBuilder* builder, HValue* context, | |
| 1700 Direction direction, HValue* increment_amount); | |
| 1701 Zone* zone() { return builder_->zone(); } | |
| 1702 | |
| 1703 HGraphBuilder* builder_; | |
| 1704 HValue* context_; | |
| 1705 HValue* increment_amount_; | |
| 1706 HInstruction* increment_; | |
| 1707 HPhi* phi_; | |
| 1708 HBasicBlock* header_block_; | |
| 1709 HBasicBlock* body_block_; | |
| 1710 HBasicBlock* exit_block_; | |
| 1711 HBasicBlock* exit_trampoline_block_; | |
| 1712 Direction direction_; | |
| 1713 bool finished_; | |
| 1714 }; | |
| 1715 | |
| 1716 HValue* BuildNewElementsCapacity(HValue* old_capacity); | |
| 1717 | |
| 1718 class JSArrayBuilder final { | |
| 1719 public: | |
| 1720 JSArrayBuilder(HGraphBuilder* builder, | |
| 1721 ElementsKind kind, | |
| 1722 HValue* allocation_site_payload, | |
| 1723 HValue* constructor_function, | |
| 1724 AllocationSiteOverrideMode override_mode); | |
| 1725 | |
| 1726 JSArrayBuilder(HGraphBuilder* builder, | |
| 1727 ElementsKind kind, | |
| 1728 HValue* constructor_function = NULL); | |
| 1729 | |
| 1730 enum FillMode { | |
| 1731 DONT_FILL_WITH_HOLE, | |
| 1732 FILL_WITH_HOLE | |
| 1733 }; | |
| 1734 | |
| 1735 ElementsKind kind() { return kind_; } | |
| 1736 HAllocate* elements_location() { return elements_location_; } | |
| 1737 | |
| 1738 HAllocate* AllocateEmptyArray(); | |
| 1739 HAllocate* AllocateArray(HValue* capacity, | |
| 1740 HValue* length_field, | |
| 1741 FillMode fill_mode = FILL_WITH_HOLE); | |
| 1742 // Use these allocators when capacity could be unknown at compile time | |
| 1743 // but its limit is known. For constant |capacity| the value of | |
| 1744 // |capacity_upper_bound| is ignored and the actual |capacity| | |
| 1745 // value is used as an upper bound. | |
| 1746 HAllocate* AllocateArray(HValue* capacity, | |
| 1747 int capacity_upper_bound, | |
| 1748 HValue* length_field, | |
| 1749 FillMode fill_mode = FILL_WITH_HOLE); | |
| 1750 HAllocate* AllocateArray(HValue* capacity, | |
| 1751 HConstant* capacity_upper_bound, | |
| 1752 HValue* length_field, | |
| 1753 FillMode fill_mode = FILL_WITH_HOLE); | |
| 1754 HValue* GetElementsLocation() { return elements_location_; } | |
| 1755 HValue* EmitMapCode(); | |
| 1756 | |
| 1757 private: | |
| 1758 Zone* zone() const { return builder_->zone(); } | |
| 1759 int elements_size() const { | |
| 1760 return IsFastDoubleElementsKind(kind_) ? kDoubleSize : kPointerSize; | |
| 1761 } | |
| 1762 HGraphBuilder* builder() { return builder_; } | |
| 1763 HGraph* graph() { return builder_->graph(); } | |
| 1764 int initial_capacity() { | |
| 1765 STATIC_ASSERT(JSArray::kPreallocatedArrayElements > 0); | |
| 1766 return JSArray::kPreallocatedArrayElements; | |
| 1767 } | |
| 1768 | |
| 1769 HValue* EmitInternalMapCode(); | |
| 1770 | |
| 1771 HGraphBuilder* builder_; | |
| 1772 ElementsKind kind_; | |
| 1773 AllocationSiteMode mode_; | |
| 1774 HValue* allocation_site_payload_; | |
| 1775 HValue* constructor_function_; | |
| 1776 HAllocate* elements_location_; | |
| 1777 }; | |
| 1778 | |
| 1779 HValue* BuildAllocateArrayFromLength(JSArrayBuilder* array_builder, | |
| 1780 HValue* length_argument); | |
| 1781 HValue* BuildCalculateElementsSize(ElementsKind kind, | |
| 1782 HValue* capacity); | |
| 1783 HAllocate* AllocateJSArrayObject(AllocationSiteMode mode); | |
| 1784 HConstant* EstablishElementsAllocationSize(ElementsKind kind, int capacity); | |
| 1785 | |
| 1786 HAllocate* BuildAllocateElements(ElementsKind kind, HValue* size_in_bytes); | |
| 1787 | |
| 1788 void BuildInitializeElementsHeader(HValue* elements, | |
| 1789 ElementsKind kind, | |
| 1790 HValue* capacity); | |
| 1791 | |
| 1792 // Build allocation and header initialization code for respective successor | |
| 1793 // of FixedArrayBase. | |
| 1794 HValue* BuildAllocateAndInitializeArray(ElementsKind kind, HValue* capacity); | |
| 1795 | |
| 1796 // |array| must have been allocated with enough room for | |
| 1797 // 1) the JSArray and 2) an AllocationMemento if mode requires it. | |
| 1798 // If the |elements| value provided is NULL then the array elements storage | |
| 1799 // is initialized with empty array. | |
| 1800 void BuildJSArrayHeader(HValue* array, | |
| 1801 HValue* array_map, | |
| 1802 HValue* elements, | |
| 1803 AllocationSiteMode mode, | |
| 1804 ElementsKind elements_kind, | |
| 1805 HValue* allocation_site_payload, | |
| 1806 HValue* length_field); | |
| 1807 | |
| 1808 HValue* BuildGrowElementsCapacity(HValue* object, | |
| 1809 HValue* elements, | |
| 1810 ElementsKind kind, | |
| 1811 ElementsKind new_kind, | |
| 1812 HValue* length, | |
| 1813 HValue* new_capacity); | |
| 1814 | |
| 1815 void BuildFillElementsWithValue(HValue* elements, | |
| 1816 ElementsKind elements_kind, | |
| 1817 HValue* from, | |
| 1818 HValue* to, | |
| 1819 HValue* value); | |
| 1820 | |
| 1821 void BuildFillElementsWithHole(HValue* elements, | |
| 1822 ElementsKind elements_kind, | |
| 1823 HValue* from, | |
| 1824 HValue* to); | |
| 1825 | |
| 1826 void BuildCopyProperties(HValue* from_properties, HValue* to_properties, | |
| 1827 HValue* length, HValue* capacity); | |
| 1828 | |
| 1829 void BuildCopyElements(HValue* from_elements, | |
| 1830 ElementsKind from_elements_kind, | |
| 1831 HValue* to_elements, | |
| 1832 ElementsKind to_elements_kind, | |
| 1833 HValue* length, | |
| 1834 HValue* capacity); | |
| 1835 | |
| 1836 HValue* BuildCloneShallowArrayCow(HValue* boilerplate, | |
| 1837 HValue* allocation_site, | |
| 1838 AllocationSiteMode mode, | |
| 1839 ElementsKind kind); | |
| 1840 | |
| 1841 HValue* BuildCloneShallowArrayEmpty(HValue* boilerplate, | |
| 1842 HValue* allocation_site, | |
| 1843 AllocationSiteMode mode); | |
| 1844 | |
| 1845 HValue* BuildCloneShallowArrayNonEmpty(HValue* boilerplate, | |
| 1846 HValue* allocation_site, | |
| 1847 AllocationSiteMode mode, | |
| 1848 ElementsKind kind); | |
| 1849 | |
| 1850 HValue* BuildElementIndexHash(HValue* index); | |
| 1851 | |
| 1852 enum MapEmbedding { kEmbedMapsDirectly, kEmbedMapsViaWeakCells }; | |
| 1853 | |
| 1854 void BuildCompareNil(HValue* value, Type* type, HIfContinuation* continuation, | |
| 1855 MapEmbedding map_embedding = kEmbedMapsDirectly); | |
| 1856 | |
| 1857 void BuildCreateAllocationMemento(HValue* previous_object, | |
| 1858 HValue* previous_object_size, | |
| 1859 HValue* payload); | |
| 1860 | |
| 1861 HInstruction* BuildConstantMapCheck(Handle<JSObject> constant); | |
| 1862 HInstruction* BuildCheckPrototypeMaps(Handle<JSObject> prototype, | |
| 1863 Handle<JSObject> holder); | |
| 1864 | |
| 1865 HInstruction* BuildGetNativeContext(HValue* closure); | |
| 1866 HInstruction* BuildGetNativeContext(); | |
| 1867 HInstruction* BuildGetScriptContext(int context_index); | |
| 1868 // Builds a loop version if |depth| is specified or unrolls the loop to | |
| 1869 // |depth_value| iterations otherwise. | |
| 1870 HValue* BuildGetParentContext(HValue* depth, int depth_value); | |
| 1871 | |
| 1872 HInstruction* BuildGetArrayFunction(); | |
| 1873 HValue* BuildArrayBufferViewFieldAccessor(HValue* object, | |
| 1874 HValue* checked_object, | |
| 1875 FieldIndex index); | |
| 1876 | |
| 1877 | |
| 1878 protected: | |
| 1879 void SetSourcePosition(int position) { | |
| 1880 if (position != RelocInfo::kNoPosition) { | |
| 1881 position_.set_position(position - start_position_); | |
| 1882 } | |
| 1883 // Otherwise position remains unknown. | |
| 1884 } | |
| 1885 | |
| 1886 void EnterInlinedSource(int start_position, int id) { | |
| 1887 if (top_info()->is_tracking_positions()) { | |
| 1888 start_position_ = start_position; | |
| 1889 position_.set_inlining_id(id); | |
| 1890 } | |
| 1891 } | |
| 1892 | |
| 1893 // Convert the given absolute offset from the start of the script to | |
| 1894 // the SourcePosition assuming that this position corresponds to the | |
| 1895 // same function as current position_. | |
| 1896 SourcePosition ScriptPositionToSourcePosition(int position) { | |
| 1897 if (position == RelocInfo::kNoPosition) { | |
| 1898 return SourcePosition::Unknown(); | |
| 1899 } | |
| 1900 SourcePosition pos = position_; | |
| 1901 pos.set_position(position - start_position_); | |
| 1902 return pos; | |
| 1903 } | |
| 1904 | |
| 1905 SourcePosition source_position() { return position_; } | |
| 1906 void set_source_position(SourcePosition position) { position_ = position; } | |
| 1907 | |
| 1908 HValue* BuildAllocateEmptyArrayBuffer(HValue* byte_length); | |
| 1909 template <typename ViewClass> | |
| 1910 void BuildArrayBufferViewInitialization(HValue* obj, | |
| 1911 HValue* buffer, | |
| 1912 HValue* byte_offset, | |
| 1913 HValue* byte_length); | |
| 1914 | |
| 1915 private: | |
| 1916 HGraphBuilder(); | |
| 1917 | |
| 1918 template <class I> | |
| 1919 I* AddInstructionTyped(I* instr) { | |
| 1920 return I::cast(AddInstruction(instr)); | |
| 1921 } | |
| 1922 | |
| 1923 CompilationInfo* info_; | |
| 1924 HGraph* graph_; | |
| 1925 HBasicBlock* current_block_; | |
| 1926 Scope* scope_; | |
| 1927 SourcePosition position_; | |
| 1928 int start_position_; | |
| 1929 }; | |
| 1930 | |
| 1931 | |
| 1932 template <> | |
| 1933 inline HDeoptimize* HGraphBuilder::Add<HDeoptimize>( | |
| 1934 Deoptimizer::DeoptReason reason, Deoptimizer::BailoutType type) { | |
| 1935 if (type == Deoptimizer::SOFT) { | |
| 1936 isolate()->counters()->soft_deopts_requested()->Increment(); | |
| 1937 if (FLAG_always_opt) return NULL; | |
| 1938 } | |
| 1939 if (current_block()->IsDeoptimizing()) return NULL; | |
| 1940 HBasicBlock* after_deopt_block = CreateBasicBlock( | |
| 1941 current_block()->last_environment()); | |
| 1942 HDeoptimize* instr = New<HDeoptimize>(reason, type, after_deopt_block); | |
| 1943 if (type == Deoptimizer::SOFT) { | |
| 1944 isolate()->counters()->soft_deopts_inserted()->Increment(); | |
| 1945 } | |
| 1946 FinishCurrentBlock(instr); | |
| 1947 set_current_block(after_deopt_block); | |
| 1948 return instr; | |
| 1949 } | |
| 1950 | |
| 1951 | |
| 1952 template <> | |
| 1953 inline HInstruction* HGraphBuilder::AddUncasted<HDeoptimize>( | |
| 1954 Deoptimizer::DeoptReason reason, Deoptimizer::BailoutType type) { | |
| 1955 return Add<HDeoptimize>(reason, type); | |
| 1956 } | |
| 1957 | |
| 1958 | |
| 1959 template<> | |
| 1960 inline HSimulate* HGraphBuilder::Add<HSimulate>( | |
| 1961 BailoutId id, | |
| 1962 RemovableSimulate removable) { | |
| 1963 HSimulate* instr = current_block()->CreateSimulate(id, removable); | |
| 1964 AddInstruction(instr); | |
| 1965 return instr; | |
| 1966 } | |
| 1967 | |
| 1968 | |
| 1969 template<> | |
| 1970 inline HSimulate* HGraphBuilder::Add<HSimulate>( | |
| 1971 BailoutId id) { | |
| 1972 return Add<HSimulate>(id, FIXED_SIMULATE); | |
| 1973 } | |
| 1974 | |
| 1975 | |
| 1976 template<> | |
| 1977 inline HInstruction* HGraphBuilder::AddUncasted<HSimulate>(BailoutId id) { | |
| 1978 return Add<HSimulate>(id, FIXED_SIMULATE); | |
| 1979 } | |
| 1980 | |
| 1981 | |
| 1982 template<> | |
| 1983 inline HReturn* HGraphBuilder::Add<HReturn>(HValue* value) { | |
| 1984 int num_parameters = graph()->info()->num_parameters(); | |
| 1985 HValue* params = AddUncasted<HConstant>(num_parameters); | |
| 1986 HReturn* return_instruction = New<HReturn>(value, params); | |
| 1987 FinishExitCurrentBlock(return_instruction); | |
| 1988 return return_instruction; | |
| 1989 } | |
| 1990 | |
| 1991 | |
| 1992 template<> | |
| 1993 inline HReturn* HGraphBuilder::Add<HReturn>(HConstant* value) { | |
| 1994 return Add<HReturn>(static_cast<HValue*>(value)); | |
| 1995 } | |
| 1996 | |
| 1997 template<> | |
| 1998 inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HValue* value) { | |
| 1999 return Add<HReturn>(value); | |
| 2000 } | |
| 2001 | |
| 2002 | |
| 2003 template<> | |
| 2004 inline HInstruction* HGraphBuilder::AddUncasted<HReturn>(HConstant* value) { | |
| 2005 return Add<HReturn>(value); | |
| 2006 } | |
| 2007 | |
| 2008 | |
| 2009 template<> | |
| 2010 inline HCallRuntime* HGraphBuilder::Add<HCallRuntime>( | |
| 2011 const Runtime::Function* c_function, | |
| 2012 int argument_count) { | |
| 2013 HCallRuntime* instr = New<HCallRuntime>(c_function, argument_count); | |
| 2014 if (graph()->info()->IsStub()) { | |
| 2015 // When compiling code stubs, we don't want to save all double registers | |
| 2016 // upon entry to the stub, but instead have the call runtime instruction | |
| 2017 // save the double registers only on-demand (in the fallback case). | |
| 2018 instr->set_save_doubles(kSaveFPRegs); | |
| 2019 } | |
| 2020 AddInstruction(instr); | |
| 2021 return instr; | |
| 2022 } | |
| 2023 | |
| 2024 | |
| 2025 template<> | |
| 2026 inline HInstruction* HGraphBuilder::AddUncasted<HCallRuntime>( | |
| 2027 Handle<String> name, | |
| 2028 const Runtime::Function* c_function, | |
| 2029 int argument_count) { | |
| 2030 return Add<HCallRuntime>(c_function, argument_count); | |
| 2031 } | |
| 2032 | |
| 2033 | |
| 2034 template <> | |
| 2035 inline HParameter* HGraphBuilder::New<HParameter>(unsigned index) { | |
| 2036 return HParameter::New(isolate(), zone(), nullptr, index); | |
| 2037 } | |
| 2038 | |
| 2039 | |
| 2040 template <> | |
| 2041 inline HParameter* HGraphBuilder::New<HParameter>( | |
| 2042 unsigned index, HParameter::ParameterKind kind) { | |
| 2043 return HParameter::New(isolate(), zone(), nullptr, index, kind); | |
| 2044 } | |
| 2045 | |
| 2046 | |
| 2047 template <> | |
| 2048 inline HParameter* HGraphBuilder::New<HParameter>( | |
| 2049 unsigned index, HParameter::ParameterKind kind, Representation r) { | |
| 2050 return HParameter::New(isolate(), zone(), nullptr, index, kind, r); | |
| 2051 } | |
| 2052 | |
| 2053 | |
| 2054 template <> | |
| 2055 inline HPrologue* HGraphBuilder::New<HPrologue>() { | |
| 2056 return HPrologue::New(zone()); | |
| 2057 } | |
| 2058 | |
| 2059 | |
| 2060 template <> | |
| 2061 inline HContext* HGraphBuilder::New<HContext>() { | |
| 2062 return HContext::New(zone()); | |
| 2063 } | |
| 2064 | |
| 2065 | |
| 2066 class HOptimizedGraphBuilder : public HGraphBuilder, public AstVisitor { | |
| 2067 public: | |
| 2068 // A class encapsulating (lazily-allocated) break and continue blocks for | |
| 2069 // a breakable statement. Separated from BreakAndContinueScope so that it | |
| 2070 // can have a separate lifetime. | |
| 2071 class BreakAndContinueInfo final BASE_EMBEDDED { | |
| 2072 public: | |
| 2073 explicit BreakAndContinueInfo(BreakableStatement* target, | |
| 2074 Scope* scope, | |
| 2075 int drop_extra = 0) | |
| 2076 : target_(target), | |
| 2077 break_block_(NULL), | |
| 2078 continue_block_(NULL), | |
| 2079 scope_(scope), | |
| 2080 drop_extra_(drop_extra) { | |
| 2081 } | |
| 2082 | |
| 2083 BreakableStatement* target() { return target_; } | |
| 2084 HBasicBlock* break_block() { return break_block_; } | |
| 2085 void set_break_block(HBasicBlock* block) { break_block_ = block; } | |
| 2086 HBasicBlock* continue_block() { return continue_block_; } | |
| 2087 void set_continue_block(HBasicBlock* block) { continue_block_ = block; } | |
| 2088 Scope* scope() { return scope_; } | |
| 2089 int drop_extra() { return drop_extra_; } | |
| 2090 | |
| 2091 private: | |
| 2092 BreakableStatement* target_; | |
| 2093 HBasicBlock* break_block_; | |
| 2094 HBasicBlock* continue_block_; | |
| 2095 Scope* scope_; | |
| 2096 int drop_extra_; | |
| 2097 }; | |
| 2098 | |
| 2099 // A helper class to maintain a stack of current BreakAndContinueInfo | |
| 2100 // structures mirroring BreakableStatement nesting. | |
| 2101 class BreakAndContinueScope final BASE_EMBEDDED { | |
| 2102 public: | |
| 2103 BreakAndContinueScope(BreakAndContinueInfo* info, | |
| 2104 HOptimizedGraphBuilder* owner) | |
| 2105 : info_(info), owner_(owner), next_(owner->break_scope()) { | |
| 2106 owner->set_break_scope(this); | |
| 2107 } | |
| 2108 | |
| 2109 ~BreakAndContinueScope() { owner_->set_break_scope(next_); } | |
| 2110 | |
| 2111 BreakAndContinueInfo* info() { return info_; } | |
| 2112 HOptimizedGraphBuilder* owner() { return owner_; } | |
| 2113 BreakAndContinueScope* next() { return next_; } | |
| 2114 | |
| 2115 // Search the break stack for a break or continue target. | |
| 2116 enum BreakType { BREAK, CONTINUE }; | |
| 2117 HBasicBlock* Get(BreakableStatement* stmt, BreakType type, | |
| 2118 Scope** scope, int* drop_extra); | |
| 2119 | |
| 2120 private: | |
| 2121 BreakAndContinueInfo* info_; | |
| 2122 HOptimizedGraphBuilder* owner_; | |
| 2123 BreakAndContinueScope* next_; | |
| 2124 }; | |
| 2125 | |
| 2126 explicit HOptimizedGraphBuilder(CompilationInfo* info); | |
| 2127 | |
| 2128 bool BuildGraph() override; | |
| 2129 | |
| 2130 // Simple accessors. | |
| 2131 BreakAndContinueScope* break_scope() const { return break_scope_; } | |
| 2132 void set_break_scope(BreakAndContinueScope* head) { break_scope_ = head; } | |
| 2133 | |
| 2134 HValue* context() override { return environment()->context(); } | |
| 2135 | |
| 2136 HOsrBuilder* osr() const { return osr_; } | |
| 2137 | |
| 2138 void Bailout(BailoutReason reason); | |
| 2139 | |
| 2140 HBasicBlock* CreateJoin(HBasicBlock* first, | |
| 2141 HBasicBlock* second, | |
| 2142 BailoutId join_id); | |
| 2143 | |
| 2144 FunctionState* function_state() const { return function_state_; } | |
| 2145 | |
| 2146 void VisitDeclarations(ZoneList<Declaration*>* declarations) override; | |
| 2147 | |
| 2148 void* operator new(size_t size, Zone* zone) { return zone->New(size); } | |
| 2149 void operator delete(void* pointer, Zone* zone) { } | |
| 2150 void operator delete(void* pointer) { } | |
| 2151 | |
| 2152 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); | |
| 2153 | |
| 2154 protected: | |
| 2155 // Forward declarations for inner scope classes. | |
| 2156 class SubgraphScope; | |
| 2157 | |
| 2158 static const int kMaxCallPolymorphism = 4; | |
| 2159 static const int kMaxLoadPolymorphism = 4; | |
| 2160 static const int kMaxStorePolymorphism = 4; | |
| 2161 | |
| 2162 // Even in the 'unlimited' case we have to have some limit in order not to | |
| 2163 // overflow the stack. | |
| 2164 static const int kUnlimitedMaxInlinedSourceSize = 100000; | |
| 2165 static const int kUnlimitedMaxInlinedNodes = 10000; | |
| 2166 static const int kUnlimitedMaxInlinedNodesCumulative = 10000; | |
| 2167 | |
| 2168 // Maximum depth and total number of elements and properties for literal | |
| 2169 // graphs to be considered for fast deep-copying. | |
| 2170 static const int kMaxFastLiteralDepth = 3; | |
| 2171 static const int kMaxFastLiteralProperties = 8; | |
| 2172 | |
| 2173 // Simple accessors. | |
| 2174 void set_function_state(FunctionState* state) { function_state_ = state; } | |
| 2175 | |
| 2176 AstContext* ast_context() const { return ast_context_; } | |
| 2177 void set_ast_context(AstContext* context) { ast_context_ = context; } | |
| 2178 | |
| 2179 // Accessors forwarded to the function state. | |
| 2180 CompilationInfo* current_info() const { | |
| 2181 return function_state()->compilation_info(); | |
| 2182 } | |
| 2183 AstContext* call_context() const { | |
| 2184 return function_state()->call_context(); | |
| 2185 } | |
| 2186 HBasicBlock* function_return() const { | |
| 2187 return function_state()->function_return(); | |
| 2188 } | |
| 2189 TestContext* inlined_test_context() const { | |
| 2190 return function_state()->test_context(); | |
| 2191 } | |
| 2192 Handle<SharedFunctionInfo> current_shared_info() const { | |
| 2193 return current_info()->shared_info(); | |
| 2194 } | |
| 2195 TypeFeedbackVector* current_feedback_vector() const { | |
| 2196 return current_shared_info()->feedback_vector(); | |
| 2197 } | |
| 2198 void ClearInlinedTestContext() { | |
| 2199 function_state()->ClearInlinedTestContext(); | |
| 2200 } | |
| 2201 LanguageMode function_language_mode() { | |
| 2202 return function_state()->compilation_info()->language_mode(); | |
| 2203 } | |
| 2204 | |
| 2205 #define FOR_EACH_HYDROGEN_INTRINSIC(F) \ | |
| 2206 F(IsSmi) \ | |
| 2207 F(IsArray) \ | |
| 2208 F(IsTypedArray) \ | |
| 2209 F(IsRegExp) \ | |
| 2210 F(IsJSProxy) \ | |
| 2211 F(IsConstructCall) \ | |
| 2212 F(Call) \ | |
| 2213 F(CallFunction) \ | |
| 2214 F(ArgumentsLength) \ | |
| 2215 F(Arguments) \ | |
| 2216 F(ValueOf) \ | |
| 2217 F(SetValueOf) \ | |
| 2218 F(IsDate) \ | |
| 2219 F(DateField) \ | |
| 2220 F(ThrowNotDateError) \ | |
| 2221 F(StringCharFromCode) \ | |
| 2222 F(StringCharAt) \ | |
| 2223 F(OneByteSeqStringSetChar) \ | |
| 2224 F(TwoByteSeqStringSetChar) \ | |
| 2225 F(ObjectEquals) \ | |
| 2226 F(ToInteger) \ | |
| 2227 F(ToObject) \ | |
| 2228 F(ToString) \ | |
| 2229 F(ToLength) \ | |
| 2230 F(ToNumber) \ | |
| 2231 F(IsFunction) \ | |
| 2232 F(IsSpecObject) \ | |
| 2233 F(MathPow) \ | |
| 2234 F(IsMinusZero) \ | |
| 2235 F(HasCachedArrayIndex) \ | |
| 2236 F(GetCachedArrayIndex) \ | |
| 2237 F(FastOneByteArrayJoin) \ | |
| 2238 F(DebugBreakInOptimizedCode) \ | |
| 2239 F(StringCharCodeAt) \ | |
| 2240 F(StringAdd) \ | |
| 2241 F(SubString) \ | |
| 2242 F(RegExpExec) \ | |
| 2243 F(RegExpConstructResult) \ | |
| 2244 F(NumberToString) \ | |
| 2245 F(DebugIsActive) \ | |
| 2246 F(Likely) \ | |
| 2247 F(Unlikely) \ | |
| 2248 F(HasInPrototypeChain) \ | |
| 2249 /* Typed Arrays */ \ | |
| 2250 F(TypedArrayInitialize) \ | |
| 2251 F(DataViewInitialize) \ | |
| 2252 F(MaxSmi) \ | |
| 2253 F(TypedArrayMaxSizeInHeap) \ | |
| 2254 F(ArrayBufferViewGetByteLength) \ | |
| 2255 F(ArrayBufferViewGetByteOffset) \ | |
| 2256 F(TypedArrayGetLength) \ | |
| 2257 /* ArrayBuffer */ \ | |
| 2258 F(ArrayBufferGetByteLength) \ | |
| 2259 /* Maths */ \ | |
| 2260 F(ConstructDouble) \ | |
| 2261 F(DoubleHi) \ | |
| 2262 F(DoubleLo) \ | |
| 2263 F(MathClz32) \ | |
| 2264 F(MathFloor) \ | |
| 2265 F(MathSqrt) \ | |
| 2266 F(MathLogRT) \ | |
| 2267 /* ES6 Collections */ \ | |
| 2268 F(MapClear) \ | |
| 2269 F(MapInitialize) \ | |
| 2270 F(SetClear) \ | |
| 2271 F(SetInitialize) \ | |
| 2272 F(FixedArrayGet) \ | |
| 2273 F(FixedArraySet) \ | |
| 2274 F(JSCollectionGetTable) \ | |
| 2275 F(StringGetRawHashField) \ | |
| 2276 F(TheHole) \ | |
| 2277 /* ES6 Iterators */ \ | |
| 2278 F(CreateIterResultObject) \ | |
| 2279 /* Arrays */ \ | |
| 2280 F(HasFastPackedElements) \ | |
| 2281 /* Strings */ \ | |
| 2282 F(StringGetLength) \ | |
| 2283 /* JSValue */ \ | |
| 2284 F(JSValueGetValue) | |
| 2285 | |
| 2286 #define GENERATOR_DECLARATION(Name) void Generate##Name(CallRuntime* call); | |
| 2287 FOR_EACH_HYDROGEN_INTRINSIC(GENERATOR_DECLARATION) | |
| 2288 #undef GENERATOR_DECLARATION | |
| 2289 | |
| 2290 void VisitDelete(UnaryOperation* expr); | |
| 2291 void VisitVoid(UnaryOperation* expr); | |
| 2292 void VisitTypeof(UnaryOperation* expr); | |
| 2293 void VisitNot(UnaryOperation* expr); | |
| 2294 | |
| 2295 void VisitComma(BinaryOperation* expr); | |
| 2296 void VisitLogicalExpression(BinaryOperation* expr); | |
| 2297 void VisitArithmeticExpression(BinaryOperation* expr); | |
| 2298 | |
| 2299 void VisitLoopBody(IterationStatement* stmt, | |
| 2300 HBasicBlock* loop_entry); | |
| 2301 | |
| 2302 void BuildForInBody(ForInStatement* stmt, Variable* each_var, | |
| 2303 HValue* enumerable); | |
| 2304 | |
| 2305 // Create a back edge in the flow graph. body_exit is the predecessor | |
| 2306 // block and loop_entry is the successor block. loop_successor is the | |
| 2307 // block where control flow exits the loop normally (e.g., via failure of | |
| 2308 // the condition) and break_block is the block where control flow breaks | |
| 2309 // from the loop. All blocks except loop_entry can be NULL. The return | |
| 2310 // value is the new successor block which is the join of loop_successor | |
| 2311 // and break_block, or NULL. | |
| 2312 HBasicBlock* CreateLoop(IterationStatement* statement, | |
| 2313 HBasicBlock* loop_entry, | |
| 2314 HBasicBlock* body_exit, | |
| 2315 HBasicBlock* loop_successor, | |
| 2316 HBasicBlock* break_block); | |
| 2317 | |
| 2318 // Build a loop entry | |
| 2319 HBasicBlock* BuildLoopEntry(); | |
| 2320 | |
| 2321 // Builds a loop entry respectful of OSR requirements | |
| 2322 HBasicBlock* BuildLoopEntry(IterationStatement* statement); | |
| 2323 | |
| 2324 HBasicBlock* JoinContinue(IterationStatement* statement, | |
| 2325 HBasicBlock* exit_block, | |
| 2326 HBasicBlock* continue_block); | |
| 2327 | |
| 2328 HValue* Top() const { return environment()->Top(); } | |
| 2329 void Drop(int n) { environment()->Drop(n); } | |
| 2330 void Bind(Variable* var, HValue* value) { environment()->Bind(var, value); } | |
| 2331 bool IsEligibleForEnvironmentLivenessAnalysis(Variable* var, | |
| 2332 int index, | |
| 2333 HValue* value, | |
| 2334 HEnvironment* env) { | |
| 2335 if (!FLAG_analyze_environment_liveness) return false; | |
| 2336 // |this| and |arguments| are always live; zapping parameters isn't | |
| 2337 // safe because function.arguments can inspect them at any time. | |
| 2338 return !var->is_this() && | |
| 2339 !var->is_arguments() && | |
| 2340 !value->IsArgumentsObject() && | |
| 2341 env->is_local_index(index); | |
| 2342 } | |
| 2343 void BindIfLive(Variable* var, HValue* value) { | |
| 2344 HEnvironment* env = environment(); | |
| 2345 int index = env->IndexFor(var); | |
| 2346 env->Bind(index, value); | |
| 2347 if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) { | |
| 2348 HEnvironmentMarker* bind = | |
| 2349 Add<HEnvironmentMarker>(HEnvironmentMarker::BIND, index); | |
| 2350 USE(bind); | |
| 2351 #ifdef DEBUG | |
| 2352 bind->set_closure(env->closure()); | |
| 2353 #endif | |
| 2354 } | |
| 2355 } | |
| 2356 HValue* LookupAndMakeLive(Variable* var) { | |
| 2357 HEnvironment* env = environment(); | |
| 2358 int index = env->IndexFor(var); | |
| 2359 HValue* value = env->Lookup(index); | |
| 2360 if (IsEligibleForEnvironmentLivenessAnalysis(var, index, value, env)) { | |
| 2361 HEnvironmentMarker* lookup = | |
| 2362 Add<HEnvironmentMarker>(HEnvironmentMarker::LOOKUP, index); | |
| 2363 USE(lookup); | |
| 2364 #ifdef DEBUG | |
| 2365 lookup->set_closure(env->closure()); | |
| 2366 #endif | |
| 2367 } | |
| 2368 return value; | |
| 2369 } | |
| 2370 | |
| 2371 // The value of the arguments object is allowed in some but not most value | |
| 2372 // contexts. (It's allowed in all effect contexts and disallowed in all | |
| 2373 // test contexts.) | |
| 2374 void VisitForValue(Expression* expr, | |
| 2375 ArgumentsAllowedFlag flag = ARGUMENTS_NOT_ALLOWED); | |
| 2376 void VisitForTypeOf(Expression* expr); | |
| 2377 void VisitForEffect(Expression* expr); | |
| 2378 void VisitForControl(Expression* expr, | |
| 2379 HBasicBlock* true_block, | |
| 2380 HBasicBlock* false_block); | |
| 2381 | |
| 2382 // Visit a list of expressions from left to right, each in a value context. | |
| 2383 void VisitExpressions(ZoneList<Expression*>* exprs) override; | |
| 2384 void VisitExpressions(ZoneList<Expression*>* exprs, | |
| 2385 ArgumentsAllowedFlag flag); | |
| 2386 | |
| 2387 // Remove the arguments from the bailout environment and emit instructions | |
| 2388 // to push them as outgoing parameters. | |
| 2389 template <class Instruction> HInstruction* PreProcessCall(Instruction* call); | |
| 2390 void PushArgumentsFromEnvironment(int count); | |
| 2391 | |
| 2392 void SetUpScope(Scope* scope); | |
| 2393 void VisitStatements(ZoneList<Statement*>* statements) override; | |
| 2394 | |
| 2395 #define DECLARE_VISIT(type) virtual void Visit##type(type* node) override; | |
| 2396 AST_NODE_LIST(DECLARE_VISIT) | |
| 2397 #undef DECLARE_VISIT | |
| 2398 | |
| 2399 private: | |
| 2400 // Helpers for flow graph construction. | |
| 2401 enum GlobalPropertyAccess { | |
| 2402 kUseCell, | |
| 2403 kUseGeneric | |
| 2404 }; | |
| 2405 GlobalPropertyAccess LookupGlobalProperty(Variable* var, LookupIterator* it, | |
| 2406 PropertyAccessType access_type); | |
| 2407 | |
| 2408 void EnsureArgumentsArePushedForAccess(); | |
| 2409 bool TryArgumentsAccess(Property* expr); | |
| 2410 | |
| 2411 // Shared code for .call and .apply optimizations. | |
| 2412 void HandleIndirectCall(Call* expr, HValue* function, int arguments_count); | |
| 2413 // Try to optimize indirect calls such as fun.apply(receiver, arguments) | |
| 2414 // or fun.call(...). | |
| 2415 bool TryIndirectCall(Call* expr); | |
| 2416 void BuildFunctionApply(Call* expr); | |
| 2417 void BuildFunctionCall(Call* expr); | |
| 2418 | |
| 2419 bool TryHandleArrayCall(Call* expr, HValue* function); | |
| 2420 bool TryHandleArrayCallNew(CallNew* expr, HValue* function); | |
| 2421 void BuildArrayCall(Expression* expr, int arguments_count, HValue* function, | |
| 2422 Handle<AllocationSite> cell); | |
| 2423 | |
| 2424 enum ArrayIndexOfMode { kFirstIndexOf, kLastIndexOf }; | |
| 2425 HValue* BuildArrayIndexOf(HValue* receiver, | |
| 2426 HValue* search_element, | |
| 2427 ElementsKind kind, | |
| 2428 ArrayIndexOfMode mode); | |
| 2429 | |
| 2430 HValue* ImplicitReceiverFor(HValue* function, | |
| 2431 Handle<JSFunction> target); | |
| 2432 | |
| 2433 int InliningAstSize(Handle<JSFunction> target); | |
| 2434 bool TryInline(Handle<JSFunction> target, int arguments_count, | |
| 2435 HValue* implicit_return_value, BailoutId ast_id, | |
| 2436 BailoutId return_id, InliningKind inlining_kind); | |
| 2437 | |
| 2438 bool TryInlineCall(Call* expr); | |
| 2439 bool TryInlineConstruct(CallNew* expr, HValue* implicit_return_value); | |
| 2440 bool TryInlineGetter(Handle<JSFunction> getter, | |
| 2441 Handle<Map> receiver_map, | |
| 2442 BailoutId ast_id, | |
| 2443 BailoutId return_id); | |
| 2444 bool TryInlineSetter(Handle<JSFunction> setter, | |
| 2445 Handle<Map> receiver_map, | |
| 2446 BailoutId id, | |
| 2447 BailoutId assignment_id, | |
| 2448 HValue* implicit_return_value); | |
| 2449 bool TryInlineIndirectCall(Handle<JSFunction> function, Call* expr, | |
| 2450 int arguments_count); | |
| 2451 bool TryInlineBuiltinMethodCall(Call* expr, Handle<JSFunction> function, | |
| 2452 Handle<Map> receiver_map, | |
| 2453 int args_count_no_receiver); | |
| 2454 bool TryInlineBuiltinFunctionCall(Call* expr); | |
| 2455 enum ApiCallType { | |
| 2456 kCallApiFunction, | |
| 2457 kCallApiMethod, | |
| 2458 kCallApiGetter, | |
| 2459 kCallApiSetter | |
| 2460 }; | |
| 2461 bool TryInlineApiMethodCall(Call* expr, | |
| 2462 HValue* receiver, | |
| 2463 SmallMapList* receiver_types); | |
| 2464 bool TryInlineApiFunctionCall(Call* expr, HValue* receiver); | |
| 2465 bool TryInlineApiGetter(Handle<JSFunction> function, | |
| 2466 Handle<Map> receiver_map, | |
| 2467 BailoutId ast_id); | |
| 2468 bool TryInlineApiSetter(Handle<JSFunction> function, | |
| 2469 Handle<Map> receiver_map, | |
| 2470 BailoutId ast_id); | |
| 2471 bool TryInlineApiCall(Handle<JSFunction> function, | |
| 2472 HValue* receiver, | |
| 2473 SmallMapList* receiver_maps, | |
| 2474 int argc, | |
| 2475 BailoutId ast_id, | |
| 2476 ApiCallType call_type); | |
| 2477 static bool IsReadOnlyLengthDescriptor(Handle<Map> jsarray_map); | |
| 2478 static bool CanInlineArrayResizeOperation(Handle<Map> receiver_map); | |
| 2479 | |
| 2480 // If --trace-inlining, print a line of the inlining trace. Inlining | |
| 2481 // succeeded if the reason string is NULL and failed if there is a | |
| 2482 // non-NULL reason string. | |
| 2483 void TraceInline(Handle<JSFunction> target, | |
| 2484 Handle<JSFunction> caller, | |
| 2485 const char* failure_reason); | |
| 2486 | |
| 2487 void HandleGlobalVariableAssignment(Variable* var, HValue* value, | |
| 2488 FeedbackVectorSlot slot, | |
| 2489 BailoutId ast_id); | |
| 2490 | |
| 2491 void HandlePropertyAssignment(Assignment* expr); | |
| 2492 void HandleCompoundAssignment(Assignment* expr); | |
| 2493 void HandlePolymorphicNamedFieldAccess( | |
| 2494 PropertyAccessType access_type, Expression* expr, FeedbackVectorSlot slot, | |
| 2495 BailoutId ast_id, BailoutId return_id, HValue* object, HValue* value, | |
| 2496 SmallMapList* types, Handle<String> name); | |
| 2497 | |
| 2498 HValue* BuildAllocateExternalElements( | |
| 2499 ExternalArrayType array_type, | |
| 2500 bool is_zero_byte_offset, | |
| 2501 HValue* buffer, HValue* byte_offset, HValue* length); | |
| 2502 HValue* BuildAllocateFixedTypedArray(ExternalArrayType array_type, | |
| 2503 size_t element_size, | |
| 2504 ElementsKind fixed_elements_kind, | |
| 2505 HValue* byte_length, HValue* length, | |
| 2506 bool initialize); | |
| 2507 | |
| 2508 // TODO(adamk): Move all OrderedHashTable functions to their own class. | |
| 2509 HValue* BuildOrderedHashTableHashToBucket(HValue* hash, HValue* num_buckets); | |
| 2510 template <typename CollectionType> | |
| 2511 HValue* BuildOrderedHashTableHashToEntry(HValue* table, HValue* hash, | |
| 2512 HValue* num_buckets); | |
| 2513 template <typename CollectionType> | |
| 2514 HValue* BuildOrderedHashTableEntryToIndex(HValue* entry, HValue* num_buckets); | |
| 2515 template <typename CollectionType> | |
| 2516 HValue* BuildOrderedHashTableFindEntry(HValue* table, HValue* key, | |
| 2517 HValue* hash); | |
| 2518 template <typename CollectionType> | |
| 2519 HValue* BuildOrderedHashTableAddEntry(HValue* table, HValue* key, | |
| 2520 HValue* hash, | |
| 2521 HIfContinuation* join_continuation); | |
| 2522 template <typename CollectionType> | |
| 2523 HValue* BuildAllocateOrderedHashTable(); | |
| 2524 template <typename CollectionType> | |
| 2525 void BuildOrderedHashTableClear(HValue* receiver); | |
| 2526 template <typename CollectionType> | |
| 2527 void BuildJSCollectionDelete(CallRuntime* call, | |
| 2528 const Runtime::Function* c_function); | |
| 2529 template <typename CollectionType> | |
| 2530 void BuildJSCollectionHas(CallRuntime* call, | |
| 2531 const Runtime::Function* c_function); | |
| 2532 HValue* BuildStringHashLoadIfIsStringAndHashComputed( | |
| 2533 HValue* object, HIfContinuation* continuation); | |
| 2534 | |
| 2535 Handle<JSFunction> array_function() { | |
| 2536 return handle(isolate()->native_context()->array_function()); | |
| 2537 } | |
| 2538 | |
| 2539 bool IsCallArrayInlineable(int argument_count, Handle<AllocationSite> site); | |
| 2540 void BuildInlinedCallArray(Expression* expression, int argument_count, | |
| 2541 Handle<AllocationSite> site); | |
| 2542 | |
| 2543 void BuildInitializeInobjectProperties(HValue* receiver, | |
| 2544 Handle<Map> initial_map); | |
| 2545 | |
| 2546 class PropertyAccessInfo { | |
| 2547 public: | |
| 2548 PropertyAccessInfo(HOptimizedGraphBuilder* builder, | |
| 2549 PropertyAccessType access_type, Handle<Map> map, | |
| 2550 Handle<Name> name) | |
| 2551 : builder_(builder), | |
| 2552 access_type_(access_type), | |
| 2553 map_(map), | |
| 2554 name_(name), | |
| 2555 field_type_(HType::Tagged()), | |
| 2556 access_(HObjectAccess::ForMap()), | |
| 2557 lookup_type_(NOT_FOUND), | |
| 2558 details_(NONE, DATA, Representation::None()) {} | |
| 2559 | |
| 2560 // Checkes whether this PropertyAccessInfo can be handled as a monomorphic | |
| 2561 // load named. It additionally fills in the fields necessary to generate the | |
| 2562 // lookup code. | |
| 2563 bool CanAccessMonomorphic(); | |
| 2564 | |
| 2565 // Checks whether all types behave uniform when loading name. If all maps | |
| 2566 // behave the same, a single monomorphic load instruction can be emitted, | |
| 2567 // guarded by a single map-checks instruction that whether the receiver is | |
| 2568 // an instance of any of the types. | |
| 2569 // This method skips the first type in types, assuming that this | |
| 2570 // PropertyAccessInfo is built for types->first(). | |
| 2571 bool CanAccessAsMonomorphic(SmallMapList* types); | |
| 2572 | |
| 2573 bool NeedsWrappingFor(Handle<JSFunction> target) const; | |
| 2574 | |
| 2575 Handle<Map> map(); | |
| 2576 Handle<Name> name() const { return name_; } | |
| 2577 | |
| 2578 bool IsJSObjectFieldAccessor() { | |
| 2579 int offset; // unused | |
| 2580 return Accessors::IsJSObjectFieldAccessor(map_, name_, &offset); | |
| 2581 } | |
| 2582 | |
| 2583 bool GetJSObjectFieldAccess(HObjectAccess* access) { | |
| 2584 int offset; | |
| 2585 if (Accessors::IsJSObjectFieldAccessor(map_, name_, &offset)) { | |
| 2586 if (IsStringType()) { | |
| 2587 DCHECK(Name::Equals(isolate()->factory()->length_string(), name_)); | |
| 2588 *access = HObjectAccess::ForStringLength(); | |
| 2589 } else if (IsArrayType()) { | |
| 2590 DCHECK(Name::Equals(isolate()->factory()->length_string(), name_)); | |
| 2591 *access = HObjectAccess::ForArrayLength(map_->elements_kind()); | |
| 2592 } else { | |
| 2593 *access = HObjectAccess::ForMapAndOffset(map_, offset); | |
| 2594 } | |
| 2595 return true; | |
| 2596 } | |
| 2597 return false; | |
| 2598 } | |
| 2599 | |
| 2600 bool IsJSArrayBufferViewFieldAccessor() { | |
| 2601 int offset; // unused | |
| 2602 return Accessors::IsJSArrayBufferViewFieldAccessor(map_, name_, &offset); | |
| 2603 } | |
| 2604 | |
| 2605 bool GetJSArrayBufferViewFieldAccess(HObjectAccess* access) { | |
| 2606 int offset; | |
| 2607 if (Accessors::IsJSArrayBufferViewFieldAccessor(map_, name_, &offset)) { | |
| 2608 *access = HObjectAccess::ForMapAndOffset(map_, offset); | |
| 2609 return true; | |
| 2610 } | |
| 2611 return false; | |
| 2612 } | |
| 2613 | |
| 2614 bool has_holder() { return !holder_.is_null(); } | |
| 2615 bool IsLoad() const { return access_type_ == LOAD; } | |
| 2616 | |
| 2617 Isolate* isolate() const { return builder_->isolate(); } | |
| 2618 Handle<JSObject> holder() { return holder_; } | |
| 2619 Handle<JSFunction> accessor() { return accessor_; } | |
| 2620 Handle<Object> constant() { return constant_; } | |
| 2621 Handle<Map> transition() { return transition_; } | |
| 2622 SmallMapList* field_maps() { return &field_maps_; } | |
| 2623 HType field_type() const { return field_type_; } | |
| 2624 HObjectAccess access() { return access_; } | |
| 2625 | |
| 2626 bool IsFound() const { return lookup_type_ != NOT_FOUND; } | |
| 2627 bool IsProperty() const { return IsFound() && !IsTransition(); } | |
| 2628 bool IsTransition() const { return lookup_type_ == TRANSITION_TYPE; } | |
| 2629 bool IsData() const { | |
| 2630 return lookup_type_ == DESCRIPTOR_TYPE && details_.type() == DATA; | |
| 2631 } | |
| 2632 bool IsDataConstant() const { | |
| 2633 return lookup_type_ == DESCRIPTOR_TYPE && | |
| 2634 details_.type() == DATA_CONSTANT; | |
| 2635 } | |
| 2636 bool IsAccessorConstant() const { | |
| 2637 return !IsTransition() && details_.type() == ACCESSOR_CONSTANT; | |
| 2638 } | |
| 2639 bool IsConfigurable() const { return details_.IsConfigurable(); } | |
| 2640 bool IsReadOnly() const { return details_.IsReadOnly(); } | |
| 2641 | |
| 2642 bool IsStringType() { return map_->instance_type() < FIRST_NONSTRING_TYPE; } | |
| 2643 bool IsNumberType() { return map_->instance_type() == HEAP_NUMBER_TYPE; } | |
| 2644 bool IsValueWrapped() { return IsStringType() || IsNumberType(); } | |
| 2645 bool IsArrayType() { return map_->instance_type() == JS_ARRAY_TYPE; } | |
| 2646 | |
| 2647 private: | |
| 2648 Handle<Object> GetConstantFromMap(Handle<Map> map) const { | |
| 2649 DCHECK_EQ(DESCRIPTOR_TYPE, lookup_type_); | |
| 2650 DCHECK(number_ < map->NumberOfOwnDescriptors()); | |
| 2651 return handle(map->instance_descriptors()->GetValue(number_), isolate()); | |
| 2652 } | |
| 2653 Handle<Object> GetAccessorsFromMap(Handle<Map> map) const { | |
| 2654 return GetConstantFromMap(map); | |
| 2655 } | |
| 2656 Handle<HeapType> GetFieldTypeFromMap(Handle<Map> map) const { | |
| 2657 DCHECK(IsFound()); | |
| 2658 DCHECK(number_ < map->NumberOfOwnDescriptors()); | |
| 2659 return handle(map->instance_descriptors()->GetFieldType(number_), | |
| 2660 isolate()); | |
| 2661 } | |
| 2662 Handle<Map> GetFieldOwnerFromMap(Handle<Map> map) const { | |
| 2663 DCHECK(IsFound()); | |
| 2664 DCHECK(number_ < map->NumberOfOwnDescriptors()); | |
| 2665 return handle(map->FindFieldOwner(number_)); | |
| 2666 } | |
| 2667 int GetLocalFieldIndexFromMap(Handle<Map> map) const { | |
| 2668 DCHECK(lookup_type_ == DESCRIPTOR_TYPE || | |
| 2669 lookup_type_ == TRANSITION_TYPE); | |
| 2670 DCHECK(number_ < map->NumberOfOwnDescriptors()); | |
| 2671 int field_index = map->instance_descriptors()->GetFieldIndex(number_); | |
| 2672 return field_index - map->GetInObjectProperties(); | |
| 2673 } | |
| 2674 | |
| 2675 void LookupDescriptor(Map* map, Name* name) { | |
| 2676 DescriptorArray* descriptors = map->instance_descriptors(); | |
| 2677 int number = descriptors->SearchWithCache(name, map); | |
| 2678 if (number == DescriptorArray::kNotFound) return NotFound(); | |
| 2679 lookup_type_ = DESCRIPTOR_TYPE; | |
| 2680 details_ = descriptors->GetDetails(number); | |
| 2681 number_ = number; | |
| 2682 } | |
| 2683 void LookupTransition(Map* map, Name* name, PropertyAttributes attributes) { | |
| 2684 Map* target = | |
| 2685 TransitionArray::SearchTransition(map, kData, name, attributes); | |
| 2686 if (target == NULL) return NotFound(); | |
| 2687 lookup_type_ = TRANSITION_TYPE; | |
| 2688 transition_ = handle(target); | |
| 2689 number_ = transition_->LastAdded(); | |
| 2690 details_ = transition_->instance_descriptors()->GetDetails(number_); | |
| 2691 } | |
| 2692 void NotFound() { | |
| 2693 lookup_type_ = NOT_FOUND; | |
| 2694 details_ = PropertyDetails::Empty(); | |
| 2695 } | |
| 2696 Representation representation() const { | |
| 2697 DCHECK(IsFound()); | |
| 2698 return details_.representation(); | |
| 2699 } | |
| 2700 bool IsTransitionToData() const { | |
| 2701 return IsTransition() && details_.type() == DATA; | |
| 2702 } | |
| 2703 | |
| 2704 Zone* zone() { return builder_->zone(); } | |
| 2705 CompilationInfo* top_info() { return builder_->top_info(); } | |
| 2706 CompilationInfo* current_info() { return builder_->current_info(); } | |
| 2707 | |
| 2708 bool LoadResult(Handle<Map> map); | |
| 2709 bool LoadFieldMaps(Handle<Map> map); | |
| 2710 bool LookupDescriptor(); | |
| 2711 bool LookupInPrototypes(); | |
| 2712 bool IsIntegerIndexedExotic(); | |
| 2713 bool IsCompatible(PropertyAccessInfo* other); | |
| 2714 | |
| 2715 void GeneralizeRepresentation(Representation r) { | |
| 2716 access_ = access_.WithRepresentation( | |
| 2717 access_.representation().generalize(r)); | |
| 2718 } | |
| 2719 | |
| 2720 HOptimizedGraphBuilder* builder_; | |
| 2721 PropertyAccessType access_type_; | |
| 2722 Handle<Map> map_; | |
| 2723 Handle<Name> name_; | |
| 2724 Handle<JSObject> holder_; | |
| 2725 Handle<JSFunction> accessor_; | |
| 2726 Handle<JSObject> api_holder_; | |
| 2727 Handle<Object> constant_; | |
| 2728 SmallMapList field_maps_; | |
| 2729 HType field_type_; | |
| 2730 HObjectAccess access_; | |
| 2731 | |
| 2732 enum { NOT_FOUND, DESCRIPTOR_TYPE, TRANSITION_TYPE } lookup_type_; | |
| 2733 Handle<Map> transition_; | |
| 2734 int number_; | |
| 2735 PropertyDetails details_; | |
| 2736 }; | |
| 2737 | |
| 2738 HValue* BuildMonomorphicAccess(PropertyAccessInfo* info, HValue* object, | |
| 2739 HValue* checked_object, HValue* value, | |
| 2740 BailoutId ast_id, BailoutId return_id, | |
| 2741 bool can_inline_accessor = true); | |
| 2742 | |
| 2743 HValue* BuildNamedAccess(PropertyAccessType access, BailoutId ast_id, | |
| 2744 BailoutId reutrn_id, Expression* expr, | |
| 2745 FeedbackVectorSlot slot, HValue* object, | |
| 2746 Handle<String> name, HValue* value, | |
| 2747 bool is_uninitialized = false); | |
| 2748 | |
| 2749 void HandlePolymorphicCallNamed(Call* expr, | |
| 2750 HValue* receiver, | |
| 2751 SmallMapList* types, | |
| 2752 Handle<String> name); | |
| 2753 void HandleLiteralCompareTypeof(CompareOperation* expr, | |
| 2754 Expression* sub_expr, | |
| 2755 Handle<String> check); | |
| 2756 void HandleLiteralCompareNil(CompareOperation* expr, | |
| 2757 Expression* sub_expr, | |
| 2758 NilValue nil); | |
| 2759 | |
| 2760 enum PushBeforeSimulateBehavior { | |
| 2761 PUSH_BEFORE_SIMULATE, | |
| 2762 NO_PUSH_BEFORE_SIMULATE | |
| 2763 }; | |
| 2764 | |
| 2765 HControlInstruction* BuildCompareInstruction( | |
| 2766 Token::Value op, HValue* left, HValue* right, Type* left_type, | |
| 2767 Type* right_type, Type* combined_type, SourcePosition left_position, | |
| 2768 SourcePosition right_position, PushBeforeSimulateBehavior push_sim_result, | |
| 2769 BailoutId bailout_id); | |
| 2770 | |
| 2771 HInstruction* BuildStringCharCodeAt(HValue* string, | |
| 2772 HValue* index); | |
| 2773 | |
| 2774 HValue* BuildBinaryOperation( | |
| 2775 BinaryOperation* expr, | |
| 2776 HValue* left, | |
| 2777 HValue* right, | |
| 2778 PushBeforeSimulateBehavior push_sim_result); | |
| 2779 HInstruction* BuildIncrement(bool returns_original_input, | |
| 2780 CountOperation* expr); | |
| 2781 HInstruction* BuildKeyedGeneric(PropertyAccessType access_type, | |
| 2782 Expression* expr, FeedbackVectorSlot slot, | |
| 2783 HValue* object, HValue* key, HValue* value); | |
| 2784 | |
| 2785 HInstruction* TryBuildConsolidatedElementLoad(HValue* object, | |
| 2786 HValue* key, | |
| 2787 HValue* val, | |
| 2788 SmallMapList* maps); | |
| 2789 | |
| 2790 LoadKeyedHoleMode BuildKeyedHoleMode(Handle<Map> map); | |
| 2791 | |
| 2792 HInstruction* BuildMonomorphicElementAccess(HValue* object, | |
| 2793 HValue* key, | |
| 2794 HValue* val, | |
| 2795 HValue* dependency, | |
| 2796 Handle<Map> map, | |
| 2797 PropertyAccessType access_type, | |
| 2798 KeyedAccessStoreMode store_mode); | |
| 2799 | |
| 2800 HValue* HandlePolymorphicElementAccess( | |
| 2801 Expression* expr, FeedbackVectorSlot slot, HValue* object, HValue* key, | |
| 2802 HValue* val, SmallMapList* maps, PropertyAccessType access_type, | |
| 2803 KeyedAccessStoreMode store_mode, bool* has_side_effects); | |
| 2804 | |
| 2805 HValue* HandleKeyedElementAccess(HValue* obj, HValue* key, HValue* val, | |
| 2806 Expression* expr, FeedbackVectorSlot slot, | |
| 2807 BailoutId ast_id, BailoutId return_id, | |
| 2808 PropertyAccessType access_type, | |
| 2809 bool* has_side_effects); | |
| 2810 | |
| 2811 HInstruction* BuildNamedGeneric(PropertyAccessType access, Expression* expr, | |
| 2812 FeedbackVectorSlot slot, HValue* object, | |
| 2813 Handle<Name> name, HValue* value, | |
| 2814 bool is_uninitialized = false); | |
| 2815 | |
| 2816 HCheckMaps* AddCheckMap(HValue* object, Handle<Map> map); | |
| 2817 | |
| 2818 void BuildLoad(Property* property, | |
| 2819 BailoutId ast_id); | |
| 2820 void PushLoad(Property* property, | |
| 2821 HValue* object, | |
| 2822 HValue* key); | |
| 2823 | |
| 2824 void BuildStoreForEffect(Expression* expression, Property* prop, | |
| 2825 FeedbackVectorSlot slot, BailoutId ast_id, | |
| 2826 BailoutId return_id, HValue* object, HValue* key, | |
| 2827 HValue* value); | |
| 2828 | |
| 2829 void BuildStore(Expression* expression, Property* prop, | |
| 2830 FeedbackVectorSlot slot, BailoutId ast_id, | |
| 2831 BailoutId return_id, bool is_uninitialized = false); | |
| 2832 | |
| 2833 HInstruction* BuildLoadNamedField(PropertyAccessInfo* info, | |
| 2834 HValue* checked_object); | |
| 2835 HInstruction* BuildStoreNamedField(PropertyAccessInfo* info, | |
| 2836 HValue* checked_object, | |
| 2837 HValue* value); | |
| 2838 | |
| 2839 HValue* BuildContextChainWalk(Variable* var); | |
| 2840 | |
| 2841 HInstruction* BuildThisFunction(); | |
| 2842 | |
| 2843 HInstruction* BuildFastLiteral(Handle<JSObject> boilerplate_object, | |
| 2844 AllocationSiteUsageContext* site_context); | |
| 2845 | |
| 2846 void BuildEmitObjectHeader(Handle<JSObject> boilerplate_object, | |
| 2847 HInstruction* object); | |
| 2848 | |
| 2849 void BuildEmitInObjectProperties(Handle<JSObject> boilerplate_object, | |
| 2850 HInstruction* object, | |
| 2851 AllocationSiteUsageContext* site_context, | |
| 2852 PretenureFlag pretenure_flag); | |
| 2853 | |
| 2854 void BuildEmitElements(Handle<JSObject> boilerplate_object, | |
| 2855 Handle<FixedArrayBase> elements, | |
| 2856 HValue* object_elements, | |
| 2857 AllocationSiteUsageContext* site_context); | |
| 2858 | |
| 2859 void BuildEmitFixedDoubleArray(Handle<FixedArrayBase> elements, | |
| 2860 ElementsKind kind, | |
| 2861 HValue* object_elements); | |
| 2862 | |
| 2863 void BuildEmitFixedArray(Handle<FixedArrayBase> elements, | |
| 2864 ElementsKind kind, | |
| 2865 HValue* object_elements, | |
| 2866 AllocationSiteUsageContext* site_context); | |
| 2867 | |
| 2868 void AddCheckPrototypeMaps(Handle<JSObject> holder, | |
| 2869 Handle<Map> receiver_map); | |
| 2870 | |
| 2871 HInstruction* NewPlainFunctionCall(HValue* fun, int argument_count); | |
| 2872 | |
| 2873 HInstruction* NewArgumentAdaptorCall(HValue* fun, HValue* context, | |
| 2874 int argument_count, | |
| 2875 HValue* expected_param_count); | |
| 2876 | |
| 2877 HInstruction* BuildCallConstantFunction(Handle<JSFunction> target, | |
| 2878 int argument_count); | |
| 2879 | |
| 2880 bool CanBeFunctionApplyArguments(Call* expr); | |
| 2881 | |
| 2882 // The translation state of the currently-being-translated function. | |
| 2883 FunctionState* function_state_; | |
| 2884 | |
| 2885 // The base of the function state stack. | |
| 2886 FunctionState initial_function_state_; | |
| 2887 | |
| 2888 // Expression context of the currently visited subexpression. NULL when | |
| 2889 // visiting statements. | |
| 2890 AstContext* ast_context_; | |
| 2891 | |
| 2892 // A stack of breakable statements entered. | |
| 2893 BreakAndContinueScope* break_scope_; | |
| 2894 | |
| 2895 int inlined_count_; | |
| 2896 ZoneList<Handle<Object> > globals_; | |
| 2897 | |
| 2898 bool inline_bailout_; | |
| 2899 | |
| 2900 HOsrBuilder* osr_; | |
| 2901 | |
| 2902 friend class FunctionState; // Pushes and pops the state stack. | |
| 2903 friend class AstContext; // Pushes and pops the AST context stack. | |
| 2904 friend class KeyedLoadFastElementStub; | |
| 2905 friend class HOsrBuilder; | |
| 2906 | |
| 2907 DISALLOW_COPY_AND_ASSIGN(HOptimizedGraphBuilder); | |
| 2908 }; | |
| 2909 | |
| 2910 | |
| 2911 Zone* AstContext::zone() const { return owner_->zone(); } | |
| 2912 | |
| 2913 | |
| 2914 class HStatistics final : public Malloced { | |
| 2915 public: | |
| 2916 HStatistics() | |
| 2917 : times_(5), | |
| 2918 names_(5), | |
| 2919 sizes_(5), | |
| 2920 total_size_(0), | |
| 2921 source_size_(0) { } | |
| 2922 | |
| 2923 void Initialize(CompilationInfo* info); | |
| 2924 void Print(); | |
| 2925 void SaveTiming(const char* name, base::TimeDelta time, size_t size); | |
| 2926 | |
| 2927 void IncrementFullCodeGen(base::TimeDelta full_code_gen) { | |
| 2928 full_code_gen_ += full_code_gen; | |
| 2929 } | |
| 2930 | |
| 2931 void IncrementCreateGraph(base::TimeDelta delta) { create_graph_ += delta; } | |
| 2932 | |
| 2933 void IncrementOptimizeGraph(base::TimeDelta delta) { | |
| 2934 optimize_graph_ += delta; | |
| 2935 } | |
| 2936 | |
| 2937 void IncrementGenerateCode(base::TimeDelta delta) { generate_code_ += delta; } | |
| 2938 | |
| 2939 void IncrementSubtotals(base::TimeDelta create_graph, | |
| 2940 base::TimeDelta optimize_graph, | |
| 2941 base::TimeDelta generate_code) { | |
| 2942 IncrementCreateGraph(create_graph); | |
| 2943 IncrementOptimizeGraph(optimize_graph); | |
| 2944 IncrementGenerateCode(generate_code); | |
| 2945 } | |
| 2946 | |
| 2947 private: | |
| 2948 List<base::TimeDelta> times_; | |
| 2949 List<const char*> names_; | |
| 2950 List<size_t> sizes_; | |
| 2951 base::TimeDelta create_graph_; | |
| 2952 base::TimeDelta optimize_graph_; | |
| 2953 base::TimeDelta generate_code_; | |
| 2954 size_t total_size_; | |
| 2955 base::TimeDelta full_code_gen_; | |
| 2956 double source_size_; | |
| 2957 }; | |
| 2958 | |
| 2959 | |
| 2960 class HPhase : public CompilationPhase { | |
| 2961 public: | |
| 2962 HPhase(const char* name, HGraph* graph) | |
| 2963 : CompilationPhase(name, graph->info()), | |
| 2964 graph_(graph) { } | |
| 2965 ~HPhase(); | |
| 2966 | |
| 2967 protected: | |
| 2968 HGraph* graph() const { return graph_; } | |
| 2969 | |
| 2970 private: | |
| 2971 HGraph* graph_; | |
| 2972 | |
| 2973 DISALLOW_COPY_AND_ASSIGN(HPhase); | |
| 2974 }; | |
| 2975 | |
| 2976 | |
| 2977 class HTracer final : public Malloced { | |
| 2978 public: | |
| 2979 explicit HTracer(int isolate_id) | |
| 2980 : trace_(&string_allocator_), indent_(0) { | |
| 2981 if (FLAG_trace_hydrogen_file == NULL) { | |
| 2982 SNPrintF(filename_, | |
| 2983 "hydrogen-%d-%d.cfg", | |
| 2984 base::OS::GetCurrentProcessId(), | |
| 2985 isolate_id); | |
| 2986 } else { | |
| 2987 StrNCpy(filename_, FLAG_trace_hydrogen_file, filename_.length()); | |
| 2988 } | |
| 2989 WriteChars(filename_.start(), "", 0, false); | |
| 2990 } | |
| 2991 | |
| 2992 void TraceCompilation(CompilationInfo* info); | |
| 2993 void TraceHydrogen(const char* name, HGraph* graph); | |
| 2994 void TraceLithium(const char* name, LChunk* chunk); | |
| 2995 void TraceLiveRanges(const char* name, LAllocator* allocator); | |
| 2996 | |
| 2997 private: | |
| 2998 class Tag final BASE_EMBEDDED { | |
| 2999 public: | |
| 3000 Tag(HTracer* tracer, const char* name) { | |
| 3001 name_ = name; | |
| 3002 tracer_ = tracer; | |
| 3003 tracer->PrintIndent(); | |
| 3004 tracer->trace_.Add("begin_%s\n", name); | |
| 3005 tracer->indent_++; | |
| 3006 } | |
| 3007 | |
| 3008 ~Tag() { | |
| 3009 tracer_->indent_--; | |
| 3010 tracer_->PrintIndent(); | |
| 3011 tracer_->trace_.Add("end_%s\n", name_); | |
| 3012 DCHECK(tracer_->indent_ >= 0); | |
| 3013 tracer_->FlushToFile(); | |
| 3014 } | |
| 3015 | |
| 3016 private: | |
| 3017 HTracer* tracer_; | |
| 3018 const char* name_; | |
| 3019 }; | |
| 3020 | |
| 3021 void TraceLiveRange(LiveRange* range, const char* type, Zone* zone); | |
| 3022 void Trace(const char* name, HGraph* graph, LChunk* chunk); | |
| 3023 void FlushToFile(); | |
| 3024 | |
| 3025 void PrintEmptyProperty(const char* name) { | |
| 3026 PrintIndent(); | |
| 3027 trace_.Add("%s\n", name); | |
| 3028 } | |
| 3029 | |
| 3030 void PrintStringProperty(const char* name, const char* value) { | |
| 3031 PrintIndent(); | |
| 3032 trace_.Add("%s \"%s\"\n", name, value); | |
| 3033 } | |
| 3034 | |
| 3035 void PrintLongProperty(const char* name, int64_t value) { | |
| 3036 PrintIndent(); | |
| 3037 trace_.Add("%s %d000\n", name, static_cast<int>(value / 1000)); | |
| 3038 } | |
| 3039 | |
| 3040 void PrintBlockProperty(const char* name, int block_id) { | |
| 3041 PrintIndent(); | |
| 3042 trace_.Add("%s \"B%d\"\n", name, block_id); | |
| 3043 } | |
| 3044 | |
| 3045 void PrintIntProperty(const char* name, int value) { | |
| 3046 PrintIndent(); | |
| 3047 trace_.Add("%s %d\n", name, value); | |
| 3048 } | |
| 3049 | |
| 3050 void PrintIndent() { | |
| 3051 for (int i = 0; i < indent_; i++) { | |
| 3052 trace_.Add(" "); | |
| 3053 } | |
| 3054 } | |
| 3055 | |
| 3056 EmbeddedVector<char, 64> filename_; | |
| 3057 HeapStringAllocator string_allocator_; | |
| 3058 StringStream trace_; | |
| 3059 int indent_; | |
| 3060 }; | |
| 3061 | |
| 3062 | |
| 3063 class NoObservableSideEffectsScope final { | |
| 3064 public: | |
| 3065 explicit NoObservableSideEffectsScope(HGraphBuilder* builder) : | |
| 3066 builder_(builder) { | |
| 3067 builder_->graph()->IncrementInNoSideEffectsScope(); | |
| 3068 } | |
| 3069 ~NoObservableSideEffectsScope() { | |
| 3070 builder_->graph()->DecrementInNoSideEffectsScope(); | |
| 3071 } | |
| 3072 | |
| 3073 private: | |
| 3074 HGraphBuilder* builder_; | |
| 3075 }; | |
| 3076 | |
| 3077 | |
| 3078 } // namespace internal | |
| 3079 } // namespace v8 | |
| 3080 | |
| 3081 #endif // V8_HYDROGEN_H_ | |
| OLD | NEW |