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