| 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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 61 #include "runtime.h" | 61 #include "runtime.h" |
| 62 #include "scopeinfo.h" | 62 #include "scopeinfo.h" |
| 63 #include "scopes.h" | 63 #include "scopes.h" |
| 64 #include "stub-cache.h" | 64 #include "stub-cache.h" |
| 65 #include "typing.h" | 65 #include "typing.h" |
| 66 | 66 |
| 67 #if V8_TARGET_ARCH_IA32 | 67 #if V8_TARGET_ARCH_IA32 |
| 68 #include "ia32/lithium-codegen-ia32.h" | 68 #include "ia32/lithium-codegen-ia32.h" |
| 69 #elif V8_TARGET_ARCH_X64 | 69 #elif V8_TARGET_ARCH_X64 |
| 70 #include "x64/lithium-codegen-x64.h" | 70 #include "x64/lithium-codegen-x64.h" |
| 71 #elif V8_TARGET_ARCH_A64 | |
| 72 #include "a64/lithium-codegen-a64.h" | |
| 73 #elif V8_TARGET_ARCH_ARM | 71 #elif V8_TARGET_ARCH_ARM |
| 74 #include "arm/lithium-codegen-arm.h" | 72 #include "arm/lithium-codegen-arm.h" |
| 75 #elif V8_TARGET_ARCH_MIPS | 73 #elif V8_TARGET_ARCH_MIPS |
| 76 #include "mips/lithium-codegen-mips.h" | 74 #include "mips/lithium-codegen-mips.h" |
| 77 #else | 75 #else |
| 78 #error Unsupported target architecture. | 76 #error Unsupported target architecture. |
| 79 #endif | 77 #endif |
| 80 | 78 |
| 81 namespace v8 { | 79 namespace v8 { |
| 82 namespace internal { | 80 namespace internal { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 136 | 134 |
| 137 void HBasicBlock::RemovePhi(HPhi* phi) { | 135 void HBasicBlock::RemovePhi(HPhi* phi) { |
| 138 ASSERT(phi->block() == this); | 136 ASSERT(phi->block() == this); |
| 139 ASSERT(phis_.Contains(phi)); | 137 ASSERT(phis_.Contains(phi)); |
| 140 phi->Kill(); | 138 phi->Kill(); |
| 141 phis_.RemoveElement(phi); | 139 phis_.RemoveElement(phi); |
| 142 phi->SetBlock(NULL); | 140 phi->SetBlock(NULL); |
| 143 } | 141 } |
| 144 | 142 |
| 145 | 143 |
| 146 void HBasicBlock::AddInstruction(HInstruction* instr, | 144 void HBasicBlock::AddInstruction(HInstruction* instr, int position) { |
| 147 HSourcePosition position) { | |
| 148 ASSERT(!IsStartBlock() || !IsFinished()); | 145 ASSERT(!IsStartBlock() || !IsFinished()); |
| 149 ASSERT(!instr->IsLinked()); | 146 ASSERT(!instr->IsLinked()); |
| 150 ASSERT(!IsFinished()); | 147 ASSERT(!IsFinished()); |
| 151 | 148 |
| 152 if (!position.IsUnknown()) { | 149 if (position != RelocInfo::kNoPosition) { |
| 153 instr->set_position(position); | 150 instr->set_position(position); |
| 154 } | 151 } |
| 155 if (first_ == NULL) { | 152 if (first_ == NULL) { |
| 156 ASSERT(last_environment() != NULL); | 153 ASSERT(last_environment() != NULL); |
| 157 ASSERT(!last_environment()->ast_id().IsNone()); | 154 ASSERT(!last_environment()->ast_id().IsNone()); |
| 158 HBlockEntry* entry = new(zone()) HBlockEntry(); | 155 HBlockEntry* entry = new(zone()) HBlockEntry(); |
| 159 entry->InitializeAsFirst(this); | 156 entry->InitializeAsFirst(this); |
| 160 if (!position.IsUnknown()) { | 157 if (position != RelocInfo::kNoPosition) { |
| 161 entry->set_position(position); | 158 entry->set_position(position); |
| 162 } else { | 159 } else { |
| 163 ASSERT(!FLAG_hydrogen_track_positions || | 160 ASSERT(!FLAG_emit_opt_code_positions || |
| 164 !graph()->info()->IsOptimizing()); | 161 !graph()->info()->IsOptimizing()); |
| 165 } | 162 } |
| 166 first_ = last_ = entry; | 163 first_ = last_ = entry; |
| 167 } | 164 } |
| 168 instr->InsertAfter(last_); | 165 instr->InsertAfter(last_); |
| 169 } | 166 } |
| 170 | 167 |
| 171 | 168 |
| 172 HPhi* HBasicBlock::AddNewPhi(int merged_index) { | 169 HPhi* HBasicBlock::AddNewPhi(int merged_index) { |
| 173 if (graph()->IsInsideNoSideEffectsScope()) { | 170 if (graph()->IsInsideNoSideEffectsScope()) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 206 !it.Done(); | 203 !it.Done(); |
| 207 it.Advance()) { | 204 it.Advance()) { |
| 208 int index = it.Current(); | 205 int index = it.Current(); |
| 209 instr->AddAssignedValue(index, environment->Lookup(index)); | 206 instr->AddAssignedValue(index, environment->Lookup(index)); |
| 210 } | 207 } |
| 211 environment->ClearHistory(); | 208 environment->ClearHistory(); |
| 212 return instr; | 209 return instr; |
| 213 } | 210 } |
| 214 | 211 |
| 215 | 212 |
| 216 void HBasicBlock::Finish(HControlInstruction* end, HSourcePosition position) { | 213 void HBasicBlock::Finish(HControlInstruction* end, int position) { |
| 217 ASSERT(!IsFinished()); | 214 ASSERT(!IsFinished()); |
| 218 AddInstruction(end, position); | 215 AddInstruction(end, position); |
| 219 end_ = end; | 216 end_ = end; |
| 220 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { | 217 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { |
| 221 it.Current()->RegisterPredecessor(this); | 218 it.Current()->RegisterPredecessor(this); |
| 222 } | 219 } |
| 223 } | 220 } |
| 224 | 221 |
| 225 | 222 |
| 226 void HBasicBlock::Goto(HBasicBlock* block, | 223 void HBasicBlock::Goto(HBasicBlock* block, |
| 227 HSourcePosition position, | 224 int position, |
| 228 FunctionState* state, | 225 FunctionState* state, |
| 229 bool add_simulate) { | 226 bool add_simulate) { |
| 230 bool drop_extra = state != NULL && | 227 bool drop_extra = state != NULL && |
| 231 state->inlining_kind() == NORMAL_RETURN; | 228 state->inlining_kind() == NORMAL_RETURN; |
| 232 | 229 |
| 233 if (block->IsInlineReturnTarget()) { | 230 if (block->IsInlineReturnTarget()) { |
| 234 HEnvironment* env = last_environment(); | 231 HEnvironment* env = last_environment(); |
| 235 int argument_count = env->arguments_environment()->parameter_count(); | 232 int argument_count = env->arguments_environment()->parameter_count(); |
| 236 AddInstruction(new(zone()) | 233 AddInstruction(new(zone()) |
| 237 HLeaveInlined(state->entry(), argument_count), | 234 HLeaveInlined(state->entry(), argument_count), |
| 238 position); | 235 position); |
| 239 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); | 236 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); |
| 240 } | 237 } |
| 241 | 238 |
| 242 if (add_simulate) AddNewSimulate(BailoutId::None(), position); | 239 if (add_simulate) AddNewSimulate(BailoutId::None(), position); |
| 243 HGoto* instr = new(zone()) HGoto(block); | 240 HGoto* instr = new(zone()) HGoto(block); |
| 244 Finish(instr, position); | 241 Finish(instr, position); |
| 245 } | 242 } |
| 246 | 243 |
| 247 | 244 |
| 248 void HBasicBlock::AddLeaveInlined(HValue* return_value, | 245 void HBasicBlock::AddLeaveInlined(HValue* return_value, |
| 249 FunctionState* state, | 246 FunctionState* state, |
| 250 HSourcePosition position) { | 247 int position) { |
| 251 HBasicBlock* target = state->function_return(); | 248 HBasicBlock* target = state->function_return(); |
| 252 bool drop_extra = state->inlining_kind() == NORMAL_RETURN; | 249 bool drop_extra = state->inlining_kind() == NORMAL_RETURN; |
| 253 | 250 |
| 254 ASSERT(target->IsInlineReturnTarget()); | 251 ASSERT(target->IsInlineReturnTarget()); |
| 255 ASSERT(return_value != NULL); | 252 ASSERT(return_value != NULL); |
| 256 HEnvironment* env = last_environment(); | 253 HEnvironment* env = last_environment(); |
| 257 int argument_count = env->arguments_environment()->parameter_count(); | 254 int argument_count = env->arguments_environment()->parameter_count(); |
| 258 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count), | 255 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count), |
| 259 position); | 256 position); |
| 260 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); | 257 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 333 } | 330 } |
| 334 | 331 |
| 335 // Only the first entry into the loop is from outside the loop. All other | 332 // Only the first entry into the loop is from outside the loop. All other |
| 336 // entries must be back edges. | 333 // entries must be back edges. |
| 337 for (int i = 1; i < predecessors()->length(); ++i) { | 334 for (int i = 1; i < predecessors()->length(); ++i) { |
| 338 loop_information()->RegisterBackEdge(predecessors()->at(i)); | 335 loop_information()->RegisterBackEdge(predecessors()->at(i)); |
| 339 } | 336 } |
| 340 } | 337 } |
| 341 | 338 |
| 342 | 339 |
| 343 void HBasicBlock::MarkSuccEdgeUnreachable(int succ) { | |
| 344 ASSERT(IsFinished()); | |
| 345 HBasicBlock* succ_block = end()->SuccessorAt(succ); | |
| 346 | |
| 347 ASSERT(succ_block->predecessors()->length() == 1); | |
| 348 succ_block->MarkUnreachable(); | |
| 349 } | |
| 350 | |
| 351 | |
| 352 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) { | 340 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) { |
| 353 if (HasPredecessor()) { | 341 if (HasPredecessor()) { |
| 354 // Only loop header blocks can have a predecessor added after | 342 // Only loop header blocks can have a predecessor added after |
| 355 // instructions have been added to the block (they have phis for all | 343 // instructions have been added to the block (they have phis for all |
| 356 // values in the environment, these phis may be eliminated later). | 344 // values in the environment, these phis may be eliminated later). |
| 357 ASSERT(IsLoopHeader() || first_ == NULL); | 345 ASSERT(IsLoopHeader() || first_ == NULL); |
| 358 HEnvironment* incoming_env = pred->last_environment(); | 346 HEnvironment* incoming_env = pred->last_environment(); |
| 359 if (IsLoopHeader()) { | 347 if (IsLoopHeader()) { |
| 360 ASSERT(phis()->length() == incoming_env->length()); | 348 ASSERT(phis()->length() == incoming_env->length()); |
| 361 for (int i = 0; i < phis_.length(); ++i) { | 349 for (int i = 0; i < phis_.length(); ++i) { |
| (...skipping 675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1037 } | 1025 } |
| 1038 builder_->GotoNoSimulate(current->block_, merge_block); | 1026 builder_->GotoNoSimulate(current->block_, merge_block); |
| 1039 } | 1027 } |
| 1040 current = current->next_; | 1028 current = current->next_; |
| 1041 } | 1029 } |
| 1042 | 1030 |
| 1043 // Merge deopt blocks, padding when necessary. | 1031 // Merge deopt blocks, padding when necessary. |
| 1044 current = merge_at_join_blocks_; | 1032 current = merge_at_join_blocks_; |
| 1045 while (current != NULL) { | 1033 while (current != NULL) { |
| 1046 if (current->deopt_ && current->block_ != NULL) { | 1034 if (current->deopt_ && current->block_ != NULL) { |
| 1047 current->block_->FinishExit( | 1035 builder_->PadEnvironmentForContinuation(current->block_, |
| 1048 HAbnormalExit::New(builder_->zone(), NULL), | 1036 merge_block); |
| 1049 HSourcePosition::Unknown()); | 1037 builder_->GotoNoSimulate(current->block_, merge_block); |
| 1050 } | 1038 } |
| 1051 current = current->next_; | 1039 current = current->next_; |
| 1052 } | 1040 } |
| 1053 builder_->set_current_block(merge_block); | 1041 builder_->set_current_block(merge_block); |
| 1054 } | 1042 } |
| 1055 | 1043 |
| 1056 | 1044 |
| 1057 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, | 1045 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, |
| 1058 HValue* context, | 1046 HValue* context, |
| 1059 LoopBuilder::Direction direction) | 1047 LoopBuilder::Direction direction) |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1172 CompilationPhase phase("H_Block building", info_); | 1160 CompilationPhase phase("H_Block building", info_); |
| 1173 set_current_block(graph()->entry_block()); | 1161 set_current_block(graph()->entry_block()); |
| 1174 if (!BuildGraph()) return NULL; | 1162 if (!BuildGraph()) return NULL; |
| 1175 graph()->FinalizeUniqueness(); | 1163 graph()->FinalizeUniqueness(); |
| 1176 return graph_; | 1164 return graph_; |
| 1177 } | 1165 } |
| 1178 | 1166 |
| 1179 | 1167 |
| 1180 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { | 1168 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { |
| 1181 ASSERT(current_block() != NULL); | 1169 ASSERT(current_block() != NULL); |
| 1182 ASSERT(!FLAG_hydrogen_track_positions || | 1170 ASSERT(!FLAG_emit_opt_code_positions || |
| 1183 !position_.IsUnknown() || | 1171 position_ != RelocInfo::kNoPosition || !info_->IsOptimizing()); |
| 1184 !info_->IsOptimizing()); | 1172 current_block()->AddInstruction(instr, position_); |
| 1185 current_block()->AddInstruction(instr, source_position()); | |
| 1186 if (graph()->IsInsideNoSideEffectsScope()) { | 1173 if (graph()->IsInsideNoSideEffectsScope()) { |
| 1187 instr->SetFlag(HValue::kHasNoObservableSideEffects); | 1174 instr->SetFlag(HValue::kHasNoObservableSideEffects); |
| 1188 } | 1175 } |
| 1189 return instr; | 1176 return instr; |
| 1190 } | 1177 } |
| 1191 | 1178 |
| 1192 | 1179 |
| 1193 void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) { | 1180 void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) { |
| 1194 ASSERT(!FLAG_hydrogen_track_positions || | 1181 ASSERT(!FLAG_emit_opt_code_positions || !info_->IsOptimizing() || |
| 1195 !info_->IsOptimizing() || | 1182 position_ != RelocInfo::kNoPosition); |
| 1196 !position_.IsUnknown()); | 1183 current_block()->Finish(last, position_); |
| 1197 current_block()->Finish(last, source_position()); | |
| 1198 if (last->IsReturn() || last->IsAbnormalExit()) { | 1184 if (last->IsReturn() || last->IsAbnormalExit()) { |
| 1199 set_current_block(NULL); | 1185 set_current_block(NULL); |
| 1200 } | 1186 } |
| 1201 } | 1187 } |
| 1202 | 1188 |
| 1203 | 1189 |
| 1204 void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) { | 1190 void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) { |
| 1205 ASSERT(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() || | 1191 ASSERT(!FLAG_emit_opt_code_positions || !info_->IsOptimizing() || |
| 1206 !position_.IsUnknown()); | 1192 position_ != RelocInfo::kNoPosition); |
| 1207 current_block()->FinishExit(instruction, source_position()); | 1193 current_block()->FinishExit(instruction, position_); |
| 1208 if (instruction->IsReturn() || instruction->IsAbnormalExit()) { | 1194 if (instruction->IsReturn() || instruction->IsAbnormalExit()) { |
| 1209 set_current_block(NULL); | 1195 set_current_block(NULL); |
| 1210 } | 1196 } |
| 1211 } | 1197 } |
| 1212 | 1198 |
| 1213 | 1199 |
| 1214 void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) { | 1200 void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) { |
| 1215 if (FLAG_native_code_counters && counter->Enabled()) { | 1201 if (FLAG_native_code_counters && counter->Enabled()) { |
| 1216 HValue* reference = Add<HConstant>(ExternalReference(counter)); | 1202 HValue* reference = Add<HConstant>(ExternalReference(counter)); |
| 1217 HValue* old_value = Add<HLoadNamedField>( | 1203 HValue* old_value = Add<HLoadNamedField>( |
| 1218 reference, static_cast<HValue*>(NULL), HObjectAccess::ForCounter()); | 1204 reference, static_cast<HValue*>(NULL), HObjectAccess::ForCounter()); |
| 1219 HValue* new_value = AddUncasted<HAdd>(old_value, graph()->GetConstant1()); | 1205 HValue* new_value = AddUncasted<HAdd>(old_value, graph()->GetConstant1()); |
| 1220 new_value->ClearFlag(HValue::kCanOverflow); // Ignore counter overflow | 1206 new_value->ClearFlag(HValue::kCanOverflow); // Ignore counter overflow |
| 1221 Add<HStoreNamedField>(reference, HObjectAccess::ForCounter(), | 1207 Add<HStoreNamedField>(reference, HObjectAccess::ForCounter(), |
| 1222 new_value, STORE_TO_INITIALIZED_ENTRY); | 1208 new_value, STORE_TO_INITIALIZED_ENTRY); |
| 1223 } | 1209 } |
| 1224 } | 1210 } |
| 1225 | 1211 |
| 1226 | 1212 |
| 1227 void HGraphBuilder::AddSimulate(BailoutId id, | 1213 void HGraphBuilder::AddSimulate(BailoutId id, |
| 1228 RemovableSimulate removable) { | 1214 RemovableSimulate removable) { |
| 1229 ASSERT(current_block() != NULL); | 1215 ASSERT(current_block() != NULL); |
| 1230 ASSERT(!graph()->IsInsideNoSideEffectsScope()); | 1216 ASSERT(!graph()->IsInsideNoSideEffectsScope()); |
| 1231 current_block()->AddNewSimulate(id, source_position(), removable); | 1217 current_block()->AddNewSimulate(id, position_, removable); |
| 1232 } | 1218 } |
| 1233 | 1219 |
| 1234 | 1220 |
| 1235 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { | 1221 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { |
| 1236 HBasicBlock* b = graph()->CreateBasicBlock(); | 1222 HBasicBlock* b = graph()->CreateBasicBlock(); |
| 1237 b->SetInitialEnvironment(env); | 1223 b->SetInitialEnvironment(env); |
| 1238 return b; | 1224 return b; |
| 1239 } | 1225 } |
| 1240 | 1226 |
| 1241 | 1227 |
| 1242 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { | 1228 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { |
| 1243 HBasicBlock* header = graph()->CreateBasicBlock(); | 1229 HBasicBlock* header = graph()->CreateBasicBlock(); |
| 1244 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); | 1230 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); |
| 1245 header->SetInitialEnvironment(entry_env); | 1231 header->SetInitialEnvironment(entry_env); |
| 1246 header->AttachLoopInformation(); | 1232 header->AttachLoopInformation(); |
| 1247 return header; | 1233 return header; |
| 1248 } | 1234 } |
| 1249 | 1235 |
| 1250 | 1236 |
| 1251 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { | 1237 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { |
| 1252 if (obj->type().IsHeapObject()) return obj; | 1238 if (obj->type().IsHeapObject()) return obj; |
| 1253 return Add<HCheckHeapObject>(obj); | 1239 return Add<HCheckHeapObject>(obj); |
| 1254 } | 1240 } |
| 1255 | 1241 |
| 1256 | 1242 |
| 1257 void HGraphBuilder::FinishExitWithHardDeoptimization(const char* reason) { | 1243 void HGraphBuilder::FinishExitWithHardDeoptimization( |
| 1244 const char* reason, HBasicBlock* continuation) { |
| 1245 PadEnvironmentForContinuation(current_block(), continuation); |
| 1258 Add<HDeoptimize>(reason, Deoptimizer::EAGER); | 1246 Add<HDeoptimize>(reason, Deoptimizer::EAGER); |
| 1259 FinishExitCurrentBlock(New<HAbnormalExit>()); | 1247 if (graph()->IsInsideNoSideEffectsScope()) { |
| 1248 GotoNoSimulate(continuation); |
| 1249 } else { |
| 1250 Goto(continuation); |
| 1251 } |
| 1260 } | 1252 } |
| 1261 | 1253 |
| 1262 | 1254 |
| 1255 void HGraphBuilder::PadEnvironmentForContinuation( |
| 1256 HBasicBlock* from, |
| 1257 HBasicBlock* continuation) { |
| 1258 if (continuation->last_environment() != NULL) { |
| 1259 // When merging from a deopt block to a continuation, resolve differences in |
| 1260 // environment by pushing constant 0 and popping extra values so that the |
| 1261 // environments match during the join. Push 0 since it has the most specific |
| 1262 // representation, and will not influence representation inference of the |
| 1263 // phi. |
| 1264 int continuation_env_length = continuation->last_environment()->length(); |
| 1265 while (continuation_env_length != from->last_environment()->length()) { |
| 1266 if (continuation_env_length > from->last_environment()->length()) { |
| 1267 from->last_environment()->Push(graph()->GetConstant0()); |
| 1268 } else { |
| 1269 from->last_environment()->Pop(); |
| 1270 } |
| 1271 } |
| 1272 } else { |
| 1273 ASSERT(continuation->predecessors()->length() == 0); |
| 1274 } |
| 1275 } |
| 1276 |
| 1277 |
| 1263 HValue* HGraphBuilder::BuildCheckMap(HValue* obj, Handle<Map> map) { | 1278 HValue* HGraphBuilder::BuildCheckMap(HValue* obj, Handle<Map> map) { |
| 1264 return Add<HCheckMaps>(obj, map, top_info()); | 1279 return Add<HCheckMaps>(obj, map, top_info()); |
| 1265 } | 1280 } |
| 1266 | 1281 |
| 1267 | 1282 |
| 1268 HValue* HGraphBuilder::BuildCheckString(HValue* string) { | 1283 HValue* HGraphBuilder::BuildCheckString(HValue* string) { |
| 1269 if (!string->type().IsString()) { | 1284 if (!string->type().IsString()) { |
| 1270 ASSERT(!string->IsConstant() || | 1285 ASSERT(!string->IsConstant() || |
| 1271 !HConstant::cast(string)->HasStringValue()); | 1286 !HConstant::cast(string)->HasStringValue()); |
| 1272 BuildCheckHeapObject(string); | 1287 BuildCheckHeapObject(string); |
| 1273 return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING); | 1288 return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING); |
| 1274 } | 1289 } |
| 1275 return string; | 1290 return string; |
| 1276 } | 1291 } |
| 1277 | 1292 |
| 1278 | 1293 |
| 1279 HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) { | 1294 HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) { |
| 1280 if (object->type().IsJSObject()) return object; | 1295 if (object->type().IsJSObject()) return object; |
| 1281 if (function->IsConstant() && | 1296 if (function->IsConstant() && |
| 1282 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { | 1297 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
| 1283 Handle<JSFunction> f = Handle<JSFunction>::cast( | 1298 Handle<JSFunction> f = Handle<JSFunction>::cast( |
| 1284 HConstant::cast(function)->handle(isolate())); | 1299 HConstant::cast(function)->handle(isolate())); |
| 1285 SharedFunctionInfo* shared = f->shared(); | 1300 SharedFunctionInfo* shared = f->shared(); |
| 1286 if (!shared->is_classic_mode() || shared->native()) return object; | 1301 if (!shared->is_classic_mode() || shared->native()) return object; |
| 1287 } | 1302 } |
| 1288 return Add<HWrapReceiver>(object, function); | 1303 return Add<HWrapReceiver>(object, function); |
| 1289 } | 1304 } |
| 1290 | 1305 |
| 1291 | 1306 |
| 1292 HValue* HGraphBuilder::BuildCheckForCapacityGrow( | 1307 HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, |
| 1293 HValue* object, | 1308 HValue* elements, |
| 1294 HValue* elements, | 1309 ElementsKind kind, |
| 1295 ElementsKind kind, | 1310 HValue* length, |
| 1296 HValue* length, | 1311 HValue* key, |
| 1297 HValue* key, | 1312 bool is_js_array, |
| 1298 bool is_js_array, | 1313 bool is_store) { |
| 1299 PropertyAccessType access_type) { | |
| 1300 IfBuilder length_checker(this); | 1314 IfBuilder length_checker(this); |
| 1301 | 1315 |
| 1302 Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ; | 1316 Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ; |
| 1303 length_checker.If<HCompareNumericAndBranch>(key, length, token); | 1317 length_checker.If<HCompareNumericAndBranch>(key, length, token); |
| 1304 | 1318 |
| 1305 length_checker.Then(); | 1319 length_checker.Then(); |
| 1306 | 1320 |
| 1307 HValue* current_capacity = AddLoadFixedArrayLength(elements); | 1321 HValue* current_capacity = AddLoadFixedArrayLength(elements); |
| 1308 | 1322 |
| 1309 IfBuilder capacity_checker(this); | 1323 IfBuilder capacity_checker(this); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1332 capacity_checker.End(); | 1346 capacity_checker.End(); |
| 1333 | 1347 |
| 1334 if (is_js_array) { | 1348 if (is_js_array) { |
| 1335 HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1()); | 1349 HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1()); |
| 1336 new_length->ClearFlag(HValue::kCanOverflow); | 1350 new_length->ClearFlag(HValue::kCanOverflow); |
| 1337 | 1351 |
| 1338 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind), | 1352 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind), |
| 1339 new_length); | 1353 new_length); |
| 1340 } | 1354 } |
| 1341 | 1355 |
| 1342 if (access_type == STORE && kind == FAST_SMI_ELEMENTS) { | 1356 if (is_store && kind == FAST_SMI_ELEMENTS) { |
| 1343 HValue* checked_elements = environment()->Top(); | 1357 HValue* checked_elements = environment()->Top(); |
| 1344 | 1358 |
| 1345 // Write zero to ensure that the new element is initialized with some smi. | 1359 // Write zero to ensure that the new element is initialized with some smi. |
| 1346 Add<HStoreKeyed>(checked_elements, key, graph()->GetConstant0(), kind); | 1360 Add<HStoreKeyed>(checked_elements, key, graph()->GetConstant0(), kind); |
| 1347 } | 1361 } |
| 1348 | 1362 |
| 1349 length_checker.Else(); | 1363 length_checker.Else(); |
| 1350 Add<HBoundsCheck>(key, length); | 1364 Add<HBoundsCheck>(key, length); |
| 1351 | 1365 |
| 1352 environment()->Push(elements); | 1366 environment()->Push(elements); |
| 1353 length_checker.End(); | 1367 length_checker.End(); |
| 1354 | 1368 |
| 1355 return environment()->Pop(); | 1369 return environment()->Pop(); |
| 1356 } | 1370 } |
| 1357 | 1371 |
| 1358 | 1372 |
| 1359 HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object, | 1373 HValue* HGraphBuilder::BuildCopyElementsOnWrite(HValue* object, |
| 1360 HValue* elements, | 1374 HValue* elements, |
| 1361 ElementsKind kind, | 1375 ElementsKind kind, |
| 1362 HValue* length) { | 1376 HValue* length) { |
| 1363 Factory* factory = isolate()->factory(); | 1377 Factory* factory = isolate()->factory(); |
| 1364 | 1378 |
| 1365 IfBuilder cow_checker(this); | 1379 IfBuilder cow_checker(this); |
| 1366 | 1380 |
| 1367 cow_checker.If<HCompareMap>( | 1381 cow_checker.If<HCompareMap>(elements, factory->fixed_cow_array_map()); |
| 1368 elements, factory->fixed_cow_array_map(), top_info()); | |
| 1369 cow_checker.Then(); | 1382 cow_checker.Then(); |
| 1370 | 1383 |
| 1371 HValue* capacity = AddLoadFixedArrayLength(elements); | 1384 HValue* capacity = AddLoadFixedArrayLength(elements); |
| 1372 | 1385 |
| 1373 HValue* new_elements = BuildGrowElementsCapacity(object, elements, kind, | 1386 HValue* new_elements = BuildGrowElementsCapacity(object, elements, kind, |
| 1374 kind, length, capacity); | 1387 kind, length, capacity); |
| 1375 | 1388 |
| 1376 environment()->Push(new_elements); | 1389 environment()->Push(new_elements); |
| 1377 | 1390 |
| 1378 cow_checker.Else(); | 1391 cow_checker.Else(); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1444 int32_t entry_size = SeededNumberDictionary::kEntrySize; | 1457 int32_t entry_size = SeededNumberDictionary::kEntrySize; |
| 1445 raw_index = AddUncasted<HMul>(raw_index, Add<HConstant>(entry_size)); | 1458 raw_index = AddUncasted<HMul>(raw_index, Add<HConstant>(entry_size)); |
| 1446 raw_index->ClearFlag(HValue::kCanOverflow); | 1459 raw_index->ClearFlag(HValue::kCanOverflow); |
| 1447 | 1460 |
| 1448 int32_t base_offset = SeededNumberDictionary::kElementsStartIndex; | 1461 int32_t base_offset = SeededNumberDictionary::kElementsStartIndex; |
| 1449 HValue* key_index = AddUncasted<HAdd>(raw_index, Add<HConstant>(base_offset)); | 1462 HValue* key_index = AddUncasted<HAdd>(raw_index, Add<HConstant>(base_offset)); |
| 1450 key_index->ClearFlag(HValue::kCanOverflow); | 1463 key_index->ClearFlag(HValue::kCanOverflow); |
| 1451 | 1464 |
| 1452 HValue* candidate_key = Add<HLoadKeyed>(elements, key_index, | 1465 HValue* candidate_key = Add<HLoadKeyed>(elements, key_index, |
| 1453 static_cast<HValue*>(NULL), | 1466 static_cast<HValue*>(NULL), |
| 1454 FAST_ELEMENTS); | 1467 FAST_SMI_ELEMENTS); |
| 1455 | 1468 |
| 1456 IfBuilder key_compare(this); | 1469 IfBuilder key_compare(this); |
| 1457 key_compare.IfNot<HCompareObjectEqAndBranch>(key, candidate_key); | 1470 key_compare.IfNot<HCompareObjectEqAndBranch>(key, candidate_key); |
| 1458 key_compare.Then(); | 1471 key_compare.Then(); |
| 1459 { | 1472 { |
| 1460 // Key at the current probe doesn't match, try at the next probe. | 1473 // Key at the current probe doesn't match, try at the next probe. |
| 1461 HValue* result = BuildUncheckedDictionaryElementLoadHelper( | 1474 HValue* result = BuildUncheckedDictionaryElementLoadHelper( |
| 1462 elements, key, hash, mask, current_probe + 1); | 1475 elements, key, hash, mask, current_probe + 1); |
| 1463 if (result == NULL) { | 1476 if (result == NULL) { |
| 1464 key_compare.Deopt("probes exhausted in keyed load dictionary lookup"); | 1477 key_compare.Deopt("probes exhausted in keyed load dictionary lookup"); |
| 1465 result = graph()->GetConstantUndefined(); | 1478 result = graph()->GetConstantUndefined(); |
| 1466 } else { | 1479 } else { |
| 1467 Push(result); | 1480 Push(result); |
| 1468 } | 1481 } |
| 1469 } | 1482 } |
| 1470 key_compare.Else(); | 1483 key_compare.Else(); |
| 1471 { | 1484 { |
| 1472 // Key at current probe matches. Details must be zero, otherwise the | 1485 // Key at current probe matches. Details must be zero, otherwise the |
| 1473 // dictionary element requires special handling. | 1486 // dictionary element requires special handling. |
| 1474 HValue* details_index = AddUncasted<HAdd>( | 1487 HValue* details_index = AddUncasted<HAdd>( |
| 1475 raw_index, Add<HConstant>(base_offset + 2)); | 1488 raw_index, Add<HConstant>(base_offset + 2)); |
| 1476 details_index->ClearFlag(HValue::kCanOverflow); | 1489 details_index->ClearFlag(HValue::kCanOverflow); |
| 1477 | 1490 |
| 1478 HValue* details = Add<HLoadKeyed>(elements, details_index, | 1491 HValue* details = Add<HLoadKeyed>(elements, details_index, |
| 1479 static_cast<HValue*>(NULL), | 1492 static_cast<HValue*>(NULL), |
| 1480 FAST_ELEMENTS); | 1493 FAST_SMI_ELEMENTS); |
| 1481 IfBuilder details_compare(this); | 1494 IfBuilder details_compare(this); |
| 1482 details_compare.If<HCompareNumericAndBranch>(details, | 1495 details_compare.If<HCompareNumericAndBranch>(details, |
| 1483 graph()->GetConstant0(), | 1496 graph()->GetConstant0(), |
| 1484 Token::NE); | 1497 Token::NE); |
| 1485 details_compare.ThenDeopt("keyed load dictionary element not fast case"); | 1498 details_compare.ThenDeopt("keyed load dictionary element not fast case"); |
| 1486 | 1499 |
| 1487 details_compare.Else(); | 1500 details_compare.Else(); |
| 1488 { | 1501 { |
| 1489 // Key matches and details are zero --> fast case. Load and return the | 1502 // Key matches and details are zero --> fast case. Load and return the |
| 1490 // value. | 1503 // value. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1540 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, | 1553 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, |
| 1541 HValue* key) { | 1554 HValue* key) { |
| 1542 HValue* elements = AddLoadElements(receiver); | 1555 HValue* elements = AddLoadElements(receiver); |
| 1543 | 1556 |
| 1544 HValue* hash = BuildElementIndexHash(key); | 1557 HValue* hash = BuildElementIndexHash(key); |
| 1545 | 1558 |
| 1546 HValue* capacity = Add<HLoadKeyed>( | 1559 HValue* capacity = Add<HLoadKeyed>( |
| 1547 elements, | 1560 elements, |
| 1548 Add<HConstant>(NameDictionary::kCapacityIndex), | 1561 Add<HConstant>(NameDictionary::kCapacityIndex), |
| 1549 static_cast<HValue*>(NULL), | 1562 static_cast<HValue*>(NULL), |
| 1550 FAST_ELEMENTS); | 1563 FAST_SMI_ELEMENTS); |
| 1551 | 1564 |
| 1552 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1()); | 1565 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1()); |
| 1553 mask->ChangeRepresentation(Representation::Integer32()); | 1566 mask->ChangeRepresentation(Representation::Integer32()); |
| 1554 mask->ClearFlag(HValue::kCanOverflow); | 1567 mask->ClearFlag(HValue::kCanOverflow); |
| 1555 | 1568 |
| 1556 return BuildUncheckedDictionaryElementLoadHelper(elements, key, | 1569 return BuildUncheckedDictionaryElementLoadHelper(elements, key, |
| 1557 hash, mask, 0); | 1570 hash, mask, 0); |
| 1558 } | 1571 } |
| 1559 | 1572 |
| 1560 | 1573 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1675 if_objectiskey.JoinContinuation(&found); | 1688 if_objectiskey.JoinContinuation(&found); |
| 1676 } | 1689 } |
| 1677 if_objectissmi.Else(); | 1690 if_objectissmi.Else(); |
| 1678 { | 1691 { |
| 1679 if (type->Is(Type::Smi())) { | 1692 if (type->Is(Type::Smi())) { |
| 1680 if_objectissmi.Deopt("Expected smi"); | 1693 if_objectissmi.Deopt("Expected smi"); |
| 1681 } else { | 1694 } else { |
| 1682 // Check if the object is a heap number. | 1695 // Check if the object is a heap number. |
| 1683 IfBuilder if_objectisnumber(this); | 1696 IfBuilder if_objectisnumber(this); |
| 1684 HValue* objectisnumber = if_objectisnumber.If<HCompareMap>( | 1697 HValue* objectisnumber = if_objectisnumber.If<HCompareMap>( |
| 1685 object, isolate()->factory()->heap_number_map(), top_info()); | 1698 object, isolate()->factory()->heap_number_map()); |
| 1686 if_objectisnumber.Then(); | 1699 if_objectisnumber.Then(); |
| 1687 { | 1700 { |
| 1688 // Compute hash for heap number similar to double_get_hash(). | 1701 // Compute hash for heap number similar to double_get_hash(). |
| 1689 HValue* low = Add<HLoadNamedField>( | 1702 HValue* low = Add<HLoadNamedField>( |
| 1690 object, objectisnumber, | 1703 object, objectisnumber, |
| 1691 HObjectAccess::ForHeapNumberValueLowestBits()); | 1704 HObjectAccess::ForHeapNumberValueLowestBits()); |
| 1692 HValue* high = Add<HLoadNamedField>( | 1705 HValue* high = Add<HLoadNamedField>( |
| 1693 object, objectisnumber, | 1706 object, objectisnumber, |
| 1694 HObjectAccess::ForHeapNumberValueHighestBits()); | 1707 HObjectAccess::ForHeapNumberValueHighestBits()); |
| 1695 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, low, high); | 1708 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, low, high); |
| (...skipping 443 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2139 return Pop(); | 2152 return Pop(); |
| 2140 } | 2153 } |
| 2141 | 2154 |
| 2142 | 2155 |
| 2143 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 2156 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
| 2144 HValue* checked_object, | 2157 HValue* checked_object, |
| 2145 HValue* key, | 2158 HValue* key, |
| 2146 HValue* val, | 2159 HValue* val, |
| 2147 bool is_js_array, | 2160 bool is_js_array, |
| 2148 ElementsKind elements_kind, | 2161 ElementsKind elements_kind, |
| 2149 PropertyAccessType access_type, | 2162 bool is_store, |
| 2150 LoadKeyedHoleMode load_mode, | 2163 LoadKeyedHoleMode load_mode, |
| 2151 KeyedAccessStoreMode store_mode) { | 2164 KeyedAccessStoreMode store_mode) { |
| 2152 ASSERT((!IsExternalArrayElementsKind(elements_kind) && | 2165 ASSERT((!IsExternalArrayElementsKind(elements_kind) && |
| 2153 !IsFixedTypedArrayElementsKind(elements_kind)) || | 2166 !IsFixedTypedArrayElementsKind(elements_kind)) || |
| 2154 !is_js_array); | 2167 !is_js_array); |
| 2155 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency | 2168 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency |
| 2156 // on a HElementsTransition instruction. The flag can also be removed if the | 2169 // on a HElementsTransition instruction. The flag can also be removed if the |
| 2157 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further | 2170 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further |
| 2158 // ElementsKind transitions. Finally, the dependency can be removed for stores | 2171 // ElementsKind transitions. Finally, the dependency can be removed for stores |
| 2159 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the | 2172 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the |
| 2160 // generated store code. | 2173 // generated store code. |
| 2161 if ((elements_kind == FAST_HOLEY_ELEMENTS) || | 2174 if ((elements_kind == FAST_HOLEY_ELEMENTS) || |
| 2162 (elements_kind == FAST_ELEMENTS && access_type == STORE)) { | 2175 (elements_kind == FAST_ELEMENTS && is_store)) { |
| 2163 checked_object->ClearDependsOnFlag(kElementsKind); | 2176 checked_object->ClearGVNFlag(kDependsOnElementsKind); |
| 2164 } | 2177 } |
| 2165 | 2178 |
| 2166 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); | 2179 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); |
| 2167 bool fast_elements = IsFastObjectElementsKind(elements_kind); | 2180 bool fast_elements = IsFastObjectElementsKind(elements_kind); |
| 2168 HValue* elements = AddLoadElements(checked_object); | 2181 HValue* elements = AddLoadElements(checked_object); |
| 2169 if (access_type == STORE && (fast_elements || fast_smi_only_elements) && | 2182 if (is_store && (fast_elements || fast_smi_only_elements) && |
| 2170 store_mode != STORE_NO_TRANSITION_HANDLE_COW) { | 2183 store_mode != STORE_NO_TRANSITION_HANDLE_COW) { |
| 2171 HCheckMaps* check_cow_map = Add<HCheckMaps>( | 2184 HCheckMaps* check_cow_map = Add<HCheckMaps>( |
| 2172 elements, isolate()->factory()->fixed_array_map(), top_info()); | 2185 elements, isolate()->factory()->fixed_array_map(), top_info()); |
| 2173 check_cow_map->ClearDependsOnFlag(kElementsKind); | 2186 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
| 2174 } | 2187 } |
| 2175 HInstruction* length = NULL; | 2188 HInstruction* length = NULL; |
| 2176 if (is_js_array) { | 2189 if (is_js_array) { |
| 2177 length = Add<HLoadNamedField>( | 2190 length = Add<HLoadNamedField>( |
| 2178 checked_object, static_cast<HValue*>(NULL), | 2191 checked_object, static_cast<HValue*>(NULL), |
| 2179 HObjectAccess::ForArrayLength(elements_kind)); | 2192 HObjectAccess::ForArrayLength(elements_kind)); |
| 2180 } else { | 2193 } else { |
| 2181 length = AddLoadFixedArrayLength(elements); | 2194 length = AddLoadFixedArrayLength(elements); |
| 2182 } | 2195 } |
| 2183 length->set_type(HType::Smi()); | 2196 length->set_type(HType::Smi()); |
| (...skipping 11 matching lines...) Expand all Loading... |
| 2195 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { | 2208 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { |
| 2196 NoObservableSideEffectsScope no_effects(this); | 2209 NoObservableSideEffectsScope no_effects(this); |
| 2197 IfBuilder length_checker(this); | 2210 IfBuilder length_checker(this); |
| 2198 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT); | 2211 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT); |
| 2199 length_checker.Then(); | 2212 length_checker.Then(); |
| 2200 IfBuilder negative_checker(this); | 2213 IfBuilder negative_checker(this); |
| 2201 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>( | 2214 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>( |
| 2202 key, graph()->GetConstant0(), Token::GTE); | 2215 key, graph()->GetConstant0(), Token::GTE); |
| 2203 negative_checker.Then(); | 2216 negative_checker.Then(); |
| 2204 HInstruction* result = AddElementAccess( | 2217 HInstruction* result = AddElementAccess( |
| 2205 backing_store, key, val, bounds_check, elements_kind, access_type); | 2218 backing_store, key, val, bounds_check, elements_kind, is_store); |
| 2206 negative_checker.ElseDeopt("Negative key encountered"); | 2219 negative_checker.ElseDeopt("Negative key encountered"); |
| 2207 negative_checker.End(); | 2220 negative_checker.End(); |
| 2208 length_checker.End(); | 2221 length_checker.End(); |
| 2209 return result; | 2222 return result; |
| 2210 } else { | 2223 } else { |
| 2211 ASSERT(store_mode == STANDARD_STORE); | 2224 ASSERT(store_mode == STANDARD_STORE); |
| 2212 checked_key = Add<HBoundsCheck>(key, length); | 2225 checked_key = Add<HBoundsCheck>(key, length); |
| 2213 return AddElementAccess( | 2226 return AddElementAccess( |
| 2214 backing_store, checked_key, val, | 2227 backing_store, checked_key, val, |
| 2215 checked_object, elements_kind, access_type); | 2228 checked_object, elements_kind, is_store); |
| 2216 } | 2229 } |
| 2217 } | 2230 } |
| 2218 ASSERT(fast_smi_only_elements || | 2231 ASSERT(fast_smi_only_elements || |
| 2219 fast_elements || | 2232 fast_elements || |
| 2220 IsFastDoubleElementsKind(elements_kind)); | 2233 IsFastDoubleElementsKind(elements_kind)); |
| 2221 | 2234 |
| 2222 // In case val is stored into a fast smi array, assure that the value is a smi | 2235 // In case val is stored into a fast smi array, assure that the value is a smi |
| 2223 // before manipulating the backing store. Otherwise the actual store may | 2236 // before manipulating the backing store. Otherwise the actual store may |
| 2224 // deopt, leaving the backing store in an invalid state. | 2237 // deopt, leaving the backing store in an invalid state. |
| 2225 if (access_type == STORE && IsFastSmiElementsKind(elements_kind) && | 2238 if (is_store && IsFastSmiElementsKind(elements_kind) && |
| 2226 !val->type().IsSmi()) { | 2239 !val->type().IsSmi()) { |
| 2227 val = AddUncasted<HForceRepresentation>(val, Representation::Smi()); | 2240 val = AddUncasted<HForceRepresentation>(val, Representation::Smi()); |
| 2228 } | 2241 } |
| 2229 | 2242 |
| 2230 if (IsGrowStoreMode(store_mode)) { | 2243 if (IsGrowStoreMode(store_mode)) { |
| 2231 NoObservableSideEffectsScope no_effects(this); | 2244 NoObservableSideEffectsScope no_effects(this); |
| 2232 elements = BuildCheckForCapacityGrow(checked_object, elements, | 2245 elements = BuildCheckForCapacityGrow(checked_object, elements, |
| 2233 elements_kind, length, key, | 2246 elements_kind, length, key, |
| 2234 is_js_array, access_type); | 2247 is_js_array, is_store); |
| 2235 checked_key = key; | 2248 checked_key = key; |
| 2236 } else { | 2249 } else { |
| 2237 checked_key = Add<HBoundsCheck>(key, length); | 2250 checked_key = Add<HBoundsCheck>(key, length); |
| 2238 | 2251 |
| 2239 if (access_type == STORE && (fast_elements || fast_smi_only_elements)) { | 2252 if (is_store && (fast_elements || fast_smi_only_elements)) { |
| 2240 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { | 2253 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { |
| 2241 NoObservableSideEffectsScope no_effects(this); | 2254 NoObservableSideEffectsScope no_effects(this); |
| 2242 elements = BuildCopyElementsOnWrite(checked_object, elements, | 2255 elements = BuildCopyElementsOnWrite(checked_object, elements, |
| 2243 elements_kind, length); | 2256 elements_kind, length); |
| 2244 } else { | 2257 } else { |
| 2245 HCheckMaps* check_cow_map = Add<HCheckMaps>( | 2258 HCheckMaps* check_cow_map = Add<HCheckMaps>( |
| 2246 elements, isolate()->factory()->fixed_array_map(), top_info()); | 2259 elements, isolate()->factory()->fixed_array_map(), top_info()); |
| 2247 check_cow_map->ClearDependsOnFlag(kElementsKind); | 2260 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); |
| 2248 } | 2261 } |
| 2249 } | 2262 } |
| 2250 } | 2263 } |
| 2251 return AddElementAccess(elements, checked_key, val, checked_object, | 2264 return AddElementAccess(elements, checked_key, val, checked_object, |
| 2252 elements_kind, access_type, load_mode); | 2265 elements_kind, is_store, load_mode); |
| 2253 } | 2266 } |
| 2254 | 2267 |
| 2255 | 2268 |
| 2256 | 2269 |
| 2257 HValue* HGraphBuilder::BuildAllocateArrayFromLength( | 2270 HValue* HGraphBuilder::BuildAllocateArrayFromLength( |
| 2258 JSArrayBuilder* array_builder, | 2271 JSArrayBuilder* array_builder, |
| 2259 HValue* length_argument) { | 2272 HValue* length_argument) { |
| 2260 if (length_argument->IsConstant() && | 2273 if (length_argument->IsConstant() && |
| 2261 HConstant::cast(length_argument)->HasSmiValue()) { | 2274 HConstant::cast(length_argument)->HasSmiValue()) { |
| 2262 int array_length = HConstant::cast(length_argument)->Integer32Value(); | 2275 int array_length = HConstant::cast(length_argument)->Integer32Value(); |
| (...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2384 return elements; | 2397 return elements; |
| 2385 } | 2398 } |
| 2386 | 2399 |
| 2387 | 2400 |
| 2388 HInstruction* HGraphBuilder::AddElementAccess( | 2401 HInstruction* HGraphBuilder::AddElementAccess( |
| 2389 HValue* elements, | 2402 HValue* elements, |
| 2390 HValue* checked_key, | 2403 HValue* checked_key, |
| 2391 HValue* val, | 2404 HValue* val, |
| 2392 HValue* dependency, | 2405 HValue* dependency, |
| 2393 ElementsKind elements_kind, | 2406 ElementsKind elements_kind, |
| 2394 PropertyAccessType access_type, | 2407 bool is_store, |
| 2395 LoadKeyedHoleMode load_mode) { | 2408 LoadKeyedHoleMode load_mode) { |
| 2396 if (access_type == STORE) { | 2409 if (is_store) { |
| 2397 ASSERT(val != NULL); | 2410 ASSERT(val != NULL); |
| 2398 if (elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS || | 2411 if (elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS || |
| 2399 elements_kind == UINT8_CLAMPED_ELEMENTS) { | 2412 elements_kind == UINT8_CLAMPED_ELEMENTS) { |
| 2400 val = Add<HClampToUint8>(val); | 2413 val = Add<HClampToUint8>(val); |
| 2401 } | 2414 } |
| 2402 return Add<HStoreKeyed>(elements, checked_key, val, elements_kind, | 2415 return Add<HStoreKeyed>(elements, checked_key, val, elements_kind, |
| 2403 elements_kind == FAST_SMI_ELEMENTS | 2416 elements_kind == FAST_SMI_ELEMENTS |
| 2404 ? STORE_TO_INITIALIZED_ENTRY | 2417 ? STORE_TO_INITIALIZED_ENTRY |
| 2405 : INITIALIZING_STORE); | 2418 : INITIALIZING_STORE); |
| 2406 } | 2419 } |
| 2407 | 2420 |
| 2408 ASSERT(access_type == LOAD); | 2421 ASSERT(!is_store); |
| 2409 ASSERT(val == NULL); | 2422 ASSERT(val == NULL); |
| 2410 HLoadKeyed* load = Add<HLoadKeyed>( | 2423 HLoadKeyed* load = Add<HLoadKeyed>( |
| 2411 elements, checked_key, dependency, elements_kind, load_mode); | 2424 elements, checked_key, dependency, elements_kind, load_mode); |
| 2412 if (FLAG_opt_safe_uint32_operations && | 2425 if (FLAG_opt_safe_uint32_operations && |
| 2413 (elements_kind == EXTERNAL_UINT32_ELEMENTS || | 2426 (elements_kind == EXTERNAL_UINT32_ELEMENTS || |
| 2414 elements_kind == UINT32_ELEMENTS)) { | 2427 elements_kind == UINT32_ELEMENTS)) { |
| 2415 graph()->RecordUint32Instruction(load); | 2428 graph()->RecordUint32Instruction(load); |
| 2416 } | 2429 } |
| 2417 return load; | 2430 return load; |
| 2418 } | 2431 } |
| (...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2814 // A constant map is fine. | 2827 // A constant map is fine. |
| 2815 Handle<Map> map(builder()->isolate()->get_initial_js_array_map(kind_), | 2828 Handle<Map> map(builder()->isolate()->get_initial_js_array_map(kind_), |
| 2816 builder()->isolate()); | 2829 builder()->isolate()); |
| 2817 return builder()->Add<HConstant>(map); | 2830 return builder()->Add<HConstant>(map); |
| 2818 } | 2831 } |
| 2819 | 2832 |
| 2820 if (constructor_function_ != NULL && kind_ == GetInitialFastElementsKind()) { | 2833 if (constructor_function_ != NULL && kind_ == GetInitialFastElementsKind()) { |
| 2821 // No need for a context lookup if the kind_ matches the initial | 2834 // No need for a context lookup if the kind_ matches the initial |
| 2822 // map, because we can just load the map in that case. | 2835 // map, because we can just load the map in that case. |
| 2823 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); | 2836 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); |
| 2824 return builder()->Add<HLoadNamedField>( | 2837 return builder()->AddLoadNamedField(constructor_function_, access); |
| 2825 constructor_function_, static_cast<HValue*>(NULL), access); | |
| 2826 } | 2838 } |
| 2827 | 2839 |
| 2828 // TODO(mvstanton): we should always have a constructor function if we | 2840 // TODO(mvstanton): we should always have a constructor function if we |
| 2829 // are creating a stub. | 2841 // are creating a stub. |
| 2830 HInstruction* native_context = constructor_function_ != NULL | 2842 HInstruction* native_context = constructor_function_ != NULL |
| 2831 ? builder()->BuildGetNativeContext(constructor_function_) | 2843 ? builder()->BuildGetNativeContext(constructor_function_) |
| 2832 : builder()->BuildGetNativeContext(); | 2844 : builder()->BuildGetNativeContext(); |
| 2833 | 2845 |
| 2834 HInstruction* index = builder()->Add<HConstant>( | 2846 HInstruction* index = builder()->Add<HConstant>( |
| 2835 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX)); | 2847 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX)); |
| 2836 | 2848 |
| 2837 HInstruction* map_array = builder()->Add<HLoadKeyed>( | 2849 HInstruction* map_array = builder()->Add<HLoadKeyed>( |
| 2838 native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS); | 2850 native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS); |
| 2839 | 2851 |
| 2840 HInstruction* kind_index = builder()->Add<HConstant>(kind_); | 2852 HInstruction* kind_index = builder()->Add<HConstant>(kind_); |
| 2841 | 2853 |
| 2842 return builder()->Add<HLoadKeyed>( | 2854 return builder()->Add<HLoadKeyed>( |
| 2843 map_array, kind_index, static_cast<HValue*>(NULL), FAST_ELEMENTS); | 2855 map_array, kind_index, static_cast<HValue*>(NULL), FAST_ELEMENTS); |
| 2844 } | 2856 } |
| 2845 | 2857 |
| 2846 | 2858 |
| 2847 HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() { | 2859 HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() { |
| 2848 // Find the map near the constructor function | 2860 // Find the map near the constructor function |
| 2849 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); | 2861 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); |
| 2850 return builder()->Add<HLoadNamedField>( | 2862 return builder()->AddLoadNamedField(constructor_function_, access); |
| 2851 constructor_function_, static_cast<HValue*>(NULL), access); | |
| 2852 } | 2863 } |
| 2853 | 2864 |
| 2854 | 2865 |
| 2855 HValue* HGraphBuilder::JSArrayBuilder::EstablishAllocationSize( | 2866 HValue* HGraphBuilder::JSArrayBuilder::EstablishAllocationSize( |
| 2856 HValue* length_node) { | 2867 HValue* length_node) { |
| 2857 ASSERT(length_node != NULL); | 2868 ASSERT(length_node != NULL); |
| 2858 | 2869 |
| 2859 int base_size = JSArray::kSize; | 2870 int base_size = JSArray::kSize; |
| 2860 if (mode_ == TRACK_ALLOCATION_SITE) { | 2871 if (mode_ == TRACK_ALLOCATION_SITE) { |
| 2861 base_size += AllocationMemento::kSize; | 2872 base_size += AllocationMemento::kSize; |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2975 HObjectAccess function_access = HObjectAccess::ForObservableJSObjectOffset( | 2986 HObjectAccess function_access = HObjectAccess::ForObservableJSObjectOffset( |
| 2976 JSBuiltinsObject::OffsetOfFunctionWithId(builtin)); | 2987 JSBuiltinsObject::OffsetOfFunctionWithId(builtin)); |
| 2977 return Add<HLoadNamedField>( | 2988 return Add<HLoadNamedField>( |
| 2978 builtins, static_cast<HValue*>(NULL), function_access); | 2989 builtins, static_cast<HValue*>(NULL), function_access); |
| 2979 } | 2990 } |
| 2980 | 2991 |
| 2981 | 2992 |
| 2982 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info) | 2993 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info) |
| 2983 : HGraphBuilder(info), | 2994 : HGraphBuilder(info), |
| 2984 function_state_(NULL), | 2995 function_state_(NULL), |
| 2985 initial_function_state_(this, info, NORMAL_RETURN, 0), | 2996 initial_function_state_(this, info, NORMAL_RETURN), |
| 2986 ast_context_(NULL), | 2997 ast_context_(NULL), |
| 2987 break_scope_(NULL), | 2998 break_scope_(NULL), |
| 2988 inlined_count_(0), | 2999 inlined_count_(0), |
| 2989 globals_(10, info->zone()), | 3000 globals_(10, info->zone()), |
| 2990 inline_bailout_(false), | 3001 inline_bailout_(false), |
| 2991 osr_(new(info->zone()) HOsrBuilder(this)) { | 3002 osr_(new(info->zone()) HOsrBuilder(this)) { |
| 2992 // This is not initialized in the initializer list because the | 3003 // This is not initialized in the initializer list because the |
| 2993 // constructor for the initial state relies on function_state_ == NULL | 3004 // constructor for the initial state relies on function_state_ == NULL |
| 2994 // to know it's the initial state. | 3005 // to know it's the initial state. |
| 2995 function_state_= &initial_function_state_; | 3006 function_state_= &initial_function_state_; |
| 2996 InitializeAstVisitor(info->zone()); | 3007 InitializeAstVisitor(info->zone()); |
| 2997 if (FLAG_hydrogen_track_positions) { | 3008 if (FLAG_emit_opt_code_positions) { |
| 2998 SetSourcePosition(info->shared_info()->start_position()); | 3009 SetSourcePosition(info->shared_info()->start_position()); |
| 2999 } | 3010 } |
| 3000 } | 3011 } |
| 3001 | 3012 |
| 3002 | 3013 |
| 3003 HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first, | 3014 HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first, |
| 3004 HBasicBlock* second, | 3015 HBasicBlock* second, |
| 3005 BailoutId join_id) { | 3016 BailoutId join_id) { |
| 3006 if (first == NULL) { | 3017 if (first == NULL) { |
| 3007 return second; | 3018 return second; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3056 | 3067 |
| 3057 HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry( | 3068 HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry( |
| 3058 IterationStatement* statement) { | 3069 IterationStatement* statement) { |
| 3059 HBasicBlock* loop_entry = osr()->HasOsrEntryAt(statement) | 3070 HBasicBlock* loop_entry = osr()->HasOsrEntryAt(statement) |
| 3060 ? osr()->BuildOsrLoopEntry(statement) | 3071 ? osr()->BuildOsrLoopEntry(statement) |
| 3061 : BuildLoopEntry(); | 3072 : BuildLoopEntry(); |
| 3062 return loop_entry; | 3073 return loop_entry; |
| 3063 } | 3074 } |
| 3064 | 3075 |
| 3065 | 3076 |
| 3066 void HBasicBlock::FinishExit(HControlInstruction* instruction, | 3077 void HBasicBlock::FinishExit(HControlInstruction* instruction, int position) { |
| 3067 HSourcePosition position) { | |
| 3068 Finish(instruction, position); | 3078 Finish(instruction, position); |
| 3069 ClearEnvironment(); | 3079 ClearEnvironment(); |
| 3070 } | 3080 } |
| 3071 | 3081 |
| 3072 | 3082 |
| 3073 HGraph::HGraph(CompilationInfo* info) | 3083 HGraph::HGraph(CompilationInfo* info) |
| 3074 : isolate_(info->isolate()), | 3084 : isolate_(info->isolate()), |
| 3075 next_block_id_(0), | 3085 next_block_id_(0), |
| 3076 entry_block_(NULL), | 3086 entry_block_(NULL), |
| 3077 blocks_(8, info->zone()), | 3087 blocks_(8, info->zone()), |
| 3078 values_(16, info->zone()), | 3088 values_(16, info->zone()), |
| 3079 phi_list_(NULL), | 3089 phi_list_(NULL), |
| 3080 uint32_instructions_(NULL), | 3090 uint32_instructions_(NULL), |
| 3081 osr_(NULL), | 3091 osr_(NULL), |
| 3082 info_(info), | 3092 info_(info), |
| 3083 zone_(info->zone()), | 3093 zone_(info->zone()), |
| 3084 is_recursive_(false), | 3094 is_recursive_(false), |
| 3085 use_optimistic_licm_(false), | 3095 use_optimistic_licm_(false), |
| 3086 depends_on_empty_array_proto_elements_(false), | 3096 depends_on_empty_array_proto_elements_(false), |
| 3087 type_change_checksum_(0), | 3097 type_change_checksum_(0), |
| 3088 maximum_environment_size_(0), | 3098 maximum_environment_size_(0), |
| 3089 no_side_effects_scope_count_(0), | 3099 no_side_effects_scope_count_(0), |
| 3090 disallow_adding_new_values_(false), | 3100 disallow_adding_new_values_(false) { |
| 3091 next_inline_id_(0), | |
| 3092 inlined_functions_(5, info->zone()) { | |
| 3093 if (info->IsStub()) { | 3101 if (info->IsStub()) { |
| 3094 HydrogenCodeStub* stub = info->code_stub(); | 3102 HydrogenCodeStub* stub = info->code_stub(); |
| 3095 CodeStubInterfaceDescriptor* descriptor = | 3103 CodeStubInterfaceDescriptor* descriptor = |
| 3096 stub->GetInterfaceDescriptor(isolate_); | 3104 stub->GetInterfaceDescriptor(isolate_); |
| 3097 start_environment_ = | 3105 start_environment_ = |
| 3098 new(zone_) HEnvironment(zone_, descriptor->environment_length()); | 3106 new(zone_) HEnvironment(zone_, descriptor->environment_length()); |
| 3099 } else { | 3107 } else { |
| 3100 TraceInlinedFunction(info->shared_info(), HSourcePosition::Unknown()); | |
| 3101 start_environment_ = | 3108 start_environment_ = |
| 3102 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); | 3109 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); |
| 3103 } | 3110 } |
| 3104 start_environment_->set_ast_id(BailoutId::FunctionEntry()); | 3111 start_environment_->set_ast_id(BailoutId::FunctionEntry()); |
| 3105 entry_block_ = CreateBasicBlock(); | 3112 entry_block_ = CreateBasicBlock(); |
| 3106 entry_block_->SetInitialEnvironment(start_environment_); | 3113 entry_block_->SetInitialEnvironment(start_environment_); |
| 3107 } | 3114 } |
| 3108 | 3115 |
| 3109 | 3116 |
| 3110 HBasicBlock* HGraph::CreateBasicBlock() { | 3117 HBasicBlock* HGraph::CreateBasicBlock() { |
| 3111 HBasicBlock* result = new(zone()) HBasicBlock(this); | 3118 HBasicBlock* result = new(zone()) HBasicBlock(this); |
| 3112 blocks_.Add(result, zone()); | 3119 blocks_.Add(result, zone()); |
| 3113 return result; | 3120 return result; |
| 3114 } | 3121 } |
| 3115 | 3122 |
| 3116 | 3123 |
| 3117 void HGraph::FinalizeUniqueness() { | 3124 void HGraph::FinalizeUniqueness() { |
| 3118 DisallowHeapAllocation no_gc; | 3125 DisallowHeapAllocation no_gc; |
| 3119 ASSERT(!OptimizingCompilerThread::IsOptimizerThread(isolate())); | 3126 ASSERT(!OptimizingCompilerThread::IsOptimizerThread(isolate())); |
| 3120 for (int i = 0; i < blocks()->length(); ++i) { | 3127 for (int i = 0; i < blocks()->length(); ++i) { |
| 3121 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) { | 3128 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) { |
| 3122 it.Current()->FinalizeUniqueness(); | 3129 it.Current()->FinalizeUniqueness(); |
| 3123 } | 3130 } |
| 3124 } | 3131 } |
| 3125 } | 3132 } |
| 3126 | 3133 |
| 3127 | 3134 |
| 3128 int HGraph::TraceInlinedFunction( | |
| 3129 Handle<SharedFunctionInfo> shared, | |
| 3130 HSourcePosition position) { | |
| 3131 if (!FLAG_hydrogen_track_positions) { | |
| 3132 return 0; | |
| 3133 } | |
| 3134 | |
| 3135 int id = 0; | |
| 3136 for (; id < inlined_functions_.length(); id++) { | |
| 3137 if (inlined_functions_[id].shared().is_identical_to(shared)) { | |
| 3138 break; | |
| 3139 } | |
| 3140 } | |
| 3141 | |
| 3142 if (id == inlined_functions_.length()) { | |
| 3143 inlined_functions_.Add(InlinedFunctionInfo(shared), zone()); | |
| 3144 | |
| 3145 if (!shared->script()->IsUndefined()) { | |
| 3146 Handle<Script> script(Script::cast(shared->script())); | |
| 3147 if (!script->source()->IsUndefined()) { | |
| 3148 CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer()); | |
| 3149 PrintF(tracing_scope.file(), | |
| 3150 "--- FUNCTION SOURCE (%s) id{%d,%d} ---\n", | |
| 3151 shared->DebugName()->ToCString().get(), | |
| 3152 info()->optimization_id(), | |
| 3153 id); | |
| 3154 | |
| 3155 { | |
| 3156 ConsStringIteratorOp op; | |
| 3157 StringCharacterStream stream(String::cast(script->source()), | |
| 3158 &op, | |
| 3159 shared->start_position()); | |
| 3160 // fun->end_position() points to the last character in the stream. We | |
| 3161 // need to compensate by adding one to calculate the length. | |
| 3162 int source_len = | |
| 3163 shared->end_position() - shared->start_position() + 1; | |
| 3164 for (int i = 0; i < source_len; i++) { | |
| 3165 if (stream.HasMore()) { | |
| 3166 PrintF(tracing_scope.file(), "%c", stream.GetNext()); | |
| 3167 } | |
| 3168 } | |
| 3169 } | |
| 3170 | |
| 3171 PrintF(tracing_scope.file(), "\n--- END ---\n"); | |
| 3172 } | |
| 3173 } | |
| 3174 } | |
| 3175 | |
| 3176 int inline_id = next_inline_id_++; | |
| 3177 | |
| 3178 if (inline_id != 0) { | |
| 3179 CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer()); | |
| 3180 PrintF(tracing_scope.file(), "INLINE (%s) id{%d,%d} AS %d AT ", | |
| 3181 shared->DebugName()->ToCString().get(), | |
| 3182 info()->optimization_id(), | |
| 3183 id, | |
| 3184 inline_id); | |
| 3185 position.PrintTo(tracing_scope.file()); | |
| 3186 PrintF(tracing_scope.file(), "\n"); | |
| 3187 } | |
| 3188 | |
| 3189 return inline_id; | |
| 3190 } | |
| 3191 | |
| 3192 | |
| 3193 int HGraph::SourcePositionToScriptPosition(HSourcePosition pos) { | |
| 3194 if (!FLAG_hydrogen_track_positions || pos.IsUnknown()) { | |
| 3195 return pos.raw(); | |
| 3196 } | |
| 3197 | |
| 3198 return inlined_functions_[pos.inlining_id()].start_position() + | |
| 3199 pos.position(); | |
| 3200 } | |
| 3201 | |
| 3202 | |
| 3203 // Block ordering was implemented with two mutually recursive methods, | 3135 // Block ordering was implemented with two mutually recursive methods, |
| 3204 // HGraph::Postorder and HGraph::PostorderLoopBlocks. | 3136 // HGraph::Postorder and HGraph::PostorderLoopBlocks. |
| 3205 // The recursion could lead to stack overflow so the algorithm has been | 3137 // The recursion could lead to stack overflow so the algorithm has been |
| 3206 // implemented iteratively. | 3138 // implemented iteratively. |
| 3207 // At a high level the algorithm looks like this: | 3139 // At a high level the algorithm looks like this: |
| 3208 // | 3140 // |
| 3209 // Postorder(block, loop_header) : { | 3141 // Postorder(block, loop_header) : { |
| 3210 // if (block has already been visited or is of another loop) return; | 3142 // if (block has already been visited or is of another loop) return; |
| 3211 // mark block as visited; | 3143 // mark block as visited; |
| 3212 // if (block is a loop header) { | 3144 // if (block is a loop header) { |
| (...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3571 phi_list_->Add(phi, zone()); | 3503 phi_list_->Add(phi, zone()); |
| 3572 } | 3504 } |
| 3573 } | 3505 } |
| 3574 } | 3506 } |
| 3575 | 3507 |
| 3576 | 3508 |
| 3577 // Implementation of utility class to encapsulate the translation state for | 3509 // Implementation of utility class to encapsulate the translation state for |
| 3578 // a (possibly inlined) function. | 3510 // a (possibly inlined) function. |
| 3579 FunctionState::FunctionState(HOptimizedGraphBuilder* owner, | 3511 FunctionState::FunctionState(HOptimizedGraphBuilder* owner, |
| 3580 CompilationInfo* info, | 3512 CompilationInfo* info, |
| 3581 InliningKind inlining_kind, | 3513 InliningKind inlining_kind) |
| 3582 int inlining_id) | |
| 3583 : owner_(owner), | 3514 : owner_(owner), |
| 3584 compilation_info_(info), | 3515 compilation_info_(info), |
| 3585 call_context_(NULL), | 3516 call_context_(NULL), |
| 3586 inlining_kind_(inlining_kind), | 3517 inlining_kind_(inlining_kind), |
| 3587 function_return_(NULL), | 3518 function_return_(NULL), |
| 3588 test_context_(NULL), | 3519 test_context_(NULL), |
| 3589 entry_(NULL), | 3520 entry_(NULL), |
| 3590 arguments_object_(NULL), | 3521 arguments_object_(NULL), |
| 3591 arguments_elements_(NULL), | 3522 arguments_elements_(NULL), |
| 3592 inlining_id_(inlining_id), | |
| 3593 outer_source_position_(HSourcePosition::Unknown()), | |
| 3594 outer_(owner->function_state()) { | 3523 outer_(owner->function_state()) { |
| 3595 if (outer_ != NULL) { | 3524 if (outer_ != NULL) { |
| 3596 // State for an inline function. | 3525 // State for an inline function. |
| 3597 if (owner->ast_context()->IsTest()) { | 3526 if (owner->ast_context()->IsTest()) { |
| 3598 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); | 3527 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); |
| 3599 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); | 3528 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); |
| 3600 if_true->MarkAsInlineReturnTarget(owner->current_block()); | 3529 if_true->MarkAsInlineReturnTarget(owner->current_block()); |
| 3601 if_false->MarkAsInlineReturnTarget(owner->current_block()); | 3530 if_false->MarkAsInlineReturnTarget(owner->current_block()); |
| 3602 TestContext* outer_test_context = TestContext::cast(owner->ast_context()); | 3531 TestContext* outer_test_context = TestContext::cast(owner->ast_context()); |
| 3603 Expression* cond = outer_test_context->condition(); | 3532 Expression* cond = outer_test_context->condition(); |
| 3604 // The AstContext constructor pushed on the context stack. This newed | 3533 // The AstContext constructor pushed on the context stack. This newed |
| 3605 // instance is the reason that AstContext can't be BASE_EMBEDDED. | 3534 // instance is the reason that AstContext can't be BASE_EMBEDDED. |
| 3606 test_context_ = new TestContext(owner, cond, if_true, if_false); | 3535 test_context_ = new TestContext(owner, cond, if_true, if_false); |
| 3607 } else { | 3536 } else { |
| 3608 function_return_ = owner->graph()->CreateBasicBlock(); | 3537 function_return_ = owner->graph()->CreateBasicBlock(); |
| 3609 function_return()->MarkAsInlineReturnTarget(owner->current_block()); | 3538 function_return()->MarkAsInlineReturnTarget(owner->current_block()); |
| 3610 } | 3539 } |
| 3611 // Set this after possibly allocating a new TestContext above. | 3540 // Set this after possibly allocating a new TestContext above. |
| 3612 call_context_ = owner->ast_context(); | 3541 call_context_ = owner->ast_context(); |
| 3613 } | 3542 } |
| 3614 | 3543 |
| 3615 // Push on the state stack. | 3544 // Push on the state stack. |
| 3616 owner->set_function_state(this); | 3545 owner->set_function_state(this); |
| 3617 | |
| 3618 if (FLAG_hydrogen_track_positions) { | |
| 3619 outer_source_position_ = owner->source_position(); | |
| 3620 owner->EnterInlinedSource( | |
| 3621 info->shared_info()->start_position(), | |
| 3622 inlining_id); | |
| 3623 owner->SetSourcePosition(info->shared_info()->start_position()); | |
| 3624 } | |
| 3625 } | 3546 } |
| 3626 | 3547 |
| 3627 | 3548 |
| 3628 FunctionState::~FunctionState() { | 3549 FunctionState::~FunctionState() { |
| 3629 delete test_context_; | 3550 delete test_context_; |
| 3630 owner_->set_function_state(outer_); | 3551 owner_->set_function_state(outer_); |
| 3631 | |
| 3632 if (FLAG_hydrogen_track_positions) { | |
| 3633 owner_->set_source_position(outer_source_position_); | |
| 3634 owner_->EnterInlinedSource( | |
| 3635 outer_->compilation_info()->shared_info()->start_position(), | |
| 3636 outer_->inlining_id()); | |
| 3637 } | |
| 3638 } | 3552 } |
| 3639 | 3553 |
| 3640 | 3554 |
| 3641 // Implementation of utility classes to represent an expression's context in | 3555 // Implementation of utility classes to represent an expression's context in |
| 3642 // the AST. | 3556 // the AST. |
| 3643 AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind) | 3557 AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind) |
| 3644 : owner_(owner), | 3558 : owner_(owner), |
| 3645 kind_(kind), | 3559 kind_(kind), |
| 3646 outer_(owner->ast_context()), | 3560 outer_(owner->ast_context()), |
| 3647 for_typeof_(false) { | 3561 for_typeof_(false) { |
| (...skipping 792 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4440 } | 4354 } |
| 4441 | 4355 |
| 4442 // Generate a compare and branch. | 4356 // Generate a compare and branch. |
| 4443 CHECK_ALIVE(VisitForValue(clause->label())); | 4357 CHECK_ALIVE(VisitForValue(clause->label())); |
| 4444 HValue* label_value = Pop(); | 4358 HValue* label_value = Pop(); |
| 4445 | 4359 |
| 4446 Type* label_type = clause->label()->bounds().lower; | 4360 Type* label_type = clause->label()->bounds().lower; |
| 4447 Type* combined_type = clause->compare_type(); | 4361 Type* combined_type = clause->compare_type(); |
| 4448 HControlInstruction* compare = BuildCompareInstruction( | 4362 HControlInstruction* compare = BuildCompareInstruction( |
| 4449 Token::EQ_STRICT, tag_value, label_value, tag_type, label_type, | 4363 Token::EQ_STRICT, tag_value, label_value, tag_type, label_type, |
| 4450 combined_type, | 4364 combined_type, stmt->tag()->position(), clause->label()->position(), |
| 4451 ScriptPositionToSourcePosition(stmt->tag()->position()), | 4365 clause->id()); |
| 4452 ScriptPositionToSourcePosition(clause->label()->position()), | |
| 4453 PUSH_BEFORE_SIMULATE, clause->id()); | |
| 4454 | 4366 |
| 4455 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); | 4367 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); |
| 4456 HBasicBlock* body_block = graph()->CreateBasicBlock(); | 4368 HBasicBlock* body_block = graph()->CreateBasicBlock(); |
| 4457 body_blocks.Add(body_block, zone()); | 4369 body_blocks.Add(body_block, zone()); |
| 4458 compare->SetSuccessorAt(0, body_block); | 4370 compare->SetSuccessorAt(0, body_block); |
| 4459 compare->SetSuccessorAt(1, next_test_block); | 4371 compare->SetSuccessorAt(1, next_test_block); |
| 4460 FinishCurrentBlock(compare); | 4372 FinishCurrentBlock(compare); |
| 4461 | 4373 |
| 4462 set_current_block(body_block); | 4374 set_current_block(body_block); |
| 4463 Drop(1); // tag_value | 4375 Drop(1); // tag_value |
| (...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4863 set_current_block(join); | 4775 set_current_block(join); |
| 4864 if (join != NULL && !ast_context()->IsEffect()) { | 4776 if (join != NULL && !ast_context()->IsEffect()) { |
| 4865 return ast_context()->ReturnValue(Pop()); | 4777 return ast_context()->ReturnValue(Pop()); |
| 4866 } | 4778 } |
| 4867 } | 4779 } |
| 4868 } | 4780 } |
| 4869 | 4781 |
| 4870 | 4782 |
| 4871 HOptimizedGraphBuilder::GlobalPropertyAccess | 4783 HOptimizedGraphBuilder::GlobalPropertyAccess |
| 4872 HOptimizedGraphBuilder::LookupGlobalProperty( | 4784 HOptimizedGraphBuilder::LookupGlobalProperty( |
| 4873 Variable* var, LookupResult* lookup, PropertyAccessType access_type) { | 4785 Variable* var, LookupResult* lookup, bool is_store) { |
| 4874 if (var->is_this() || !current_info()->has_global_object()) { | 4786 if (var->is_this() || !current_info()->has_global_object()) { |
| 4875 return kUseGeneric; | 4787 return kUseGeneric; |
| 4876 } | 4788 } |
| 4877 Handle<GlobalObject> global(current_info()->global_object()); | 4789 Handle<GlobalObject> global(current_info()->global_object()); |
| 4878 global->Lookup(*var->name(), lookup); | 4790 global->Lookup(*var->name(), lookup); |
| 4879 if (!lookup->IsNormal() || | 4791 if (!lookup->IsNormal() || |
| 4880 (access_type == STORE && lookup->IsReadOnly()) || | 4792 (is_store && lookup->IsReadOnly()) || |
| 4881 lookup->holder() != *global) { | 4793 lookup->holder() != *global) { |
| 4882 return kUseGeneric; | 4794 return kUseGeneric; |
| 4883 } | 4795 } |
| 4884 | 4796 |
| 4885 return kUseCell; | 4797 return kUseCell; |
| 4886 } | 4798 } |
| 4887 | 4799 |
| 4888 | 4800 |
| 4889 HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) { | 4801 HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) { |
| 4890 ASSERT(var->IsContextSlot()); | 4802 ASSERT(var->IsContextSlot()); |
| 4891 HValue* context = environment()->context(); | 4803 HValue* context = environment()->context(); |
| 4892 int length = current_info()->scope()->ContextChainLength(var->scope()); | 4804 int length = current_info()->scope()->ContextChainLength(var->scope()); |
| 4893 while (length-- > 0) { | 4805 while (length-- > 0) { |
| 4894 context = Add<HLoadNamedField>( | 4806 context = AddLoadNamedField( |
| 4895 context, static_cast<HValue*>(NULL), | 4807 context, HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); |
| 4896 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); | |
| 4897 } | 4808 } |
| 4898 return context; | 4809 return context; |
| 4899 } | 4810 } |
| 4900 | 4811 |
| 4901 | 4812 |
| 4902 void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 4813 void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 4903 if (expr->is_this()) { | 4814 if (expr->is_this()) { |
| 4904 current_info()->set_this_has_uses(true); | 4815 current_info()->set_this_has_uses(true); |
| 4905 } | 4816 } |
| 4906 | 4817 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 4917 // Handle known global constants like 'undefined' specially to avoid a | 4828 // Handle known global constants like 'undefined' specially to avoid a |
| 4918 // load from a global cell for them. | 4829 // load from a global cell for them. |
| 4919 Handle<Object> constant_value = | 4830 Handle<Object> constant_value = |
| 4920 isolate()->factory()->GlobalConstantFor(variable->name()); | 4831 isolate()->factory()->GlobalConstantFor(variable->name()); |
| 4921 if (!constant_value.is_null()) { | 4832 if (!constant_value.is_null()) { |
| 4922 HConstant* instr = New<HConstant>(constant_value); | 4833 HConstant* instr = New<HConstant>(constant_value); |
| 4923 return ast_context()->ReturnInstruction(instr, expr->id()); | 4834 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 4924 } | 4835 } |
| 4925 | 4836 |
| 4926 LookupResult lookup(isolate()); | 4837 LookupResult lookup(isolate()); |
| 4927 GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, LOAD); | 4838 GlobalPropertyAccess type = |
| 4839 LookupGlobalProperty(variable, &lookup, false); |
| 4928 | 4840 |
| 4929 if (type == kUseCell && | 4841 if (type == kUseCell && |
| 4930 current_info()->global_object()->IsAccessCheckNeeded()) { | 4842 current_info()->global_object()->IsAccessCheckNeeded()) { |
| 4931 type = kUseGeneric; | 4843 type = kUseGeneric; |
| 4932 } | 4844 } |
| 4933 | 4845 |
| 4934 if (type == kUseCell) { | 4846 if (type == kUseCell) { |
| 4935 Handle<GlobalObject> global(current_info()->global_object()); | 4847 Handle<GlobalObject> global(current_info()->global_object()); |
| 4936 Handle<PropertyCell> cell(global->GetPropertyCell(&lookup)); | 4848 Handle<PropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 4937 if (cell->type()->IsConstant()) { | 4849 if (cell->type()->IsConstant()) { |
| (...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5152 case ObjectLiteral::Property::COMPUTED: | 5064 case ObjectLiteral::Property::COMPUTED: |
| 5153 if (key->value()->IsInternalizedString()) { | 5065 if (key->value()->IsInternalizedString()) { |
| 5154 if (property->emit_store()) { | 5066 if (property->emit_store()) { |
| 5155 CHECK_ALIVE(VisitForValue(value)); | 5067 CHECK_ALIVE(VisitForValue(value)); |
| 5156 HValue* value = Pop(); | 5068 HValue* value = Pop(); |
| 5157 Handle<Map> map = property->GetReceiverType(); | 5069 Handle<Map> map = property->GetReceiverType(); |
| 5158 Handle<String> name = property->key()->AsPropertyName(); | 5070 Handle<String> name = property->key()->AsPropertyName(); |
| 5159 HInstruction* store; | 5071 HInstruction* store; |
| 5160 if (map.is_null()) { | 5072 if (map.is_null()) { |
| 5161 // If we don't know the monomorphic type, do a generic store. | 5073 // If we don't know the monomorphic type, do a generic store. |
| 5162 CHECK_ALIVE(store = BuildNamedGeneric( | 5074 CHECK_ALIVE(store = BuildStoreNamedGeneric(literal, name, value)); |
| 5163 STORE, literal, name, value)); | |
| 5164 } else { | 5075 } else { |
| 5165 PropertyAccessInfo info(this, STORE, ToType(map), name); | 5076 PropertyAccessInfo info(this, STORE, ToType(map), name); |
| 5166 if (info.CanAccessMonomorphic()) { | 5077 if (info.CanAccessMonomorphic()) { |
| 5167 HValue* checked_literal = BuildCheckMap(literal, map); | 5078 HValue* checked_literal = BuildCheckMap(literal, map); |
| 5168 ASSERT(!info.lookup()->IsPropertyCallbacks()); | 5079 ASSERT(!info.lookup()->IsPropertyCallbacks()); |
| 5169 store = BuildMonomorphicAccess( | 5080 store = BuildMonomorphicAccess( |
| 5170 &info, literal, checked_literal, value, | 5081 &info, literal, checked_literal, value, |
| 5171 BailoutId::None(), BailoutId::None()); | 5082 BailoutId::None(), BailoutId::None()); |
| 5172 } else { | 5083 } else { |
| 5173 CHECK_ALIVE(store = BuildNamedGeneric( | 5084 CHECK_ALIVE( |
| 5174 STORE, literal, name, value)); | 5085 store = BuildStoreNamedGeneric(literal, name, value)); |
| 5175 } | 5086 } |
| 5176 } | 5087 } |
| 5177 AddInstruction(store); | 5088 AddInstruction(store); |
| 5178 if (store->HasObservableSideEffects()) { | 5089 if (store->HasObservableSideEffects()) { |
| 5179 Add<HSimulate>(key->id(), REMOVABLE_SIMULATE); | 5090 Add<HSimulate>(key->id(), REMOVABLE_SIMULATE); |
| 5180 } | 5091 } |
| 5181 } else { | 5092 } else { |
| 5182 CHECK_ALIVE(VisitForEffect(value)); | 5093 CHECK_ALIVE(VisitForEffect(value)); |
| 5183 } | 5094 } |
| 5184 break; | 5095 break; |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5340 } | 5251 } |
| 5341 | 5252 |
| 5342 | 5253 |
| 5343 HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object, | 5254 HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object, |
| 5344 Handle<Map> map) { | 5255 Handle<Map> map) { |
| 5345 BuildCheckHeapObject(object); | 5256 BuildCheckHeapObject(object); |
| 5346 return Add<HCheckMaps>(object, map, top_info()); | 5257 return Add<HCheckMaps>(object, map, top_info()); |
| 5347 } | 5258 } |
| 5348 | 5259 |
| 5349 | 5260 |
| 5350 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField( | |
| 5351 PropertyAccessInfo* info, | |
| 5352 HValue* checked_object) { | |
| 5353 HObjectAccess access = info->access(); | |
| 5354 if (access.representation().IsDouble()) { | |
| 5355 // Load the heap number. | |
| 5356 checked_object = Add<HLoadNamedField>( | |
| 5357 checked_object, static_cast<HValue*>(NULL), | |
| 5358 access.WithRepresentation(Representation::Tagged())); | |
| 5359 checked_object->set_type(HType::HeapNumber()); | |
| 5360 // Load the double value from it. | |
| 5361 access = HObjectAccess::ForHeapNumberValue(); | |
| 5362 } | |
| 5363 return New<HLoadNamedField>( | |
| 5364 checked_object, static_cast<HValue*>(NULL), access); | |
| 5365 } | |
| 5366 | |
| 5367 | |
| 5368 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( | 5261 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( |
| 5369 PropertyAccessInfo* info, | 5262 PropertyAccessInfo* info, |
| 5370 HValue* checked_object, | 5263 HValue* checked_object, |
| 5371 HValue* value) { | 5264 HValue* value) { |
| 5372 bool transition_to_field = info->lookup()->IsTransition(); | 5265 bool transition_to_field = info->lookup()->IsTransition(); |
| 5373 // TODO(verwaest): Move this logic into PropertyAccessInfo. | 5266 // TODO(verwaest): Move this logic into PropertyAccessInfo. |
| 5374 HObjectAccess field_access = HObjectAccess::ForField( | 5267 HObjectAccess field_access = HObjectAccess::ForField( |
| 5375 info->map(), info->lookup(), info->name()); | 5268 info->map(), info->lookup(), info->name()); |
| 5376 | 5269 |
| 5377 HStoreNamedField *instr; | 5270 HStoreNamedField *instr; |
| 5378 if (field_access.representation().IsDouble()) { | 5271 if (FLAG_track_double_fields && field_access.representation().IsDouble()) { |
| 5379 HObjectAccess heap_number_access = | 5272 HObjectAccess heap_number_access = |
| 5380 field_access.WithRepresentation(Representation::Tagged()); | 5273 field_access.WithRepresentation(Representation::Tagged()); |
| 5381 if (transition_to_field) { | 5274 if (transition_to_field) { |
| 5382 // The store requires a mutable HeapNumber to be allocated. | 5275 // The store requires a mutable HeapNumber to be allocated. |
| 5383 NoObservableSideEffectsScope no_side_effects(this); | 5276 NoObservableSideEffectsScope no_side_effects(this); |
| 5384 HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize); | 5277 HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize); |
| 5385 | 5278 |
| 5386 PretenureFlag pretenure_flag = !FLAG_allocation_site_pretenuring ? | 5279 PretenureFlag pretenure_flag = !FLAG_allocation_site_pretenuring ? |
| 5387 isolate()->heap()->GetPretenureMode() : NOT_TENURED; | 5280 isolate()->heap()->GetPretenureMode() : NOT_TENURED; |
| 5388 | 5281 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 5408 } else { | 5301 } else { |
| 5409 // This is a normal store. | 5302 // This is a normal store. |
| 5410 instr = New<HStoreNamedField>( | 5303 instr = New<HStoreNamedField>( |
| 5411 checked_object->ActualValue(), field_access, value, | 5304 checked_object->ActualValue(), field_access, value, |
| 5412 transition_to_field ? INITIALIZING_STORE : STORE_TO_INITIALIZED_ENTRY); | 5305 transition_to_field ? INITIALIZING_STORE : STORE_TO_INITIALIZED_ENTRY); |
| 5413 } | 5306 } |
| 5414 | 5307 |
| 5415 if (transition_to_field) { | 5308 if (transition_to_field) { |
| 5416 HConstant* transition_constant = Add<HConstant>(info->transition()); | 5309 HConstant* transition_constant = Add<HConstant>(info->transition()); |
| 5417 instr->SetTransition(transition_constant, top_info()); | 5310 instr->SetTransition(transition_constant, top_info()); |
| 5418 instr->SetChangesFlag(kMaps); | 5311 instr->SetGVNFlag(kChangesMaps); |
| 5419 } | 5312 } |
| 5420 return instr; | 5313 return instr; |
| 5421 } | 5314 } |
| 5422 | 5315 |
| 5423 | 5316 |
| 5317 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedGeneric( |
| 5318 HValue* object, |
| 5319 Handle<String> name, |
| 5320 HValue* value, |
| 5321 bool is_uninitialized) { |
| 5322 if (is_uninitialized) { |
| 5323 Add<HDeoptimize>("Insufficient type feedback for property assignment", |
| 5324 Deoptimizer::SOFT); |
| 5325 } |
| 5326 |
| 5327 return New<HStoreNamedGeneric>( |
| 5328 object, |
| 5329 name, |
| 5330 value, |
| 5331 function_strict_mode_flag()); |
| 5332 } |
| 5333 |
| 5334 |
| 5424 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible( | 5335 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible( |
| 5425 PropertyAccessInfo* info) { | 5336 PropertyAccessInfo* info) { |
| 5426 if (!CanInlinePropertyAccess(type_)) return false; | 5337 if (!CanInlinePropertyAccess(type_)) return false; |
| 5427 | 5338 |
| 5428 // Currently only handle Type::Number as a polymorphic case. | 5339 // Currently only handle Type::Number as a polymorphic case. |
| 5429 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber | 5340 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber |
| 5430 // instruction. | 5341 // instruction. |
| 5431 if (type_->Is(Type::Number())) return false; | 5342 if (type_->Is(Type::Number())) return false; |
| 5432 | 5343 |
| 5433 // Values are only compatible for monomorphic load if they all behave the same | 5344 // Values are only compatible for monomorphic load if they all behave the same |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5548 if (lookup_.IsFound()) { | 5459 if (lookup_.IsFound()) { |
| 5549 if (IsLoad()) return true; | 5460 if (IsLoad()) return true; |
| 5550 return !lookup_.IsReadOnly() && lookup_.IsCacheable(); | 5461 return !lookup_.IsReadOnly() && lookup_.IsCacheable(); |
| 5551 } | 5462 } |
| 5552 if (!LookupInPrototypes()) return false; | 5463 if (!LookupInPrototypes()) return false; |
| 5553 if (IsLoad()) return true; | 5464 if (IsLoad()) return true; |
| 5554 | 5465 |
| 5555 if (lookup_.IsPropertyCallbacks()) return true; | 5466 if (lookup_.IsPropertyCallbacks()) return true; |
| 5556 Handle<Map> map = this->map(); | 5467 Handle<Map> map = this->map(); |
| 5557 map->LookupTransition(NULL, *name_, &lookup_); | 5468 map->LookupTransition(NULL, *name_, &lookup_); |
| 5558 if (lookup_.IsTransitionToField() && map->unused_property_fields() > 0) { | 5469 if (lookup_.IsTransitionToField(*map) && map->unused_property_fields() > 0) { |
| 5470 transition_ = handle(lookup_.GetTransitionMapFromMap(*map)); |
| 5559 return true; | 5471 return true; |
| 5560 } | 5472 } |
| 5561 return false; | 5473 return false; |
| 5562 } | 5474 } |
| 5563 | 5475 |
| 5564 | 5476 |
| 5565 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic( | 5477 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic( |
| 5566 SmallMapList* types) { | 5478 SmallMapList* types) { |
| 5567 ASSERT(type_->Is(ToType(types->first()))); | 5479 ASSERT(type_->Is(ToType(types->first()))); |
| 5568 if (!CanAccessMonomorphic()) return false; | 5480 if (!CanAccessMonomorphic()) return false; |
| (...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5628 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); | 5540 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); |
| 5629 } | 5541 } |
| 5630 | 5542 |
| 5631 if (!info->lookup()->IsFound()) { | 5543 if (!info->lookup()->IsFound()) { |
| 5632 ASSERT(info->IsLoad()); | 5544 ASSERT(info->IsLoad()); |
| 5633 return graph()->GetConstantUndefined(); | 5545 return graph()->GetConstantUndefined(); |
| 5634 } | 5546 } |
| 5635 | 5547 |
| 5636 if (info->lookup()->IsField()) { | 5548 if (info->lookup()->IsField()) { |
| 5637 if (info->IsLoad()) { | 5549 if (info->IsLoad()) { |
| 5638 return BuildLoadNamedField(info, checked_holder); | 5550 return BuildLoadNamedField(checked_holder, info->access()); |
| 5639 } else { | 5551 } else { |
| 5640 return BuildStoreNamedField(info, checked_object, value); | 5552 return BuildStoreNamedField(info, checked_object, value); |
| 5641 } | 5553 } |
| 5642 } | 5554 } |
| 5643 | 5555 |
| 5644 if (info->lookup()->IsTransition()) { | 5556 if (info->lookup()->IsTransition()) { |
| 5645 ASSERT(!info->IsLoad()); | 5557 ASSERT(!info->IsLoad()); |
| 5646 return BuildStoreNamedField(info, checked_object, value); | 5558 return BuildStoreNamedField(info, checked_object, value); |
| 5647 } | 5559 } |
| 5648 | 5560 |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5724 | 5636 |
| 5725 if (count == 0) { | 5637 if (count == 0) { |
| 5726 join = graph()->CreateBasicBlock(); | 5638 join = graph()->CreateBasicBlock(); |
| 5727 if (handle_smi) { | 5639 if (handle_smi) { |
| 5728 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); | 5640 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
| 5729 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); | 5641 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
| 5730 number_block = graph()->CreateBasicBlock(); | 5642 number_block = graph()->CreateBasicBlock(); |
| 5731 smi_check = New<HIsSmiAndBranch>( | 5643 smi_check = New<HIsSmiAndBranch>( |
| 5732 object, empty_smi_block, not_smi_block); | 5644 object, empty_smi_block, not_smi_block); |
| 5733 FinishCurrentBlock(smi_check); | 5645 FinishCurrentBlock(smi_check); |
| 5734 GotoNoSimulate(empty_smi_block, number_block); | 5646 Goto(empty_smi_block, number_block); |
| 5735 set_current_block(not_smi_block); | 5647 set_current_block(not_smi_block); |
| 5736 } else { | 5648 } else { |
| 5737 BuildCheckHeapObject(object); | 5649 BuildCheckHeapObject(object); |
| 5738 } | 5650 } |
| 5739 } | 5651 } |
| 5740 ++count; | 5652 ++count; |
| 5741 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 5653 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 5742 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 5654 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 5743 HUnaryControlInstruction* compare; | 5655 HUnaryControlInstruction* compare; |
| 5744 | 5656 |
| 5745 HValue* dependency; | 5657 HValue* dependency; |
| 5746 if (info.type()->Is(Type::Number())) { | 5658 if (info.type()->Is(Type::Number())) { |
| 5747 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); | 5659 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
| 5748 compare = New<HCompareMap>(object, heap_number_map, top_info(), | 5660 compare = New<HCompareMap>(object, heap_number_map, if_true, if_false); |
| 5749 if_true, if_false); | |
| 5750 dependency = smi_check; | 5661 dependency = smi_check; |
| 5751 } else if (info.type()->Is(Type::String())) { | 5662 } else if (info.type()->Is(Type::String())) { |
| 5752 compare = New<HIsStringAndBranch>(object, if_true, if_false); | 5663 compare = New<HIsStringAndBranch>(object, if_true, if_false); |
| 5753 dependency = compare; | 5664 dependency = compare; |
| 5754 } else { | 5665 } else { |
| 5755 compare = New<HCompareMap>(object, info.map(), top_info(), | 5666 compare = New<HCompareMap>(object, info.map(), if_true, if_false); |
| 5756 if_true, if_false); | |
| 5757 dependency = compare; | 5667 dependency = compare; |
| 5758 } | 5668 } |
| 5759 FinishCurrentBlock(compare); | 5669 FinishCurrentBlock(compare); |
| 5760 | 5670 |
| 5761 if (info.type()->Is(Type::Number())) { | 5671 if (info.type()->Is(Type::Number())) { |
| 5762 GotoNoSimulate(if_true, number_block); | 5672 Goto(if_true, number_block); |
| 5763 if_true = number_block; | 5673 if_true = number_block; |
| 5674 number_block->SetJoinId(ast_id); |
| 5764 } | 5675 } |
| 5765 | 5676 |
| 5766 set_current_block(if_true); | 5677 set_current_block(if_true); |
| 5767 | 5678 |
| 5768 HInstruction* access = BuildMonomorphicAccess( | 5679 HInstruction* access = BuildMonomorphicAccess( |
| 5769 &info, object, dependency, value, ast_id, | 5680 &info, object, dependency, value, ast_id, |
| 5770 return_id, FLAG_polymorphic_inlining); | 5681 return_id, FLAG_polymorphic_inlining); |
| 5771 | 5682 |
| 5772 HValue* result = NULL; | 5683 HValue* result = NULL; |
| 5773 switch (access_type) { | 5684 switch (access_type) { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 5787 } | 5698 } |
| 5788 | 5699 |
| 5789 if (current_block() != NULL) Goto(join); | 5700 if (current_block() != NULL) Goto(join); |
| 5790 set_current_block(if_false); | 5701 set_current_block(if_false); |
| 5791 } | 5702 } |
| 5792 | 5703 |
| 5793 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 5704 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 5794 // know about and do not want to handle ones we've never seen. Otherwise | 5705 // know about and do not want to handle ones we've never seen. Otherwise |
| 5795 // use a generic IC. | 5706 // use a generic IC. |
| 5796 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 5707 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 5797 FinishExitWithHardDeoptimization("Uknown map in polymorphic access"); | 5708 // Because the deopt may be the only path in the polymorphic load, make sure |
| 5709 // that the environment stack matches the depth on deopt that it otherwise |
| 5710 // would have had after a successful load. |
| 5711 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); |
| 5712 const char* message = ""; |
| 5713 switch (access_type) { |
| 5714 case LOAD: |
| 5715 message = "Unknown map in polymorphic load"; |
| 5716 break; |
| 5717 case STORE: |
| 5718 message = "Unknown map in polymorphic store"; |
| 5719 break; |
| 5720 } |
| 5721 FinishExitWithHardDeoptimization(message, join); |
| 5798 } else { | 5722 } else { |
| 5799 HInstruction* instr = BuildNamedGeneric(access_type, object, name, value); | 5723 HValue* result = NULL; |
| 5800 AddInstruction(instr); | 5724 switch (access_type) { |
| 5801 if (!ast_context()->IsEffect()) Push(access_type == LOAD ? instr : value); | 5725 case LOAD: |
| 5726 result = Add<HLoadNamedGeneric>(object, name); |
| 5727 break; |
| 5728 case STORE: |
| 5729 AddInstruction(BuildStoreNamedGeneric(object, name, value)); |
| 5730 result = value; |
| 5731 break; |
| 5732 } |
| 5733 if (!ast_context()->IsEffect()) Push(result); |
| 5802 | 5734 |
| 5803 if (join != NULL) { | 5735 if (join != NULL) { |
| 5804 Goto(join); | 5736 Goto(join); |
| 5805 } else { | 5737 } else { |
| 5806 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 5738 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 5807 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | 5739 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 5808 return; | 5740 return; |
| 5809 } | 5741 } |
| 5810 } | 5742 } |
| 5811 | 5743 |
| 5812 ASSERT(join != NULL); | 5744 ASSERT(join != NULL); |
| 5813 if (join->HasPredecessor()) { | 5745 join->SetJoinId(ast_id); |
| 5814 join->SetJoinId(ast_id); | 5746 set_current_block(join); |
| 5815 set_current_block(join); | 5747 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 5816 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | |
| 5817 } else { | |
| 5818 set_current_block(NULL); | |
| 5819 } | |
| 5820 } | 5748 } |
| 5821 | 5749 |
| 5822 | 5750 |
| 5823 static bool ComputeReceiverTypes(Expression* expr, | 5751 static bool ComputeReceiverTypes(Expression* expr, |
| 5824 HValue* receiver, | 5752 HValue* receiver, |
| 5825 SmallMapList** t, | 5753 SmallMapList** t, |
| 5826 Zone* zone) { | 5754 Zone* zone) { |
| 5827 SmallMapList* types = expr->GetReceiverTypes(); | 5755 SmallMapList* types = expr->GetReceiverTypes(); |
| 5828 *t = types; | 5756 *t = types; |
| 5829 bool monomorphic = expr->IsMonomorphic(); | 5757 bool monomorphic = expr->IsMonomorphic(); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 5850 BailoutId ast_id, | 5778 BailoutId ast_id, |
| 5851 BailoutId return_id, | 5779 BailoutId return_id, |
| 5852 bool is_uninitialized) { | 5780 bool is_uninitialized) { |
| 5853 if (!prop->key()->IsPropertyName()) { | 5781 if (!prop->key()->IsPropertyName()) { |
| 5854 // Keyed store. | 5782 // Keyed store. |
| 5855 HValue* value = environment()->ExpressionStackAt(0); | 5783 HValue* value = environment()->ExpressionStackAt(0); |
| 5856 HValue* key = environment()->ExpressionStackAt(1); | 5784 HValue* key = environment()->ExpressionStackAt(1); |
| 5857 HValue* object = environment()->ExpressionStackAt(2); | 5785 HValue* object = environment()->ExpressionStackAt(2); |
| 5858 bool has_side_effects = false; | 5786 bool has_side_effects = false; |
| 5859 HandleKeyedElementAccess(object, key, value, expr, | 5787 HandleKeyedElementAccess(object, key, value, expr, |
| 5860 STORE, &has_side_effects); | 5788 true, // is_store |
| 5789 &has_side_effects); |
| 5861 Drop(3); | 5790 Drop(3); |
| 5862 Push(value); | 5791 Push(value); |
| 5863 Add<HSimulate>(return_id, REMOVABLE_SIMULATE); | 5792 Add<HSimulate>(return_id, REMOVABLE_SIMULATE); |
| 5864 return ast_context()->ReturnValue(Pop()); | 5793 return ast_context()->ReturnValue(Pop()); |
| 5865 } | 5794 } |
| 5866 | 5795 |
| 5867 // Named store. | 5796 // Named store. |
| 5868 HValue* value = Pop(); | 5797 HValue* value = Pop(); |
| 5869 HValue* object = Pop(); | 5798 HValue* object = Pop(); |
| 5870 | 5799 |
| (...skipping 29 matching lines...) Expand all Loading... |
| 5900 | 5829 |
| 5901 | 5830 |
| 5902 // Because not every expression has a position and there is not common | 5831 // Because not every expression has a position and there is not common |
| 5903 // superclass of Assignment and CountOperation, we cannot just pass the | 5832 // superclass of Assignment and CountOperation, we cannot just pass the |
| 5904 // owning expression instead of position and ast_id separately. | 5833 // owning expression instead of position and ast_id separately. |
| 5905 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( | 5834 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( |
| 5906 Variable* var, | 5835 Variable* var, |
| 5907 HValue* value, | 5836 HValue* value, |
| 5908 BailoutId ast_id) { | 5837 BailoutId ast_id) { |
| 5909 LookupResult lookup(isolate()); | 5838 LookupResult lookup(isolate()); |
| 5910 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, STORE); | 5839 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true); |
| 5911 if (type == kUseCell) { | 5840 if (type == kUseCell) { |
| 5912 Handle<GlobalObject> global(current_info()->global_object()); | 5841 Handle<GlobalObject> global(current_info()->global_object()); |
| 5913 Handle<PropertyCell> cell(global->GetPropertyCell(&lookup)); | 5842 Handle<PropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 5914 if (cell->type()->IsConstant()) { | 5843 if (cell->type()->IsConstant()) { |
| 5915 IfBuilder builder(this); | 5844 IfBuilder builder(this); |
| 5916 HValue* constant = Add<HConstant>(cell->type()->AsConstant()); | 5845 HValue* constant = Add<HConstant>(cell->type()->AsConstant()); |
| 5917 if (cell->type()->AsConstant()->IsNumber()) { | 5846 if (cell->type()->AsConstant()->IsNumber()) { |
| 5918 builder.If<HCompareNumericAndBranch>(value, constant, Token::EQ); | 5847 builder.If<HCompareNumericAndBranch>(value, constant, Token::EQ); |
| 5919 } else { | 5848 } else { |
| 5920 builder.If<HCompareObjectEqAndBranch>(value, constant); | 5849 builder.If<HCompareObjectEqAndBranch>(value, constant); |
| (...skipping 263 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6184 ASSERT(!HasStackOverflow()); | 6113 ASSERT(!HasStackOverflow()); |
| 6185 ASSERT(current_block() != NULL); | 6114 ASSERT(current_block() != NULL); |
| 6186 ASSERT(current_block()->HasPredecessor()); | 6115 ASSERT(current_block()->HasPredecessor()); |
| 6187 // We don't optimize functions with invalid left-hand sides in | 6116 // We don't optimize functions with invalid left-hand sides in |
| 6188 // assignments, count operations, or for-in. Consequently throw can | 6117 // assignments, count operations, or for-in. Consequently throw can |
| 6189 // currently only occur in an effect context. | 6118 // currently only occur in an effect context. |
| 6190 ASSERT(ast_context()->IsEffect()); | 6119 ASSERT(ast_context()->IsEffect()); |
| 6191 CHECK_ALIVE(VisitForValue(expr->exception())); | 6120 CHECK_ALIVE(VisitForValue(expr->exception())); |
| 6192 | 6121 |
| 6193 HValue* value = environment()->Pop(); | 6122 HValue* value = environment()->Pop(); |
| 6194 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); | 6123 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
| 6195 Add<HPushArgument>(value); | 6124 Add<HPushArgument>(value); |
| 6196 Add<HCallRuntime>(isolate()->factory()->empty_string(), | 6125 Add<HCallRuntime>(isolate()->factory()->empty_string(), |
| 6197 Runtime::FunctionForId(Runtime::kThrow), 1); | 6126 Runtime::FunctionForId(Runtime::kThrow), 1); |
| 6198 Add<HSimulate>(expr->id()); | 6127 Add<HSimulate>(expr->id()); |
| 6199 | 6128 |
| 6200 // If the throw definitely exits the function, we can finish with a dummy | 6129 // If the throw definitely exits the function, we can finish with a dummy |
| 6201 // control flow at this point. This is not the case if the throw is inside | 6130 // control flow at this point. This is not the case if the throw is inside |
| 6202 // an inlined function which may be replaced. | 6131 // an inlined function which may be replaced. |
| 6203 if (call_context() == NULL) { | 6132 if (call_context() == NULL) { |
| 6204 FinishExitCurrentBlock(New<HAbnormalExit>()); | 6133 FinishExitCurrentBlock(New<HAbnormalExit>()); |
| 6205 } | 6134 } |
| 6206 } | 6135 } |
| 6207 | 6136 |
| 6208 | 6137 |
| 6138 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, |
| 6139 HObjectAccess access) { |
| 6140 if (FLAG_track_double_fields && access.representation().IsDouble()) { |
| 6141 // load the heap number |
| 6142 HLoadNamedField* heap_number = Add<HLoadNamedField>( |
| 6143 object, static_cast<HValue*>(NULL), |
| 6144 access.WithRepresentation(Representation::Tagged())); |
| 6145 heap_number->set_type(HType::HeapNumber()); |
| 6146 // load the double value from it |
| 6147 return New<HLoadNamedField>( |
| 6148 heap_number, static_cast<HValue*>(NULL), |
| 6149 HObjectAccess::ForHeapNumberValue()); |
| 6150 } |
| 6151 return New<HLoadNamedField>(object, static_cast<HValue*>(NULL), access); |
| 6152 } |
| 6153 |
| 6154 |
| 6155 HInstruction* HGraphBuilder::AddLoadNamedField(HValue* object, |
| 6156 HObjectAccess access) { |
| 6157 return AddInstruction(BuildLoadNamedField(object, access)); |
| 6158 } |
| 6159 |
| 6160 |
| 6209 HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) { | 6161 HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) { |
| 6210 if (string->IsConstant()) { | 6162 if (string->IsConstant()) { |
| 6211 HConstant* c_string = HConstant::cast(string); | 6163 HConstant* c_string = HConstant::cast(string); |
| 6212 if (c_string->HasStringValue()) { | 6164 if (c_string->HasStringValue()) { |
| 6213 return Add<HConstant>(c_string->StringValue()->map()->instance_type()); | 6165 return Add<HConstant>(c_string->StringValue()->map()->instance_type()); |
| 6214 } | 6166 } |
| 6215 } | 6167 } |
| 6216 return Add<HLoadNamedField>( | 6168 return AddLoadNamedField( |
| 6217 Add<HLoadNamedField>(string, static_cast<HValue*>(NULL), | 6169 AddLoadNamedField(string, HObjectAccess::ForMap()), |
| 6218 HObjectAccess::ForMap()), | 6170 HObjectAccess::ForMapInstanceType()); |
| 6219 static_cast<HValue*>(NULL), HObjectAccess::ForMapInstanceType()); | |
| 6220 } | 6171 } |
| 6221 | 6172 |
| 6222 | 6173 |
| 6223 HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) { | 6174 HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) { |
| 6224 if (string->IsConstant()) { | 6175 if (string->IsConstant()) { |
| 6225 HConstant* c_string = HConstant::cast(string); | 6176 HConstant* c_string = HConstant::cast(string); |
| 6226 if (c_string->HasStringValue()) { | 6177 if (c_string->HasStringValue()) { |
| 6227 return Add<HConstant>(c_string->StringValue()->length()); | 6178 return Add<HConstant>(c_string->StringValue()->length()); |
| 6228 } | 6179 } |
| 6229 } | 6180 } |
| 6230 return Add<HLoadNamedField>(string, static_cast<HValue*>(NULL), | 6181 return AddLoadNamedField(string, HObjectAccess::ForStringLength()); |
| 6231 HObjectAccess::ForStringLength()); | |
| 6232 } | 6182 } |
| 6233 | 6183 |
| 6234 | 6184 |
| 6235 HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( | 6185 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( |
| 6236 PropertyAccessType access_type, | |
| 6237 HValue* object, | 6186 HValue* object, |
| 6238 Handle<String> name, | 6187 Handle<String> name, |
| 6239 HValue* value, | |
| 6240 bool is_uninitialized) { | 6188 bool is_uninitialized) { |
| 6241 if (is_uninitialized) { | 6189 if (is_uninitialized) { |
| 6242 Add<HDeoptimize>("Insufficient type feedback for generic named access", | 6190 Add<HDeoptimize>("Insufficient type feedback for generic named load", |
| 6243 Deoptimizer::SOFT); | 6191 Deoptimizer::SOFT); |
| 6244 } | 6192 } |
| 6245 if (access_type == LOAD) { | 6193 return New<HLoadNamedGeneric>(object, name); |
| 6246 return New<HLoadNamedGeneric>(object, name); | |
| 6247 } else { | |
| 6248 return New<HStoreNamedGeneric>( | |
| 6249 object, name, value, function_strict_mode_flag()); | |
| 6250 } | |
| 6251 } | 6194 } |
| 6252 | 6195 |
| 6253 | 6196 |
| 6254 | 6197 |
| 6255 HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric( | 6198 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
| 6256 PropertyAccessType access_type, | 6199 HValue* key) { |
| 6257 HValue* object, | 6200 return New<HLoadKeyedGeneric>(object, key); |
| 6258 HValue* key, | |
| 6259 HValue* value) { | |
| 6260 if (access_type == LOAD) { | |
| 6261 return New<HLoadKeyedGeneric>(object, key); | |
| 6262 } else { | |
| 6263 return New<HStoreKeyedGeneric>( | |
| 6264 object, key, value, function_strict_mode_flag()); | |
| 6265 } | |
| 6266 } | 6201 } |
| 6267 | 6202 |
| 6268 | 6203 |
| 6269 LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) { | 6204 LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) { |
| 6270 // Loads from a "stock" fast holey double arrays can elide the hole check. | 6205 // Loads from a "stock" fast holey double arrays can elide the hole check. |
| 6271 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE; | 6206 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE; |
| 6272 if (*map == isolate()->get_initial_js_array_map(FAST_HOLEY_DOUBLE_ELEMENTS) && | 6207 if (*map == isolate()->get_initial_js_array_map(FAST_HOLEY_DOUBLE_ELEMENTS) && |
| 6273 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { | 6208 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { |
| 6274 Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate()); | 6209 Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate()); |
| 6275 Handle<JSObject> object_prototype = isolate()->initial_object_prototype(); | 6210 Handle<JSObject> object_prototype = isolate()->initial_object_prototype(); |
| 6276 BuildCheckPrototypeMaps(prototype, object_prototype); | 6211 BuildCheckPrototypeMaps(prototype, object_prototype); |
| 6277 load_mode = ALLOW_RETURN_HOLE; | 6212 load_mode = ALLOW_RETURN_HOLE; |
| 6278 graph()->MarkDependsOnEmptyArrayProtoElements(); | 6213 graph()->MarkDependsOnEmptyArrayProtoElements(); |
| 6279 } | 6214 } |
| 6280 | 6215 |
| 6281 return load_mode; | 6216 return load_mode; |
| 6282 } | 6217 } |
| 6283 | 6218 |
| 6284 | 6219 |
| 6285 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( | 6220 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( |
| 6286 HValue* object, | 6221 HValue* object, |
| 6287 HValue* key, | 6222 HValue* key, |
| 6288 HValue* val, | 6223 HValue* val, |
| 6289 HValue* dependency, | 6224 HValue* dependency, |
| 6290 Handle<Map> map, | 6225 Handle<Map> map, |
| 6291 PropertyAccessType access_type, | 6226 bool is_store, |
| 6292 KeyedAccessStoreMode store_mode) { | 6227 KeyedAccessStoreMode store_mode) { |
| 6293 HCheckMaps* checked_object = Add<HCheckMaps>(object, map, top_info(), | 6228 HCheckMaps* checked_object = Add<HCheckMaps>(object, map, top_info(), |
| 6294 dependency); | 6229 dependency); |
| 6295 if (dependency) { | 6230 if (dependency) { |
| 6296 checked_object->ClearDependsOnFlag(kElementsKind); | 6231 checked_object->ClearGVNFlag(kDependsOnElementsKind); |
| 6297 } | 6232 } |
| 6298 | 6233 |
| 6299 if (access_type == STORE && map->prototype()->IsJSObject()) { | 6234 if (is_store && map->prototype()->IsJSObject()) { |
| 6300 // monomorphic stores need a prototype chain check because shape | 6235 // monomorphic stores need a prototype chain check because shape |
| 6301 // changes could allow callbacks on elements in the chain that | 6236 // changes could allow callbacks on elements in the chain that |
| 6302 // aren't compatible with monomorphic keyed stores. | 6237 // aren't compatible with monomorphic keyed stores. |
| 6303 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | 6238 Handle<JSObject> prototype(JSObject::cast(map->prototype())); |
| 6304 Object* holder = map->prototype(); | 6239 Object* holder = map->prototype(); |
| 6305 while (holder->GetPrototype(isolate())->IsJSObject()) { | 6240 while (holder->GetPrototype(isolate())->IsJSObject()) { |
| 6306 holder = holder->GetPrototype(isolate()); | 6241 holder = holder->GetPrototype(isolate()); |
| 6307 } | 6242 } |
| 6308 ASSERT(holder->GetPrototype(isolate())->IsNull()); | 6243 ASSERT(holder->GetPrototype(isolate())->IsNull()); |
| 6309 | 6244 |
| 6310 BuildCheckPrototypeMaps(prototype, | 6245 BuildCheckPrototypeMaps(prototype, |
| 6311 Handle<JSObject>(JSObject::cast(holder))); | 6246 Handle<JSObject>(JSObject::cast(holder))); |
| 6312 } | 6247 } |
| 6313 | 6248 |
| 6314 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); | 6249 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); |
| 6315 return BuildUncheckedMonomorphicElementAccess( | 6250 return BuildUncheckedMonomorphicElementAccess( |
| 6316 checked_object, key, val, | 6251 checked_object, key, val, |
| 6317 map->instance_type() == JS_ARRAY_TYPE, | 6252 map->instance_type() == JS_ARRAY_TYPE, |
| 6318 map->elements_kind(), access_type, | 6253 map->elements_kind(), is_store, |
| 6319 load_mode, store_mode); | 6254 load_mode, store_mode); |
| 6320 } | 6255 } |
| 6321 | 6256 |
| 6322 | 6257 |
| 6323 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( | 6258 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( |
| 6324 HValue* object, | 6259 HValue* object, |
| 6325 HValue* key, | 6260 HValue* key, |
| 6326 HValue* val, | 6261 HValue* val, |
| 6327 SmallMapList* maps) { | 6262 SmallMapList* maps) { |
| 6328 // For polymorphic loads of similar elements kinds (i.e. all tagged or all | 6263 // For polymorphic loads of similar elements kinds (i.e. all tagged or all |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6364 // Remember the most general elements kind, the code for its load will | 6299 // Remember the most general elements kind, the code for its load will |
| 6365 // properly handle all of the more specific cases. | 6300 // properly handle all of the more specific cases. |
| 6366 if ((i == 0) || IsMoreGeneralElementsKindTransition( | 6301 if ((i == 0) || IsMoreGeneralElementsKindTransition( |
| 6367 most_general_consolidated_map->elements_kind(), | 6302 most_general_consolidated_map->elements_kind(), |
| 6368 map->elements_kind())) { | 6303 map->elements_kind())) { |
| 6369 most_general_consolidated_map = map; | 6304 most_general_consolidated_map = map; |
| 6370 } | 6305 } |
| 6371 } | 6306 } |
| 6372 if (!has_double_maps && !has_smi_or_object_maps) return NULL; | 6307 if (!has_double_maps && !has_smi_or_object_maps) return NULL; |
| 6373 | 6308 |
| 6374 HCheckMaps* checked_object = Add<HCheckMaps>(object, maps, top_info()); | 6309 HCheckMaps* checked_object = Add<HCheckMaps>(object, maps); |
| 6375 // FAST_ELEMENTS is considered more general than FAST_HOLEY_SMI_ELEMENTS. | 6310 // FAST_ELEMENTS is considered more general than FAST_HOLEY_SMI_ELEMENTS. |
| 6376 // If we've seen both, the consolidated load must use FAST_HOLEY_ELEMENTS. | 6311 // If we've seen both, the consolidated load must use FAST_HOLEY_ELEMENTS. |
| 6377 ElementsKind consolidated_elements_kind = has_seen_holey_elements | 6312 ElementsKind consolidated_elements_kind = has_seen_holey_elements |
| 6378 ? GetHoleyElementsKind(most_general_consolidated_map->elements_kind()) | 6313 ? GetHoleyElementsKind(most_general_consolidated_map->elements_kind()) |
| 6379 : most_general_consolidated_map->elements_kind(); | 6314 : most_general_consolidated_map->elements_kind(); |
| 6380 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( | 6315 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( |
| 6381 checked_object, key, val, | 6316 checked_object, key, val, |
| 6382 most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE, | 6317 most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE, |
| 6383 consolidated_elements_kind, | 6318 consolidated_elements_kind, |
| 6384 LOAD, NEVER_RETURN_HOLE, STANDARD_STORE); | 6319 false, NEVER_RETURN_HOLE, STANDARD_STORE); |
| 6385 return instr; | 6320 return instr; |
| 6386 } | 6321 } |
| 6387 | 6322 |
| 6388 | 6323 |
| 6389 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( | 6324 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( |
| 6390 HValue* object, | 6325 HValue* object, |
| 6391 HValue* key, | 6326 HValue* key, |
| 6392 HValue* val, | 6327 HValue* val, |
| 6393 SmallMapList* maps, | 6328 SmallMapList* maps, |
| 6394 PropertyAccessType access_type, | 6329 bool is_store, |
| 6395 KeyedAccessStoreMode store_mode, | 6330 KeyedAccessStoreMode store_mode, |
| 6396 bool* has_side_effects) { | 6331 bool* has_side_effects) { |
| 6397 *has_side_effects = false; | 6332 *has_side_effects = false; |
| 6398 BuildCheckHeapObject(object); | 6333 BuildCheckHeapObject(object); |
| 6399 | 6334 |
| 6400 if (access_type == LOAD) { | 6335 if (!is_store) { |
| 6401 HInstruction* consolidated_load = | 6336 HInstruction* consolidated_load = |
| 6402 TryBuildConsolidatedElementLoad(object, key, val, maps); | 6337 TryBuildConsolidatedElementLoad(object, key, val, maps); |
| 6403 if (consolidated_load != NULL) { | 6338 if (consolidated_load != NULL) { |
| 6404 *has_side_effects |= consolidated_load->HasObservableSideEffects(); | 6339 *has_side_effects |= consolidated_load->HasObservableSideEffects(); |
| 6405 return consolidated_load; | 6340 return consolidated_load; |
| 6406 } | 6341 } |
| 6407 } | 6342 } |
| 6408 | 6343 |
| 6409 // Elements_kind transition support. | 6344 // Elements_kind transition support. |
| 6410 MapHandleList transition_target(maps->length()); | 6345 MapHandleList transition_target(maps->length()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6443 } | 6378 } |
| 6444 | 6379 |
| 6445 // If only one map is left after transitioning, handle this case | 6380 // If only one map is left after transitioning, handle this case |
| 6446 // monomorphically. | 6381 // monomorphically. |
| 6447 ASSERT(untransitionable_maps.length() >= 1); | 6382 ASSERT(untransitionable_maps.length() >= 1); |
| 6448 if (untransitionable_maps.length() == 1) { | 6383 if (untransitionable_maps.length() == 1) { |
| 6449 Handle<Map> untransitionable_map = untransitionable_maps[0]; | 6384 Handle<Map> untransitionable_map = untransitionable_maps[0]; |
| 6450 HInstruction* instr = NULL; | 6385 HInstruction* instr = NULL; |
| 6451 if (untransitionable_map->has_slow_elements_kind() || | 6386 if (untransitionable_map->has_slow_elements_kind() || |
| 6452 !untransitionable_map->IsJSObjectMap()) { | 6387 !untransitionable_map->IsJSObjectMap()) { |
| 6453 instr = AddInstruction(BuildKeyedGeneric(access_type, object, key, val)); | 6388 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) |
| 6389 : BuildLoadKeyedGeneric(object, key)); |
| 6454 } else { | 6390 } else { |
| 6455 instr = BuildMonomorphicElementAccess( | 6391 instr = BuildMonomorphicElementAccess( |
| 6456 object, key, val, transition, untransitionable_map, access_type, | 6392 object, key, val, transition, untransitionable_map, is_store, |
| 6457 store_mode); | 6393 store_mode); |
| 6458 } | 6394 } |
| 6459 *has_side_effects |= instr->HasObservableSideEffects(); | 6395 *has_side_effects |= instr->HasObservableSideEffects(); |
| 6460 return access_type == STORE ? NULL : instr; | 6396 return is_store ? NULL : instr; |
| 6461 } | 6397 } |
| 6462 | 6398 |
| 6463 HBasicBlock* join = graph()->CreateBasicBlock(); | 6399 HBasicBlock* join = graph()->CreateBasicBlock(); |
| 6464 | 6400 |
| 6465 for (int i = 0; i < untransitionable_maps.length(); ++i) { | 6401 for (int i = 0; i < untransitionable_maps.length(); ++i) { |
| 6466 Handle<Map> map = untransitionable_maps[i]; | 6402 Handle<Map> map = untransitionable_maps[i]; |
| 6467 if (!map->IsJSObjectMap()) continue; | 6403 if (!map->IsJSObjectMap()) continue; |
| 6468 ElementsKind elements_kind = map->elements_kind(); | 6404 ElementsKind elements_kind = map->elements_kind(); |
| 6469 HBasicBlock* this_map = graph()->CreateBasicBlock(); | 6405 HBasicBlock* this_map = graph()->CreateBasicBlock(); |
| 6470 HBasicBlock* other_map = graph()->CreateBasicBlock(); | 6406 HBasicBlock* other_map = graph()->CreateBasicBlock(); |
| 6471 HCompareMap* mapcompare = | 6407 HCompareMap* mapcompare = |
| 6472 New<HCompareMap>(object, map, top_info(), this_map, other_map); | 6408 New<HCompareMap>(object, map, this_map, other_map); |
| 6473 FinishCurrentBlock(mapcompare); | 6409 FinishCurrentBlock(mapcompare); |
| 6474 | 6410 |
| 6475 set_current_block(this_map); | 6411 set_current_block(this_map); |
| 6476 HInstruction* access = NULL; | 6412 HInstruction* access = NULL; |
| 6477 if (IsDictionaryElementsKind(elements_kind)) { | 6413 if (IsDictionaryElementsKind(elements_kind)) { |
| 6478 access = AddInstruction(BuildKeyedGeneric(access_type, object, key, val)); | 6414 access = is_store |
| 6415 ? AddInstruction(BuildStoreKeyedGeneric(object, key, val)) |
| 6416 : AddInstruction(BuildLoadKeyedGeneric(object, key)); |
| 6479 } else { | 6417 } else { |
| 6480 ASSERT(IsFastElementsKind(elements_kind) || | 6418 ASSERT(IsFastElementsKind(elements_kind) || |
| 6481 IsExternalArrayElementsKind(elements_kind)); | 6419 IsExternalArrayElementsKind(elements_kind)); |
| 6482 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); | 6420 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); |
| 6483 // Happily, mapcompare is a checked object. | 6421 // Happily, mapcompare is a checked object. |
| 6484 access = BuildUncheckedMonomorphicElementAccess( | 6422 access = BuildUncheckedMonomorphicElementAccess( |
| 6485 mapcompare, key, val, | 6423 mapcompare, key, val, |
| 6486 map->instance_type() == JS_ARRAY_TYPE, | 6424 map->instance_type() == JS_ARRAY_TYPE, |
| 6487 elements_kind, access_type, | 6425 elements_kind, is_store, |
| 6488 load_mode, | 6426 load_mode, |
| 6489 store_mode); | 6427 store_mode); |
| 6490 } | 6428 } |
| 6491 *has_side_effects |= access->HasObservableSideEffects(); | 6429 *has_side_effects |= access->HasObservableSideEffects(); |
| 6492 // The caller will use has_side_effects and add a correct Simulate. | 6430 // The caller will use has_side_effects and add a correct Simulate. |
| 6493 access->SetFlag(HValue::kHasNoObservableSideEffects); | 6431 access->SetFlag(HValue::kHasNoObservableSideEffects); |
| 6494 if (access_type == LOAD) { | 6432 if (!is_store) { |
| 6495 Push(access); | 6433 Push(access); |
| 6496 } | 6434 } |
| 6497 NoObservableSideEffectsScope scope(this); | 6435 NoObservableSideEffectsScope scope(this); |
| 6498 GotoNoSimulate(join); | 6436 GotoNoSimulate(join); |
| 6499 set_current_block(other_map); | 6437 set_current_block(other_map); |
| 6500 } | 6438 } |
| 6501 | 6439 |
| 6502 // Ensure that we visited at least one map above that goes to join. This is | |
| 6503 // necessary because FinishExitWithHardDeoptimization does an AbnormalExit | |
| 6504 // rather than joining the join block. If this becomes an issue, insert a | |
| 6505 // generic access in the case length() == 0. | |
| 6506 ASSERT(join->predecessors()->length() > 0); | |
| 6507 // Deopt if none of the cases matched. | 6440 // Deopt if none of the cases matched. |
| 6508 NoObservableSideEffectsScope scope(this); | 6441 NoObservableSideEffectsScope scope(this); |
| 6509 FinishExitWithHardDeoptimization("Unknown map in polymorphic element access"); | 6442 FinishExitWithHardDeoptimization("Unknown map in polymorphic element access", |
| 6443 join); |
| 6510 set_current_block(join); | 6444 set_current_block(join); |
| 6511 return access_type == STORE ? NULL : Pop(); | 6445 return is_store ? NULL : Pop(); |
| 6512 } | 6446 } |
| 6513 | 6447 |
| 6514 | 6448 |
| 6515 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( | 6449 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( |
| 6516 HValue* obj, | 6450 HValue* obj, |
| 6517 HValue* key, | 6451 HValue* key, |
| 6518 HValue* val, | 6452 HValue* val, |
| 6519 Expression* expr, | 6453 Expression* expr, |
| 6520 PropertyAccessType access_type, | 6454 bool is_store, |
| 6521 bool* has_side_effects) { | 6455 bool* has_side_effects) { |
| 6522 ASSERT(!expr->IsPropertyName()); | 6456 ASSERT(!expr->IsPropertyName()); |
| 6523 HInstruction* instr = NULL; | 6457 HInstruction* instr = NULL; |
| 6524 | 6458 |
| 6525 SmallMapList* types; | 6459 SmallMapList* types; |
| 6526 bool monomorphic = ComputeReceiverTypes(expr, obj, &types, zone()); | 6460 bool monomorphic = ComputeReceiverTypes(expr, obj, &types, zone()); |
| 6527 | 6461 |
| 6528 bool force_generic = false; | 6462 bool force_generic = false; |
| 6529 if (access_type == STORE && | 6463 if (is_store && (monomorphic || (types != NULL && !types->is_empty()))) { |
| 6530 (monomorphic || (types != NULL && !types->is_empty()))) { | |
| 6531 // Stores can't be mono/polymorphic if their prototype chain has dictionary | 6464 // Stores can't be mono/polymorphic if their prototype chain has dictionary |
| 6532 // elements. However a receiver map that has dictionary elements itself | 6465 // elements. However a receiver map that has dictionary elements itself |
| 6533 // should be left to normal mono/poly behavior (the other maps may benefit | 6466 // should be left to normal mono/poly behavior (the other maps may benefit |
| 6534 // from highly optimized stores). | 6467 // from highly optimized stores). |
| 6535 for (int i = 0; i < types->length(); i++) { | 6468 for (int i = 0; i < types->length(); i++) { |
| 6536 Handle<Map> current_map = types->at(i); | 6469 Handle<Map> current_map = types->at(i); |
| 6537 if (current_map->DictionaryElementsInPrototypeChainOnly()) { | 6470 if (current_map->DictionaryElementsInPrototypeChainOnly()) { |
| 6538 force_generic = true; | 6471 force_generic = true; |
| 6539 monomorphic = false; | 6472 monomorphic = false; |
| 6540 break; | 6473 break; |
| 6541 } | 6474 } |
| 6542 } | 6475 } |
| 6543 } | 6476 } |
| 6544 | 6477 |
| 6545 if (monomorphic) { | 6478 if (monomorphic) { |
| 6546 Handle<Map> map = types->first(); | 6479 Handle<Map> map = types->first(); |
| 6547 if (map->has_slow_elements_kind() || !map->IsJSObjectMap()) { | 6480 if (map->has_slow_elements_kind() || !map->IsJSObjectMap()) { |
| 6548 instr = AddInstruction(BuildKeyedGeneric(access_type, obj, key, val)); | 6481 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) |
| 6482 : BuildLoadKeyedGeneric(obj, key); |
| 6483 AddInstruction(instr); |
| 6549 } else { | 6484 } else { |
| 6550 BuildCheckHeapObject(obj); | 6485 BuildCheckHeapObject(obj); |
| 6551 instr = BuildMonomorphicElementAccess( | 6486 instr = BuildMonomorphicElementAccess( |
| 6552 obj, key, val, NULL, map, access_type, expr->GetStoreMode()); | 6487 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); |
| 6553 } | 6488 } |
| 6554 } else if (!force_generic && (types != NULL && !types->is_empty())) { | 6489 } else if (!force_generic && (types != NULL && !types->is_empty())) { |
| 6555 return HandlePolymorphicElementAccess( | 6490 return HandlePolymorphicElementAccess( |
| 6556 obj, key, val, types, access_type, | 6491 obj, key, val, types, is_store, |
| 6557 expr->GetStoreMode(), has_side_effects); | 6492 expr->GetStoreMode(), has_side_effects); |
| 6558 } else { | 6493 } else { |
| 6559 if (access_type == STORE) { | 6494 if (is_store) { |
| 6560 if (expr->IsAssignment() && | 6495 if (expr->IsAssignment() && |
| 6561 expr->AsAssignment()->HasNoTypeInformation()) { | 6496 expr->AsAssignment()->HasNoTypeInformation()) { |
| 6562 Add<HDeoptimize>("Insufficient type feedback for keyed store", | 6497 Add<HDeoptimize>("Insufficient type feedback for keyed store", |
| 6563 Deoptimizer::SOFT); | 6498 Deoptimizer::SOFT); |
| 6564 } | 6499 } |
| 6500 instr = BuildStoreKeyedGeneric(obj, key, val); |
| 6565 } else { | 6501 } else { |
| 6566 if (expr->AsProperty()->HasNoTypeInformation()) { | 6502 if (expr->AsProperty()->HasNoTypeInformation()) { |
| 6567 Add<HDeoptimize>("Insufficient type feedback for keyed load", | 6503 Add<HDeoptimize>("Insufficient type feedback for keyed load", |
| 6568 Deoptimizer::SOFT); | 6504 Deoptimizer::SOFT); |
| 6569 } | 6505 } |
| 6506 instr = BuildLoadKeyedGeneric(obj, key); |
| 6570 } | 6507 } |
| 6571 instr = AddInstruction(BuildKeyedGeneric(access_type, obj, key, val)); | 6508 AddInstruction(instr); |
| 6572 } | 6509 } |
| 6573 *has_side_effects = instr->HasObservableSideEffects(); | 6510 *has_side_effects = instr->HasObservableSideEffects(); |
| 6574 return instr; | 6511 return instr; |
| 6575 } | 6512 } |
| 6576 | 6513 |
| 6577 | 6514 |
| 6515 HInstruction* HOptimizedGraphBuilder::BuildStoreKeyedGeneric( |
| 6516 HValue* object, |
| 6517 HValue* key, |
| 6518 HValue* value) { |
| 6519 return New<HStoreKeyedGeneric>( |
| 6520 object, |
| 6521 key, |
| 6522 value, |
| 6523 function_strict_mode_flag()); |
| 6524 } |
| 6525 |
| 6526 |
| 6578 void HOptimizedGraphBuilder::EnsureArgumentsArePushedForAccess() { | 6527 void HOptimizedGraphBuilder::EnsureArgumentsArePushedForAccess() { |
| 6579 // Outermost function already has arguments on the stack. | 6528 // Outermost function already has arguments on the stack. |
| 6580 if (function_state()->outer() == NULL) return; | 6529 if (function_state()->outer() == NULL) return; |
| 6581 | 6530 |
| 6582 if (function_state()->arguments_pushed()) return; | 6531 if (function_state()->arguments_pushed()) return; |
| 6583 | 6532 |
| 6584 // Push arguments when entering inlined function. | 6533 // Push arguments when entering inlined function. |
| 6585 HEnterInlined* entry = function_state()->entry(); | 6534 HEnterInlined* entry = function_state()->entry(); |
| 6586 entry->set_arguments_pushed(); | 6535 entry->set_arguments_pushed(); |
| 6587 | 6536 |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6674 } | 6623 } |
| 6675 | 6624 |
| 6676 HValue* checked_object; | 6625 HValue* checked_object; |
| 6677 // Type::Number() is only supported by polymorphic load/call handling. | 6626 // Type::Number() is only supported by polymorphic load/call handling. |
| 6678 ASSERT(!info.type()->Is(Type::Number())); | 6627 ASSERT(!info.type()->Is(Type::Number())); |
| 6679 BuildCheckHeapObject(object); | 6628 BuildCheckHeapObject(object); |
| 6680 if (AreStringTypes(types)) { | 6629 if (AreStringTypes(types)) { |
| 6681 checked_object = | 6630 checked_object = |
| 6682 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); | 6631 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); |
| 6683 } else { | 6632 } else { |
| 6684 checked_object = Add<HCheckMaps>(object, types, top_info()); | 6633 checked_object = Add<HCheckMaps>(object, types); |
| 6685 } | 6634 } |
| 6686 return BuildMonomorphicAccess( | 6635 return BuildMonomorphicAccess( |
| 6687 &info, object, checked_object, value, ast_id, return_id); | 6636 &info, object, checked_object, value, ast_id, return_id); |
| 6688 } | 6637 } |
| 6689 | 6638 |
| 6690 return BuildNamedGeneric(access, object, name, value, is_uninitialized); | 6639 if (access == LOAD) { |
| 6640 return BuildLoadNamedGeneric(object, name, is_uninitialized); |
| 6641 } else { |
| 6642 return BuildStoreNamedGeneric(object, name, value, is_uninitialized); |
| 6643 } |
| 6691 } | 6644 } |
| 6692 | 6645 |
| 6693 | 6646 |
| 6694 void HOptimizedGraphBuilder::PushLoad(Property* expr, | 6647 void HOptimizedGraphBuilder::PushLoad(Property* expr, |
| 6695 HValue* object, | 6648 HValue* object, |
| 6696 HValue* key) { | 6649 HValue* key) { |
| 6697 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); | 6650 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); |
| 6698 Push(object); | 6651 Push(object); |
| 6699 if (key != NULL) Push(key); | 6652 if (key != NULL) Push(key); |
| 6700 BuildLoad(expr, expr->LoadId()); | 6653 BuildLoad(expr, expr->LoadId()); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 6724 object, name, NULL, expr->IsUninitialized()); | 6677 object, name, NULL, expr->IsUninitialized()); |
| 6725 if (instr == NULL) return; | 6678 if (instr == NULL) return; |
| 6726 if (instr->IsLinked()) return ast_context()->ReturnValue(instr); | 6679 if (instr->IsLinked()) return ast_context()->ReturnValue(instr); |
| 6727 | 6680 |
| 6728 } else { | 6681 } else { |
| 6729 HValue* key = Pop(); | 6682 HValue* key = Pop(); |
| 6730 HValue* obj = Pop(); | 6683 HValue* obj = Pop(); |
| 6731 | 6684 |
| 6732 bool has_side_effects = false; | 6685 bool has_side_effects = false; |
| 6733 HValue* load = HandleKeyedElementAccess( | 6686 HValue* load = HandleKeyedElementAccess( |
| 6734 obj, key, NULL, expr, LOAD, &has_side_effects); | 6687 obj, key, NULL, expr, |
| 6688 false, // is_store |
| 6689 &has_side_effects); |
| 6735 if (has_side_effects) { | 6690 if (has_side_effects) { |
| 6736 if (ast_context()->IsEffect()) { | 6691 if (ast_context()->IsEffect()) { |
| 6737 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 6692 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 6738 } else { | 6693 } else { |
| 6739 Push(load); | 6694 Push(load); |
| 6740 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 6695 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 6741 Drop(1); | 6696 Drop(1); |
| 6742 } | 6697 } |
| 6743 } | 6698 } |
| 6744 return ast_context()->ReturnValue(load); | 6699 return ast_context()->ReturnValue(load); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 6770 | 6725 |
| 6771 if (constant->map()->CanOmitMapChecks()) { | 6726 if (constant->map()->CanOmitMapChecks()) { |
| 6772 constant->map()->AddDependentCompilationInfo( | 6727 constant->map()->AddDependentCompilationInfo( |
| 6773 DependentCode::kPrototypeCheckGroup, info); | 6728 DependentCode::kPrototypeCheckGroup, info); |
| 6774 return constant_value; | 6729 return constant_value; |
| 6775 } | 6730 } |
| 6776 | 6731 |
| 6777 AddInstruction(constant_value); | 6732 AddInstruction(constant_value); |
| 6778 HCheckMaps* check = | 6733 HCheckMaps* check = |
| 6779 Add<HCheckMaps>(constant_value, handle(constant->map()), info); | 6734 Add<HCheckMaps>(constant_value, handle(constant->map()), info); |
| 6780 check->ClearDependsOnFlag(kElementsKind); | 6735 check->ClearGVNFlag(kDependsOnElementsKind); |
| 6781 return check; | 6736 return check; |
| 6782 } | 6737 } |
| 6783 | 6738 |
| 6784 | 6739 |
| 6785 HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype, | 6740 HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype, |
| 6786 Handle<JSObject> holder) { | 6741 Handle<JSObject> holder) { |
| 6787 while (!prototype.is_identical_to(holder)) { | 6742 while (!prototype.is_identical_to(holder)) { |
| 6788 BuildConstantMapCheck(prototype, top_info()); | 6743 BuildConstantMapCheck(prototype, top_info()); |
| 6789 prototype = handle(JSObject::cast(prototype->GetPrototype())); | 6744 prototype = handle(JSObject::cast(prototype->GetPrototype())); |
| 6790 } | 6745 } |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6854 target, static_cast<HValue*>(NULL), | 6809 target, static_cast<HValue*>(NULL), |
| 6855 HObjectAccess::ForFunctionContextPointer()); | 6810 HObjectAccess::ForFunctionContextPointer()); |
| 6856 return NewArgumentAdaptorCall(target, context, | 6811 return NewArgumentAdaptorCall(target, context, |
| 6857 argument_count, param_count_value); | 6812 argument_count, param_count_value); |
| 6858 } | 6813 } |
| 6859 UNREACHABLE(); | 6814 UNREACHABLE(); |
| 6860 return NULL; | 6815 return NULL; |
| 6861 } | 6816 } |
| 6862 | 6817 |
| 6863 | 6818 |
| 6819 class FunctionSorter { |
| 6820 public: |
| 6821 FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { } |
| 6822 FunctionSorter(int index, int ticks, int ast_length, int src_length) |
| 6823 : index_(index), |
| 6824 ticks_(ticks), |
| 6825 ast_length_(ast_length), |
| 6826 src_length_(src_length) { } |
| 6827 |
| 6828 int index() const { return index_; } |
| 6829 int ticks() const { return ticks_; } |
| 6830 int ast_length() const { return ast_length_; } |
| 6831 int src_length() const { return src_length_; } |
| 6832 |
| 6833 private: |
| 6834 int index_; |
| 6835 int ticks_; |
| 6836 int ast_length_; |
| 6837 int src_length_; |
| 6838 }; |
| 6839 |
| 6840 |
| 6841 inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) { |
| 6842 int diff = lhs.ticks() - rhs.ticks(); |
| 6843 if (diff != 0) return diff > 0; |
| 6844 diff = lhs.ast_length() - rhs.ast_length(); |
| 6845 if (diff != 0) return diff < 0; |
| 6846 return lhs.src_length() < rhs.src_length(); |
| 6847 } |
| 6848 |
| 6849 |
| 6864 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( | 6850 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
| 6865 Call* expr, | 6851 Call* expr, |
| 6866 HValue* receiver, | 6852 HValue* receiver, |
| 6867 SmallMapList* types, | 6853 SmallMapList* types, |
| 6868 Handle<String> name) { | 6854 Handle<String> name) { |
| 6869 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 6855 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
| 6870 int order[kMaxCallPolymorphism]; | 6856 FunctionSorter order[kMaxCallPolymorphism]; |
| 6871 | 6857 |
| 6872 bool handle_smi = false; | 6858 bool handle_smi = false; |
| 6873 bool handled_string = false; | 6859 bool handled_string = false; |
| 6874 int ordered_functions = 0; | 6860 int ordered_functions = 0; |
| 6875 | 6861 |
| 6876 for (int i = 0; | 6862 for (int i = 0; |
| 6877 i < types->length() && ordered_functions < kMaxCallPolymorphism; | 6863 i < types->length() && ordered_functions < kMaxCallPolymorphism; |
| 6878 ++i) { | 6864 ++i) { |
| 6879 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); | 6865 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); |
| 6880 if (info.CanAccessMonomorphic() && | 6866 if (info.CanAccessMonomorphic() && |
| 6881 info.lookup()->IsConstant() && | 6867 info.lookup()->IsConstant() && |
| 6882 info.constant()->IsJSFunction()) { | 6868 info.constant()->IsJSFunction()) { |
| 6883 if (info.type()->Is(Type::String())) { | 6869 if (info.type()->Is(Type::String())) { |
| 6884 if (handled_string) continue; | 6870 if (handled_string) continue; |
| 6885 handled_string = true; | 6871 handled_string = true; |
| 6886 } | 6872 } |
| 6887 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); | 6873 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); |
| 6888 if (info.type()->Is(Type::Number())) { | 6874 if (info.type()->Is(Type::Number())) { |
| 6889 handle_smi = true; | 6875 handle_smi = true; |
| 6890 } | 6876 } |
| 6891 expr->set_target(target); | 6877 expr->set_target(target); |
| 6892 order[ordered_functions++] = i; | 6878 order[ordered_functions++] = |
| 6879 FunctionSorter(i, |
| 6880 expr->target()->shared()->profiler_ticks(), |
| 6881 InliningAstSize(expr->target()), |
| 6882 expr->target()->shared()->SourceSize()); |
| 6893 } | 6883 } |
| 6894 } | 6884 } |
| 6895 | 6885 |
| 6886 std::sort(order, order + ordered_functions); |
| 6887 |
| 6896 HBasicBlock* number_block = NULL; | 6888 HBasicBlock* number_block = NULL; |
| 6897 HBasicBlock* join = NULL; | 6889 HBasicBlock* join = NULL; |
| 6898 handled_string = false; | 6890 handled_string = false; |
| 6899 int count = 0; | 6891 int count = 0; |
| 6900 | 6892 |
| 6901 for (int fn = 0; fn < ordered_functions; ++fn) { | 6893 for (int fn = 0; fn < ordered_functions; ++fn) { |
| 6902 int i = order[fn]; | 6894 int i = order[fn].index(); |
| 6903 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); | 6895 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); |
| 6904 if (info.type()->Is(Type::String())) { | 6896 if (info.type()->Is(Type::String())) { |
| 6905 if (handled_string) continue; | 6897 if (handled_string) continue; |
| 6906 handled_string = true; | 6898 handled_string = true; |
| 6907 } | 6899 } |
| 6908 // Reloads the target. | 6900 // Reloads the target. |
| 6909 info.CanAccessMonomorphic(); | 6901 info.CanAccessMonomorphic(); |
| 6910 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); | 6902 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); |
| 6911 | 6903 |
| 6912 expr->set_target(target); | 6904 expr->set_target(target); |
| 6913 if (count == 0) { | 6905 if (count == 0) { |
| 6914 // Only needed once. | 6906 // Only needed once. |
| 6915 join = graph()->CreateBasicBlock(); | 6907 join = graph()->CreateBasicBlock(); |
| 6916 if (handle_smi) { | 6908 if (handle_smi) { |
| 6917 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); | 6909 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
| 6918 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); | 6910 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
| 6919 number_block = graph()->CreateBasicBlock(); | 6911 number_block = graph()->CreateBasicBlock(); |
| 6920 FinishCurrentBlock(New<HIsSmiAndBranch>( | 6912 FinishCurrentBlock(New<HIsSmiAndBranch>( |
| 6921 receiver, empty_smi_block, not_smi_block)); | 6913 receiver, empty_smi_block, not_smi_block)); |
| 6922 GotoNoSimulate(empty_smi_block, number_block); | 6914 Goto(empty_smi_block, number_block); |
| 6923 set_current_block(not_smi_block); | 6915 set_current_block(not_smi_block); |
| 6924 } else { | 6916 } else { |
| 6925 BuildCheckHeapObject(receiver); | 6917 BuildCheckHeapObject(receiver); |
| 6926 } | 6918 } |
| 6927 } | 6919 } |
| 6928 ++count; | 6920 ++count; |
| 6929 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 6921 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 6930 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 6922 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 6931 HUnaryControlInstruction* compare; | 6923 HUnaryControlInstruction* compare; |
| 6932 | 6924 |
| 6933 Handle<Map> map = info.map(); | 6925 Handle<Map> map = info.map(); |
| 6934 if (info.type()->Is(Type::Number())) { | 6926 if (info.type()->Is(Type::Number())) { |
| 6935 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); | 6927 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
| 6936 compare = New<HCompareMap>(receiver, heap_number_map, top_info(), | 6928 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); |
| 6937 if_true, if_false); | |
| 6938 } else if (info.type()->Is(Type::String())) { | 6929 } else if (info.type()->Is(Type::String())) { |
| 6939 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); | 6930 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); |
| 6940 } else { | 6931 } else { |
| 6941 compare = New<HCompareMap>(receiver, map, top_info(), | 6932 compare = New<HCompareMap>(receiver, map, if_true, if_false); |
| 6942 if_true, if_false); | |
| 6943 } | 6933 } |
| 6944 FinishCurrentBlock(compare); | 6934 FinishCurrentBlock(compare); |
| 6945 | 6935 |
| 6946 if (info.type()->Is(Type::Number())) { | 6936 if (info.type()->Is(Type::Number())) { |
| 6947 GotoNoSimulate(if_true, number_block); | 6937 Goto(if_true, number_block); |
| 6948 if_true = number_block; | 6938 if_true = number_block; |
| 6939 number_block->SetJoinId(expr->id()); |
| 6949 } | 6940 } |
| 6950 | 6941 |
| 6951 set_current_block(if_true); | 6942 set_current_block(if_true); |
| 6952 | 6943 |
| 6953 AddCheckPrototypeMaps(info.holder(), map); | 6944 AddCheckPrototypeMaps(info.holder(), map); |
| 6954 | 6945 |
| 6955 HValue* function = Add<HConstant>(expr->target()); | 6946 HValue* function = Add<HConstant>(expr->target()); |
| 6956 environment()->SetExpressionStackAt(0, function); | 6947 environment()->SetExpressionStackAt(0, function); |
| 6957 Push(receiver); | 6948 Push(receiver); |
| 6958 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 6949 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| (...skipping 27 matching lines...) Expand all Loading... |
| 6986 } | 6977 } |
| 6987 | 6978 |
| 6988 if (current_block() != NULL) Goto(join); | 6979 if (current_block() != NULL) Goto(join); |
| 6989 set_current_block(if_false); | 6980 set_current_block(if_false); |
| 6990 } | 6981 } |
| 6991 | 6982 |
| 6992 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 6983 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 6993 // know about and do not want to handle ones we've never seen. Otherwise | 6984 // know about and do not want to handle ones we've never seen. Otherwise |
| 6994 // use a generic IC. | 6985 // use a generic IC. |
| 6995 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { | 6986 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 6996 FinishExitWithHardDeoptimization("Unknown map in polymorphic call"); | 6987 // Because the deopt may be the only path in the polymorphic call, make sure |
| 6988 // that the environment stack matches the depth on deopt that it otherwise |
| 6989 // would have had after a successful call. |
| 6990 Drop(1); // Drop receiver. |
| 6991 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); |
| 6992 FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); |
| 6997 } else { | 6993 } else { |
| 6998 Property* prop = expr->expression()->AsProperty(); | 6994 Property* prop = expr->expression()->AsProperty(); |
| 6999 HInstruction* function = BuildNamedGeneric( | 6995 HInstruction* function = BuildLoadNamedGeneric( |
| 7000 LOAD, receiver, name, NULL, prop->IsUninitialized()); | 6996 receiver, name, prop->IsUninitialized()); |
| 7001 AddInstruction(function); | 6997 AddInstruction(function); |
| 7002 Push(function); | 6998 Push(function); |
| 7003 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); | 6999 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
| 7004 | 7000 |
| 7005 environment()->SetExpressionStackAt(1, function); | 7001 environment()->SetExpressionStackAt(1, function); |
| 7006 environment()->SetExpressionStackAt(0, receiver); | 7002 environment()->SetExpressionStackAt(0, receiver); |
| 7007 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 7003 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7008 | 7004 |
| 7009 CallFunctionFlags flags = receiver->type().IsJSObject() | 7005 CallFunctionFlags flags = receiver->type().IsJSObject() |
| 7010 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; | 7006 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; |
| (...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7094 int nodes_added = target_shared->ast_node_count(); | 7090 int nodes_added = target_shared->ast_node_count(); |
| 7095 return nodes_added; | 7091 return nodes_added; |
| 7096 } | 7092 } |
| 7097 | 7093 |
| 7098 | 7094 |
| 7099 bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, | 7095 bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, |
| 7100 int arguments_count, | 7096 int arguments_count, |
| 7101 HValue* implicit_return_value, | 7097 HValue* implicit_return_value, |
| 7102 BailoutId ast_id, | 7098 BailoutId ast_id, |
| 7103 BailoutId return_id, | 7099 BailoutId return_id, |
| 7104 InliningKind inlining_kind, | 7100 InliningKind inlining_kind) { |
| 7105 HSourcePosition position) { | |
| 7106 int nodes_added = InliningAstSize(target); | 7101 int nodes_added = InliningAstSize(target); |
| 7107 if (nodes_added == kNotInlinable) return false; | 7102 if (nodes_added == kNotInlinable) return false; |
| 7108 | 7103 |
| 7109 Handle<JSFunction> caller = current_info()->closure(); | 7104 Handle<JSFunction> caller = current_info()->closure(); |
| 7110 | 7105 |
| 7111 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { | 7106 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { |
| 7112 TraceInline(target, caller, "target AST is too large [early]"); | 7107 TraceInline(target, caller, "target AST is too large [early]"); |
| 7113 return false; | 7108 return false; |
| 7114 } | 7109 } |
| 7115 | 7110 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7227 } | 7222 } |
| 7228 | 7223 |
| 7229 // ---------------------------------------------------------------- | 7224 // ---------------------------------------------------------------- |
| 7230 // After this point, we've made a decision to inline this function (so | 7225 // After this point, we've made a decision to inline this function (so |
| 7231 // TryInline should always return true). | 7226 // TryInline should always return true). |
| 7232 | 7227 |
| 7233 // Type-check the inlined function. | 7228 // Type-check the inlined function. |
| 7234 ASSERT(target_shared->has_deoptimization_support()); | 7229 ASSERT(target_shared->has_deoptimization_support()); |
| 7235 AstTyper::Run(&target_info); | 7230 AstTyper::Run(&target_info); |
| 7236 | 7231 |
| 7237 int function_id = graph()->TraceInlinedFunction(target_shared, position); | |
| 7238 | |
| 7239 // Save the pending call context. Set up new one for the inlined function. | 7232 // Save the pending call context. Set up new one for the inlined function. |
| 7240 // The function state is new-allocated because we need to delete it | 7233 // The function state is new-allocated because we need to delete it |
| 7241 // in two different places. | 7234 // in two different places. |
| 7242 FunctionState* target_state = new FunctionState( | 7235 FunctionState* target_state = new FunctionState( |
| 7243 this, &target_info, inlining_kind, function_id); | 7236 this, &target_info, inlining_kind); |
| 7244 | 7237 |
| 7245 HConstant* undefined = graph()->GetConstantUndefined(); | 7238 HConstant* undefined = graph()->GetConstantUndefined(); |
| 7246 | 7239 |
| 7247 HEnvironment* inner_env = | 7240 HEnvironment* inner_env = |
| 7248 environment()->CopyForInlining(target, | 7241 environment()->CopyForInlining(target, |
| 7249 arguments_count, | 7242 arguments_count, |
| 7250 function, | 7243 function, |
| 7251 undefined, | 7244 undefined, |
| 7252 function_state()->inlining_kind()); | 7245 function_state()->inlining_kind()); |
| 7253 | 7246 |
| (...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7380 return true; | 7373 return true; |
| 7381 } | 7374 } |
| 7382 | 7375 |
| 7383 | 7376 |
| 7384 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) { | 7377 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) { |
| 7385 return TryInline(expr->target(), | 7378 return TryInline(expr->target(), |
| 7386 expr->arguments()->length(), | 7379 expr->arguments()->length(), |
| 7387 NULL, | 7380 NULL, |
| 7388 expr->id(), | 7381 expr->id(), |
| 7389 expr->ReturnId(), | 7382 expr->ReturnId(), |
| 7390 NORMAL_RETURN, | 7383 NORMAL_RETURN); |
| 7391 ScriptPositionToSourcePosition(expr->position())); | |
| 7392 } | 7384 } |
| 7393 | 7385 |
| 7394 | 7386 |
| 7395 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, | 7387 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, |
| 7396 HValue* implicit_return_value) { | 7388 HValue* implicit_return_value) { |
| 7397 return TryInline(expr->target(), | 7389 return TryInline(expr->target(), |
| 7398 expr->arguments()->length(), | 7390 expr->arguments()->length(), |
| 7399 implicit_return_value, | 7391 implicit_return_value, |
| 7400 expr->id(), | 7392 expr->id(), |
| 7401 expr->ReturnId(), | 7393 expr->ReturnId(), |
| 7402 CONSTRUCT_CALL_RETURN, | 7394 CONSTRUCT_CALL_RETURN); |
| 7403 ScriptPositionToSourcePosition(expr->position())); | |
| 7404 } | 7395 } |
| 7405 | 7396 |
| 7406 | 7397 |
| 7407 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, | 7398 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, |
| 7408 Handle<Map> receiver_map, | 7399 Handle<Map> receiver_map, |
| 7409 BailoutId ast_id, | 7400 BailoutId ast_id, |
| 7410 BailoutId return_id) { | 7401 BailoutId return_id) { |
| 7411 if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true; | 7402 if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true; |
| 7412 return TryInline(getter, | 7403 return TryInline(getter, |
| 7413 0, | 7404 0, |
| 7414 NULL, | 7405 NULL, |
| 7415 ast_id, | 7406 ast_id, |
| 7416 return_id, | 7407 return_id, |
| 7417 GETTER_CALL_RETURN, | 7408 GETTER_CALL_RETURN); |
| 7418 source_position()); | |
| 7419 } | 7409 } |
| 7420 | 7410 |
| 7421 | 7411 |
| 7422 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, | 7412 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, |
| 7423 Handle<Map> receiver_map, | 7413 Handle<Map> receiver_map, |
| 7424 BailoutId id, | 7414 BailoutId id, |
| 7425 BailoutId assignment_id, | 7415 BailoutId assignment_id, |
| 7426 HValue* implicit_return_value) { | 7416 HValue* implicit_return_value) { |
| 7427 if (TryInlineApiSetter(setter, receiver_map, id)) return true; | 7417 if (TryInlineApiSetter(setter, receiver_map, id)) return true; |
| 7428 return TryInline(setter, | 7418 return TryInline(setter, |
| 7429 1, | 7419 1, |
| 7430 implicit_return_value, | 7420 implicit_return_value, |
| 7431 id, assignment_id, | 7421 id, assignment_id, |
| 7432 SETTER_CALL_RETURN, | 7422 SETTER_CALL_RETURN); |
| 7433 source_position()); | |
| 7434 } | 7423 } |
| 7435 | 7424 |
| 7436 | 7425 |
| 7437 bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, | 7426 bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, |
| 7438 Call* expr, | 7427 Call* expr, |
| 7439 int arguments_count) { | 7428 int arguments_count) { |
| 7440 return TryInline(function, | 7429 return TryInline(function, |
| 7441 arguments_count, | 7430 arguments_count, |
| 7442 NULL, | 7431 NULL, |
| 7443 expr->id(), | 7432 expr->id(), |
| 7444 expr->ReturnId(), | 7433 expr->ReturnId(), |
| 7445 NORMAL_RETURN, | 7434 NORMAL_RETURN); |
| 7446 ScriptPositionToSourcePosition(expr->position())); | |
| 7447 } | 7435 } |
| 7448 | 7436 |
| 7449 | 7437 |
| 7450 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { | 7438 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { |
| 7451 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 7439 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
| 7452 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 7440 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 7453 switch (id) { | 7441 switch (id) { |
| 7454 case kMathExp: | 7442 case kMathExp: |
| 7455 if (!FLAG_fast_math) break; | 7443 if (!FLAG_fast_math) break; |
| 7456 // Fall through if FLAG_fast_math. | 7444 // Fall through if FLAG_fast_math. |
| 7457 case kMathRound: | 7445 case kMathRound: |
| 7458 case kMathFloor: | 7446 case kMathFloor: |
| 7459 case kMathAbs: | 7447 case kMathAbs: |
| 7460 case kMathSqrt: | 7448 case kMathSqrt: |
| 7461 case kMathLog: | 7449 case kMathLog: |
| 7462 case kMathClz32: | |
| 7463 if (expr->arguments()->length() == 1) { | 7450 if (expr->arguments()->length() == 1) { |
| 7464 HValue* argument = Pop(); | 7451 HValue* argument = Pop(); |
| 7465 Drop(2); // Receiver and function. | 7452 Drop(2); // Receiver and function. |
| 7466 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); | 7453 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
| 7467 ast_context()->ReturnInstruction(op, expr->id()); | 7454 ast_context()->ReturnInstruction(op, expr->id()); |
| 7468 return true; | 7455 return true; |
| 7469 } | 7456 } |
| 7470 break; | 7457 break; |
| 7471 case kMathImul: | 7458 case kMathImul: |
| 7472 if (expr->arguments()->length() == 2) { | 7459 if (expr->arguments()->length() == 2) { |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7523 } | 7510 } |
| 7524 break; | 7511 break; |
| 7525 case kMathExp: | 7512 case kMathExp: |
| 7526 if (!FLAG_fast_math) break; | 7513 if (!FLAG_fast_math) break; |
| 7527 // Fall through if FLAG_fast_math. | 7514 // Fall through if FLAG_fast_math. |
| 7528 case kMathRound: | 7515 case kMathRound: |
| 7529 case kMathFloor: | 7516 case kMathFloor: |
| 7530 case kMathAbs: | 7517 case kMathAbs: |
| 7531 case kMathSqrt: | 7518 case kMathSqrt: |
| 7532 case kMathLog: | 7519 case kMathLog: |
| 7533 case kMathClz32: | |
| 7534 if (argument_count == 2) { | 7520 if (argument_count == 2) { |
| 7535 HValue* argument = Pop(); | 7521 HValue* argument = Pop(); |
| 7536 Drop(2); // Receiver and function. | 7522 Drop(2); // Receiver and function. |
| 7537 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); | 7523 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
| 7538 ast_context()->ReturnInstruction(op, expr->id()); | 7524 ast_context()->ReturnInstruction(op, expr->id()); |
| 7539 return true; | 7525 return true; |
| 7540 } | 7526 } |
| 7541 break; | 7527 break; |
| 7542 case kMathPow: | 7528 case kMathPow: |
| 7543 if (argument_count == 3) { | 7529 if (argument_count == 3) { |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7622 | 7608 |
| 7623 length_checker.Else(); | 7609 length_checker.Else(); |
| 7624 HValue* elements = AddLoadElements(checked_object); | 7610 HValue* elements = AddLoadElements(checked_object); |
| 7625 // Ensure that we aren't popping from a copy-on-write array. | 7611 // Ensure that we aren't popping from a copy-on-write array. |
| 7626 if (IsFastSmiOrObjectElementsKind(elements_kind)) { | 7612 if (IsFastSmiOrObjectElementsKind(elements_kind)) { |
| 7627 elements = BuildCopyElementsOnWrite(checked_object, elements, | 7613 elements = BuildCopyElementsOnWrite(checked_object, elements, |
| 7628 elements_kind, length); | 7614 elements_kind, length); |
| 7629 } | 7615 } |
| 7630 reduced_length = AddUncasted<HSub>(length, graph()->GetConstant1()); | 7616 reduced_length = AddUncasted<HSub>(length, graph()->GetConstant1()); |
| 7631 result = AddElementAccess(elements, reduced_length, NULL, | 7617 result = AddElementAccess(elements, reduced_length, NULL, |
| 7632 bounds_check, elements_kind, LOAD); | 7618 bounds_check, elements_kind, false); |
| 7633 Factory* factory = isolate()->factory(); | 7619 Factory* factory = isolate()->factory(); |
| 7634 double nan_double = FixedDoubleArray::hole_nan_as_double(); | 7620 double nan_double = FixedDoubleArray::hole_nan_as_double(); |
| 7635 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) | 7621 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) |
| 7636 ? Add<HConstant>(factory->the_hole_value()) | 7622 ? Add<HConstant>(factory->the_hole_value()) |
| 7637 : Add<HConstant>(nan_double); | 7623 : Add<HConstant>(nan_double); |
| 7638 if (IsFastSmiOrObjectElementsKind(elements_kind)) { | 7624 if (IsFastSmiOrObjectElementsKind(elements_kind)) { |
| 7639 elements_kind = FAST_HOLEY_ELEMENTS; | 7625 elements_kind = FAST_HOLEY_ELEMENTS; |
| 7640 } | 7626 } |
| 7641 AddElementAccess( | 7627 AddElementAccess( |
| 7642 elements, reduced_length, hole, bounds_check, elements_kind, STORE); | 7628 elements, reduced_length, hole, bounds_check, elements_kind, true); |
| 7643 Add<HStoreNamedField>( | 7629 Add<HStoreNamedField>( |
| 7644 checked_object, HObjectAccess::ForArrayLength(elements_kind), | 7630 checked_object, HObjectAccess::ForArrayLength(elements_kind), |
| 7645 reduced_length, STORE_TO_INITIALIZED_ENTRY); | 7631 reduced_length, STORE_TO_INITIALIZED_ENTRY); |
| 7646 | 7632 |
| 7647 if (!ast_context()->IsEffect()) Push(result); | 7633 if (!ast_context()->IsEffect()) Push(result); |
| 7648 | 7634 |
| 7649 length_checker.End(); | 7635 length_checker.End(); |
| 7650 } | 7636 } |
| 7651 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top(); | 7637 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top(); |
| 7652 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 7638 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
| (...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7777 receiver_maps->first(), &holder_lookup); | 7763 receiver_maps->first(), &holder_lookup); |
| 7778 if (holder_lookup == CallOptimization::kHolderNotFound) return false; | 7764 if (holder_lookup == CallOptimization::kHolderNotFound) return false; |
| 7779 | 7765 |
| 7780 if (FLAG_trace_inlining) { | 7766 if (FLAG_trace_inlining) { |
| 7781 PrintF("Inlining api function "); | 7767 PrintF("Inlining api function "); |
| 7782 function->ShortPrint(); | 7768 function->ShortPrint(); |
| 7783 PrintF("\n"); | 7769 PrintF("\n"); |
| 7784 } | 7770 } |
| 7785 | 7771 |
| 7786 bool drop_extra = false; | 7772 bool drop_extra = false; |
| 7787 bool is_store = false; | |
| 7788 switch (call_type) { | 7773 switch (call_type) { |
| 7789 case kCallApiFunction: | 7774 case kCallApiFunction: |
| 7790 case kCallApiMethod: | 7775 case kCallApiMethod: |
| 7791 // Need to check that none of the receiver maps could have changed. | 7776 // Need to check that none of the receiver maps could have changed. |
| 7792 Add<HCheckMaps>(receiver, receiver_maps, top_info()); | 7777 Add<HCheckMaps>(receiver, receiver_maps); |
| 7793 // Need to ensure the chain between receiver and api_holder is intact. | 7778 // Need to ensure the chain between receiver and api_holder is intact. |
| 7794 if (holder_lookup == CallOptimization::kHolderFound) { | 7779 if (holder_lookup == CallOptimization::kHolderFound) { |
| 7795 AddCheckPrototypeMaps(api_holder, receiver_maps->first()); | 7780 AddCheckPrototypeMaps(api_holder, receiver_maps->first()); |
| 7796 } else { | 7781 } else { |
| 7797 ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); | 7782 ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); |
| 7798 } | 7783 } |
| 7799 // Includes receiver. | 7784 // Includes receiver. |
| 7800 PushArgumentsFromEnvironment(argc + 1); | 7785 PushArgumentsFromEnvironment(argc + 1); |
| 7801 // Drop function after call. | 7786 // Drop function after call. |
| 7802 drop_extra = true; | 7787 drop_extra = true; |
| 7803 break; | 7788 break; |
| 7804 case kCallApiGetter: | 7789 case kCallApiGetter: |
| 7805 // Receiver and prototype chain cannot have changed. | 7790 // Receiver and prototype chain cannot have changed. |
| 7806 ASSERT_EQ(0, argc); | 7791 ASSERT_EQ(0, argc); |
| 7807 ASSERT_EQ(NULL, receiver); | 7792 ASSERT_EQ(NULL, receiver); |
| 7808 // Receiver is on expression stack. | 7793 // Receiver is on expression stack. |
| 7809 receiver = Pop(); | 7794 receiver = Pop(); |
| 7810 Add<HPushArgument>(receiver); | 7795 Add<HPushArgument>(receiver); |
| 7811 break; | 7796 break; |
| 7812 case kCallApiSetter: | 7797 case kCallApiSetter: |
| 7813 { | 7798 { |
| 7814 is_store = true; | |
| 7815 // Receiver and prototype chain cannot have changed. | 7799 // Receiver and prototype chain cannot have changed. |
| 7816 ASSERT_EQ(1, argc); | 7800 ASSERT_EQ(1, argc); |
| 7817 ASSERT_EQ(NULL, receiver); | 7801 ASSERT_EQ(NULL, receiver); |
| 7818 // Receiver and value are on expression stack. | 7802 // Receiver and value are on expression stack. |
| 7819 HValue* value = Pop(); | 7803 HValue* value = Pop(); |
| 7820 receiver = Pop(); | 7804 receiver = Pop(); |
| 7821 Add<HPushArgument>(receiver); | 7805 Add<HPushArgument>(receiver); |
| 7822 Add<HPushArgument>(value); | 7806 Add<HPushArgument>(value); |
| 7823 break; | 7807 break; |
| 7824 } | 7808 } |
| (...skipping 25 matching lines...) Expand all Loading... |
| 7850 Add<HConstant>(function), | 7834 Add<HConstant>(function), |
| 7851 call_data, | 7835 call_data, |
| 7852 holder, | 7836 holder, |
| 7853 api_function_address, | 7837 api_function_address, |
| 7854 context() | 7838 context() |
| 7855 }; | 7839 }; |
| 7856 | 7840 |
| 7857 CallInterfaceDescriptor* descriptor = | 7841 CallInterfaceDescriptor* descriptor = |
| 7858 isolate()->call_descriptor(Isolate::ApiFunctionCall); | 7842 isolate()->call_descriptor(Isolate::ApiFunctionCall); |
| 7859 | 7843 |
| 7860 CallApiFunctionStub stub(is_store, call_data_is_undefined, argc); | 7844 CallApiFunctionStub stub(true, call_data_is_undefined, argc); |
| 7861 Handle<Code> code = stub.GetCode(isolate()); | 7845 Handle<Code> code = stub.GetCode(isolate()); |
| 7862 HConstant* code_value = Add<HConstant>(code); | 7846 HConstant* code_value = Add<HConstant>(code); |
| 7863 | 7847 |
| 7864 ASSERT((sizeof(op_vals) / kPointerSize) == | 7848 ASSERT((sizeof(op_vals) / kPointerSize) == |
| 7865 descriptor->environment_length()); | 7849 descriptor->environment_length()); |
| 7866 | 7850 |
| 7867 HInstruction* call = New<HCallWithDescriptor>( | 7851 HInstruction* call = New<HCallWithDescriptor>( |
| 7868 code_value, argc + 1, descriptor, | 7852 code_value, argc + 1, descriptor, |
| 7869 Vector<HValue*>(op_vals, descriptor->environment_length())); | 7853 Vector<HValue*>(op_vals, descriptor->environment_length())); |
| 7870 | 7854 |
| (...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7988 | 7972 |
| 7989 HValue* key = NULL; | 7973 HValue* key = NULL; |
| 7990 if (!prop->key()->IsPropertyName()) { | 7974 if (!prop->key()->IsPropertyName()) { |
| 7991 CHECK_ALIVE(VisitForValue(prop->key())); | 7975 CHECK_ALIVE(VisitForValue(prop->key())); |
| 7992 key = Pop(); | 7976 key = Pop(); |
| 7993 } | 7977 } |
| 7994 | 7978 |
| 7995 CHECK_ALIVE(PushLoad(prop, receiver, key)); | 7979 CHECK_ALIVE(PushLoad(prop, receiver, key)); |
| 7996 HValue* function = Pop(); | 7980 HValue* function = Pop(); |
| 7997 | 7981 |
| 7998 if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); | |
| 7999 | |
| 8000 // Push the function under the receiver. | 7982 // Push the function under the receiver. |
| 8001 environment()->SetExpressionStackAt(0, function); | 7983 environment()->SetExpressionStackAt(0, function); |
| 8002 | 7984 |
| 8003 Push(receiver); | 7985 Push(receiver); |
| 8004 | 7986 |
| 8005 if (function->IsConstant() && | 7987 if (function->IsConstant() && |
| 8006 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { | 7988 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
| 8007 Handle<JSFunction> known_function = Handle<JSFunction>::cast( | 7989 Handle<JSFunction> known_function = Handle<JSFunction>::cast( |
| 8008 HConstant::cast(function)->handle(isolate())); | 7990 HConstant::cast(function)->handle(isolate())); |
| 8009 expr->set_target(known_function); | 7991 expr->set_target(known_function); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8052 } | 8034 } |
| 8053 | 8035 |
| 8054 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); | 8036 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); |
| 8055 if (global_call) { | 8037 if (global_call) { |
| 8056 Variable* var = proxy->var(); | 8038 Variable* var = proxy->var(); |
| 8057 bool known_global_function = false; | 8039 bool known_global_function = false; |
| 8058 // If there is a global property cell for the name at compile time and | 8040 // If there is a global property cell for the name at compile time and |
| 8059 // access check is not enabled we assume that the function will not change | 8041 // access check is not enabled we assume that the function will not change |
| 8060 // and generate optimized code for calling the function. | 8042 // and generate optimized code for calling the function. |
| 8061 LookupResult lookup(isolate()); | 8043 LookupResult lookup(isolate()); |
| 8062 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, LOAD); | 8044 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); |
| 8063 if (type == kUseCell && | 8045 if (type == kUseCell && |
| 8064 !current_info()->global_object()->IsAccessCheckNeeded()) { | 8046 !current_info()->global_object()->IsAccessCheckNeeded()) { |
| 8065 Handle<GlobalObject> global(current_info()->global_object()); | 8047 Handle<GlobalObject> global(current_info()->global_object()); |
| 8066 known_global_function = expr->ComputeGlobalTarget(global, &lookup); | 8048 known_global_function = expr->ComputeGlobalTarget(global, &lookup); |
| 8067 } | 8049 } |
| 8068 CHECK_ALIVE(VisitForValue(expr->expression())); | 8050 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 8069 HValue* function = Top(); | 8051 HValue* function = Top(); |
| 8070 if (known_global_function) { | 8052 if (known_global_function) { |
| 8071 Add<HCheckValue>(function, expr->target()); | 8053 Add<HCheckValue>(function, expr->target()); |
| 8072 | 8054 |
| (...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8262 TraceInline(target, caller, NULL); | 8244 TraceInline(target, caller, NULL); |
| 8263 } | 8245 } |
| 8264 return inline_ok; | 8246 return inline_ok; |
| 8265 } | 8247 } |
| 8266 | 8248 |
| 8267 | 8249 |
| 8268 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { | 8250 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
| 8269 ASSERT(!HasStackOverflow()); | 8251 ASSERT(!HasStackOverflow()); |
| 8270 ASSERT(current_block() != NULL); | 8252 ASSERT(current_block() != NULL); |
| 8271 ASSERT(current_block()->HasPredecessor()); | 8253 ASSERT(current_block()->HasPredecessor()); |
| 8272 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); | 8254 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
| 8273 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 8255 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
| 8274 Factory* factory = isolate()->factory(); | 8256 Factory* factory = isolate()->factory(); |
| 8275 | 8257 |
| 8276 // The constructor function is on the stack in the unoptimized code | 8258 // The constructor function is on the stack in the unoptimized code |
| 8277 // during evaluation of the arguments. | 8259 // during evaluation of the arguments. |
| 8278 CHECK_ALIVE(VisitForValue(expr->expression())); | 8260 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 8279 HValue* function = Top(); | 8261 HValue* function = Top(); |
| 8280 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8262 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 8281 | 8263 |
| 8282 if (FLAG_inline_construct && | 8264 if (FLAG_inline_construct && |
| (...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8805 if (key != NULL) Push(key); | 8787 if (key != NULL) Push(key); |
| 8806 Push(value); | 8788 Push(value); |
| 8807 BuildStore(expr, prop, ast_id, return_id); | 8789 BuildStore(expr, prop, ast_id, return_id); |
| 8808 } | 8790 } |
| 8809 | 8791 |
| 8810 | 8792 |
| 8811 void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { | 8793 void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { |
| 8812 ASSERT(!HasStackOverflow()); | 8794 ASSERT(!HasStackOverflow()); |
| 8813 ASSERT(current_block() != NULL); | 8795 ASSERT(current_block() != NULL); |
| 8814 ASSERT(current_block()->HasPredecessor()); | 8796 ASSERT(current_block()->HasPredecessor()); |
| 8815 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); | 8797 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
| 8816 Expression* target = expr->expression(); | 8798 Expression* target = expr->expression(); |
| 8817 VariableProxy* proxy = target->AsVariableProxy(); | 8799 VariableProxy* proxy = target->AsVariableProxy(); |
| 8818 Property* prop = target->AsProperty(); | 8800 Property* prop = target->AsProperty(); |
| 8819 if (proxy == NULL && prop == NULL) { | 8801 if (proxy == NULL && prop == NULL) { |
| 8820 return Bailout(kInvalidLhsInCountOperation); | 8802 return Bailout(kInvalidLhsInCountOperation); |
| 8821 } | 8803 } |
| 8822 | 8804 |
| 8823 // Match the full code generator stack by simulating an extra stack | 8805 // Match the full code generator stack by simulating an extra stack |
| 8824 // element for postfix operations in a non-effect context. The return | 8806 // element for postfix operations in a non-effect context. The return |
| 8825 // value is ToNumber(input). | 8807 // value is ToNumber(input). |
| (...skipping 255 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9081 : HAllocationMode(allocation_site)) | 9063 : HAllocationMode(allocation_site)) |
| 9082 : HAllocationMode(pretenure_flag); | 9064 : HAllocationMode(pretenure_flag); |
| 9083 | 9065 |
| 9084 HValue* result = HGraphBuilder::BuildBinaryOperation( | 9066 HValue* result = HGraphBuilder::BuildBinaryOperation( |
| 9085 expr->op(), left, right, left_type, right_type, result_type, | 9067 expr->op(), left, right, left_type, right_type, result_type, |
| 9086 fixed_right_arg, allocation_mode); | 9068 fixed_right_arg, allocation_mode); |
| 9087 // Add a simulate after instructions with observable side effects, and | 9069 // Add a simulate after instructions with observable side effects, and |
| 9088 // after phis, which are the result of BuildBinaryOperation when we | 9070 // after phis, which are the result of BuildBinaryOperation when we |
| 9089 // inlined some complex subgraph. | 9071 // inlined some complex subgraph. |
| 9090 if (result->HasObservableSideEffects() || result->IsPhi()) { | 9072 if (result->HasObservableSideEffects() || result->IsPhi()) { |
| 9091 if (push_sim_result == PUSH_BEFORE_SIMULATE) { | 9073 if (push_sim_result == NO_PUSH_BEFORE_SIMULATE) { |
| 9074 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
| 9075 } else { |
| 9076 ASSERT(push_sim_result == PUSH_BEFORE_SIMULATE); |
| 9092 Push(result); | 9077 Push(result); |
| 9093 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 9078 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
| 9094 Drop(1); | 9079 Drop(1); |
| 9095 } else { | |
| 9096 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | |
| 9097 } | 9080 } |
| 9098 } | 9081 } |
| 9099 return result; | 9082 return result; |
| 9100 } | 9083 } |
| 9101 | 9084 |
| 9102 | 9085 |
| 9103 HValue* HGraphBuilder::BuildBinaryOperation( | 9086 HValue* HGraphBuilder::BuildBinaryOperation( |
| 9104 Token::Value op, | 9087 Token::Value op, |
| 9105 HValue* left, | 9088 HValue* left, |
| 9106 HValue* right, | 9089 HValue* right, |
| (...skipping 364 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9471 void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) { | 9454 void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) { |
| 9472 CHECK_ALIVE(VisitForValue(expr->left())); | 9455 CHECK_ALIVE(VisitForValue(expr->left())); |
| 9473 CHECK_ALIVE(VisitForValue(expr->right())); | 9456 CHECK_ALIVE(VisitForValue(expr->right())); |
| 9474 SetSourcePosition(expr->position()); | 9457 SetSourcePosition(expr->position()); |
| 9475 HValue* right = Pop(); | 9458 HValue* right = Pop(); |
| 9476 HValue* left = Pop(); | 9459 HValue* left = Pop(); |
| 9477 HValue* result = | 9460 HValue* result = |
| 9478 BuildBinaryOperation(expr, left, right, | 9461 BuildBinaryOperation(expr, left, right, |
| 9479 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE | 9462 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE |
| 9480 : PUSH_BEFORE_SIMULATE); | 9463 : PUSH_BEFORE_SIMULATE); |
| 9481 if (FLAG_hydrogen_track_positions && result->IsBinaryOperation()) { | 9464 if (FLAG_emit_opt_code_positions && result->IsBinaryOperation()) { |
| 9482 HBinaryOperation::cast(result)->SetOperandPositions( | 9465 HBinaryOperation::cast(result)->SetOperandPositions( |
| 9483 zone(), | 9466 zone(), expr->left()->position(), expr->right()->position()); |
| 9484 ScriptPositionToSourcePosition(expr->left()->position()), | |
| 9485 ScriptPositionToSourcePosition(expr->right()->position())); | |
| 9486 } | 9467 } |
| 9487 return ast_context()->ReturnValue(result); | 9468 return ast_context()->ReturnValue(result); |
| 9488 } | 9469 } |
| 9489 | 9470 |
| 9490 | 9471 |
| 9491 void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, | 9472 void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, |
| 9492 Expression* sub_expr, | 9473 Expression* sub_expr, |
| 9493 Handle<String> check) { | 9474 Handle<String> check) { |
| 9494 CHECK_ALIVE(VisitForTypeOf(sub_expr)); | 9475 CHECK_ALIVE(VisitForTypeOf(sub_expr)); |
| 9495 SetSourcePosition(expr->position()); | 9476 SetSourcePosition(expr->position()); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 9509 (right->IsConstant() && | 9490 (right->IsConstant() && |
| 9510 HConstant::cast(right)->handle(isolate)->IsBoolean())); | 9491 HConstant::cast(right)->handle(isolate)->IsBoolean())); |
| 9511 } | 9492 } |
| 9512 | 9493 |
| 9513 | 9494 |
| 9514 void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { | 9495 void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
| 9515 ASSERT(!HasStackOverflow()); | 9496 ASSERT(!HasStackOverflow()); |
| 9516 ASSERT(current_block() != NULL); | 9497 ASSERT(current_block() != NULL); |
| 9517 ASSERT(current_block()->HasPredecessor()); | 9498 ASSERT(current_block()->HasPredecessor()); |
| 9518 | 9499 |
| 9519 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); | 9500 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
| 9520 | 9501 |
| 9521 // Check for a few fast cases. The AST visiting behavior must be in sync | 9502 // Check for a few fast cases. The AST visiting behavior must be in sync |
| 9522 // with the full codegen: We don't push both left and right values onto | 9503 // with the full codegen: We don't push both left and right values onto |
| 9523 // the expression stack when one side is a special-case literal. | 9504 // the expression stack when one side is a special-case literal. |
| 9524 Expression* sub_expr = NULL; | 9505 Expression* sub_expr = NULL; |
| 9525 Handle<String> check; | 9506 Handle<String> check; |
| 9526 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { | 9507 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { |
| 9527 return HandleLiteralCompareTypeof(expr, sub_expr, check); | 9508 return HandleLiteralCompareTypeof(expr, sub_expr, check); |
| 9528 } | 9509 } |
| 9529 if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) { | 9510 if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 9544 return ast_context()->ReturnControl(instr, expr->id()); | 9525 return ast_context()->ReturnControl(instr, expr->id()); |
| 9545 } | 9526 } |
| 9546 | 9527 |
| 9547 Type* left_type = expr->left()->bounds().lower; | 9528 Type* left_type = expr->left()->bounds().lower; |
| 9548 Type* right_type = expr->right()->bounds().lower; | 9529 Type* right_type = expr->right()->bounds().lower; |
| 9549 Type* combined_type = expr->combined_type(); | 9530 Type* combined_type = expr->combined_type(); |
| 9550 | 9531 |
| 9551 CHECK_ALIVE(VisitForValue(expr->left())); | 9532 CHECK_ALIVE(VisitForValue(expr->left())); |
| 9552 CHECK_ALIVE(VisitForValue(expr->right())); | 9533 CHECK_ALIVE(VisitForValue(expr->right())); |
| 9553 | 9534 |
| 9554 if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); | 9535 if (FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
| 9555 | 9536 |
| 9556 HValue* right = Pop(); | 9537 HValue* right = Pop(); |
| 9557 HValue* left = Pop(); | 9538 HValue* left = Pop(); |
| 9558 Token::Value op = expr->op(); | 9539 Token::Value op = expr->op(); |
| 9559 | 9540 |
| 9560 if (IsLiteralCompareBool(isolate(), left, op, right)) { | 9541 if (IsLiteralCompareBool(isolate(), left, op, right)) { |
| 9561 HCompareObjectEqAndBranch* result = | 9542 HCompareObjectEqAndBranch* result = |
| 9562 New<HCompareObjectEqAndBranch>(left, right); | 9543 New<HCompareObjectEqAndBranch>(left, right); |
| 9563 return ast_context()->ReturnControl(result, expr->id()); | 9544 return ast_context()->ReturnControl(result, expr->id()); |
| 9564 } | 9545 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9604 } else if (op == Token::IN) { | 9585 } else if (op == Token::IN) { |
| 9605 HValue* function = AddLoadJSBuiltin(Builtins::IN); | 9586 HValue* function = AddLoadJSBuiltin(Builtins::IN); |
| 9606 Add<HPushArgument>(left); | 9587 Add<HPushArgument>(left); |
| 9607 Add<HPushArgument>(right); | 9588 Add<HPushArgument>(right); |
| 9608 // TODO(olivf) InvokeFunction produces a check for the parameter count, | 9589 // TODO(olivf) InvokeFunction produces a check for the parameter count, |
| 9609 // even though we are certain to pass the correct number of arguments here. | 9590 // even though we are certain to pass the correct number of arguments here. |
| 9610 HInstruction* result = New<HInvokeFunction>(function, 2); | 9591 HInstruction* result = New<HInvokeFunction>(function, 2); |
| 9611 return ast_context()->ReturnInstruction(result, expr->id()); | 9592 return ast_context()->ReturnInstruction(result, expr->id()); |
| 9612 } | 9593 } |
| 9613 | 9594 |
| 9614 PushBeforeSimulateBehavior push_behavior = | |
| 9615 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE | |
| 9616 : PUSH_BEFORE_SIMULATE; | |
| 9617 HControlInstruction* compare = BuildCompareInstruction( | 9595 HControlInstruction* compare = BuildCompareInstruction( |
| 9618 op, left, right, left_type, right_type, combined_type, | 9596 op, left, right, left_type, right_type, combined_type, |
| 9619 ScriptPositionToSourcePosition(expr->left()->position()), | 9597 expr->left()->position(), expr->right()->position(), expr->id()); |
| 9620 ScriptPositionToSourcePosition(expr->right()->position()), | |
| 9621 push_behavior, expr->id()); | |
| 9622 if (compare == NULL) return; // Bailed out. | 9598 if (compare == NULL) return; // Bailed out. |
| 9623 return ast_context()->ReturnControl(compare, expr->id()); | 9599 return ast_context()->ReturnControl(compare, expr->id()); |
| 9624 } | 9600 } |
| 9625 | 9601 |
| 9626 | 9602 |
| 9627 HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction( | 9603 HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction( |
| 9628 Token::Value op, | 9604 Token::Value op, |
| 9629 HValue* left, | 9605 HValue* left, |
| 9630 HValue* right, | 9606 HValue* right, |
| 9631 Type* left_type, | 9607 Type* left_type, |
| 9632 Type* right_type, | 9608 Type* right_type, |
| 9633 Type* combined_type, | 9609 Type* combined_type, |
| 9634 HSourcePosition left_position, | 9610 int left_position, |
| 9635 HSourcePosition right_position, | 9611 int right_position, |
| 9636 PushBeforeSimulateBehavior push_sim_result, | |
| 9637 BailoutId bailout_id) { | 9612 BailoutId bailout_id) { |
| 9638 // Cases handled below depend on collected type feedback. They should | 9613 // Cases handled below depend on collected type feedback. They should |
| 9639 // soft deoptimize when there is no type feedback. | 9614 // soft deoptimize when there is no type feedback. |
| 9640 if (combined_type->Is(Type::None())) { | 9615 if (combined_type->Is(Type::None())) { |
| 9641 Add<HDeoptimize>("Insufficient type feedback for combined type " | 9616 Add<HDeoptimize>("Insufficient type feedback for combined type " |
| 9642 "of binary operation", | 9617 "of binary operation", |
| 9643 Deoptimizer::SOFT); | 9618 Deoptimizer::SOFT); |
| 9644 combined_type = left_type = right_type = Type::Any(zone()); | 9619 combined_type = left_type = right_type = Type::Any(zone()); |
| 9645 } | 9620 } |
| 9646 | 9621 |
| 9647 Representation left_rep = Representation::FromType(left_type); | 9622 Representation left_rep = Representation::FromType(left_type); |
| 9648 Representation right_rep = Representation::FromType(right_type); | 9623 Representation right_rep = Representation::FromType(right_type); |
| 9649 Representation combined_rep = Representation::FromType(combined_type); | 9624 Representation combined_rep = Representation::FromType(combined_type); |
| 9650 | 9625 |
| 9651 if (combined_type->Is(Type::Receiver())) { | 9626 if (combined_type->Is(Type::Receiver())) { |
| 9652 if (Token::IsEqualityOp(op)) { | 9627 if (Token::IsEqualityOp(op)) { |
| 9653 // Can we get away with map check and not instance type check? | 9628 // Can we get away with map check and not instance type check? |
| 9654 HValue* operand_to_check = | 9629 HValue* operand_to_check = |
| 9655 left->block()->block_id() < right->block()->block_id() ? left : right; | 9630 left->block()->block_id() < right->block()->block_id() ? left : right; |
| 9656 if (combined_type->IsClass()) { | 9631 if (combined_type->IsClass()) { |
| 9657 Handle<Map> map = combined_type->AsClass(); | 9632 Handle<Map> map = combined_type->AsClass(); |
| 9658 AddCheckMap(operand_to_check, map); | 9633 AddCheckMap(operand_to_check, map); |
| 9659 HCompareObjectEqAndBranch* result = | 9634 HCompareObjectEqAndBranch* result = |
| 9660 New<HCompareObjectEqAndBranch>(left, right); | 9635 New<HCompareObjectEqAndBranch>(left, right); |
| 9661 if (FLAG_hydrogen_track_positions) { | 9636 if (FLAG_emit_opt_code_positions) { |
| 9662 result->set_operand_position(zone(), 0, left_position); | 9637 result->set_operand_position(zone(), 0, left_position); |
| 9663 result->set_operand_position(zone(), 1, right_position); | 9638 result->set_operand_position(zone(), 1, right_position); |
| 9664 } | 9639 } |
| 9665 return result; | 9640 return result; |
| 9666 } else { | 9641 } else { |
| 9667 BuildCheckHeapObject(operand_to_check); | 9642 BuildCheckHeapObject(operand_to_check); |
| 9668 Add<HCheckInstanceType>(operand_to_check, | 9643 Add<HCheckInstanceType>(operand_to_check, |
| 9669 HCheckInstanceType::IS_SPEC_OBJECT); | 9644 HCheckInstanceType::IS_SPEC_OBJECT); |
| 9670 HCompareObjectEqAndBranch* result = | 9645 HCompareObjectEqAndBranch* result = |
| 9671 New<HCompareObjectEqAndBranch>(left, right); | 9646 New<HCompareObjectEqAndBranch>(left, right); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 9691 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING); | 9666 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING); |
| 9692 HStringCompareAndBranch* result = | 9667 HStringCompareAndBranch* result = |
| 9693 New<HStringCompareAndBranch>(left, right, op); | 9668 New<HStringCompareAndBranch>(left, right, op); |
| 9694 return result; | 9669 return result; |
| 9695 } else { | 9670 } else { |
| 9696 if (combined_rep.IsTagged() || combined_rep.IsNone()) { | 9671 if (combined_rep.IsTagged() || combined_rep.IsNone()) { |
| 9697 HCompareGeneric* result = Add<HCompareGeneric>(left, right, op); | 9672 HCompareGeneric* result = Add<HCompareGeneric>(left, right, op); |
| 9698 result->set_observed_input_representation(1, left_rep); | 9673 result->set_observed_input_representation(1, left_rep); |
| 9699 result->set_observed_input_representation(2, right_rep); | 9674 result->set_observed_input_representation(2, right_rep); |
| 9700 if (result->HasObservableSideEffects()) { | 9675 if (result->HasObservableSideEffects()) { |
| 9701 if (push_sim_result == PUSH_BEFORE_SIMULATE) { | 9676 Push(result); |
| 9702 Push(result); | 9677 AddSimulate(bailout_id, REMOVABLE_SIMULATE); |
| 9703 AddSimulate(bailout_id, REMOVABLE_SIMULATE); | 9678 Drop(1); |
| 9704 Drop(1); | |
| 9705 } else { | |
| 9706 AddSimulate(bailout_id, REMOVABLE_SIMULATE); | |
| 9707 } | |
| 9708 } | 9679 } |
| 9709 // TODO(jkummerow): Can we make this more efficient? | 9680 // TODO(jkummerow): Can we make this more efficient? |
| 9710 HBranch* branch = New<HBranch>(result); | 9681 HBranch* branch = New<HBranch>(result); |
| 9711 return branch; | 9682 return branch; |
| 9712 } else { | 9683 } else { |
| 9713 HCompareNumericAndBranch* result = | 9684 HCompareNumericAndBranch* result = |
| 9714 New<HCompareNumericAndBranch>(left, right, op); | 9685 New<HCompareNumericAndBranch>(left, right, op); |
| 9715 result->set_observed_input_representation(left_rep, right_rep); | 9686 result->set_observed_input_representation(left_rep, right_rep); |
| 9716 if (FLAG_hydrogen_track_positions) { | 9687 if (FLAG_emit_opt_code_positions) { |
| 9717 result->SetOperandPositions(zone(), left_position, right_position); | 9688 result->SetOperandPositions(zone(), left_position, right_position); |
| 9718 } | 9689 } |
| 9719 return result; | 9690 return result; |
| 9720 } | 9691 } |
| 9721 } | 9692 } |
| 9722 } | 9693 } |
| 9723 | 9694 |
| 9724 | 9695 |
| 9725 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, | 9696 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, |
| 9726 Expression* sub_expr, | 9697 Expression* sub_expr, |
| 9727 NilValue nil) { | 9698 NilValue nil) { |
| 9728 ASSERT(!HasStackOverflow()); | 9699 ASSERT(!HasStackOverflow()); |
| 9729 ASSERT(current_block() != NULL); | 9700 ASSERT(current_block() != NULL); |
| 9730 ASSERT(current_block()->HasPredecessor()); | 9701 ASSERT(current_block()->HasPredecessor()); |
| 9731 ASSERT(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT); | 9702 ASSERT(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT); |
| 9732 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); | 9703 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
| 9733 CHECK_ALIVE(VisitForValue(sub_expr)); | 9704 CHECK_ALIVE(VisitForValue(sub_expr)); |
| 9734 HValue* value = Pop(); | 9705 HValue* value = Pop(); |
| 9735 if (expr->op() == Token::EQ_STRICT) { | 9706 if (expr->op() == Token::EQ_STRICT) { |
| 9736 HConstant* nil_constant = nil == kNullValue | 9707 HConstant* nil_constant = nil == kNullValue |
| 9737 ? graph()->GetConstantNull() | 9708 ? graph()->GetConstantNull() |
| 9738 : graph()->GetConstantUndefined(); | 9709 : graph()->GetConstantUndefined(); |
| 9739 HCompareObjectEqAndBranch* instr = | 9710 HCompareObjectEqAndBranch* instr = |
| 9740 New<HCompareObjectEqAndBranch>(value, nil_constant); | 9711 New<HCompareObjectEqAndBranch>(value, nil_constant); |
| 9741 return ast_context()->ReturnControl(instr, expr->id()); | 9712 return ast_context()->ReturnControl(instr, expr->id()); |
| 9742 } else { | 9713 } else { |
| (...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9917 // 1) it's a child object of another object with a valid allocation site | 9888 // 1) it's a child object of another object with a valid allocation site |
| 9918 // 2) we can just use the mode of the parent object for pretenuring | 9889 // 2) we can just use the mode of the parent object for pretenuring |
| 9919 HInstruction* double_box = | 9890 HInstruction* double_box = |
| 9920 Add<HAllocate>(heap_number_constant, HType::HeapNumber(), | 9891 Add<HAllocate>(heap_number_constant, HType::HeapNumber(), |
| 9921 pretenure_flag, HEAP_NUMBER_TYPE); | 9892 pretenure_flag, HEAP_NUMBER_TYPE); |
| 9922 AddStoreMapConstant(double_box, | 9893 AddStoreMapConstant(double_box, |
| 9923 isolate()->factory()->heap_number_map()); | 9894 isolate()->factory()->heap_number_map()); |
| 9924 Add<HStoreNamedField>(double_box, HObjectAccess::ForHeapNumberValue(), | 9895 Add<HStoreNamedField>(double_box, HObjectAccess::ForHeapNumberValue(), |
| 9925 Add<HConstant>(value)); | 9896 Add<HConstant>(value)); |
| 9926 value_instruction = double_box; | 9897 value_instruction = double_box; |
| 9927 } else if (representation.IsSmi()) { | 9898 } else if (representation.IsSmi() && value->IsUninitialized()) { |
| 9928 value_instruction = value->IsUninitialized() | 9899 value_instruction = graph()->GetConstant0(); |
| 9929 ? graph()->GetConstant0() | |
| 9930 : Add<HConstant>(value); | |
| 9931 // Ensure that value is stored as smi. | |
| 9932 access = access.WithRepresentation(representation); | |
| 9933 } else { | 9900 } else { |
| 9934 value_instruction = Add<HConstant>(value); | 9901 value_instruction = Add<HConstant>(value); |
| 9935 } | 9902 } |
| 9936 | 9903 |
| 9937 Add<HStoreNamedField>(object, access, value_instruction); | 9904 Add<HStoreNamedField>(object, access, value_instruction); |
| 9938 } | 9905 } |
| 9939 } | 9906 } |
| 9940 | 9907 |
| 9941 int inobject_properties = boilerplate_object->map()->inobject_properties(); | 9908 int inobject_properties = boilerplate_object->map()->inobject_properties(); |
| 9942 HInstruction* value_instruction = | 9909 HInstruction* value_instruction = |
| (...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10355 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10322 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10356 HValue* date = Pop(); | 10323 HValue* date = Pop(); |
| 10357 HDateField* result = New<HDateField>(date, index); | 10324 HDateField* result = New<HDateField>(date, index); |
| 10358 return ast_context()->ReturnInstruction(result, call->id()); | 10325 return ast_context()->ReturnInstruction(result, call->id()); |
| 10359 } | 10326 } |
| 10360 | 10327 |
| 10361 | 10328 |
| 10362 void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar( | 10329 void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar( |
| 10363 CallRuntime* call) { | 10330 CallRuntime* call) { |
| 10364 ASSERT(call->arguments()->length() == 3); | 10331 ASSERT(call->arguments()->length() == 3); |
| 10365 // We need to follow the evaluation order of full codegen. | 10332 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10366 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 10333 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 10367 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); | 10334 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); |
| 10368 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | |
| 10369 HValue* string = Pop(); | |
| 10370 HValue* value = Pop(); | 10335 HValue* value = Pop(); |
| 10371 HValue* index = Pop(); | 10336 HValue* index = Pop(); |
| 10337 HValue* string = Pop(); |
| 10372 Add<HSeqStringSetChar>(String::ONE_BYTE_ENCODING, string, | 10338 Add<HSeqStringSetChar>(String::ONE_BYTE_ENCODING, string, |
| 10373 index, value); | 10339 index, value); |
| 10374 Add<HSimulate>(call->id(), FIXED_SIMULATE); | 10340 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10375 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 10341 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 10376 } | 10342 } |
| 10377 | 10343 |
| 10378 | 10344 |
| 10379 void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar( | 10345 void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar( |
| 10380 CallRuntime* call) { | 10346 CallRuntime* call) { |
| 10381 ASSERT(call->arguments()->length() == 3); | 10347 ASSERT(call->arguments()->length() == 3); |
| 10382 // We need to follow the evaluation order of full codegen. | 10348 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10383 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 10349 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 10384 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); | 10350 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); |
| 10385 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | |
| 10386 HValue* string = Pop(); | |
| 10387 HValue* value = Pop(); | 10351 HValue* value = Pop(); |
| 10388 HValue* index = Pop(); | 10352 HValue* index = Pop(); |
| 10353 HValue* string = Pop(); |
| 10389 Add<HSeqStringSetChar>(String::TWO_BYTE_ENCODING, string, | 10354 Add<HSeqStringSetChar>(String::TWO_BYTE_ENCODING, string, |
| 10390 index, value); | 10355 index, value); |
| 10391 Add<HSimulate>(call->id(), FIXED_SIMULATE); | 10356 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10392 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 10357 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 10393 } | 10358 } |
| 10394 | 10359 |
| 10395 | 10360 |
| 10396 void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) { | 10361 void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) { |
| 10397 ASSERT(call->arguments()->length() == 2); | 10362 ASSERT(call->arguments()->length() == 2); |
| 10398 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10363 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10399 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 10364 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 10400 HValue* value = Pop(); | 10365 HValue* value = Pop(); |
| 10401 HValue* object = Pop(); | 10366 HValue* object = Pop(); |
| 10402 | 10367 |
| 10403 // Check if object is a JSValue. | 10368 // Check if object is a JSValue. |
| 10404 IfBuilder if_objectisvalue(this); | 10369 IfBuilder if_objectisvalue(this); |
| 10405 if_objectisvalue.If<HHasInstanceTypeAndBranch>(object, JS_VALUE_TYPE); | 10370 if_objectisvalue.If<HHasInstanceTypeAndBranch>(object, JS_VALUE_TYPE); |
| 10406 if_objectisvalue.Then(); | 10371 if_objectisvalue.Then(); |
| 10407 { | 10372 { |
| 10408 // Create in-object property store to kValueOffset. | 10373 // Create in-object property store to kValueOffset. |
| 10409 Add<HStoreNamedField>(object, | 10374 Add<HStoreNamedField>(object, |
| 10410 HObjectAccess::ForObservableJSObjectOffset(JSValue::kValueOffset), | 10375 HObjectAccess::ForObservableJSObjectOffset(JSValue::kValueOffset), |
| 10411 value); | 10376 value); |
| 10412 if (!ast_context()->IsEffect()) { | |
| 10413 Push(value); | |
| 10414 } | |
| 10415 Add<HSimulate>(call->id(), FIXED_SIMULATE); | 10377 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10416 } | 10378 } |
| 10417 if_objectisvalue.Else(); | 10379 if_objectisvalue.Else(); |
| 10418 { | 10380 { |
| 10419 // Nothing to do in this case. | 10381 // Nothing to do in this case. |
| 10420 if (!ast_context()->IsEffect()) { | |
| 10421 Push(value); | |
| 10422 } | |
| 10423 Add<HSimulate>(call->id(), FIXED_SIMULATE); | 10382 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10424 } | 10383 } |
| 10425 if_objectisvalue.End(); | 10384 if_objectisvalue.End(); |
| 10426 if (!ast_context()->IsEffect()) { | |
| 10427 Drop(1); | |
| 10428 } | |
| 10429 return ast_context()->ReturnValue(value); | 10385 return ast_context()->ReturnValue(value); |
| 10430 } | 10386 } |
| 10431 | 10387 |
| 10432 | 10388 |
| 10433 // Fast support for charCodeAt(n). | 10389 // Fast support for charCodeAt(n). |
| 10434 void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) { | 10390 void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) { |
| 10435 ASSERT(call->arguments()->length() == 2); | 10391 ASSERT(call->arguments()->length() == 2); |
| 10436 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10392 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10437 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 10393 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 10438 HValue* index = Pop(); | 10394 HValue* index = Pop(); |
| (...skipping 522 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10961 PrintTo(&trace); | 10917 PrintTo(&trace); |
| 10962 PrintF("%s", trace.ToCString().get()); | 10918 PrintF("%s", trace.ToCString().get()); |
| 10963 } | 10919 } |
| 10964 | 10920 |
| 10965 | 10921 |
| 10966 void HTracer::TraceCompilation(CompilationInfo* info) { | 10922 void HTracer::TraceCompilation(CompilationInfo* info) { |
| 10967 Tag tag(this, "compilation"); | 10923 Tag tag(this, "compilation"); |
| 10968 if (info->IsOptimizing()) { | 10924 if (info->IsOptimizing()) { |
| 10969 Handle<String> name = info->function()->debug_name(); | 10925 Handle<String> name = info->function()->debug_name(); |
| 10970 PrintStringProperty("name", name->ToCString().get()); | 10926 PrintStringProperty("name", name->ToCString().get()); |
| 10971 PrintIndent(); | 10927 PrintStringProperty("method", name->ToCString().get()); |
| 10972 trace_.Add("method \"%s:%d\"\n", | |
| 10973 name->ToCString().get(), | |
| 10974 info->optimization_id()); | |
| 10975 } else { | 10928 } else { |
| 10976 CodeStub::Major major_key = info->code_stub()->MajorKey(); | 10929 CodeStub::Major major_key = info->code_stub()->MajorKey(); |
| 10977 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); | 10930 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); |
| 10978 PrintStringProperty("method", "stub"); | 10931 PrintStringProperty("method", "stub"); |
| 10979 } | 10932 } |
| 10980 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); | 10933 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); |
| 10981 } | 10934 } |
| 10982 | 10935 |
| 10983 | 10936 |
| 10984 void HTracer::TraceLithium(const char* name, LChunk* chunk) { | 10937 void HTracer::TraceLithium(const char* name, LChunk* chunk) { |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11078 trace_.Add(" "); | 11031 trace_.Add(" "); |
| 11079 phi->PrintTo(&trace_); | 11032 phi->PrintTo(&trace_); |
| 11080 trace_.Add("\n"); | 11033 trace_.Add("\n"); |
| 11081 } | 11034 } |
| 11082 } | 11035 } |
| 11083 | 11036 |
| 11084 { | 11037 { |
| 11085 Tag HIR_tag(this, "HIR"); | 11038 Tag HIR_tag(this, "HIR"); |
| 11086 for (HInstructionIterator it(current); !it.Done(); it.Advance()) { | 11039 for (HInstructionIterator it(current); !it.Done(); it.Advance()) { |
| 11087 HInstruction* instruction = it.Current(); | 11040 HInstruction* instruction = it.Current(); |
| 11041 int bci = FLAG_emit_opt_code_positions && instruction->has_position() ? |
| 11042 instruction->position() : 0; |
| 11088 int uses = instruction->UseCount(); | 11043 int uses = instruction->UseCount(); |
| 11089 PrintIndent(); | 11044 PrintIndent(); |
| 11090 trace_.Add("0 %d ", uses); | 11045 trace_.Add("%d %d ", bci, uses); |
| 11091 instruction->PrintNameTo(&trace_); | 11046 instruction->PrintNameTo(&trace_); |
| 11092 trace_.Add(" "); | 11047 trace_.Add(" "); |
| 11093 instruction->PrintTo(&trace_); | 11048 instruction->PrintTo(&trace_); |
| 11094 if (FLAG_hydrogen_track_positions && | |
| 11095 instruction->has_position() && | |
| 11096 instruction->position().raw() != 0) { | |
| 11097 const HSourcePosition pos = instruction->position(); | |
| 11098 trace_.Add(" pos:"); | |
| 11099 if (pos.inlining_id() != 0) { | |
| 11100 trace_.Add("%d_", pos.inlining_id()); | |
| 11101 } | |
| 11102 trace_.Add("%d", pos.position()); | |
| 11103 } | |
| 11104 trace_.Add(" <|@\n"); | 11049 trace_.Add(" <|@\n"); |
| 11105 } | 11050 } |
| 11106 } | 11051 } |
| 11107 | 11052 |
| 11108 | 11053 |
| 11109 if (chunk != NULL) { | 11054 if (chunk != NULL) { |
| 11110 Tag LIR_tag(this, "LIR"); | 11055 Tag LIR_tag(this, "LIR"); |
| 11111 int first_index = current->first_instruction_index(); | 11056 int first_index = current->first_instruction_index(); |
| 11112 int last_index = current->last_instruction_index(); | 11057 int last_index = current->last_instruction_index(); |
| 11113 if (first_index != -1 && last_index != -1) { | 11058 if (first_index != -1 && last_index != -1) { |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11294 if (ShouldProduceTraceOutput()) { | 11239 if (ShouldProduceTraceOutput()) { |
| 11295 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 11240 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 11296 } | 11241 } |
| 11297 | 11242 |
| 11298 #ifdef DEBUG | 11243 #ifdef DEBUG |
| 11299 graph_->Verify(false); // No full verify. | 11244 graph_->Verify(false); // No full verify. |
| 11300 #endif | 11245 #endif |
| 11301 } | 11246 } |
| 11302 | 11247 |
| 11303 } } // namespace v8::internal | 11248 } } // namespace v8::internal |
| OLD | NEW |