| OLD | NEW |
| 1 // Copyright 2013 the V8 project authors. All rights reserved. | 1 // Copyright 2013 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 21 matching lines...) Expand all Loading... |
| 32 #include "v8.h" | 32 #include "v8.h" |
| 33 #include "codegen.h" | 33 #include "codegen.h" |
| 34 #include "full-codegen.h" | 34 #include "full-codegen.h" |
| 35 #include "hashmap.h" | 35 #include "hashmap.h" |
| 36 #include "hydrogen-bce.h" | 36 #include "hydrogen-bce.h" |
| 37 #include "hydrogen-bch.h" | 37 #include "hydrogen-bch.h" |
| 38 #include "hydrogen-canonicalize.h" | 38 #include "hydrogen-canonicalize.h" |
| 39 #include "hydrogen-check-elimination.h" | 39 #include "hydrogen-check-elimination.h" |
| 40 #include "hydrogen-dce.h" | 40 #include "hydrogen-dce.h" |
| 41 #include "hydrogen-dehoist.h" | 41 #include "hydrogen-dehoist.h" |
| 42 #include "hydrogen-deoptimizing-mark.h" | |
| 43 #include "hydrogen-environment-liveness.h" | 42 #include "hydrogen-environment-liveness.h" |
| 44 #include "hydrogen-escape-analysis.h" | 43 #include "hydrogen-escape-analysis.h" |
| 45 #include "hydrogen-infer-representation.h" | 44 #include "hydrogen-infer-representation.h" |
| 46 #include "hydrogen-infer-types.h" | 45 #include "hydrogen-infer-types.h" |
| 47 #include "hydrogen-load-elimination.h" | 46 #include "hydrogen-load-elimination.h" |
| 48 #include "hydrogen-gvn.h" | 47 #include "hydrogen-gvn.h" |
| 49 #include "hydrogen-mark-deoptimize.h" | 48 #include "hydrogen-mark-deoptimize.h" |
| 49 #include "hydrogen-mark-unreachable.h" |
| 50 #include "hydrogen-minus-zero.h" | 50 #include "hydrogen-minus-zero.h" |
| 51 #include "hydrogen-osr.h" | 51 #include "hydrogen-osr.h" |
| 52 #include "hydrogen-range-analysis.h" | 52 #include "hydrogen-range-analysis.h" |
| 53 #include "hydrogen-redundant-phi.h" | 53 #include "hydrogen-redundant-phi.h" |
| 54 #include "hydrogen-removable-simulates.h" | 54 #include "hydrogen-removable-simulates.h" |
| 55 #include "hydrogen-representation-changes.h" | 55 #include "hydrogen-representation-changes.h" |
| 56 #include "hydrogen-sce.h" | 56 #include "hydrogen-sce.h" |
| 57 #include "hydrogen-uint32-analysis.h" | 57 #include "hydrogen-uint32-analysis.h" |
| 58 #include "lithium-allocator.h" | 58 #include "lithium-allocator.h" |
| 59 #include "parser.h" | 59 #include "parser.h" |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 91 dominator_(NULL), | 91 dominator_(NULL), |
| 92 dominated_blocks_(4, graph->zone()), | 92 dominated_blocks_(4, graph->zone()), |
| 93 last_environment_(NULL), | 93 last_environment_(NULL), |
| 94 argument_count_(-1), | 94 argument_count_(-1), |
| 95 first_instruction_index_(-1), | 95 first_instruction_index_(-1), |
| 96 last_instruction_index_(-1), | 96 last_instruction_index_(-1), |
| 97 deleted_phis_(4, graph->zone()), | 97 deleted_phis_(4, graph->zone()), |
| 98 parent_loop_header_(NULL), | 98 parent_loop_header_(NULL), |
| 99 inlined_entry_block_(NULL), | 99 inlined_entry_block_(NULL), |
| 100 is_inline_return_target_(false), | 100 is_inline_return_target_(false), |
| 101 is_deoptimizing_(false), | 101 is_reachable_(true), |
| 102 dominates_loop_successors_(false), | 102 dominates_loop_successors_(false), |
| 103 is_osr_entry_(false) { } | 103 is_osr_entry_(false) { } |
| 104 | 104 |
| 105 | 105 |
| 106 Isolate* HBasicBlock::isolate() const { | 106 Isolate* HBasicBlock::isolate() const { |
| 107 return graph_->isolate(); | 107 return graph_->isolate(); |
| 108 } | 108 } |
| 109 | 109 |
| 110 | 110 |
| 111 void HBasicBlock::MarkUnreachable() { |
| 112 is_reachable_ = false; |
| 113 } |
| 114 |
| 115 |
| 111 void HBasicBlock::AttachLoopInformation() { | 116 void HBasicBlock::AttachLoopInformation() { |
| 112 ASSERT(!IsLoopHeader()); | 117 ASSERT(!IsLoopHeader()); |
| 113 loop_information_ = new(zone()) HLoopInformation(this, zone()); | 118 loop_information_ = new(zone()) HLoopInformation(this, zone()); |
| 114 } | 119 } |
| 115 | 120 |
| 116 | 121 |
| 117 void HBasicBlock::DetachLoopInformation() { | 122 void HBasicBlock::DetachLoopInformation() { |
| 118 ASSERT(IsLoopHeader()); | 123 ASSERT(IsLoopHeader()); |
| 119 loop_information_ = NULL; | 124 loop_information_ = NULL; |
| 120 } | 125 } |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 } | 211 } |
| 207 | 212 |
| 208 | 213 |
| 209 void HBasicBlock::Goto(HBasicBlock* block, | 214 void HBasicBlock::Goto(HBasicBlock* block, |
| 210 FunctionState* state, | 215 FunctionState* state, |
| 211 bool add_simulate) { | 216 bool add_simulate) { |
| 212 bool drop_extra = state != NULL && | 217 bool drop_extra = state != NULL && |
| 213 state->inlining_kind() == DROP_EXTRA_ON_RETURN; | 218 state->inlining_kind() == DROP_EXTRA_ON_RETURN; |
| 214 | 219 |
| 215 if (block->IsInlineReturnTarget()) { | 220 if (block->IsInlineReturnTarget()) { |
| 216 AddInstruction(new(zone()) HLeaveInlined()); | 221 HEnvironment* env = last_environment(); |
| 222 int argument_count = env->arguments_environment()->parameter_count(); |
| 223 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count)); |
| 217 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); | 224 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); |
| 218 } | 225 } |
| 219 | 226 |
| 220 if (add_simulate) AddNewSimulate(BailoutId::None()); | 227 if (add_simulate) AddNewSimulate(BailoutId::None()); |
| 221 HGoto* instr = new(zone()) HGoto(block); | 228 HGoto* instr = new(zone()) HGoto(block); |
| 222 Finish(instr); | 229 Finish(instr); |
| 223 } | 230 } |
| 224 | 231 |
| 225 | 232 |
| 226 void HBasicBlock::AddLeaveInlined(HValue* return_value, | 233 void HBasicBlock::AddLeaveInlined(HValue* return_value, |
| 227 FunctionState* state) { | 234 FunctionState* state) { |
| 228 HBasicBlock* target = state->function_return(); | 235 HBasicBlock* target = state->function_return(); |
| 229 bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN; | 236 bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN; |
| 230 | 237 |
| 231 ASSERT(target->IsInlineReturnTarget()); | 238 ASSERT(target->IsInlineReturnTarget()); |
| 232 ASSERT(return_value != NULL); | 239 ASSERT(return_value != NULL); |
| 233 AddInstruction(new(zone()) HLeaveInlined()); | 240 HEnvironment* env = last_environment(); |
| 241 int argument_count = env->arguments_environment()->parameter_count(); |
| 242 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count)); |
| 234 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); | 243 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); |
| 235 last_environment()->Push(return_value); | 244 last_environment()->Push(return_value); |
| 236 AddNewSimulate(BailoutId::None()); | 245 AddNewSimulate(BailoutId::None()); |
| 237 HGoto* instr = new(zone()) HGoto(target); | 246 HGoto* instr = new(zone()) HGoto(target); |
| 238 Finish(instr); | 247 Finish(instr); |
| 239 } | 248 } |
| 240 | 249 |
| 241 | 250 |
| 242 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { | 251 void HBasicBlock::SetInitialEnvironment(HEnvironment* env) { |
| 243 ASSERT(!HasEnvironment()); | 252 ASSERT(!HasEnvironment()); |
| (...skipping 2034 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2278 entry_block_(NULL), | 2287 entry_block_(NULL), |
| 2279 blocks_(8, info->zone()), | 2288 blocks_(8, info->zone()), |
| 2280 values_(16, info->zone()), | 2289 values_(16, info->zone()), |
| 2281 phi_list_(NULL), | 2290 phi_list_(NULL), |
| 2282 uint32_instructions_(NULL), | 2291 uint32_instructions_(NULL), |
| 2283 osr_(NULL), | 2292 osr_(NULL), |
| 2284 info_(info), | 2293 info_(info), |
| 2285 zone_(info->zone()), | 2294 zone_(info->zone()), |
| 2286 is_recursive_(false), | 2295 is_recursive_(false), |
| 2287 use_optimistic_licm_(false), | 2296 use_optimistic_licm_(false), |
| 2288 has_soft_deoptimize_(false), | |
| 2289 depends_on_empty_array_proto_elements_(false), | 2297 depends_on_empty_array_proto_elements_(false), |
| 2290 type_change_checksum_(0), | 2298 type_change_checksum_(0), |
| 2291 maximum_environment_size_(0), | 2299 maximum_environment_size_(0), |
| 2292 no_side_effects_scope_count_(0) { | 2300 no_side_effects_scope_count_(0) { |
| 2293 if (info->IsStub()) { | 2301 if (info->IsStub()) { |
| 2294 HydrogenCodeStub* stub = info->code_stub(); | 2302 HydrogenCodeStub* stub = info->code_stub(); |
| 2295 CodeStubInterfaceDescriptor* descriptor = | 2303 CodeStubInterfaceDescriptor* descriptor = |
| 2296 stub->GetInterfaceDescriptor(isolate_); | 2304 stub->GetInterfaceDescriptor(isolate_); |
| 2297 start_environment_ = | 2305 start_environment_ = |
| 2298 new(zone_) HEnvironment(zone_, descriptor->environment_length()); | 2306 new(zone_) HEnvironment(zone_, descriptor->environment_length()); |
| (...skipping 826 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3125 | 3133 |
| 3126 #ifdef DEBUG | 3134 #ifdef DEBUG |
| 3127 // Do a full verify after building the graph and computing dominators. | 3135 // Do a full verify after building the graph and computing dominators. |
| 3128 Verify(true); | 3136 Verify(true); |
| 3129 #endif | 3137 #endif |
| 3130 | 3138 |
| 3131 if (FLAG_analyze_environment_liveness && maximum_environment_size() != 0) { | 3139 if (FLAG_analyze_environment_liveness && maximum_environment_size() != 0) { |
| 3132 Run<HEnvironmentLivenessAnalysisPhase>(); | 3140 Run<HEnvironmentLivenessAnalysisPhase>(); |
| 3133 } | 3141 } |
| 3134 | 3142 |
| 3135 Run<HPropagateDeoptimizingMarkPhase>(); | |
| 3136 if (!CheckConstPhiUses()) { | 3143 if (!CheckConstPhiUses()) { |
| 3137 *bailout_reason = kUnsupportedPhiUseOfConstVariable; | 3144 *bailout_reason = kUnsupportedPhiUseOfConstVariable; |
| 3138 return false; | 3145 return false; |
| 3139 } | 3146 } |
| 3140 Run<HRedundantPhiEliminationPhase>(); | 3147 Run<HRedundantPhiEliminationPhase>(); |
| 3141 if (!CheckArgumentsPhiUses()) { | 3148 if (!CheckArgumentsPhiUses()) { |
| 3142 *bailout_reason = kUnsupportedPhiUseOfArguments; | 3149 *bailout_reason = kUnsupportedPhiUseOfArguments; |
| 3143 return false; | 3150 return false; |
| 3144 } | 3151 } |
| 3145 | 3152 |
| 3153 // Find and mark unreachable code to simplify optimizations, especially gvn, |
| 3154 // where unreachable code could unnecessarily defeat LICM. |
| 3155 Run<HMarkUnreachableBlocksPhase>(); |
| 3156 |
| 3146 if (FLAG_check_elimination) Run<HCheckEliminationPhase>(); | 3157 if (FLAG_check_elimination) Run<HCheckEliminationPhase>(); |
| 3147 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); | 3158 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); |
| 3148 if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>(); | 3159 if (FLAG_use_escape_analysis) Run<HEscapeAnalysisPhase>(); |
| 3149 | 3160 |
| 3150 if (FLAG_load_elimination) Run<HLoadEliminationPhase>(); | 3161 if (FLAG_load_elimination) Run<HLoadEliminationPhase>(); |
| 3151 | 3162 |
| 3152 CollectPhis(); | 3163 CollectPhis(); |
| 3153 | 3164 |
| 3154 if (has_osr()) osr()->FinishOsrValues(); | 3165 if (has_osr()) osr()->FinishOsrValues(); |
| 3155 | 3166 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 3182 // Eliminate redundant stack checks on backwards branches. | 3193 // Eliminate redundant stack checks on backwards branches. |
| 3183 Run<HStackCheckEliminationPhase>(); | 3194 Run<HStackCheckEliminationPhase>(); |
| 3184 | 3195 |
| 3185 if (FLAG_array_bounds_checks_elimination) Run<HBoundsCheckEliminationPhase>(); | 3196 if (FLAG_array_bounds_checks_elimination) Run<HBoundsCheckEliminationPhase>(); |
| 3186 if (FLAG_array_bounds_checks_hoisting) Run<HBoundsCheckHoistingPhase>(); | 3197 if (FLAG_array_bounds_checks_hoisting) Run<HBoundsCheckHoistingPhase>(); |
| 3187 if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>(); | 3198 if (FLAG_array_index_dehoisting) Run<HDehoistIndexComputationsPhase>(); |
| 3188 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); | 3199 if (FLAG_dead_code_elimination) Run<HDeadCodeEliminationPhase>(); |
| 3189 | 3200 |
| 3190 RestoreActualValues(); | 3201 RestoreActualValues(); |
| 3191 | 3202 |
| 3203 // Find unreachable code a second time, GVN and other optimizations may have |
| 3204 // made blocks unreachable that were previously reachable. |
| 3205 Run<HMarkUnreachableBlocksPhase>(); |
| 3206 |
| 3192 return true; | 3207 return true; |
| 3193 } | 3208 } |
| 3194 | 3209 |
| 3195 | 3210 |
| 3196 void HGraph::RestoreActualValues() { | 3211 void HGraph::RestoreActualValues() { |
| 3197 HPhase phase("H_Restore actual values", this); | 3212 HPhase phase("H_Restore actual values", this); |
| 3198 | 3213 |
| 3199 for (int block_index = 0; block_index < blocks()->length(); block_index++) { | 3214 for (int block_index = 0; block_index < blocks()->length(); block_index++) { |
| 3200 HBasicBlock* block = blocks()->at(block_index); | 3215 HBasicBlock* block = blocks()->at(block_index); |
| 3201 | 3216 |
| (...skipping 414 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3616 | 3631 |
| 3617 // Identify the block where normal (non-fall-through) control flow | 3632 // Identify the block where normal (non-fall-through) control flow |
| 3618 // goes to. | 3633 // goes to. |
| 3619 HBasicBlock* normal_block = NULL; | 3634 HBasicBlock* normal_block = NULL; |
| 3620 if (clause->is_default()) { | 3635 if (clause->is_default()) { |
| 3621 if (last_block != NULL) { | 3636 if (last_block != NULL) { |
| 3622 normal_block = last_block; | 3637 normal_block = last_block; |
| 3623 last_block = NULL; // Cleared to indicate we've handled it. | 3638 last_block = NULL; // Cleared to indicate we've handled it. |
| 3624 } | 3639 } |
| 3625 } else { | 3640 } else { |
| 3641 // If the current test block is deoptimizing due to an unhandled clause |
| 3642 // of the switch, the test instruction is in the next block since the |
| 3643 // deopt must end the current block. |
| 3644 if (curr_test_block->IsDeoptimizing()) { |
| 3645 ASSERT(curr_test_block->end()->SecondSuccessor() == NULL); |
| 3646 curr_test_block = curr_test_block->end()->FirstSuccessor(); |
| 3647 } |
| 3626 normal_block = curr_test_block->end()->FirstSuccessor(); | 3648 normal_block = curr_test_block->end()->FirstSuccessor(); |
| 3627 curr_test_block = curr_test_block->end()->SecondSuccessor(); | 3649 curr_test_block = curr_test_block->end()->SecondSuccessor(); |
| 3628 } | 3650 } |
| 3629 | 3651 |
| 3630 // Identify a block to emit the body into. | 3652 // Identify a block to emit the body into. |
| 3631 if (normal_block == NULL) { | 3653 if (normal_block == NULL) { |
| 3632 if (fall_through_block == NULL) { | 3654 if (fall_through_block == NULL) { |
| 3633 // (a) Unreachable. | 3655 // (a) Unreachable. |
| 3634 if (clause->is_default()) { | 3656 if (clause->is_default()) { |
| 3635 continue; // Might still be reachable clause bodies. | 3657 continue; // Might still be reachable clause bodies. |
| (...skipping 342 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3978 shared_info = Compiler::BuildFunctionInfo(expr, current_info()->script()); | 4000 shared_info = Compiler::BuildFunctionInfo(expr, current_info()->script()); |
| 3979 } | 4001 } |
| 3980 // We also have a stack overflow if the recursive compilation did. | 4002 // We also have a stack overflow if the recursive compilation did. |
| 3981 if (HasStackOverflow()) return; | 4003 if (HasStackOverflow()) return; |
| 3982 HFunctionLiteral* instr = | 4004 HFunctionLiteral* instr = |
| 3983 New<HFunctionLiteral>(shared_info, expr->pretenure()); | 4005 New<HFunctionLiteral>(shared_info, expr->pretenure()); |
| 3984 return ast_context()->ReturnInstruction(instr, expr->id()); | 4006 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 3985 } | 4007 } |
| 3986 | 4008 |
| 3987 | 4009 |
| 3988 void HOptimizedGraphBuilder::VisitSharedFunctionInfoLiteral( | 4010 void HOptimizedGraphBuilder::VisitNativeFunctionLiteral( |
| 3989 SharedFunctionInfoLiteral* expr) { | 4011 NativeFunctionLiteral* expr) { |
| 3990 ASSERT(!HasStackOverflow()); | 4012 ASSERT(!HasStackOverflow()); |
| 3991 ASSERT(current_block() != NULL); | 4013 ASSERT(current_block() != NULL); |
| 3992 ASSERT(current_block()->HasPredecessor()); | 4014 ASSERT(current_block()->HasPredecessor()); |
| 3993 return Bailout(kSharedFunctionInfoLiteral); | 4015 return Bailout(kNativeFunctionLiteral); |
| 3994 } | 4016 } |
| 3995 | 4017 |
| 3996 | 4018 |
| 3997 void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) { | 4019 void HOptimizedGraphBuilder::VisitConditional(Conditional* expr) { |
| 3998 ASSERT(!HasStackOverflow()); | 4020 ASSERT(!HasStackOverflow()); |
| 3999 ASSERT(current_block() != NULL); | 4021 ASSERT(current_block() != NULL); |
| 4000 ASSERT(current_block()->HasPredecessor()); | 4022 ASSERT(current_block()->HasPredecessor()); |
| 4001 HBasicBlock* cond_true = graph()->CreateBasicBlock(); | 4023 HBasicBlock* cond_true = graph()->CreateBasicBlock(); |
| 4002 HBasicBlock* cond_false = graph()->CreateBasicBlock(); | 4024 HBasicBlock* cond_false = graph()->CreateBasicBlock(); |
| 4003 CHECK_BAILOUT(VisitForControl(expr->condition(), cond_true, cond_false)); | 4025 CHECK_BAILOUT(VisitForControl(expr->condition(), cond_true, cond_false)); |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4316 // Check whether to use fast or slow deep-copying for boilerplate. | 4338 // Check whether to use fast or slow deep-copying for boilerplate. |
| 4317 int max_properties = kMaxFastLiteralProperties; | 4339 int max_properties = kMaxFastLiteralProperties; |
| 4318 Handle<Object> boilerplate(closure->literals()->get( | 4340 Handle<Object> boilerplate(closure->literals()->get( |
| 4319 expr->literal_index()), isolate()); | 4341 expr->literal_index()), isolate()); |
| 4320 if (boilerplate->IsJSObject() && | 4342 if (boilerplate->IsJSObject() && |
| 4321 IsFastLiteral(Handle<JSObject>::cast(boilerplate), | 4343 IsFastLiteral(Handle<JSObject>::cast(boilerplate), |
| 4322 kMaxFastLiteralDepth, | 4344 kMaxFastLiteralDepth, |
| 4323 &max_properties)) { | 4345 &max_properties)) { |
| 4324 Handle<JSObject> boilerplate_object = Handle<JSObject>::cast(boilerplate); | 4346 Handle<JSObject> boilerplate_object = Handle<JSObject>::cast(boilerplate); |
| 4325 | 4347 |
| 4326 literal = BuildFastLiteral(boilerplate_object, | 4348 literal = BuildFastLiteral(boilerplate_object); |
| 4327 Handle<Object>::null(), | |
| 4328 DONT_TRACK_ALLOCATION_SITE); | |
| 4329 } else { | 4349 } else { |
| 4330 NoObservableSideEffectsScope no_effects(this); | 4350 NoObservableSideEffectsScope no_effects(this); |
| 4331 Handle<FixedArray> closure_literals(closure->literals(), isolate()); | 4351 Handle<FixedArray> closure_literals(closure->literals(), isolate()); |
| 4332 Handle<FixedArray> constant_properties = expr->constant_properties(); | 4352 Handle<FixedArray> constant_properties = expr->constant_properties(); |
| 4333 int literal_index = expr->literal_index(); | 4353 int literal_index = expr->literal_index(); |
| 4334 int flags = expr->fast_elements() | 4354 int flags = expr->fast_elements() |
| 4335 ? ObjectLiteral::kFastElements : ObjectLiteral::kNoFlags; | 4355 ? ObjectLiteral::kFastElements : ObjectLiteral::kNoFlags; |
| 4336 flags |= expr->has_function() | 4356 flags |= expr->has_function() |
| 4337 ? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags; | 4357 ? ObjectLiteral::kHasFunction : ObjectLiteral::kNoFlags; |
| 4338 | 4358 |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4462 ElementsKind boilerplate_elements_kind = | 4482 ElementsKind boilerplate_elements_kind = |
| 4463 Handle<JSObject>::cast(boilerplate_object)->GetElementsKind(); | 4483 Handle<JSObject>::cast(boilerplate_object)->GetElementsKind(); |
| 4464 | 4484 |
| 4465 ASSERT(AllocationSite::CanTrack(boilerplate_object->map()->instance_type())); | 4485 ASSERT(AllocationSite::CanTrack(boilerplate_object->map()->instance_type())); |
| 4466 | 4486 |
| 4467 // Check whether to use fast or slow deep-copying for boilerplate. | 4487 // Check whether to use fast or slow deep-copying for boilerplate. |
| 4468 int max_properties = kMaxFastLiteralProperties; | 4488 int max_properties = kMaxFastLiteralProperties; |
| 4469 if (IsFastLiteral(boilerplate_object, | 4489 if (IsFastLiteral(boilerplate_object, |
| 4470 kMaxFastLiteralDepth, | 4490 kMaxFastLiteralDepth, |
| 4471 &max_properties)) { | 4491 &max_properties)) { |
| 4472 // TODO(mvstanton): This heuristic is only a temporary solution. In the | 4492 literal = BuildFastLiteral(boilerplate_object); |
| 4473 // end, we want to quit creating allocation site info after a certain number | |
| 4474 // of GCs for a call site. | |
| 4475 AllocationSiteMode mode = AllocationSite::GetMode( | |
| 4476 boilerplate_elements_kind); | |
| 4477 | |
| 4478 // it doesn't make sense to create allocation mementos if we are going to | |
| 4479 // create in old space. | |
| 4480 if (mode == TRACK_ALLOCATION_SITE && | |
| 4481 isolate()->heap()->GetPretenureMode() == TENURED) { | |
| 4482 mode = DONT_TRACK_ALLOCATION_SITE; | |
| 4483 } | |
| 4484 | |
| 4485 literal = BuildFastLiteral(boilerplate_object, | |
| 4486 site, | |
| 4487 mode); | |
| 4488 } else { | 4493 } else { |
| 4489 NoObservableSideEffectsScope no_effects(this); | 4494 NoObservableSideEffectsScope no_effects(this); |
| 4490 // Boilerplate already exists and constant elements are never accessed, | 4495 // Boilerplate already exists and constant elements are never accessed, |
| 4491 // pass an empty fixed array to the runtime function instead. | 4496 // pass an empty fixed array to the runtime function instead. |
| 4492 Handle<FixedArray> constants = isolate()->factory()->empty_fixed_array(); | 4497 Handle<FixedArray> constants = isolate()->factory()->empty_fixed_array(); |
| 4493 int literal_index = expr->literal_index(); | 4498 int literal_index = expr->literal_index(); |
| 4494 | 4499 |
| 4495 Add<HPushArgument>(Add<HConstant>(literals)); | 4500 Add<HPushArgument>(Add<HConstant>(literals)); |
| 4496 Add<HPushArgument>(Add<HConstant>(literal_index)); | 4501 Add<HPushArgument>(Add<HConstant>(literal_index)); |
| 4497 Add<HPushArgument>(Add<HConstant>(constants)); | 4502 Add<HPushArgument>(Add<HConstant>(constants)); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4547 } | 4552 } |
| 4548 | 4553 |
| 4549 Add<HSimulate>(expr->GetIdForElement(i)); | 4554 Add<HSimulate>(expr->GetIdForElement(i)); |
| 4550 } | 4555 } |
| 4551 | 4556 |
| 4552 Drop(1); // array literal index | 4557 Drop(1); // array literal index |
| 4553 return ast_context()->ReturnValue(Pop()); | 4558 return ast_context()->ReturnValue(Pop()); |
| 4554 } | 4559 } |
| 4555 | 4560 |
| 4556 | 4561 |
| 4557 // Sets the lookup result and returns true if the load/store can be inlined. | |
| 4558 static bool ComputeLoadStoreField(Handle<Map> type, | |
| 4559 Handle<String> name, | |
| 4560 LookupResult* lookup, | |
| 4561 bool is_store) { | |
| 4562 ASSERT(!is_store || !type->is_observed()); | |
| 4563 if (!CanInlinePropertyAccess(*type)) { | |
| 4564 lookup->NotFound(); | |
| 4565 return false; | |
| 4566 } | |
| 4567 // If we directly find a field, the access can be inlined. | |
| 4568 type->LookupDescriptor(NULL, *name, lookup); | |
| 4569 if (lookup->IsField()) return true; | |
| 4570 | |
| 4571 // For a load, we are out of luck if there is no such field. | |
| 4572 if (!is_store) return false; | |
| 4573 | |
| 4574 // 2nd chance: A store into a non-existent field can still be inlined if we | |
| 4575 // have a matching transition and some room left in the object. | |
| 4576 type->LookupTransition(NULL, *name, lookup); | |
| 4577 return lookup->IsTransitionToField(*type) && | |
| 4578 (type->unused_property_fields() > 0); | |
| 4579 } | |
| 4580 | |
| 4581 | |
| 4582 HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object, | 4562 HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object, |
| 4583 Handle<Map> map) { | 4563 Handle<Map> map) { |
| 4584 BuildCheckHeapObject(object); | 4564 BuildCheckHeapObject(object); |
| 4585 return Add<HCheckMaps>(object, map, top_info()); | 4565 return Add<HCheckMaps>(object, map, top_info()); |
| 4586 } | 4566 } |
| 4587 | 4567 |
| 4588 | 4568 |
| 4589 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( | 4569 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( |
| 4590 HValue* checked_object, | 4570 HValue* checked_object, |
| 4591 Handle<String> name, | 4571 Handle<String> name, |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4677 HValue* context = environment()->context(); | 4657 HValue* context = environment()->context(); |
| 4678 return new(zone()) HStoreNamedGeneric( | 4658 return new(zone()) HStoreNamedGeneric( |
| 4679 context, | 4659 context, |
| 4680 object, | 4660 object, |
| 4681 name, | 4661 name, |
| 4682 value, | 4662 value, |
| 4683 function_strict_mode_flag()); | 4663 function_strict_mode_flag()); |
| 4684 } | 4664 } |
| 4685 | 4665 |
| 4686 | 4666 |
| 4667 // Sets the lookup result and returns true if the load/store can be inlined. |
| 4668 static bool ComputeStoreField(Handle<Map> type, |
| 4669 Handle<String> name, |
| 4670 LookupResult* lookup, |
| 4671 bool lookup_transition = true) { |
| 4672 ASSERT(!type->is_observed()); |
| 4673 if (!CanInlinePropertyAccess(*type)) { |
| 4674 lookup->NotFound(); |
| 4675 return false; |
| 4676 } |
| 4677 // If we directly find a field, the access can be inlined. |
| 4678 type->LookupDescriptor(NULL, *name, lookup); |
| 4679 if (lookup->IsField()) return true; |
| 4680 |
| 4681 if (!lookup_transition) return false; |
| 4682 |
| 4683 type->LookupTransition(NULL, *name, lookup); |
| 4684 return lookup->IsTransitionToField(*type) && |
| 4685 (type->unused_property_fields() > 0); |
| 4686 } |
| 4687 |
| 4688 |
| 4687 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic( | 4689 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic( |
| 4688 HValue* object, | 4690 HValue* object, |
| 4689 Handle<String> name, | 4691 Handle<String> name, |
| 4690 HValue* value, | 4692 HValue* value, |
| 4691 Handle<Map> map) { | 4693 Handle<Map> map) { |
| 4692 // Handle a store to a known field. | 4694 // Handle a store to a known field. |
| 4693 LookupResult lookup(isolate()); | 4695 LookupResult lookup(isolate()); |
| 4694 if (ComputeLoadStoreField(map, name, &lookup, true)) { | 4696 if (ComputeStoreField(map, name, &lookup)) { |
| 4695 HCheckMaps* checked_object = AddCheckMap(object, map); | 4697 HCheckMaps* checked_object = AddCheckMap(object, map); |
| 4696 return BuildStoreNamedField(checked_object, name, value, map, &lookup); | 4698 return BuildStoreNamedField(checked_object, name, value, map, &lookup); |
| 4697 } | 4699 } |
| 4698 | 4700 |
| 4699 // No luck, do a generic store. | 4701 // No luck, do a generic store. |
| 4700 return BuildStoreNamedGeneric(object, name, value); | 4702 return BuildStoreNamedGeneric(object, name, value); |
| 4701 } | 4703 } |
| 4702 | 4704 |
| 4703 | 4705 |
| 4704 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad( | 4706 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad( |
| 4705 PropertyAccessInfo* info) { | 4707 PropertyAccessInfo* info) { |
| 4706 if (!CanInlinePropertyAccess(*map_)) return false; | 4708 if (!CanInlinePropertyAccess(*map_)) return false; |
| 4707 | 4709 |
| 4708 if (!LookupDescriptor()) return false; | 4710 if (!LookupDescriptor()) return false; |
| 4709 | 4711 |
| 4710 if (!lookup_.IsFound()) { | 4712 if (!lookup_.IsFound()) { |
| 4711 return (!info->lookup_.IsFound() || !info->holder_.is_null()) && | 4713 return (!info->lookup_.IsFound() || info->has_holder()) && |
| 4712 map_->prototype() == info->map_->prototype(); | 4714 map_->prototype() == info->map_->prototype(); |
| 4713 } | 4715 } |
| 4714 | 4716 |
| 4717 // Mismatch if the other access info found the property in the prototype |
| 4718 // chain. |
| 4719 if (info->has_holder()) return false; |
| 4720 |
| 4715 if (lookup_.IsPropertyCallbacks()) { | 4721 if (lookup_.IsPropertyCallbacks()) { |
| 4716 return accessor_.is_identical_to(info->accessor_); | 4722 return accessor_.is_identical_to(info->accessor_); |
| 4717 } | 4723 } |
| 4718 | 4724 |
| 4719 if (lookup_.IsConstant()) { | 4725 if (lookup_.IsConstant()) { |
| 4720 return constant_.is_identical_to(info->constant_); | 4726 return constant_.is_identical_to(info->constant_); |
| 4721 } | 4727 } |
| 4722 | 4728 |
| 4723 ASSERT(lookup_.IsField()); | 4729 ASSERT(lookup_.IsField()); |
| 4724 if (!info->lookup_.IsField()) return false; | 4730 if (!info->lookup_.IsField()) return false; |
| (...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4950 // for all maps. Requires special map check on the set of all handled maps. | 4956 // for all maps. Requires special map check on the set of all handled maps. |
| 4951 if (types->length() > kMaxStorePolymorphism) return false; | 4957 if (types->length() > kMaxStorePolymorphism) return false; |
| 4952 | 4958 |
| 4953 LookupResult lookup(isolate()); | 4959 LookupResult lookup(isolate()); |
| 4954 int count; | 4960 int count; |
| 4955 Representation representation = Representation::None(); | 4961 Representation representation = Representation::None(); |
| 4956 HObjectAccess access = HObjectAccess::ForMap(); // initial value unused. | 4962 HObjectAccess access = HObjectAccess::ForMap(); // initial value unused. |
| 4957 for (count = 0; count < types->length(); ++count) { | 4963 for (count = 0; count < types->length(); ++count) { |
| 4958 Handle<Map> map = types->at(count); | 4964 Handle<Map> map = types->at(count); |
| 4959 // Pass false to ignore transitions. | 4965 // Pass false to ignore transitions. |
| 4960 if (!ComputeLoadStoreField(map, name, &lookup, false)) break; | 4966 if (!ComputeStoreField(map, name, &lookup, false)) break; |
| 4961 ASSERT(!map->is_observed()); | 4967 ASSERT(!map->is_observed()); |
| 4962 | 4968 |
| 4963 HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name); | 4969 HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name); |
| 4964 Representation new_representation = new_access.representation(); | 4970 Representation new_representation = new_access.representation(); |
| 4965 | 4971 |
| 4966 if (count == 0) { | 4972 if (count == 0) { |
| 4967 // First time through the loop; set access and representation. | 4973 // First time through the loop; set access and representation. |
| 4968 access = new_access; | 4974 access = new_access; |
| 4969 representation = new_representation; | 4975 representation = new_representation; |
| 4970 } else if (!representation.IsCompatibleForStore(new_representation)) { | 4976 } else if (!representation.IsCompatibleForStore(new_representation)) { |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5012 } | 5018 } |
| 5013 | 5019 |
| 5014 // TODO(ager): We should recognize when the prototype chains for different | 5020 // TODO(ager): We should recognize when the prototype chains for different |
| 5015 // maps are identical. In that case we can avoid repeatedly generating the | 5021 // maps are identical. In that case we can avoid repeatedly generating the |
| 5016 // same prototype map checks. | 5022 // same prototype map checks. |
| 5017 int count = 0; | 5023 int count = 0; |
| 5018 HBasicBlock* join = NULL; | 5024 HBasicBlock* join = NULL; |
| 5019 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { | 5025 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { |
| 5020 Handle<Map> map = types->at(i); | 5026 Handle<Map> map = types->at(i); |
| 5021 LookupResult lookup(isolate()); | 5027 LookupResult lookup(isolate()); |
| 5022 if (ComputeLoadStoreField(map, name, &lookup, true)) { | 5028 if (ComputeStoreField(map, name, &lookup)) { |
| 5023 if (count == 0) { | 5029 if (count == 0) { |
| 5024 BuildCheckHeapObject(object); | 5030 BuildCheckHeapObject(object); |
| 5025 join = graph()->CreateBasicBlock(); | 5031 join = graph()->CreateBasicBlock(); |
| 5026 } | 5032 } |
| 5027 ++count; | 5033 ++count; |
| 5028 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 5034 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 5029 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 5035 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 5030 HCompareMap* compare = New<HCompareMap>(object, map, if_true, if_false); | 5036 HCompareMap* compare = New<HCompareMap>(object, map, if_true, if_false); |
| 5031 current_block()->Finish(compare); | 5037 current_block()->Finish(compare); |
| 5032 | 5038 |
| (...skipping 1345 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6378 int nodes_added = InliningAstSize(target); | 6384 int nodes_added = InliningAstSize(target); |
| 6379 if (nodes_added == kNotInlinable) return false; | 6385 if (nodes_added == kNotInlinable) return false; |
| 6380 | 6386 |
| 6381 Handle<JSFunction> caller = current_info()->closure(); | 6387 Handle<JSFunction> caller = current_info()->closure(); |
| 6382 | 6388 |
| 6383 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { | 6389 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { |
| 6384 TraceInline(target, caller, "target AST is too large [early]"); | 6390 TraceInline(target, caller, "target AST is too large [early]"); |
| 6385 return false; | 6391 return false; |
| 6386 } | 6392 } |
| 6387 | 6393 |
| 6388 #if !V8_TARGET_ARCH_IA32 | 6394 #if !V8_TARGET_ARCH_IA32 && !V8_TARGET_ARCH_ARM && !V8_TARGET_ARCH_MIPS |
| 6389 // Target must be able to use caller's context. | 6395 // Target must be able to use caller's context. |
| 6390 CompilationInfo* outer_info = current_info(); | 6396 CompilationInfo* outer_info = current_info(); |
| 6391 if (target->context() != outer_info->closure()->context() || | 6397 if (target->context() != outer_info->closure()->context() || |
| 6392 outer_info->scope()->contains_with() || | 6398 outer_info->scope()->contains_with() || |
| 6393 outer_info->scope()->num_heap_slots() > 0) { | 6399 outer_info->scope()->num_heap_slots() > 0) { |
| 6394 TraceInline(target, caller, "target requires context change"); | 6400 TraceInline(target, caller, "target requires context change"); |
| 6395 return false; | 6401 return false; |
| 6396 } | 6402 } |
| 6397 #endif | 6403 #endif |
| 6398 | 6404 |
| (...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6527 HConstant* undefined = graph()->GetConstantUndefined(); | 6533 HConstant* undefined = graph()->GetConstantUndefined(); |
| 6528 bool undefined_receiver = HEnvironment::UseUndefinedReceiver( | 6534 bool undefined_receiver = HEnvironment::UseUndefinedReceiver( |
| 6529 target, function, call_kind, inlining_kind); | 6535 target, function, call_kind, inlining_kind); |
| 6530 HEnvironment* inner_env = | 6536 HEnvironment* inner_env = |
| 6531 environment()->CopyForInlining(target, | 6537 environment()->CopyForInlining(target, |
| 6532 arguments_count, | 6538 arguments_count, |
| 6533 function, | 6539 function, |
| 6534 undefined, | 6540 undefined, |
| 6535 function_state()->inlining_kind(), | 6541 function_state()->inlining_kind(), |
| 6536 undefined_receiver); | 6542 undefined_receiver); |
| 6537 #if V8_TARGET_ARCH_IA32 | 6543 #if V8_TARGET_ARCH_IA32 || V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS |
| 6538 // IA32 only, overwrite the caller's context in the deoptimization | 6544 // IA32, ARM and MIPS only, overwrite the caller's context in the |
| 6539 // environment with the correct one. | 6545 // deoptimization environment with the correct one. |
| 6540 // | 6546 // |
| 6541 // TODO(kmillikin): implement the same inlining on other platforms so we | 6547 // TODO(kmillikin): implement the same inlining on other platforms so we |
| 6542 // can remove the unsightly ifdefs in this function. | 6548 // can remove the unsightly ifdefs in this function. |
| 6543 HConstant* context = Add<HConstant>(Handle<Context>(target->context())); | 6549 HConstant* context = Add<HConstant>(Handle<Context>(target->context())); |
| 6544 inner_env->BindContext(context); | 6550 inner_env->BindContext(context); |
| 6545 #endif | 6551 #endif |
| 6546 | 6552 |
| 6547 Add<HSimulate>(return_id); | 6553 Add<HSimulate>(return_id); |
| 6548 current_block()->UpdateEnvironment(inner_env); | 6554 current_block()->UpdateEnvironment(inner_env); |
| 6549 HArgumentsObject* arguments_object = NULL; | 6555 HArgumentsObject* arguments_object = NULL; |
| (...skipping 963 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7513 CreateJoin(materialize_false, materialize_true, expr->id()); | 7519 CreateJoin(materialize_false, materialize_true, expr->id()); |
| 7514 set_current_block(join); | 7520 set_current_block(join); |
| 7515 if (join != NULL) return ast_context()->ReturnValue(Pop()); | 7521 if (join != NULL) return ast_context()->ReturnValue(Pop()); |
| 7516 } | 7522 } |
| 7517 | 7523 |
| 7518 | 7524 |
| 7519 HInstruction* HOptimizedGraphBuilder::BuildIncrement( | 7525 HInstruction* HOptimizedGraphBuilder::BuildIncrement( |
| 7520 bool returns_original_input, | 7526 bool returns_original_input, |
| 7521 CountOperation* expr) { | 7527 CountOperation* expr) { |
| 7522 // The input to the count operation is on top of the expression stack. | 7528 // The input to the count operation is on top of the expression stack. |
| 7523 TypeInfo info = expr->type(); | 7529 Handle<Type> info = expr->type(); |
| 7524 Representation rep = Representation::FromType(info); | 7530 Representation rep = Representation::FromType(info); |
| 7525 if (rep.IsNone() || rep.IsTagged()) { | 7531 if (rep.IsNone() || rep.IsTagged()) { |
| 7526 rep = Representation::Smi(); | 7532 rep = Representation::Smi(); |
| 7527 } | 7533 } |
| 7528 | 7534 |
| 7529 if (returns_original_input) { | 7535 if (returns_original_input) { |
| 7530 // We need an explicit HValue representing ToNumber(input). The | 7536 // We need an explicit HValue representing ToNumber(input). The |
| 7531 // actual HChange instruction we need is (sometimes) added in a later | 7537 // actual HChange instruction we need is (sometimes) added in a later |
| 7532 // phase, so it is not available now to be used as an input to HAdd and | 7538 // phase, so it is not available now to be used as an input to HAdd and |
| 7533 // as the return value. | 7539 // as the return value. |
| (...skipping 283 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7817 return value; | 7823 return value; |
| 7818 } | 7824 } |
| 7819 | 7825 |
| 7820 if (expected_obj->Is(Type::Undefined())) { | 7826 if (expected_obj->Is(Type::Undefined())) { |
| 7821 // This is already done by HChange. | 7827 // This is already done by HChange. |
| 7822 *expected = handle(Type::Union( | 7828 *expected = handle(Type::Union( |
| 7823 expected_number, handle(Type::Double(), isolate())), isolate()); | 7829 expected_number, handle(Type::Double(), isolate())), isolate()); |
| 7824 return value; | 7830 return value; |
| 7825 } | 7831 } |
| 7826 | 7832 |
| 7827 if (expected_obj->Is(Type::Null())) { | |
| 7828 *expected = handle(Type::Union( | |
| 7829 expected_number, handle(Type::Smi(), isolate())), isolate()); | |
| 7830 IfBuilder if_null(this); | |
| 7831 if_null.If<HCompareObjectEqAndBranch>(value, | |
| 7832 graph()->GetConstantNull()); | |
| 7833 if_null.Then(); | |
| 7834 Push(graph()->GetConstant0()); | |
| 7835 if_null.Else(); | |
| 7836 Push(value); | |
| 7837 if_null.End(); | |
| 7838 return Pop(); | |
| 7839 } | |
| 7840 | |
| 7841 if (expected_obj->Is(Type::Boolean())) { | |
| 7842 *expected = handle(Type::Union( | |
| 7843 expected_number, handle(Type::Smi(), isolate())), isolate()); | |
| 7844 IfBuilder if_true(this); | |
| 7845 if_true.If<HCompareObjectEqAndBranch>(value, | |
| 7846 graph()->GetConstantTrue()); | |
| 7847 if_true.Then(); | |
| 7848 Push(graph()->GetConstant1()); | |
| 7849 if_true.Else(); | |
| 7850 IfBuilder if_false(this); | |
| 7851 if_false.If<HCompareObjectEqAndBranch>(value, | |
| 7852 graph()->GetConstantFalse()); | |
| 7853 if_false.Then(); | |
| 7854 Push(graph()->GetConstant0()); | |
| 7855 if_false.Else(); | |
| 7856 Push(value); | |
| 7857 if_false.End(); | |
| 7858 if_true.End(); | |
| 7859 return Pop(); | |
| 7860 } | |
| 7861 | |
| 7862 return value; | 7833 return value; |
| 7863 } | 7834 } |
| 7864 | 7835 |
| 7865 | 7836 |
| 7866 HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( | 7837 HInstruction* HOptimizedGraphBuilder::BuildBinaryOperation( |
| 7867 BinaryOperation* expr, | 7838 BinaryOperation* expr, |
| 7868 HValue* left, | 7839 HValue* left, |
| 7869 HValue* right) { | 7840 HValue* right) { |
| 7870 Handle<Type> left_type = expr->left()->bounds().lower; | 7841 Handle<Type> left_type = expr->left()->bounds().lower; |
| 7871 Handle<Type> right_type = expr->right()->bounds().lower; | 7842 Handle<Type> right_type = expr->right()->bounds().lower; |
| 7872 Handle<Type> result_type = expr->bounds().lower; | 7843 Handle<Type> result_type = expr->bounds().lower; |
| 7873 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); | 7844 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); |
| 7874 | 7845 |
| 7875 return HGraphBuilder::BuildBinaryOperation(expr->op(), left, right, | 7846 return HGraphBuilder::BuildBinaryOperation(expr->op(), left, right, |
| 7876 left_type, right_type, result_type, fixed_right_arg); | 7847 left_type, right_type, result_type, fixed_right_arg); |
| 7877 } | 7848 } |
| 7878 | 7849 |
| 7879 | 7850 |
| 7880 HInstruction* HGraphBuilder::BuildBinaryOperation( | 7851 HInstruction* HGraphBuilder::BuildBinaryOperation( |
| 7881 Token::Value op, | 7852 Token::Value op, |
| 7882 HValue* left, | 7853 HValue* left, |
| 7883 HValue* right, | 7854 HValue* right, |
| 7884 Handle<Type> left_type, | 7855 Handle<Type> left_type, |
| 7885 Handle<Type> right_type, | 7856 Handle<Type> right_type, |
| 7886 Handle<Type> result_type, | 7857 Handle<Type> result_type, |
| 7887 Maybe<int> fixed_right_arg) { | 7858 Maybe<int> fixed_right_arg, |
| 7859 bool binop_stub) { |
| 7888 | 7860 |
| 7889 Representation left_rep = Representation::FromType(left_type); | 7861 Representation left_rep = Representation::FromType(left_type); |
| 7890 Representation right_rep = Representation::FromType(right_type); | 7862 Representation right_rep = Representation::FromType(right_type); |
| 7891 | 7863 |
| 7892 bool maybe_string_add = op == Token::ADD && | 7864 bool maybe_string_add = op == Token::ADD && |
| 7893 (left_type->Maybe(Type::String()) || | 7865 (left_type->Maybe(Type::String()) || |
| 7894 right_type->Maybe(Type::String())); | 7866 right_type->Maybe(Type::String())); |
| 7895 | 7867 |
| 7896 if (left_type->Is(Type::None())) { | 7868 if (left_type->Is(Type::None())) { |
| 7897 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", | 7869 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", |
| 7898 Deoptimizer::SOFT); | 7870 Deoptimizer::SOFT); |
| 7899 // TODO(rossberg): we should be able to get rid of non-continuous | 7871 // TODO(rossberg): we should be able to get rid of non-continuous |
| 7900 // defaults. | 7872 // defaults. |
| 7901 left_type = handle(Type::Any(), isolate()); | 7873 left_type = handle(Type::Any(), isolate()); |
| 7902 } else { | 7874 } else { |
| 7903 if (!maybe_string_add) left = TruncateToNumber(left, &left_type); | 7875 if (!maybe_string_add) left = TruncateToNumber(left, &left_type); |
| 7904 left_rep = Representation::FromType(left_type); | 7876 left_rep = Representation::FromType(left_type); |
| 7905 } | 7877 } |
| 7906 | 7878 |
| 7907 if (right_type->Is(Type::None())) { | 7879 if (right_type->Is(Type::None())) { |
| 7908 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", | 7880 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", |
| 7909 Deoptimizer::SOFT); | 7881 Deoptimizer::SOFT); |
| 7910 right_type = handle(Type::Any(), isolate()); | 7882 right_type = handle(Type::Any(), isolate()); |
| 7911 } else { | 7883 } else { |
| 7912 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); | 7884 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); |
| 7913 right_rep = Representation::FromType(right_type); | 7885 right_rep = Representation::FromType(right_type); |
| 7914 } | 7886 } |
| 7915 | 7887 |
| 7888 if (binop_stub) { |
| 7889 left = EnforceNumberType(left, left_type); |
| 7890 right = EnforceNumberType(right, right_type); |
| 7891 } |
| 7892 |
| 7916 Representation result_rep = Representation::FromType(result_type); | 7893 Representation result_rep = Representation::FromType(result_type); |
| 7917 | 7894 |
| 7918 bool is_string_add = op == Token::ADD && | 7895 bool is_non_primitive = (left_rep.IsTagged() && !left_rep.IsSmi()) || |
| 7919 (left_type->Is(Type::String()) || | 7896 (right_rep.IsTagged() && !right_rep.IsSmi()); |
| 7920 right_type->Is(Type::String())); | 7897 bool is_string_add = op == Token::ADD && |
| 7898 (left_type->Is(Type::String()) || |
| 7899 right_type->Is(Type::String())); |
| 7921 | 7900 |
| 7922 HInstruction* instr = NULL; | 7901 HInstruction* instr = NULL; |
| 7923 switch (op) { | 7902 // Only the stub is allowed to call into the runtime, since otherwise we would |
| 7924 case Token::ADD: | 7903 // inline several instructions (including the two pushes) for every tagged |
| 7925 if (is_string_add) { | 7904 // operation in optimized code, which is more expensive, than a stub call. |
| 7926 StringAddFlags flags = STRING_ADD_CHECK_BOTH; | 7905 if (binop_stub && is_non_primitive && !is_string_add) { |
| 7927 if (left_type->Is(Type::String())) { | 7906 HValue* function = AddLoadJSBuiltin(BinaryOpIC::TokenToJSBuiltin(op)); |
| 7928 BuildCheckHeapObject(left); | 7907 Add<HPushArgument>(left); |
| 7929 AddInstruction(HCheckInstanceType::NewIsString(left, zone())); | 7908 Add<HPushArgument>(right); |
| 7930 flags = STRING_ADD_CHECK_RIGHT; | 7909 instr = NewUncasted<HInvokeFunction>(function, 2); |
| 7910 } else { |
| 7911 switch (op) { |
| 7912 case Token::ADD: |
| 7913 if (is_string_add) { |
| 7914 StringAddFlags flags = STRING_ADD_CHECK_BOTH; |
| 7915 if (left_type->Is(Type::String())) { |
| 7916 BuildCheckHeapObject(left); |
| 7917 AddInstruction(HCheckInstanceType::NewIsString(left, zone())); |
| 7918 flags = STRING_ADD_CHECK_RIGHT; |
| 7919 } |
| 7920 if (right_type->Is(Type::String())) { |
| 7921 BuildCheckHeapObject(right); |
| 7922 AddInstruction(HCheckInstanceType::NewIsString(right, zone())); |
| 7923 flags = (flags == STRING_ADD_CHECK_BOTH) |
| 7924 ? STRING_ADD_CHECK_LEFT : STRING_ADD_CHECK_NONE; |
| 7925 } |
| 7926 instr = NewUncasted<HStringAdd>(left, right, flags); |
| 7927 } else { |
| 7928 instr = NewUncasted<HAdd>(left, right); |
| 7931 } | 7929 } |
| 7932 if (right_type->Is(Type::String())) { | 7930 break; |
| 7933 BuildCheckHeapObject(right); | 7931 case Token::SUB: |
| 7934 AddInstruction(HCheckInstanceType::NewIsString(right, zone())); | 7932 instr = NewUncasted<HSub>(left, right); |
| 7935 flags = (flags == STRING_ADD_CHECK_BOTH) | 7933 break; |
| 7936 ? STRING_ADD_CHECK_LEFT : STRING_ADD_CHECK_NONE; | 7934 case Token::MUL: |
| 7935 instr = NewUncasted<HMul>(left, right); |
| 7936 break; |
| 7937 case Token::MOD: |
| 7938 instr = NewUncasted<HMod>(left, right, fixed_right_arg); |
| 7939 break; |
| 7940 case Token::DIV: |
| 7941 instr = NewUncasted<HDiv>(left, right); |
| 7942 break; |
| 7943 case Token::BIT_XOR: |
| 7944 case Token::BIT_AND: |
| 7945 instr = NewUncasted<HBitwise>(op, left, right); |
| 7946 break; |
| 7947 case Token::BIT_OR: { |
| 7948 HValue* operand, *shift_amount; |
| 7949 if (left_type->Is(Type::Signed32()) && |
| 7950 right_type->Is(Type::Signed32()) && |
| 7951 MatchRotateRight(left, right, &operand, &shift_amount)) { |
| 7952 instr = NewUncasted<HRor>(operand, shift_amount); |
| 7953 } else { |
| 7954 instr = NewUncasted<HBitwise>(op, left, right); |
| 7937 } | 7955 } |
| 7938 instr = NewUncasted<HStringAdd>(left, right, flags); | 7956 break; |
| 7939 } else { | |
| 7940 instr = NewUncasted<HAdd>(left, right); | |
| 7941 } | 7957 } |
| 7942 break; | 7958 case Token::SAR: |
| 7943 case Token::SUB: | 7959 instr = NewUncasted<HSar>(left, right); |
| 7944 instr = NewUncasted<HSub>(left, right); | 7960 break; |
| 7945 break; | 7961 case Token::SHR: |
| 7946 case Token::MUL: | 7962 instr = NewUncasted<HShr>(left, right); |
| 7947 instr = NewUncasted<HMul>(left, right); | 7963 if (FLAG_opt_safe_uint32_operations && instr->IsShr() && |
| 7948 break; | 7964 CanBeZero(right)) { |
| 7949 case Token::MOD: | 7965 graph()->RecordUint32Instruction(instr); |
| 7950 instr = NewUncasted<HMod>(left, right, fixed_right_arg); | 7966 } |
| 7951 break; | 7967 break; |
| 7952 case Token::DIV: | 7968 case Token::SHL: |
| 7953 instr = NewUncasted<HDiv>(left, right); | 7969 instr = NewUncasted<HShl>(left, right); |
| 7954 break; | 7970 break; |
| 7955 case Token::BIT_XOR: | 7971 default: |
| 7956 case Token::BIT_AND: | 7972 UNREACHABLE(); |
| 7957 instr = NewUncasted<HBitwise>(op, left, right); | |
| 7958 break; | |
| 7959 case Token::BIT_OR: { | |
| 7960 HValue* operand, *shift_amount; | |
| 7961 if (left_type->Is(Type::Signed32()) && | |
| 7962 right_type->Is(Type::Signed32()) && | |
| 7963 MatchRotateRight(left, right, &operand, &shift_amount)) { | |
| 7964 instr = NewUncasted<HRor>(operand, shift_amount); | |
| 7965 } else { | |
| 7966 instr = NewUncasted<HBitwise>(op, left, right); | |
| 7967 } | |
| 7968 break; | |
| 7969 } | 7973 } |
| 7970 case Token::SAR: | |
| 7971 instr = NewUncasted<HSar>(left, right); | |
| 7972 break; | |
| 7973 case Token::SHR: | |
| 7974 instr = NewUncasted<HShr>(left, right); | |
| 7975 if (FLAG_opt_safe_uint32_operations && instr->IsShr() && | |
| 7976 CanBeZero(right)) { | |
| 7977 graph()->RecordUint32Instruction(instr); | |
| 7978 } | |
| 7979 break; | |
| 7980 case Token::SHL: | |
| 7981 instr = NewUncasted<HShl>(left, right); | |
| 7982 break; | |
| 7983 default: | |
| 7984 UNREACHABLE(); | |
| 7985 } | 7974 } |
| 7986 | 7975 |
| 7987 if (instr->IsBinaryOperation()) { | 7976 if (instr->IsBinaryOperation()) { |
| 7988 HBinaryOperation* binop = HBinaryOperation::cast(instr); | 7977 HBinaryOperation* binop = HBinaryOperation::cast(instr); |
| 7989 binop->set_observed_input_representation(1, left_rep); | 7978 binop->set_observed_input_representation(1, left_rep); |
| 7990 binop->set_observed_input_representation(2, right_rep); | 7979 binop->set_observed_input_representation(2, right_rep); |
| 7991 binop->initialize_output_representation(result_rep); | 7980 binop->initialize_output_representation(result_rep); |
| 7981 if (binop_stub) { |
| 7982 // Stub should not call into stub. |
| 7983 instr->SetFlag(HValue::kCannotBeTagged); |
| 7984 // And should truncate on HForceRepresentation already. |
| 7985 if (left->IsForceRepresentation()) { |
| 7986 left->CopyFlag(HValue::kTruncatingToSmi, instr); |
| 7987 left->CopyFlag(HValue::kTruncatingToInt32, instr); |
| 7988 } |
| 7989 if (right->IsForceRepresentation()) { |
| 7990 right->CopyFlag(HValue::kTruncatingToSmi, instr); |
| 7991 right->CopyFlag(HValue::kTruncatingToInt32, instr); |
| 7992 } |
| 7993 } |
| 7992 } | 7994 } |
| 7993 return instr; | 7995 return instr; |
| 7994 } | 7996 } |
| 7995 | 7997 |
| 7996 | 7998 |
| 7997 // Check for the form (%_ClassOf(foo) === 'BarClass'). | 7999 // Check for the form (%_ClassOf(foo) === 'BarClass'). |
| 7998 static bool IsClassOfTest(CompareOperation* expr) { | 8000 static bool IsClassOfTest(CompareOperation* expr) { |
| 7999 if (expr->op() != Token::EQ_STRICT) return false; | 8001 if (expr->op() != Token::EQ_STRICT) return false; |
| 8000 CallRuntime* call = expr->left()->AsCallRuntime(); | 8002 CallRuntime* call = expr->left()->AsCallRuntime(); |
| 8001 if (call == NULL) return false; | 8003 if (call == NULL) return false; |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8313 } else if (combined_type->Is(Type::InternalizedString()) && | 8315 } else if (combined_type->Is(Type::InternalizedString()) && |
| 8314 Token::IsEqualityOp(op)) { | 8316 Token::IsEqualityOp(op)) { |
| 8315 BuildCheckHeapObject(left); | 8317 BuildCheckHeapObject(left); |
| 8316 AddInstruction(HCheckInstanceType::NewIsInternalizedString(left, zone())); | 8318 AddInstruction(HCheckInstanceType::NewIsInternalizedString(left, zone())); |
| 8317 BuildCheckHeapObject(right); | 8319 BuildCheckHeapObject(right); |
| 8318 AddInstruction(HCheckInstanceType::NewIsInternalizedString(right, zone())); | 8320 AddInstruction(HCheckInstanceType::NewIsInternalizedString(right, zone())); |
| 8319 HCompareObjectEqAndBranch* result = | 8321 HCompareObjectEqAndBranch* result = |
| 8320 New<HCompareObjectEqAndBranch>(left, right); | 8322 New<HCompareObjectEqAndBranch>(left, right); |
| 8321 result->set_position(expr->position()); | 8323 result->set_position(expr->position()); |
| 8322 return ast_context()->ReturnControl(result, expr->id()); | 8324 return ast_context()->ReturnControl(result, expr->id()); |
| 8325 } else if (combined_type->Is(Type::String())) { |
| 8326 BuildCheckHeapObject(left); |
| 8327 AddInstruction(HCheckInstanceType::NewIsString(left, zone())); |
| 8328 BuildCheckHeapObject(right); |
| 8329 AddInstruction(HCheckInstanceType::NewIsString(right, zone())); |
| 8330 HStringCompareAndBranch* result = |
| 8331 New<HStringCompareAndBranch>(left, right, op); |
| 8332 result->set_position(expr->position()); |
| 8333 return ast_context()->ReturnControl(result, expr->id()); |
| 8334 } else if (combined_type->NumClasses() == 1 && Token::IsEqualityOp(op)) { |
| 8335 BuildCheckHeapObject(left); |
| 8336 BuildCheckMap(left, combined_type->Classes().Current()); |
| 8337 BuildCheckHeapObject(right); |
| 8338 BuildCheckMap(right, combined_type->Classes().Current()); |
| 8339 HCompareObjectEqAndBranch* result = |
| 8340 New<HCompareObjectEqAndBranch>(left, right); |
| 8341 result->set_position(expr->position()); |
| 8342 return ast_context()->ReturnInstruction(result, expr->id()); |
| 8343 } else if (combined_type->Is(Type::Receiver()) && Token::IsEqualityOp(op)) { |
| 8344 BuildCheckHeapObject(left); |
| 8345 AddInstruction(HCheckInstanceType::NewIsSpecObject(left, zone())); |
| 8346 BuildCheckHeapObject(right); |
| 8347 AddInstruction(HCheckInstanceType::NewIsSpecObject(right, zone())); |
| 8348 HCompareObjectEqAndBranch* result = |
| 8349 New<HCompareObjectEqAndBranch>(left, right); |
| 8350 result->set_position(expr->position()); |
| 8351 return ast_context()->ReturnInstruction(result, expr->id()); |
| 8323 } else { | 8352 } else { |
| 8324 if (combined_rep.IsTagged() || combined_rep.IsNone()) { | 8353 if (combined_rep.IsTagged() || combined_rep.IsNone()) { |
| 8325 HCompareGeneric* result = | 8354 HCompareGeneric* result = |
| 8326 new(zone()) HCompareGeneric(context, left, right, op); | 8355 new(zone()) HCompareGeneric(context, left, right, op); |
| 8327 result->set_observed_input_representation(1, left_rep); | 8356 result->set_observed_input_representation(1, left_rep); |
| 8328 result->set_observed_input_representation(2, right_rep); | 8357 result->set_observed_input_representation(2, right_rep); |
| 8329 result->set_position(expr->position()); | 8358 result->set_position(expr->position()); |
| 8330 return ast_context()->ReturnInstruction(result, expr->id()); | 8359 return ast_context()->ReturnInstruction(result, expr->id()); |
| 8331 } else { | 8360 } else { |
| 8332 HCompareNumericAndBranch* result = | 8361 HCompareNumericAndBranch* result = |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8374 if (function_state()->outer() != NULL) { | 8403 if (function_state()->outer() != NULL) { |
| 8375 return New<HConstant>( | 8404 return New<HConstant>( |
| 8376 function_state()->compilation_info()->closure()); | 8405 function_state()->compilation_info()->closure()); |
| 8377 } else { | 8406 } else { |
| 8378 return new(zone()) HThisFunction; | 8407 return new(zone()) HThisFunction; |
| 8379 } | 8408 } |
| 8380 } | 8409 } |
| 8381 | 8410 |
| 8382 | 8411 |
| 8383 HInstruction* HOptimizedGraphBuilder::BuildFastLiteral( | 8412 HInstruction* HOptimizedGraphBuilder::BuildFastLiteral( |
| 8384 Handle<JSObject> boilerplate_object, | 8413 Handle<JSObject> boilerplate_object) { |
| 8385 Handle<Object> allocation_site_object, | |
| 8386 AllocationSiteMode mode) { | |
| 8387 NoObservableSideEffectsScope no_effects(this); | 8414 NoObservableSideEffectsScope no_effects(this); |
| 8415 InstanceType instance_type = boilerplate_object->map()->instance_type(); |
| 8416 ASSERT(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE); |
| 8388 | 8417 |
| 8389 Handle<FixedArrayBase> elements(boilerplate_object->elements()); | |
| 8390 int object_size = boilerplate_object->map()->instance_size(); | |
| 8391 int object_offset = object_size; | |
| 8392 | |
| 8393 InstanceType instance_type = boilerplate_object->map()->instance_type(); | |
| 8394 bool create_allocation_site_info = mode == TRACK_ALLOCATION_SITE; | |
| 8395 | |
| 8396 // If using allocation sites, then | |
| 8397 // 1) the payload on the site should already be filled in as a valid | |
| 8398 // (boilerplate) array, and | |
| 8399 // 2) we shouldn't be pretenuring the allocations. | |
| 8400 ASSERT(!create_allocation_site_info || | |
| 8401 (AllocationSite::cast(*allocation_site_object)->IsLiteralSite() && | |
| 8402 isolate()->heap()->GetPretenureMode() == NOT_TENURED)); | |
| 8403 | |
| 8404 if (create_allocation_site_info) { | |
| 8405 object_size += AllocationMemento::kSize; | |
| 8406 } | |
| 8407 | |
| 8408 ASSERT(instance_type == JS_ARRAY_TYPE || instance_type == JS_OBJECT_TYPE); | |
| 8409 HType type = instance_type == JS_ARRAY_TYPE | 8418 HType type = instance_type == JS_ARRAY_TYPE |
| 8410 ? HType::JSArray() : HType::JSObject(); | 8419 ? HType::JSArray() : HType::JSObject(); |
| 8411 HValue* object_size_constant = Add<HConstant>(object_size); | 8420 HValue* object_size_constant = Add<HConstant>( |
| 8421 boilerplate_object->map()->instance_size()); |
| 8412 HInstruction* object = Add<HAllocate>(object_size_constant, type, | 8422 HInstruction* object = Add<HAllocate>(object_size_constant, type, |
| 8413 isolate()->heap()->GetPretenureMode(), instance_type); | 8423 isolate()->heap()->GetPretenureMode(), instance_type); |
| 8414 | 8424 |
| 8415 BuildEmitObjectHeader(boilerplate_object, object); | 8425 BuildEmitObjectHeader(boilerplate_object, object); |
| 8416 | 8426 |
| 8417 if (create_allocation_site_info) { | 8427 Handle<FixedArrayBase> elements(boilerplate_object->elements()); |
| 8418 HInstruction* allocation_site = Add<HConstant>(allocation_site_object); | |
| 8419 BuildCreateAllocationMemento(object, object_offset, allocation_site); | |
| 8420 } | |
| 8421 | |
| 8422 int elements_size = (elements->length() > 0 && | 8428 int elements_size = (elements->length() > 0 && |
| 8423 elements->map() != isolate()->heap()->fixed_cow_array_map()) ? | 8429 elements->map() != isolate()->heap()->fixed_cow_array_map()) ? |
| 8424 elements->Size() : 0; | 8430 elements->Size() : 0; |
| 8425 | 8431 |
| 8426 HInstruction* object_elements = NULL; | 8432 HInstruction* object_elements = NULL; |
| 8427 if (elements_size > 0) { | 8433 if (elements_size > 0) { |
| 8428 HValue* object_elements_size = Add<HConstant>(elements_size); | 8434 HValue* object_elements_size = Add<HConstant>(elements_size); |
| 8429 if (boilerplate_object->HasFastDoubleElements()) { | 8435 if (boilerplate_object->HasFastDoubleElements()) { |
| 8430 object_elements = Add<HAllocate>(object_elements_size, HType::JSObject(), | 8436 object_elements = Add<HAllocate>(object_elements_size, HType::JSObject(), |
| 8431 isolate()->heap()->GetPretenureMode(), FIXED_DOUBLE_ARRAY_TYPE); | 8437 isolate()->heap()->GetPretenureMode(), FIXED_DOUBLE_ARRAY_TYPE); |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8513 Handle<Object>(boilerplate_object->InObjectPropertyAt(index), | 8519 Handle<Object>(boilerplate_object->InObjectPropertyAt(index), |
| 8514 isolate()); | 8520 isolate()); |
| 8515 | 8521 |
| 8516 // The access for the store depends on the type of the boilerplate. | 8522 // The access for the store depends on the type of the boilerplate. |
| 8517 HObjectAccess access = boilerplate_object->IsJSArray() ? | 8523 HObjectAccess access = boilerplate_object->IsJSArray() ? |
| 8518 HObjectAccess::ForJSArrayOffset(property_offset) : | 8524 HObjectAccess::ForJSArrayOffset(property_offset) : |
| 8519 HObjectAccess::ForJSObjectOffset(property_offset); | 8525 HObjectAccess::ForJSObjectOffset(property_offset); |
| 8520 | 8526 |
| 8521 if (value->IsJSObject()) { | 8527 if (value->IsJSObject()) { |
| 8522 Handle<JSObject> value_object = Handle<JSObject>::cast(value); | 8528 Handle<JSObject> value_object = Handle<JSObject>::cast(value); |
| 8523 HInstruction* result = | 8529 HInstruction* result = BuildFastLiteral(value_object); |
| 8524 BuildFastLiteral(value_object, | |
| 8525 Handle<Object>::null(), DONT_TRACK_ALLOCATION_SITE); | |
| 8526 Add<HStoreNamedField>(object, access, result); | 8530 Add<HStoreNamedField>(object, access, result); |
| 8527 } else { | 8531 } else { |
| 8528 Representation representation = details.representation(); | 8532 Representation representation = details.representation(); |
| 8529 HInstruction* value_instruction = Add<HConstant>(value); | 8533 HInstruction* value_instruction = Add<HConstant>(value); |
| 8530 | 8534 |
| 8531 if (representation.IsDouble()) { | 8535 if (representation.IsDouble()) { |
| 8532 // Allocate a HeapNumber box and store the value into it. | 8536 // Allocate a HeapNumber box and store the value into it. |
| 8533 HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize); | 8537 HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize); |
| 8534 HInstruction* double_box = | 8538 HInstruction* double_box = |
| 8535 Add<HAllocate>(heap_number_constant, HType::HeapNumber(), | 8539 Add<HAllocate>(heap_number_constant, HType::HeapNumber(), |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8601 ElementsKind kind, | 8605 ElementsKind kind, |
| 8602 HValue* object_elements) { | 8606 HValue* object_elements) { |
| 8603 HInstruction* boilerplate_elements = Add<HConstant>(elements); | 8607 HInstruction* boilerplate_elements = Add<HConstant>(elements); |
| 8604 int elements_length = elements->length(); | 8608 int elements_length = elements->length(); |
| 8605 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); | 8609 Handle<FixedArray> fast_elements = Handle<FixedArray>::cast(elements); |
| 8606 for (int i = 0; i < elements_length; i++) { | 8610 for (int i = 0; i < elements_length; i++) { |
| 8607 Handle<Object> value(fast_elements->get(i), isolate()); | 8611 Handle<Object> value(fast_elements->get(i), isolate()); |
| 8608 HValue* key_constant = Add<HConstant>(i); | 8612 HValue* key_constant = Add<HConstant>(i); |
| 8609 if (value->IsJSObject()) { | 8613 if (value->IsJSObject()) { |
| 8610 Handle<JSObject> value_object = Handle<JSObject>::cast(value); | 8614 Handle<JSObject> value_object = Handle<JSObject>::cast(value); |
| 8611 HInstruction* result = | 8615 HInstruction* result = BuildFastLiteral(value_object); |
| 8612 BuildFastLiteral(value_object, | |
| 8613 Handle<Object>::null(), DONT_TRACK_ALLOCATION_SITE); | |
| 8614 Add<HStoreKeyed>(object_elements, key_constant, result, kind); | 8616 Add<HStoreKeyed>(object_elements, key_constant, result, kind); |
| 8615 } else { | 8617 } else { |
| 8616 HInstruction* value_instruction = | 8618 HInstruction* value_instruction = |
| 8617 Add<HLoadKeyed>(boilerplate_elements, key_constant, | 8619 Add<HLoadKeyed>(boilerplate_elements, key_constant, |
| 8618 static_cast<HValue*>(NULL), kind, | 8620 static_cast<HValue*>(NULL), kind, |
| 8619 ALLOW_RETURN_HOLE); | 8621 ALLOW_RETURN_HOLE); |
| 8620 Add<HStoreKeyed>(object_elements, key_constant, value_instruction, kind); | 8622 Add<HStoreKeyed>(object_elements, key_constant, value_instruction, kind); |
| 8621 } | 8623 } |
| 8622 } | 8624 } |
| 8623 } | 8625 } |
| (...skipping 1251 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9875 if (ShouldProduceTraceOutput()) { | 9877 if (ShouldProduceTraceOutput()) { |
| 9876 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 9878 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 9877 } | 9879 } |
| 9878 | 9880 |
| 9879 #ifdef DEBUG | 9881 #ifdef DEBUG |
| 9880 graph_->Verify(false); // No full verify. | 9882 graph_->Verify(false); // No full verify. |
| 9881 #endif | 9883 #endif |
| 9882 } | 9884 } |
| 9883 | 9885 |
| 9884 } } // namespace v8::internal | 9886 } } // namespace v8::internal |
| OLD | NEW |