| 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" |
| 71 #elif V8_TARGET_ARCH_ARM | 73 #elif V8_TARGET_ARCH_ARM |
| 72 #include "arm/lithium-codegen-arm.h" | 74 #include "arm/lithium-codegen-arm.h" |
| 73 #elif V8_TARGET_ARCH_MIPS | 75 #elif V8_TARGET_ARCH_MIPS |
| 74 #include "mips/lithium-codegen-mips.h" | 76 #include "mips/lithium-codegen-mips.h" |
| 75 #else | 77 #else |
| 76 #error Unsupported target architecture. | 78 #error Unsupported target architecture. |
| 77 #endif | 79 #endif |
| 78 | 80 |
| 79 namespace v8 { | 81 namespace v8 { |
| 80 namespace internal { | 82 namespace internal { |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 134 | 136 |
| 135 void HBasicBlock::RemovePhi(HPhi* phi) { | 137 void HBasicBlock::RemovePhi(HPhi* phi) { |
| 136 ASSERT(phi->block() == this); | 138 ASSERT(phi->block() == this); |
| 137 ASSERT(phis_.Contains(phi)); | 139 ASSERT(phis_.Contains(phi)); |
| 138 phi->Kill(); | 140 phi->Kill(); |
| 139 phis_.RemoveElement(phi); | 141 phis_.RemoveElement(phi); |
| 140 phi->SetBlock(NULL); | 142 phi->SetBlock(NULL); |
| 141 } | 143 } |
| 142 | 144 |
| 143 | 145 |
| 144 void HBasicBlock::AddInstruction(HInstruction* instr, int position) { | 146 void HBasicBlock::AddInstruction(HInstruction* instr, |
| 147 HSourcePosition position) { |
| 145 ASSERT(!IsStartBlock() || !IsFinished()); | 148 ASSERT(!IsStartBlock() || !IsFinished()); |
| 146 ASSERT(!instr->IsLinked()); | 149 ASSERT(!instr->IsLinked()); |
| 147 ASSERT(!IsFinished()); | 150 ASSERT(!IsFinished()); |
| 148 | 151 |
| 149 if (position != RelocInfo::kNoPosition) { | 152 if (!position.IsUnknown()) { |
| 150 instr->set_position(position); | 153 instr->set_position(position); |
| 151 } | 154 } |
| 152 if (first_ == NULL) { | 155 if (first_ == NULL) { |
| 153 ASSERT(last_environment() != NULL); | 156 ASSERT(last_environment() != NULL); |
| 154 ASSERT(!last_environment()->ast_id().IsNone()); | 157 ASSERT(!last_environment()->ast_id().IsNone()); |
| 155 HBlockEntry* entry = new(zone()) HBlockEntry(); | 158 HBlockEntry* entry = new(zone()) HBlockEntry(); |
| 156 entry->InitializeAsFirst(this); | 159 entry->InitializeAsFirst(this); |
| 157 if (position != RelocInfo::kNoPosition) { | 160 if (!position.IsUnknown()) { |
| 158 entry->set_position(position); | 161 entry->set_position(position); |
| 159 } else { | 162 } else { |
| 160 ASSERT(!FLAG_emit_opt_code_positions || | 163 ASSERT(!FLAG_hydrogen_track_positions || |
| 161 !graph()->info()->IsOptimizing()); | 164 !graph()->info()->IsOptimizing()); |
| 162 } | 165 } |
| 163 first_ = last_ = entry; | 166 first_ = last_ = entry; |
| 164 } | 167 } |
| 165 instr->InsertAfter(last_); | 168 instr->InsertAfter(last_); |
| 166 } | 169 } |
| 167 | 170 |
| 168 | 171 |
| 169 HPhi* HBasicBlock::AddNewPhi(int merged_index) { | 172 HPhi* HBasicBlock::AddNewPhi(int merged_index) { |
| 170 if (graph()->IsInsideNoSideEffectsScope()) { | 173 if (graph()->IsInsideNoSideEffectsScope()) { |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 203 !it.Done(); | 206 !it.Done(); |
| 204 it.Advance()) { | 207 it.Advance()) { |
| 205 int index = it.Current(); | 208 int index = it.Current(); |
| 206 instr->AddAssignedValue(index, environment->Lookup(index)); | 209 instr->AddAssignedValue(index, environment->Lookup(index)); |
| 207 } | 210 } |
| 208 environment->ClearHistory(); | 211 environment->ClearHistory(); |
| 209 return instr; | 212 return instr; |
| 210 } | 213 } |
| 211 | 214 |
| 212 | 215 |
| 213 void HBasicBlock::Finish(HControlInstruction* end, int position) { | 216 void HBasicBlock::Finish(HControlInstruction* end, HSourcePosition position) { |
| 214 ASSERT(!IsFinished()); | 217 ASSERT(!IsFinished()); |
| 215 AddInstruction(end, position); | 218 AddInstruction(end, position); |
| 216 end_ = end; | 219 end_ = end; |
| 217 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { | 220 for (HSuccessorIterator it(end); !it.Done(); it.Advance()) { |
| 218 it.Current()->RegisterPredecessor(this); | 221 it.Current()->RegisterPredecessor(this); |
| 219 } | 222 } |
| 220 } | 223 } |
| 221 | 224 |
| 222 | 225 |
| 223 void HBasicBlock::Goto(HBasicBlock* block, | 226 void HBasicBlock::Goto(HBasicBlock* block, |
| 224 int position, | 227 HSourcePosition position, |
| 225 FunctionState* state, | 228 FunctionState* state, |
| 226 bool add_simulate) { | 229 bool add_simulate) { |
| 227 bool drop_extra = state != NULL && | 230 bool drop_extra = state != NULL && |
| 228 state->inlining_kind() == DROP_EXTRA_ON_RETURN; | 231 state->inlining_kind() == NORMAL_RETURN; |
| 229 | 232 |
| 230 if (block->IsInlineReturnTarget()) { | 233 if (block->IsInlineReturnTarget()) { |
| 231 HEnvironment* env = last_environment(); | 234 HEnvironment* env = last_environment(); |
| 232 int argument_count = env->arguments_environment()->parameter_count(); | 235 int argument_count = env->arguments_environment()->parameter_count(); |
| 233 AddInstruction(new(zone()) | 236 AddInstruction(new(zone()) |
| 234 HLeaveInlined(state->entry(), argument_count), | 237 HLeaveInlined(state->entry(), argument_count), |
| 235 position); | 238 position); |
| 236 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); | 239 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); |
| 237 } | 240 } |
| 238 | 241 |
| 239 if (add_simulate) AddNewSimulate(BailoutId::None(), position); | 242 if (add_simulate) AddNewSimulate(BailoutId::None(), position); |
| 240 HGoto* instr = new(zone()) HGoto(block); | 243 HGoto* instr = new(zone()) HGoto(block); |
| 241 Finish(instr, position); | 244 Finish(instr, position); |
| 242 } | 245 } |
| 243 | 246 |
| 244 | 247 |
| 245 void HBasicBlock::AddLeaveInlined(HValue* return_value, | 248 void HBasicBlock::AddLeaveInlined(HValue* return_value, |
| 246 FunctionState* state, | 249 FunctionState* state, |
| 247 int position) { | 250 HSourcePosition position) { |
| 248 HBasicBlock* target = state->function_return(); | 251 HBasicBlock* target = state->function_return(); |
| 249 bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN; | 252 bool drop_extra = state->inlining_kind() == NORMAL_RETURN; |
| 250 | 253 |
| 251 ASSERT(target->IsInlineReturnTarget()); | 254 ASSERT(target->IsInlineReturnTarget()); |
| 252 ASSERT(return_value != NULL); | 255 ASSERT(return_value != NULL); |
| 253 HEnvironment* env = last_environment(); | 256 HEnvironment* env = last_environment(); |
| 254 int argument_count = env->arguments_environment()->parameter_count(); | 257 int argument_count = env->arguments_environment()->parameter_count(); |
| 255 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count), | 258 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count), |
| 256 position); | 259 position); |
| 257 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); | 260 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); |
| 258 last_environment()->Push(return_value); | 261 last_environment()->Push(return_value); |
| 259 AddNewSimulate(BailoutId::None(), position); | 262 AddNewSimulate(BailoutId::None(), position); |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 295 bool HBasicBlock::Dominates(HBasicBlock* other) const { | 298 bool HBasicBlock::Dominates(HBasicBlock* other) const { |
| 296 HBasicBlock* current = other->dominator(); | 299 HBasicBlock* current = other->dominator(); |
| 297 while (current != NULL) { | 300 while (current != NULL) { |
| 298 if (current == this) return true; | 301 if (current == this) return true; |
| 299 current = current->dominator(); | 302 current = current->dominator(); |
| 300 } | 303 } |
| 301 return false; | 304 return false; |
| 302 } | 305 } |
| 303 | 306 |
| 304 | 307 |
| 308 bool HBasicBlock::EqualToOrDominates(HBasicBlock* other) const { |
| 309 if (this == other) return true; |
| 310 return Dominates(other); |
| 311 } |
| 312 |
| 313 |
| 305 int HBasicBlock::LoopNestingDepth() const { | 314 int HBasicBlock::LoopNestingDepth() const { |
| 306 const HBasicBlock* current = this; | 315 const HBasicBlock* current = this; |
| 307 int result = (current->IsLoopHeader()) ? 1 : 0; | 316 int result = (current->IsLoopHeader()) ? 1 : 0; |
| 308 while (current->parent_loop_header() != NULL) { | 317 while (current->parent_loop_header() != NULL) { |
| 309 current = current->parent_loop_header(); | 318 current = current->parent_loop_header(); |
| 310 result++; | 319 result++; |
| 311 } | 320 } |
| 312 return result; | 321 return result; |
| 313 } | 322 } |
| 314 | 323 |
| 315 | 324 |
| 316 void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) { | 325 void HBasicBlock::PostProcessLoopHeader(IterationStatement* stmt) { |
| 317 ASSERT(IsLoopHeader()); | 326 ASSERT(IsLoopHeader()); |
| 318 | 327 |
| 319 SetJoinId(stmt->EntryId()); | 328 SetJoinId(stmt->EntryId()); |
| 320 if (predecessors()->length() == 1) { | 329 if (predecessors()->length() == 1) { |
| 321 // This is a degenerated loop. | 330 // This is a degenerated loop. |
| 322 DetachLoopInformation(); | 331 DetachLoopInformation(); |
| 323 return; | 332 return; |
| 324 } | 333 } |
| 325 | 334 |
| 326 // Only the first entry into the loop is from outside the loop. All other | 335 // Only the first entry into the loop is from outside the loop. All other |
| 327 // entries must be back edges. | 336 // entries must be back edges. |
| 328 for (int i = 1; i < predecessors()->length(); ++i) { | 337 for (int i = 1; i < predecessors()->length(); ++i) { |
| 329 loop_information()->RegisterBackEdge(predecessors()->at(i)); | 338 loop_information()->RegisterBackEdge(predecessors()->at(i)); |
| 330 } | 339 } |
| 331 } | 340 } |
| 332 | 341 |
| 333 | 342 |
| 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 |
| 334 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) { | 352 void HBasicBlock::RegisterPredecessor(HBasicBlock* pred) { |
| 335 if (HasPredecessor()) { | 353 if (HasPredecessor()) { |
| 336 // Only loop header blocks can have a predecessor added after | 354 // Only loop header blocks can have a predecessor added after |
| 337 // instructions have been added to the block (they have phis for all | 355 // instructions have been added to the block (they have phis for all |
| 338 // values in the environment, these phis may be eliminated later). | 356 // values in the environment, these phis may be eliminated later). |
| 339 ASSERT(IsLoopHeader() || first_ == NULL); | 357 ASSERT(IsLoopHeader() || first_ == NULL); |
| 340 HEnvironment* incoming_env = pred->last_environment(); | 358 HEnvironment* incoming_env = pred->last_environment(); |
| 341 if (IsLoopHeader()) { | 359 if (IsLoopHeader()) { |
| 342 ASSERT(phis()->length() == incoming_env->length()); | 360 ASSERT(phis()->length() == incoming_env->length()); |
| 343 for (int i = 0; i < phis_.length(); ++i) { | 361 for (int i = 0; i < phis_.length(); ++i) { |
| (...skipping 675 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1019 } | 1037 } |
| 1020 builder_->GotoNoSimulate(current->block_, merge_block); | 1038 builder_->GotoNoSimulate(current->block_, merge_block); |
| 1021 } | 1039 } |
| 1022 current = current->next_; | 1040 current = current->next_; |
| 1023 } | 1041 } |
| 1024 | 1042 |
| 1025 // Merge deopt blocks, padding when necessary. | 1043 // Merge deopt blocks, padding when necessary. |
| 1026 current = merge_at_join_blocks_; | 1044 current = merge_at_join_blocks_; |
| 1027 while (current != NULL) { | 1045 while (current != NULL) { |
| 1028 if (current->deopt_ && current->block_ != NULL) { | 1046 if (current->deopt_ && current->block_ != NULL) { |
| 1029 builder_->PadEnvironmentForContinuation(current->block_, | 1047 current->block_->FinishExit( |
| 1030 merge_block); | 1048 HAbnormalExit::New(builder_->zone(), NULL), |
| 1031 builder_->GotoNoSimulate(current->block_, merge_block); | 1049 HSourcePosition::Unknown()); |
| 1032 } | 1050 } |
| 1033 current = current->next_; | 1051 current = current->next_; |
| 1034 } | 1052 } |
| 1035 builder_->set_current_block(merge_block); | 1053 builder_->set_current_block(merge_block); |
| 1036 } | 1054 } |
| 1037 | 1055 |
| 1038 | 1056 |
| 1039 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, | 1057 HGraphBuilder::LoopBuilder::LoopBuilder(HGraphBuilder* builder, |
| 1040 HValue* context, | 1058 HValue* context, |
| 1041 LoopBuilder::Direction direction) | 1059 LoopBuilder::Direction direction) |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1154 CompilationPhase phase("H_Block building", info_); | 1172 CompilationPhase phase("H_Block building", info_); |
| 1155 set_current_block(graph()->entry_block()); | 1173 set_current_block(graph()->entry_block()); |
| 1156 if (!BuildGraph()) return NULL; | 1174 if (!BuildGraph()) return NULL; |
| 1157 graph()->FinalizeUniqueness(); | 1175 graph()->FinalizeUniqueness(); |
| 1158 return graph_; | 1176 return graph_; |
| 1159 } | 1177 } |
| 1160 | 1178 |
| 1161 | 1179 |
| 1162 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { | 1180 HInstruction* HGraphBuilder::AddInstruction(HInstruction* instr) { |
| 1163 ASSERT(current_block() != NULL); | 1181 ASSERT(current_block() != NULL); |
| 1164 ASSERT(!FLAG_emit_opt_code_positions || | 1182 ASSERT(!FLAG_hydrogen_track_positions || |
| 1165 position_ != RelocInfo::kNoPosition || !info_->IsOptimizing()); | 1183 !position_.IsUnknown() || |
| 1166 current_block()->AddInstruction(instr, position_); | 1184 !info_->IsOptimizing()); |
| 1185 current_block()->AddInstruction(instr, source_position()); |
| 1167 if (graph()->IsInsideNoSideEffectsScope()) { | 1186 if (graph()->IsInsideNoSideEffectsScope()) { |
| 1168 instr->SetFlag(HValue::kHasNoObservableSideEffects); | 1187 instr->SetFlag(HValue::kHasNoObservableSideEffects); |
| 1169 } | 1188 } |
| 1170 return instr; | 1189 return instr; |
| 1171 } | 1190 } |
| 1172 | 1191 |
| 1173 | 1192 |
| 1174 void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) { | 1193 void HGraphBuilder::FinishCurrentBlock(HControlInstruction* last) { |
| 1175 ASSERT(!FLAG_emit_opt_code_positions || !info_->IsOptimizing() || | 1194 ASSERT(!FLAG_hydrogen_track_positions || |
| 1176 position_ != RelocInfo::kNoPosition); | 1195 !info_->IsOptimizing() || |
| 1177 current_block()->Finish(last, position_); | 1196 !position_.IsUnknown()); |
| 1197 current_block()->Finish(last, source_position()); |
| 1178 if (last->IsReturn() || last->IsAbnormalExit()) { | 1198 if (last->IsReturn() || last->IsAbnormalExit()) { |
| 1179 set_current_block(NULL); | 1199 set_current_block(NULL); |
| 1180 } | 1200 } |
| 1181 } | 1201 } |
| 1182 | 1202 |
| 1183 | 1203 |
| 1184 void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) { | 1204 void HGraphBuilder::FinishExitCurrentBlock(HControlInstruction* instruction) { |
| 1185 ASSERT(!FLAG_emit_opt_code_positions || !info_->IsOptimizing() || | 1205 ASSERT(!FLAG_hydrogen_track_positions || !info_->IsOptimizing() || |
| 1186 position_ != RelocInfo::kNoPosition); | 1206 !position_.IsUnknown()); |
| 1187 current_block()->FinishExit(instruction, position_); | 1207 current_block()->FinishExit(instruction, source_position()); |
| 1188 if (instruction->IsReturn() || instruction->IsAbnormalExit()) { | 1208 if (instruction->IsReturn() || instruction->IsAbnormalExit()) { |
| 1189 set_current_block(NULL); | 1209 set_current_block(NULL); |
| 1190 } | 1210 } |
| 1191 } | 1211 } |
| 1192 | 1212 |
| 1193 | 1213 |
| 1194 void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) { | 1214 void HGraphBuilder::AddIncrementCounter(StatsCounter* counter) { |
| 1195 if (FLAG_native_code_counters && counter->Enabled()) { | 1215 if (FLAG_native_code_counters && counter->Enabled()) { |
| 1196 HValue* reference = Add<HConstant>(ExternalReference(counter)); | 1216 HValue* reference = Add<HConstant>(ExternalReference(counter)); |
| 1197 HValue* old_value = Add<HLoadNamedField>(reference, | 1217 HValue* old_value = Add<HLoadNamedField>( |
| 1198 HObjectAccess::ForCounter()); | 1218 reference, static_cast<HValue*>(NULL), HObjectAccess::ForCounter()); |
| 1199 HValue* new_value = AddUncasted<HAdd>(old_value, graph()->GetConstant1()); | 1219 HValue* new_value = AddUncasted<HAdd>(old_value, graph()->GetConstant1()); |
| 1200 new_value->ClearFlag(HValue::kCanOverflow); // Ignore counter overflow | 1220 new_value->ClearFlag(HValue::kCanOverflow); // Ignore counter overflow |
| 1201 Add<HStoreNamedField>(reference, HObjectAccess::ForCounter(), | 1221 Add<HStoreNamedField>(reference, HObjectAccess::ForCounter(), |
| 1202 new_value); | 1222 new_value, STORE_TO_INITIALIZED_ENTRY); |
| 1203 } | 1223 } |
| 1204 } | 1224 } |
| 1205 | 1225 |
| 1206 | 1226 |
| 1207 void HGraphBuilder::AddSimulate(BailoutId id, | 1227 void HGraphBuilder::AddSimulate(BailoutId id, |
| 1208 RemovableSimulate removable) { | 1228 RemovableSimulate removable) { |
| 1209 ASSERT(current_block() != NULL); | 1229 ASSERT(current_block() != NULL); |
| 1210 ASSERT(!graph()->IsInsideNoSideEffectsScope()); | 1230 ASSERT(!graph()->IsInsideNoSideEffectsScope()); |
| 1211 current_block()->AddNewSimulate(id, removable); | 1231 current_block()->AddNewSimulate(id, source_position(), removable); |
| 1212 } | 1232 } |
| 1213 | 1233 |
| 1214 | 1234 |
| 1215 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { | 1235 HBasicBlock* HGraphBuilder::CreateBasicBlock(HEnvironment* env) { |
| 1216 HBasicBlock* b = graph()->CreateBasicBlock(); | 1236 HBasicBlock* b = graph()->CreateBasicBlock(); |
| 1217 b->SetInitialEnvironment(env); | 1237 b->SetInitialEnvironment(env); |
| 1218 return b; | 1238 return b; |
| 1219 } | 1239 } |
| 1220 | 1240 |
| 1221 | 1241 |
| 1222 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { | 1242 HBasicBlock* HGraphBuilder::CreateLoopHeaderBlock() { |
| 1223 HBasicBlock* header = graph()->CreateBasicBlock(); | 1243 HBasicBlock* header = graph()->CreateBasicBlock(); |
| 1224 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); | 1244 HEnvironment* entry_env = environment()->CopyAsLoopHeader(header); |
| 1225 header->SetInitialEnvironment(entry_env); | 1245 header->SetInitialEnvironment(entry_env); |
| 1226 header->AttachLoopInformation(); | 1246 header->AttachLoopInformation(); |
| 1227 return header; | 1247 return header; |
| 1228 } | 1248 } |
| 1229 | 1249 |
| 1230 | 1250 |
| 1231 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { | 1251 HValue* HGraphBuilder::BuildCheckHeapObject(HValue* obj) { |
| 1232 if (obj->type().IsHeapObject()) return obj; | 1252 if (obj->type().IsHeapObject()) return obj; |
| 1233 return Add<HCheckHeapObject>(obj); | 1253 return Add<HCheckHeapObject>(obj); |
| 1234 } | 1254 } |
| 1235 | 1255 |
| 1236 | 1256 |
| 1237 void HGraphBuilder::FinishExitWithHardDeoptimization( | 1257 void HGraphBuilder::FinishExitWithHardDeoptimization(const char* reason) { |
| 1238 const char* reason, HBasicBlock* continuation) { | |
| 1239 PadEnvironmentForContinuation(current_block(), continuation); | |
| 1240 Add<HDeoptimize>(reason, Deoptimizer::EAGER); | 1258 Add<HDeoptimize>(reason, Deoptimizer::EAGER); |
| 1241 if (graph()->IsInsideNoSideEffectsScope()) { | 1259 FinishExitCurrentBlock(New<HAbnormalExit>()); |
| 1242 GotoNoSimulate(continuation); | |
| 1243 } else { | |
| 1244 Goto(continuation); | |
| 1245 } | |
| 1246 } | 1260 } |
| 1247 | 1261 |
| 1248 | 1262 |
| 1249 void HGraphBuilder::PadEnvironmentForContinuation( | |
| 1250 HBasicBlock* from, | |
| 1251 HBasicBlock* continuation) { | |
| 1252 if (continuation->last_environment() != NULL) { | |
| 1253 // When merging from a deopt block to a continuation, resolve differences in | |
| 1254 // environment by pushing constant 0 and popping extra values so that the | |
| 1255 // environments match during the join. Push 0 since it has the most specific | |
| 1256 // representation, and will not influence representation inference of the | |
| 1257 // phi. | |
| 1258 int continuation_env_length = continuation->last_environment()->length(); | |
| 1259 while (continuation_env_length != from->last_environment()->length()) { | |
| 1260 if (continuation_env_length > from->last_environment()->length()) { | |
| 1261 from->last_environment()->Push(graph()->GetConstant0()); | |
| 1262 } else { | |
| 1263 from->last_environment()->Pop(); | |
| 1264 } | |
| 1265 } | |
| 1266 } else { | |
| 1267 ASSERT(continuation->predecessors()->length() == 0); | |
| 1268 } | |
| 1269 } | |
| 1270 | |
| 1271 | |
| 1272 HValue* HGraphBuilder::BuildCheckMap(HValue* obj, Handle<Map> map) { | 1263 HValue* HGraphBuilder::BuildCheckMap(HValue* obj, Handle<Map> map) { |
| 1273 return Add<HCheckMaps>(obj, map, top_info()); | 1264 return Add<HCheckMaps>(obj, map, top_info()); |
| 1274 } | 1265 } |
| 1275 | 1266 |
| 1276 | 1267 |
| 1277 HValue* HGraphBuilder::BuildCheckString(HValue* string) { | 1268 HValue* HGraphBuilder::BuildCheckString(HValue* string) { |
| 1278 if (!string->type().IsString()) { | 1269 if (!string->type().IsString()) { |
| 1279 ASSERT(!string->IsConstant() || | 1270 ASSERT(!string->IsConstant() || |
| 1280 !HConstant::cast(string)->HasStringValue()); | 1271 !HConstant::cast(string)->HasStringValue()); |
| 1281 BuildCheckHeapObject(string); | 1272 BuildCheckHeapObject(string); |
| 1282 return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING); | 1273 return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING); |
| 1283 } | 1274 } |
| 1284 return string; | 1275 return string; |
| 1285 } | 1276 } |
| 1286 | 1277 |
| 1287 | 1278 |
| 1288 HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) { | 1279 HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) { |
| 1289 if (object->type().IsJSObject()) return object; | 1280 if (object->type().IsJSObject()) return object; |
| 1281 if (function->IsConstant() && |
| 1282 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
| 1283 Handle<JSFunction> f = Handle<JSFunction>::cast( |
| 1284 HConstant::cast(function)->handle(isolate())); |
| 1285 SharedFunctionInfo* shared = f->shared(); |
| 1286 if (!shared->is_classic_mode() || shared->native()) return object; |
| 1287 } |
| 1290 return Add<HWrapReceiver>(object, function); | 1288 return Add<HWrapReceiver>(object, function); |
| 1291 } | 1289 } |
| 1292 | 1290 |
| 1293 | 1291 |
| 1294 HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, | 1292 HValue* HGraphBuilder::BuildCheckForCapacityGrow( |
| 1295 HValue* elements, | 1293 HValue* object, |
| 1296 ElementsKind kind, | 1294 HValue* elements, |
| 1297 HValue* length, | 1295 ElementsKind kind, |
| 1298 HValue* key, | 1296 HValue* length, |
| 1299 bool is_js_array, | 1297 HValue* key, |
| 1300 bool is_store) { | 1298 bool is_js_array, |
| 1299 PropertyAccessType access_type) { |
| 1301 IfBuilder length_checker(this); | 1300 IfBuilder length_checker(this); |
| 1302 | 1301 |
| 1303 Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ; | 1302 Token::Value token = IsHoleyElementsKind(kind) ? Token::GTE : Token::EQ; |
| 1304 length_checker.If<HCompareNumericAndBranch>(key, length, token); | 1303 length_checker.If<HCompareNumericAndBranch>(key, length, token); |
| 1305 | 1304 |
| 1306 length_checker.Then(); | 1305 length_checker.Then(); |
| 1307 | 1306 |
| 1308 HValue* current_capacity = AddLoadFixedArrayLength(elements); | 1307 HValue* current_capacity = AddLoadFixedArrayLength(elements); |
| 1309 | 1308 |
| 1310 IfBuilder capacity_checker(this); | 1309 IfBuilder capacity_checker(this); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 1333 capacity_checker.End(); | 1332 capacity_checker.End(); |
| 1334 | 1333 |
| 1335 if (is_js_array) { | 1334 if (is_js_array) { |
| 1336 HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1()); | 1335 HValue* new_length = AddUncasted<HAdd>(key, graph_->GetConstant1()); |
| 1337 new_length->ClearFlag(HValue::kCanOverflow); | 1336 new_length->ClearFlag(HValue::kCanOverflow); |
| 1338 | 1337 |
| 1339 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind), | 1338 Add<HStoreNamedField>(object, HObjectAccess::ForArrayLength(kind), |
| 1340 new_length); | 1339 new_length); |
| 1341 } | 1340 } |
| 1342 | 1341 |
| 1343 if (is_store && kind == FAST_SMI_ELEMENTS) { | 1342 if (access_type == STORE && kind == FAST_SMI_ELEMENTS) { |
| 1344 HValue* checked_elements = environment()->Top(); | 1343 HValue* checked_elements = environment()->Top(); |
| 1345 | 1344 |
| 1346 // Write zero to ensure that the new element is initialized with some smi. | 1345 // Write zero to ensure that the new element is initialized with some smi. |
| 1347 Add<HStoreKeyed>(checked_elements, key, graph()->GetConstant0(), kind); | 1346 Add<HStoreKeyed>(checked_elements, key, graph()->GetConstant0(), kind); |
| 1348 } | 1347 } |
| 1349 | 1348 |
| 1350 length_checker.Else(); | 1349 length_checker.Else(); |
| 1351 Add<HBoundsCheck>(key, length); | 1350 Add<HBoundsCheck>(key, length); |
| 1352 | 1351 |
| 1353 environment()->Push(elements); | 1352 environment()->Push(elements); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1405 | 1404 |
| 1406 IfBuilder if_builder(this); | 1405 IfBuilder if_builder(this); |
| 1407 | 1406 |
| 1408 if_builder.IfNot<HCompareObjectEqAndBranch>(elements, empty_fixed_array); | 1407 if_builder.IfNot<HCompareObjectEqAndBranch>(elements, empty_fixed_array); |
| 1409 | 1408 |
| 1410 if_builder.Then(); | 1409 if_builder.Then(); |
| 1411 | 1410 |
| 1412 HInstruction* elements_length = AddLoadFixedArrayLength(elements); | 1411 HInstruction* elements_length = AddLoadFixedArrayLength(elements); |
| 1413 | 1412 |
| 1414 HInstruction* array_length = is_jsarray | 1413 HInstruction* array_length = is_jsarray |
| 1415 ? Add<HLoadNamedField>(object, HObjectAccess::ForArrayLength(from_kind)) | 1414 ? Add<HLoadNamedField>(object, static_cast<HValue*>(NULL), |
| 1415 HObjectAccess::ForArrayLength(from_kind)) |
| 1416 : elements_length; | 1416 : elements_length; |
| 1417 | 1417 |
| 1418 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, | 1418 BuildGrowElementsCapacity(object, elements, from_kind, to_kind, |
| 1419 array_length, elements_length); | 1419 array_length, elements_length); |
| 1420 | 1420 |
| 1421 if_builder.End(); | 1421 if_builder.End(); |
| 1422 } | 1422 } |
| 1423 | 1423 |
| 1424 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); | 1424 Add<HStoreNamedField>(object, HObjectAccess::ForMap(), map); |
| 1425 } | 1425 } |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1443 int32_t entry_size = SeededNumberDictionary::kEntrySize; | 1443 int32_t entry_size = SeededNumberDictionary::kEntrySize; |
| 1444 raw_index = AddUncasted<HMul>(raw_index, Add<HConstant>(entry_size)); | 1444 raw_index = AddUncasted<HMul>(raw_index, Add<HConstant>(entry_size)); |
| 1445 raw_index->ClearFlag(HValue::kCanOverflow); | 1445 raw_index->ClearFlag(HValue::kCanOverflow); |
| 1446 | 1446 |
| 1447 int32_t base_offset = SeededNumberDictionary::kElementsStartIndex; | 1447 int32_t base_offset = SeededNumberDictionary::kElementsStartIndex; |
| 1448 HValue* key_index = AddUncasted<HAdd>(raw_index, Add<HConstant>(base_offset)); | 1448 HValue* key_index = AddUncasted<HAdd>(raw_index, Add<HConstant>(base_offset)); |
| 1449 key_index->ClearFlag(HValue::kCanOverflow); | 1449 key_index->ClearFlag(HValue::kCanOverflow); |
| 1450 | 1450 |
| 1451 HValue* candidate_key = Add<HLoadKeyed>(elements, key_index, | 1451 HValue* candidate_key = Add<HLoadKeyed>(elements, key_index, |
| 1452 static_cast<HValue*>(NULL), | 1452 static_cast<HValue*>(NULL), |
| 1453 FAST_SMI_ELEMENTS); | 1453 FAST_ELEMENTS); |
| 1454 | 1454 |
| 1455 IfBuilder key_compare(this); | 1455 IfBuilder key_compare(this); |
| 1456 key_compare.IfNot<HCompareObjectEqAndBranch>(key, candidate_key); | 1456 key_compare.IfNot<HCompareObjectEqAndBranch>(key, candidate_key); |
| 1457 key_compare.Then(); | 1457 key_compare.Then(); |
| 1458 { | 1458 { |
| 1459 // Key at the current probe doesn't match, try at the next probe. | 1459 // Key at the current probe doesn't match, try at the next probe. |
| 1460 HValue* result = BuildUncheckedDictionaryElementLoadHelper( | 1460 HValue* result = BuildUncheckedDictionaryElementLoadHelper( |
| 1461 elements, key, hash, mask, current_probe + 1); | 1461 elements, key, hash, mask, current_probe + 1); |
| 1462 if (result == NULL) { | 1462 if (result == NULL) { |
| 1463 key_compare.Deopt("probes exhausted in keyed load dictionary lookup"); | 1463 key_compare.Deopt("probes exhausted in keyed load dictionary lookup"); |
| 1464 result = graph()->GetConstantUndefined(); | 1464 result = graph()->GetConstantUndefined(); |
| 1465 } else { | 1465 } else { |
| 1466 Push(result); | 1466 Push(result); |
| 1467 } | 1467 } |
| 1468 } | 1468 } |
| 1469 key_compare.Else(); | 1469 key_compare.Else(); |
| 1470 { | 1470 { |
| 1471 // Key at current probe matches. Details must be zero, otherwise the | 1471 // Key at current probe matches. Details must be zero, otherwise the |
| 1472 // dictionary element requires special handling. | 1472 // dictionary element requires special handling. |
| 1473 HValue* details_index = AddUncasted<HAdd>( | 1473 HValue* details_index = AddUncasted<HAdd>( |
| 1474 raw_index, Add<HConstant>(base_offset + 2)); | 1474 raw_index, Add<HConstant>(base_offset + 2)); |
| 1475 details_index->ClearFlag(HValue::kCanOverflow); | 1475 details_index->ClearFlag(HValue::kCanOverflow); |
| 1476 | 1476 |
| 1477 HValue* details = Add<HLoadKeyed>(elements, details_index, | 1477 HValue* details = Add<HLoadKeyed>(elements, details_index, |
| 1478 static_cast<HValue*>(NULL), | 1478 static_cast<HValue*>(NULL), |
| 1479 FAST_SMI_ELEMENTS); | 1479 FAST_ELEMENTS); |
| 1480 IfBuilder details_compare(this); | 1480 IfBuilder details_compare(this); |
| 1481 details_compare.If<HCompareNumericAndBranch>(details, | 1481 details_compare.If<HCompareNumericAndBranch>(details, |
| 1482 graph()->GetConstant0(), | 1482 graph()->GetConstant0(), |
| 1483 Token::NE); | 1483 Token::NE); |
| 1484 details_compare.ThenDeopt("keyed load dictionary element not fast case"); | 1484 details_compare.ThenDeopt("keyed load dictionary element not fast case"); |
| 1485 | 1485 |
| 1486 details_compare.Else(); | 1486 details_compare.Else(); |
| 1487 { | 1487 { |
| 1488 // Key matches and details are zero --> fast case. Load and return the | 1488 // Key matches and details are zero --> fast case. Load and return the |
| 1489 // value. | 1489 // value. |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1539 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, | 1539 HValue* HGraphBuilder::BuildUncheckedDictionaryElementLoad(HValue* receiver, |
| 1540 HValue* key) { | 1540 HValue* key) { |
| 1541 HValue* elements = AddLoadElements(receiver); | 1541 HValue* elements = AddLoadElements(receiver); |
| 1542 | 1542 |
| 1543 HValue* hash = BuildElementIndexHash(key); | 1543 HValue* hash = BuildElementIndexHash(key); |
| 1544 | 1544 |
| 1545 HValue* capacity = Add<HLoadKeyed>( | 1545 HValue* capacity = Add<HLoadKeyed>( |
| 1546 elements, | 1546 elements, |
| 1547 Add<HConstant>(NameDictionary::kCapacityIndex), | 1547 Add<HConstant>(NameDictionary::kCapacityIndex), |
| 1548 static_cast<HValue*>(NULL), | 1548 static_cast<HValue*>(NULL), |
| 1549 FAST_SMI_ELEMENTS); | 1549 FAST_ELEMENTS); |
| 1550 | 1550 |
| 1551 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1()); | 1551 HValue* mask = AddUncasted<HSub>(capacity, graph()->GetConstant1()); |
| 1552 mask->ChangeRepresentation(Representation::Integer32()); | 1552 mask->ChangeRepresentation(Representation::Integer32()); |
| 1553 mask->ClearFlag(HValue::kCanOverflow); | 1553 mask->ClearFlag(HValue::kCanOverflow); |
| 1554 | 1554 |
| 1555 return BuildUncheckedDictionaryElementLoadHelper(elements, key, | 1555 return BuildUncheckedDictionaryElementLoadHelper(elements, key, |
| 1556 hash, mask, 0); | 1556 hash, mask, 0); |
| 1557 } | 1557 } |
| 1558 | 1558 |
| 1559 | 1559 |
| 1560 HValue* HGraphBuilder::BuildNumberToString(HValue* object, | 1560 HValue* HGraphBuilder::BuildRegExpConstructResult(HValue* length, |
| 1561 Handle<Type> type) { | 1561 HValue* index, |
| 1562 HValue* input) { |
| 1563 NoObservableSideEffectsScope scope(this); |
| 1564 |
| 1565 // Compute the size of the RegExpResult followed by FixedArray with length. |
| 1566 HValue* size = length; |
| 1567 size = AddUncasted<HShl>(size, Add<HConstant>(kPointerSizeLog2)); |
| 1568 size = AddUncasted<HAdd>(size, Add<HConstant>(static_cast<int32_t>( |
| 1569 JSRegExpResult::kSize + FixedArray::kHeaderSize))); |
| 1570 |
| 1571 // Make sure size does not exceeds max regular heap object size. |
| 1572 Add<HBoundsCheck>(size, Add<HConstant>(Page::kMaxRegularHeapObjectSize)); |
| 1573 |
| 1574 // Allocate the JSRegExpResult and the FixedArray in one step. |
| 1575 HValue* result = Add<HAllocate>( |
| 1576 size, HType::JSArray(), NOT_TENURED, JS_ARRAY_TYPE); |
| 1577 |
| 1578 // Determine the elements FixedArray. |
| 1579 HValue* elements = Add<HInnerAllocatedObject>( |
| 1580 result, Add<HConstant>(JSRegExpResult::kSize)); |
| 1581 |
| 1582 // Initialize the JSRegExpResult header. |
| 1583 HValue* global_object = Add<HLoadNamedField>( |
| 1584 context(), static_cast<HValue*>(NULL), |
| 1585 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
| 1586 HValue* native_context = Add<HLoadNamedField>( |
| 1587 global_object, static_cast<HValue*>(NULL), |
| 1588 HObjectAccess::ForGlobalObjectNativeContext()); |
| 1589 AddStoreMapNoWriteBarrier(result, Add<HLoadNamedField>( |
| 1590 native_context, static_cast<HValue*>(NULL), |
| 1591 HObjectAccess::ForContextSlot(Context::REGEXP_RESULT_MAP_INDEX))); |
| 1592 Add<HStoreNamedField>( |
| 1593 result, HObjectAccess::ForJSArrayOffset(JSArray::kPropertiesOffset), |
| 1594 Add<HConstant>(isolate()->factory()->empty_fixed_array())); |
| 1595 Add<HStoreNamedField>( |
| 1596 result, HObjectAccess::ForJSArrayOffset(JSArray::kElementsOffset), |
| 1597 elements); |
| 1598 Add<HStoreNamedField>( |
| 1599 result, HObjectAccess::ForJSArrayOffset(JSArray::kLengthOffset), length); |
| 1600 |
| 1601 // Initialize the additional fields. |
| 1602 Add<HStoreNamedField>( |
| 1603 result, HObjectAccess::ForJSArrayOffset(JSRegExpResult::kIndexOffset), |
| 1604 index); |
| 1605 Add<HStoreNamedField>( |
| 1606 result, HObjectAccess::ForJSArrayOffset(JSRegExpResult::kInputOffset), |
| 1607 input); |
| 1608 |
| 1609 // Initialize the elements header. |
| 1610 AddStoreMapConstantNoWriteBarrier(elements, |
| 1611 isolate()->factory()->fixed_array_map()); |
| 1612 Add<HStoreNamedField>(elements, HObjectAccess::ForFixedArrayLength(), length); |
| 1613 |
| 1614 // Initialize the elements contents with undefined. |
| 1615 LoopBuilder loop(this, context(), LoopBuilder::kPostIncrement); |
| 1616 index = loop.BeginBody(graph()->GetConstant0(), length, Token::LT); |
| 1617 { |
| 1618 Add<HStoreKeyed>(elements, index, graph()->GetConstantUndefined(), |
| 1619 FAST_ELEMENTS); |
| 1620 } |
| 1621 loop.EndBody(); |
| 1622 |
| 1623 return result; |
| 1624 } |
| 1625 |
| 1626 |
| 1627 HValue* HGraphBuilder::BuildNumberToString(HValue* object, Type* type) { |
| 1562 NoObservableSideEffectsScope scope(this); | 1628 NoObservableSideEffectsScope scope(this); |
| 1563 | 1629 |
| 1564 // Convert constant numbers at compile time. | 1630 // Convert constant numbers at compile time. |
| 1565 if (object->IsConstant() && HConstant::cast(object)->HasNumberValue()) { | 1631 if (object->IsConstant() && HConstant::cast(object)->HasNumberValue()) { |
| 1566 Handle<Object> number = HConstant::cast(object)->handle(isolate()); | 1632 Handle<Object> number = HConstant::cast(object)->handle(isolate()); |
| 1567 Handle<String> result = isolate()->factory()->NumberToString(number); | 1633 Handle<String> result = isolate()->factory()->NumberToString(number); |
| 1568 return Add<HConstant>(result); | 1634 return Add<HConstant>(result); |
| 1569 } | 1635 } |
| 1570 | 1636 |
| 1571 // Create a joinable continuation. | 1637 // Create a joinable continuation. |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1607 } | 1673 } |
| 1608 if_objectiskey.JoinContinuation(&found); | 1674 if_objectiskey.JoinContinuation(&found); |
| 1609 } | 1675 } |
| 1610 if_objectissmi.Else(); | 1676 if_objectissmi.Else(); |
| 1611 { | 1677 { |
| 1612 if (type->Is(Type::Smi())) { | 1678 if (type->Is(Type::Smi())) { |
| 1613 if_objectissmi.Deopt("Expected smi"); | 1679 if_objectissmi.Deopt("Expected smi"); |
| 1614 } else { | 1680 } else { |
| 1615 // Check if the object is a heap number. | 1681 // Check if the object is a heap number. |
| 1616 IfBuilder if_objectisnumber(this); | 1682 IfBuilder if_objectisnumber(this); |
| 1617 if_objectisnumber.If<HCompareMap>( | 1683 HValue* objectisnumber = if_objectisnumber.If<HCompareMap>( |
| 1618 object, isolate()->factory()->heap_number_map()); | 1684 object, isolate()->factory()->heap_number_map()); |
| 1619 if_objectisnumber.Then(); | 1685 if_objectisnumber.Then(); |
| 1620 { | 1686 { |
| 1621 // Compute hash for heap number similar to double_get_hash(). | 1687 // Compute hash for heap number similar to double_get_hash(). |
| 1622 HValue* low = Add<HLoadNamedField>( | 1688 HValue* low = Add<HLoadNamedField>( |
| 1623 object, HObjectAccess::ForHeapNumberValueLowestBits()); | 1689 object, objectisnumber, |
| 1690 HObjectAccess::ForHeapNumberValueLowestBits()); |
| 1624 HValue* high = Add<HLoadNamedField>( | 1691 HValue* high = Add<HLoadNamedField>( |
| 1625 object, HObjectAccess::ForHeapNumberValueHighestBits()); | 1692 object, objectisnumber, |
| 1693 HObjectAccess::ForHeapNumberValueHighestBits()); |
| 1626 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, low, high); | 1694 HValue* hash = AddUncasted<HBitwise>(Token::BIT_XOR, low, high); |
| 1627 hash = AddUncasted<HBitwise>(Token::BIT_AND, hash, mask); | 1695 hash = AddUncasted<HBitwise>(Token::BIT_AND, hash, mask); |
| 1628 | 1696 |
| 1629 // Load the key. | 1697 // Load the key. |
| 1630 HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1()); | 1698 HValue* key_index = AddUncasted<HShl>(hash, graph()->GetConstant1()); |
| 1631 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, | 1699 HValue* key = Add<HLoadKeyed>(number_string_cache, key_index, |
| 1632 static_cast<HValue*>(NULL), | 1700 static_cast<HValue*>(NULL), |
| 1633 FAST_ELEMENTS, ALLOW_RETURN_HOLE); | 1701 FAST_ELEMENTS, ALLOW_RETURN_HOLE); |
| 1634 | 1702 |
| 1635 // Check if key is a heap number (the number string cache contains only | 1703 // Check if key is a heap number (the number string cache contains only |
| 1636 // SMIs and heap number, so it is sufficient to do a SMI check here). | 1704 // SMIs and heap number, so it is sufficient to do a SMI check here). |
| 1637 IfBuilder if_keyisnotsmi(this); | 1705 IfBuilder if_keyisnotsmi(this); |
| 1638 if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key); | 1706 HValue* keyisnotsmi = if_keyisnotsmi.IfNot<HIsSmiAndBranch>(key); |
| 1639 if_keyisnotsmi.Then(); | 1707 if_keyisnotsmi.Then(); |
| 1640 { | 1708 { |
| 1641 // Check if values of key and object match. | 1709 // Check if values of key and object match. |
| 1642 IfBuilder if_keyeqobject(this); | 1710 IfBuilder if_keyeqobject(this); |
| 1643 if_keyeqobject.If<HCompareNumericAndBranch>( | 1711 if_keyeqobject.If<HCompareNumericAndBranch>( |
| 1644 Add<HLoadNamedField>(key, HObjectAccess::ForHeapNumberValue()), | 1712 Add<HLoadNamedField>(key, keyisnotsmi, |
| 1645 Add<HLoadNamedField>(object, HObjectAccess::ForHeapNumberValue()), | 1713 HObjectAccess::ForHeapNumberValue()), |
| 1714 Add<HLoadNamedField>(object, objectisnumber, |
| 1715 HObjectAccess::ForHeapNumberValue()), |
| 1646 Token::EQ); | 1716 Token::EQ); |
| 1647 if_keyeqobject.Then(); | 1717 if_keyeqobject.Then(); |
| 1648 { | 1718 { |
| 1649 // Make the key_index available. | 1719 // Make the key_index available. |
| 1650 Push(key_index); | 1720 Push(key_index); |
| 1651 } | 1721 } |
| 1652 if_keyeqobject.JoinContinuation(&found); | 1722 if_keyeqobject.JoinContinuation(&found); |
| 1653 } | 1723 } |
| 1654 if_keyisnotsmi.JoinContinuation(&found); | 1724 if_keyisnotsmi.JoinContinuation(&found); |
| 1655 } | 1725 } |
| (...skipping 412 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2068 return Pop(); | 2138 return Pop(); |
| 2069 } | 2139 } |
| 2070 | 2140 |
| 2071 | 2141 |
| 2072 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( | 2142 HInstruction* HGraphBuilder::BuildUncheckedMonomorphicElementAccess( |
| 2073 HValue* checked_object, | 2143 HValue* checked_object, |
| 2074 HValue* key, | 2144 HValue* key, |
| 2075 HValue* val, | 2145 HValue* val, |
| 2076 bool is_js_array, | 2146 bool is_js_array, |
| 2077 ElementsKind elements_kind, | 2147 ElementsKind elements_kind, |
| 2078 bool is_store, | 2148 PropertyAccessType access_type, |
| 2079 LoadKeyedHoleMode load_mode, | 2149 LoadKeyedHoleMode load_mode, |
| 2080 KeyedAccessStoreMode store_mode) { | 2150 KeyedAccessStoreMode store_mode) { |
| 2081 ASSERT((!IsExternalArrayElementsKind(elements_kind) && | 2151 ASSERT((!IsExternalArrayElementsKind(elements_kind) && |
| 2082 !IsFixedTypedArrayElementsKind(elements_kind)) || | 2152 !IsFixedTypedArrayElementsKind(elements_kind)) || |
| 2083 !is_js_array); | 2153 !is_js_array); |
| 2084 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency | 2154 // No GVNFlag is necessary for ElementsKind if there is an explicit dependency |
| 2085 // on a HElementsTransition instruction. The flag can also be removed if the | 2155 // on a HElementsTransition instruction. The flag can also be removed if the |
| 2086 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further | 2156 // map to check has FAST_HOLEY_ELEMENTS, since there can be no further |
| 2087 // ElementsKind transitions. Finally, the dependency can be removed for stores | 2157 // ElementsKind transitions. Finally, the dependency can be removed for stores |
| 2088 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the | 2158 // for FAST_ELEMENTS, since a transition to HOLEY elements won't change the |
| 2089 // generated store code. | 2159 // generated store code. |
| 2090 if ((elements_kind == FAST_HOLEY_ELEMENTS) || | 2160 if ((elements_kind == FAST_HOLEY_ELEMENTS) || |
| 2091 (elements_kind == FAST_ELEMENTS && is_store)) { | 2161 (elements_kind == FAST_ELEMENTS && access_type == STORE)) { |
| 2092 checked_object->ClearGVNFlag(kDependsOnElementsKind); | 2162 checked_object->ClearDependsOnFlag(kElementsKind); |
| 2093 } | 2163 } |
| 2094 | 2164 |
| 2095 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); | 2165 bool fast_smi_only_elements = IsFastSmiElementsKind(elements_kind); |
| 2096 bool fast_elements = IsFastObjectElementsKind(elements_kind); | 2166 bool fast_elements = IsFastObjectElementsKind(elements_kind); |
| 2097 HValue* elements = AddLoadElements(checked_object); | 2167 HValue* elements = AddLoadElements(checked_object); |
| 2098 if (is_store && (fast_elements || fast_smi_only_elements) && | 2168 if (access_type == STORE && (fast_elements || fast_smi_only_elements) && |
| 2099 store_mode != STORE_NO_TRANSITION_HANDLE_COW) { | 2169 store_mode != STORE_NO_TRANSITION_HANDLE_COW) { |
| 2100 HCheckMaps* check_cow_map = Add<HCheckMaps>( | 2170 HCheckMaps* check_cow_map = Add<HCheckMaps>( |
| 2101 elements, isolate()->factory()->fixed_array_map(), top_info()); | 2171 elements, isolate()->factory()->fixed_array_map(), top_info()); |
| 2102 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); | 2172 check_cow_map->ClearDependsOnFlag(kElementsKind); |
| 2103 } | 2173 } |
| 2104 HInstruction* length = NULL; | 2174 HInstruction* length = NULL; |
| 2105 if (is_js_array) { | 2175 if (is_js_array) { |
| 2106 length = Add<HLoadNamedField>( | 2176 length = Add<HLoadNamedField>( |
| 2107 checked_object, HObjectAccess::ForArrayLength(elements_kind)); | 2177 checked_object, static_cast<HValue*>(NULL), |
| 2178 HObjectAccess::ForArrayLength(elements_kind)); |
| 2108 } else { | 2179 } else { |
| 2109 length = AddLoadFixedArrayLength(elements); | 2180 length = AddLoadFixedArrayLength(elements); |
| 2110 } | 2181 } |
| 2111 length->set_type(HType::Smi()); | 2182 length->set_type(HType::Smi()); |
| 2112 HValue* checked_key = NULL; | 2183 HValue* checked_key = NULL; |
| 2113 if (IsExternalArrayElementsKind(elements_kind) || | 2184 if (IsExternalArrayElementsKind(elements_kind) || |
| 2114 IsFixedTypedArrayElementsKind(elements_kind)) { | 2185 IsFixedTypedArrayElementsKind(elements_kind)) { |
| 2115 HValue* backing_store; | 2186 HValue* backing_store; |
| 2116 if (IsExternalArrayElementsKind(elements_kind)) { | 2187 if (IsExternalArrayElementsKind(elements_kind)) { |
| 2117 backing_store = | 2188 backing_store = Add<HLoadNamedField>( |
| 2118 Add<HLoadExternalArrayPointer>(elements); | 2189 elements, static_cast<HValue*>(NULL), |
| 2190 HObjectAccess::ForExternalArrayExternalPointer()); |
| 2119 } else { | 2191 } else { |
| 2120 backing_store = elements; | 2192 backing_store = elements; |
| 2121 } | 2193 } |
| 2122 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { | 2194 if (store_mode == STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS) { |
| 2123 NoObservableSideEffectsScope no_effects(this); | 2195 NoObservableSideEffectsScope no_effects(this); |
| 2124 IfBuilder length_checker(this); | 2196 IfBuilder length_checker(this); |
| 2125 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT); | 2197 length_checker.If<HCompareNumericAndBranch>(key, length, Token::LT); |
| 2126 length_checker.Then(); | 2198 length_checker.Then(); |
| 2127 IfBuilder negative_checker(this); | 2199 IfBuilder negative_checker(this); |
| 2128 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>( | 2200 HValue* bounds_check = negative_checker.If<HCompareNumericAndBranch>( |
| 2129 key, graph()->GetConstant0(), Token::GTE); | 2201 key, graph()->GetConstant0(), Token::GTE); |
| 2130 negative_checker.Then(); | 2202 negative_checker.Then(); |
| 2131 HInstruction* result = AddElementAccess( | 2203 HInstruction* result = AddElementAccess( |
| 2132 backing_store, key, val, bounds_check, elements_kind, is_store); | 2204 backing_store, key, val, bounds_check, elements_kind, access_type); |
| 2133 negative_checker.ElseDeopt("Negative key encountered"); | 2205 negative_checker.ElseDeopt("Negative key encountered"); |
| 2134 negative_checker.End(); | 2206 negative_checker.End(); |
| 2135 length_checker.End(); | 2207 length_checker.End(); |
| 2136 return result; | 2208 return result; |
| 2137 } else { | 2209 } else { |
| 2138 ASSERT(store_mode == STANDARD_STORE); | 2210 ASSERT(store_mode == STANDARD_STORE); |
| 2139 checked_key = Add<HBoundsCheck>(key, length); | 2211 checked_key = Add<HBoundsCheck>(key, length); |
| 2140 return AddElementAccess( | 2212 return AddElementAccess( |
| 2141 backing_store, checked_key, val, | 2213 backing_store, checked_key, val, |
| 2142 checked_object, elements_kind, is_store); | 2214 checked_object, elements_kind, access_type); |
| 2143 } | 2215 } |
| 2144 } | 2216 } |
| 2145 ASSERT(fast_smi_only_elements || | 2217 ASSERT(fast_smi_only_elements || |
| 2146 fast_elements || | 2218 fast_elements || |
| 2147 IsFastDoubleElementsKind(elements_kind)); | 2219 IsFastDoubleElementsKind(elements_kind)); |
| 2148 | 2220 |
| 2149 // In case val is stored into a fast smi array, assure that the value is a smi | 2221 // In case val is stored into a fast smi array, assure that the value is a smi |
| 2150 // before manipulating the backing store. Otherwise the actual store may | 2222 // before manipulating the backing store. Otherwise the actual store may |
| 2151 // deopt, leaving the backing store in an invalid state. | 2223 // deopt, leaving the backing store in an invalid state. |
| 2152 if (is_store && IsFastSmiElementsKind(elements_kind) && | 2224 if (access_type == STORE && IsFastSmiElementsKind(elements_kind) && |
| 2153 !val->type().IsSmi()) { | 2225 !val->type().IsSmi()) { |
| 2154 val = AddUncasted<HForceRepresentation>(val, Representation::Smi()); | 2226 val = AddUncasted<HForceRepresentation>(val, Representation::Smi()); |
| 2155 } | 2227 } |
| 2156 | 2228 |
| 2157 if (IsGrowStoreMode(store_mode)) { | 2229 if (IsGrowStoreMode(store_mode)) { |
| 2158 NoObservableSideEffectsScope no_effects(this); | 2230 NoObservableSideEffectsScope no_effects(this); |
| 2159 elements = BuildCheckForCapacityGrow(checked_object, elements, | 2231 elements = BuildCheckForCapacityGrow(checked_object, elements, |
| 2160 elements_kind, length, key, | 2232 elements_kind, length, key, |
| 2161 is_js_array, is_store); | 2233 is_js_array, access_type); |
| 2162 checked_key = key; | 2234 checked_key = key; |
| 2163 } else { | 2235 } else { |
| 2164 checked_key = Add<HBoundsCheck>(key, length); | 2236 checked_key = Add<HBoundsCheck>(key, length); |
| 2165 | 2237 |
| 2166 if (is_store && (fast_elements || fast_smi_only_elements)) { | 2238 if (access_type == STORE && (fast_elements || fast_smi_only_elements)) { |
| 2167 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { | 2239 if (store_mode == STORE_NO_TRANSITION_HANDLE_COW) { |
| 2168 NoObservableSideEffectsScope no_effects(this); | 2240 NoObservableSideEffectsScope no_effects(this); |
| 2169 elements = BuildCopyElementsOnWrite(checked_object, elements, | 2241 elements = BuildCopyElementsOnWrite(checked_object, elements, |
| 2170 elements_kind, length); | 2242 elements_kind, length); |
| 2171 } else { | 2243 } else { |
| 2172 HCheckMaps* check_cow_map = Add<HCheckMaps>( | 2244 HCheckMaps* check_cow_map = Add<HCheckMaps>( |
| 2173 elements, isolate()->factory()->fixed_array_map(), top_info()); | 2245 elements, isolate()->factory()->fixed_array_map(), top_info()); |
| 2174 check_cow_map->ClearGVNFlag(kDependsOnElementsKind); | 2246 check_cow_map->ClearDependsOnFlag(kElementsKind); |
| 2175 } | 2247 } |
| 2176 } | 2248 } |
| 2177 } | 2249 } |
| 2178 return AddElementAccess(elements, checked_key, val, checked_object, | 2250 return AddElementAccess(elements, checked_key, val, checked_object, |
| 2179 elements_kind, is_store, load_mode); | 2251 elements_kind, access_type, load_mode); |
| 2180 } | 2252 } |
| 2181 | 2253 |
| 2182 | 2254 |
| 2183 | 2255 |
| 2184 HValue* HGraphBuilder::BuildAllocateArrayFromLength( | 2256 HValue* HGraphBuilder::BuildAllocateArrayFromLength( |
| 2185 JSArrayBuilder* array_builder, | 2257 JSArrayBuilder* array_builder, |
| 2186 HValue* length_argument) { | 2258 HValue* length_argument) { |
| 2187 if (length_argument->IsConstant() && | 2259 if (length_argument->IsConstant() && |
| 2188 HConstant::cast(length_argument)->HasSmiValue()) { | 2260 HConstant::cast(length_argument)->HasSmiValue()) { |
| 2189 int array_length = HConstant::cast(length_argument)->Integer32Value(); | 2261 int array_length = HConstant::cast(length_argument)->Integer32Value(); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2237 } | 2309 } |
| 2238 | 2310 |
| 2239 HConstant* elements_size_value = Add<HConstant>(elements_size); | 2311 HConstant* elements_size_value = Add<HConstant>(elements_size); |
| 2240 HValue* mul = AddUncasted<HMul>(capacity, elements_size_value); | 2312 HValue* mul = AddUncasted<HMul>(capacity, elements_size_value); |
| 2241 mul->ClearFlag(HValue::kCanOverflow); | 2313 mul->ClearFlag(HValue::kCanOverflow); |
| 2242 | 2314 |
| 2243 HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize); | 2315 HConstant* header_size = Add<HConstant>(FixedArray::kHeaderSize); |
| 2244 HValue* total_size = AddUncasted<HAdd>(mul, header_size); | 2316 HValue* total_size = AddUncasted<HAdd>(mul, header_size); |
| 2245 total_size->ClearFlag(HValue::kCanOverflow); | 2317 total_size->ClearFlag(HValue::kCanOverflow); |
| 2246 | 2318 |
| 2247 return Add<HAllocate>(total_size, HType::JSArray(), | 2319 PretenureFlag pretenure_flag = !FLAG_allocation_site_pretenuring ? |
| 2248 isolate()->heap()->GetPretenureMode(), instance_type); | 2320 isolate()->heap()->GetPretenureMode() : NOT_TENURED; |
| 2321 |
| 2322 return Add<HAllocate>(total_size, HType::JSArray(), pretenure_flag, |
| 2323 instance_type); |
| 2249 } | 2324 } |
| 2250 | 2325 |
| 2251 | 2326 |
| 2252 void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements, | 2327 void HGraphBuilder::BuildInitializeElementsHeader(HValue* elements, |
| 2253 ElementsKind kind, | 2328 ElementsKind kind, |
| 2254 HValue* capacity) { | 2329 HValue* capacity) { |
| 2255 Factory* factory = isolate()->factory(); | 2330 Factory* factory = isolate()->factory(); |
| 2256 Handle<Map> map = IsFastDoubleElementsKind(kind) | 2331 Handle<Map> map = IsFastDoubleElementsKind(kind) |
| 2257 ? factory->fixed_double_array_map() | 2332 ? factory->fixed_double_array_map() |
| 2258 : factory->fixed_array_map(); | 2333 : factory->fixed_array_map(); |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2308 return elements; | 2383 return elements; |
| 2309 } | 2384 } |
| 2310 | 2385 |
| 2311 | 2386 |
| 2312 HInstruction* HGraphBuilder::AddElementAccess( | 2387 HInstruction* HGraphBuilder::AddElementAccess( |
| 2313 HValue* elements, | 2388 HValue* elements, |
| 2314 HValue* checked_key, | 2389 HValue* checked_key, |
| 2315 HValue* val, | 2390 HValue* val, |
| 2316 HValue* dependency, | 2391 HValue* dependency, |
| 2317 ElementsKind elements_kind, | 2392 ElementsKind elements_kind, |
| 2318 bool is_store, | 2393 PropertyAccessType access_type, |
| 2319 LoadKeyedHoleMode load_mode) { | 2394 LoadKeyedHoleMode load_mode) { |
| 2320 if (is_store) { | 2395 if (access_type == STORE) { |
| 2321 ASSERT(val != NULL); | 2396 ASSERT(val != NULL); |
| 2322 if (elements_kind == EXTERNAL_PIXEL_ELEMENTS || | 2397 if (elements_kind == EXTERNAL_UINT8_CLAMPED_ELEMENTS || |
| 2323 elements_kind == UINT8_CLAMPED_ELEMENTS) { | 2398 elements_kind == UINT8_CLAMPED_ELEMENTS) { |
| 2324 val = Add<HClampToUint8>(val); | 2399 val = Add<HClampToUint8>(val); |
| 2325 } | 2400 } |
| 2326 return Add<HStoreKeyed>(elements, checked_key, val, elements_kind, | 2401 return Add<HStoreKeyed>(elements, checked_key, val, elements_kind, |
| 2327 elements_kind == FAST_SMI_ELEMENTS | 2402 elements_kind == FAST_SMI_ELEMENTS |
| 2328 ? STORE_TO_INITIALIZED_ENTRY | 2403 ? STORE_TO_INITIALIZED_ENTRY |
| 2329 : INITIALIZING_STORE); | 2404 : INITIALIZING_STORE); |
| 2330 } | 2405 } |
| 2331 | 2406 |
| 2332 ASSERT(!is_store); | 2407 ASSERT(access_type == LOAD); |
| 2333 ASSERT(val == NULL); | 2408 ASSERT(val == NULL); |
| 2334 HLoadKeyed* load = Add<HLoadKeyed>( | 2409 HLoadKeyed* load = Add<HLoadKeyed>( |
| 2335 elements, checked_key, dependency, elements_kind, load_mode); | 2410 elements, checked_key, dependency, elements_kind, load_mode); |
| 2336 if (FLAG_opt_safe_uint32_operations && | 2411 if (FLAG_opt_safe_uint32_operations && |
| 2337 (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS || | 2412 (elements_kind == EXTERNAL_UINT32_ELEMENTS || |
| 2338 elements_kind == UINT32_ELEMENTS)) { | 2413 elements_kind == UINT32_ELEMENTS)) { |
| 2339 graph()->RecordUint32Instruction(load); | 2414 graph()->RecordUint32Instruction(load); |
| 2340 } | 2415 } |
| 2341 return load; | 2416 return load; |
| 2342 } | 2417 } |
| 2343 | 2418 |
| 2344 | 2419 |
| 2345 HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object) { | 2420 HLoadNamedField* HGraphBuilder::AddLoadElements(HValue* object) { |
| 2346 return Add<HLoadNamedField>(object, HObjectAccess::ForElementsPointer()); | 2421 return Add<HLoadNamedField>( |
| 2422 object, static_cast<HValue*>(NULL), HObjectAccess::ForElementsPointer()); |
| 2347 } | 2423 } |
| 2348 | 2424 |
| 2349 | 2425 |
| 2350 HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength(HValue* object) { | 2426 HLoadNamedField* HGraphBuilder::AddLoadFixedArrayLength(HValue* object) { |
| 2351 return Add<HLoadNamedField>(object, | 2427 return Add<HLoadNamedField>( |
| 2352 HObjectAccess::ForFixedArrayLength()); | 2428 object, static_cast<HValue*>(NULL), HObjectAccess::ForFixedArrayLength()); |
| 2353 } | 2429 } |
| 2354 | 2430 |
| 2355 | 2431 |
| 2356 HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* old_capacity) { | 2432 HValue* HGraphBuilder::BuildNewElementsCapacity(HValue* old_capacity) { |
| 2357 HValue* half_old_capacity = AddUncasted<HShr>(old_capacity, | 2433 HValue* half_old_capacity = AddUncasted<HShr>(old_capacity, |
| 2358 graph_->GetConstant1()); | 2434 graph_->GetConstant1()); |
| 2359 | 2435 |
| 2360 HValue* new_capacity = AddUncasted<HAdd>(half_old_capacity, old_capacity); | 2436 HValue* new_capacity = AddUncasted<HAdd>(half_old_capacity, old_capacity); |
| 2361 new_capacity->ClearFlag(HValue::kCanOverflow); | 2437 new_capacity->ClearFlag(HValue::kCanOverflow); |
| 2362 | 2438 |
| 2363 HValue* min_growth = Add<HConstant>(16); | 2439 HValue* min_growth = Add<HConstant>(16); |
| 2364 | 2440 |
| 2365 new_capacity = AddUncasted<HAdd>(new_capacity, min_growth); | 2441 new_capacity = AddUncasted<HAdd>(new_capacity, min_growth); |
| 2366 new_capacity->ClearFlag(HValue::kCanOverflow); | 2442 new_capacity->ClearFlag(HValue::kCanOverflow); |
| 2367 | 2443 |
| 2368 return new_capacity; | 2444 return new_capacity; |
| 2369 } | 2445 } |
| 2370 | 2446 |
| 2371 | 2447 |
| 2372 void HGraphBuilder::BuildNewSpaceArrayCheck(HValue* length, ElementsKind kind) { | 2448 void HGraphBuilder::BuildNewSpaceArrayCheck(HValue* length, ElementsKind kind) { |
| 2373 Heap* heap = isolate()->heap(); | |
| 2374 int element_size = IsFastDoubleElementsKind(kind) ? kDoubleSize | 2449 int element_size = IsFastDoubleElementsKind(kind) ? kDoubleSize |
| 2375 : kPointerSize; | 2450 : kPointerSize; |
| 2376 int max_size = heap->MaxRegularSpaceAllocationSize() / element_size; | 2451 int max_size = Page::kMaxRegularHeapObjectSize / element_size; |
| 2377 max_size -= JSArray::kSize / element_size; | 2452 max_size -= JSArray::kSize / element_size; |
| 2378 HConstant* max_size_constant = Add<HConstant>(max_size); | 2453 HConstant* max_size_constant = Add<HConstant>(max_size); |
| 2379 Add<HBoundsCheck>(length, max_size_constant); | 2454 Add<HBoundsCheck>(length, max_size_constant); |
| 2380 } | 2455 } |
| 2381 | 2456 |
| 2382 | 2457 |
| 2383 HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object, | 2458 HValue* HGraphBuilder::BuildGrowElementsCapacity(HValue* object, |
| 2384 HValue* elements, | 2459 HValue* elements, |
| 2385 ElementsKind kind, | 2460 ElementsKind kind, |
| 2386 ElementsKind new_kind, | 2461 ElementsKind new_kind, |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2526 HValue* size_in_bytes = Add<HConstant>(size); | 2601 HValue* size_in_bytes = Add<HConstant>(size); |
| 2527 HInstruction* object = Add<HAllocate>(size_in_bytes, | 2602 HInstruction* object = Add<HAllocate>(size_in_bytes, |
| 2528 HType::JSObject(), | 2603 HType::JSObject(), |
| 2529 NOT_TENURED, | 2604 NOT_TENURED, |
| 2530 JS_OBJECT_TYPE); | 2605 JS_OBJECT_TYPE); |
| 2531 | 2606 |
| 2532 // Copy the JS array part. | 2607 // Copy the JS array part. |
| 2533 for (int i = 0; i < JSArray::kSize; i += kPointerSize) { | 2608 for (int i = 0; i < JSArray::kSize; i += kPointerSize) { |
| 2534 if ((i != JSArray::kElementsOffset) || (length == 0)) { | 2609 if ((i != JSArray::kElementsOffset) || (length == 0)) { |
| 2535 HObjectAccess access = HObjectAccess::ForJSArrayOffset(i); | 2610 HObjectAccess access = HObjectAccess::ForJSArrayOffset(i); |
| 2536 Add<HStoreNamedField>(object, access, | 2611 Add<HStoreNamedField>( |
| 2537 Add<HLoadNamedField>(boilerplate, access)); | 2612 object, access, Add<HLoadNamedField>( |
| 2613 boilerplate, static_cast<HValue*>(NULL), access)); |
| 2538 } | 2614 } |
| 2539 } | 2615 } |
| 2540 | 2616 |
| 2541 // Create an allocation site info if requested. | 2617 // Create an allocation site info if requested. |
| 2542 if (mode == TRACK_ALLOCATION_SITE) { | 2618 if (mode == TRACK_ALLOCATION_SITE) { |
| 2543 BuildCreateAllocationMemento( | 2619 BuildCreateAllocationMemento( |
| 2544 object, Add<HConstant>(JSArray::kSize), allocation_site); | 2620 object, Add<HConstant>(JSArray::kSize), allocation_site); |
| 2545 } | 2621 } |
| 2546 | 2622 |
| 2547 if (length > 0) { | 2623 if (length > 0) { |
| 2548 HValue* boilerplate_elements = AddLoadElements(boilerplate); | 2624 HValue* boilerplate_elements = AddLoadElements(boilerplate); |
| 2549 HValue* object_elements; | 2625 HValue* object_elements; |
| 2550 if (IsFastDoubleElementsKind(kind)) { | 2626 if (IsFastDoubleElementsKind(kind)) { |
| 2551 HValue* elems_size = Add<HConstant>(FixedDoubleArray::SizeFor(length)); | 2627 HValue* elems_size = Add<HConstant>(FixedDoubleArray::SizeFor(length)); |
| 2552 object_elements = Add<HAllocate>(elems_size, HType::JSArray(), | 2628 object_elements = Add<HAllocate>(elems_size, HType::JSArray(), |
| 2553 NOT_TENURED, FIXED_DOUBLE_ARRAY_TYPE); | 2629 NOT_TENURED, FIXED_DOUBLE_ARRAY_TYPE); |
| 2554 } else { | 2630 } else { |
| 2555 HValue* elems_size = Add<HConstant>(FixedArray::SizeFor(length)); | 2631 HValue* elems_size = Add<HConstant>(FixedArray::SizeFor(length)); |
| 2556 object_elements = Add<HAllocate>(elems_size, HType::JSArray(), | 2632 object_elements = Add<HAllocate>(elems_size, HType::JSArray(), |
| 2557 NOT_TENURED, FIXED_ARRAY_TYPE); | 2633 NOT_TENURED, FIXED_ARRAY_TYPE); |
| 2558 } | 2634 } |
| 2559 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), | 2635 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), |
| 2560 object_elements); | 2636 object_elements); |
| 2561 | 2637 |
| 2562 // Copy the elements array header. | 2638 // Copy the elements array header. |
| 2563 for (int i = 0; i < FixedArrayBase::kHeaderSize; i += kPointerSize) { | 2639 for (int i = 0; i < FixedArrayBase::kHeaderSize; i += kPointerSize) { |
| 2564 HObjectAccess access = HObjectAccess::ForFixedArrayHeader(i); | 2640 HObjectAccess access = HObjectAccess::ForFixedArrayHeader(i); |
| 2565 Add<HStoreNamedField>(object_elements, access, | 2641 Add<HStoreNamedField>( |
| 2566 Add<HLoadNamedField>(boilerplate_elements, access)); | 2642 object_elements, access, Add<HLoadNamedField>( |
| 2643 boilerplate_elements, static_cast<HValue*>(NULL), access)); |
| 2567 } | 2644 } |
| 2568 | 2645 |
| 2569 // Copy the elements array contents. | 2646 // Copy the elements array contents. |
| 2570 // TODO(mstarzinger): Teach HGraphBuilder::BuildCopyElements to unfold | 2647 // TODO(mstarzinger): Teach HGraphBuilder::BuildCopyElements to unfold |
| 2571 // copying loops with constant length up to a given boundary and use this | 2648 // copying loops with constant length up to a given boundary and use this |
| 2572 // helper here instead. | 2649 // helper here instead. |
| 2573 for (int i = 0; i < length; i++) { | 2650 for (int i = 0; i < length; i++) { |
| 2574 HValue* key_constant = Add<HConstant>(i); | 2651 HValue* key_constant = Add<HConstant>(i); |
| 2575 HInstruction* value = Add<HLoadKeyed>(boilerplate_elements, key_constant, | 2652 HInstruction* value = Add<HLoadKeyed>(boilerplate_elements, key_constant, |
| 2576 static_cast<HValue*>(NULL), kind); | 2653 static_cast<HValue*>(NULL), kind); |
| 2577 Add<HStoreKeyed>(object_elements, key_constant, value, kind); | 2654 Add<HStoreKeyed>(object_elements, key_constant, value, kind); |
| 2578 } | 2655 } |
| 2579 } | 2656 } |
| 2580 | 2657 |
| 2581 return object; | 2658 return object; |
| 2582 } | 2659 } |
| 2583 | 2660 |
| 2584 | 2661 |
| 2585 void HGraphBuilder::BuildCompareNil( | 2662 void HGraphBuilder::BuildCompareNil( |
| 2586 HValue* value, | 2663 HValue* value, |
| 2587 Handle<Type> type, | 2664 Type* type, |
| 2588 HIfContinuation* continuation) { | 2665 HIfContinuation* continuation) { |
| 2589 IfBuilder if_nil(this); | 2666 IfBuilder if_nil(this); |
| 2590 bool some_case_handled = false; | 2667 bool some_case_handled = false; |
| 2591 bool some_case_missing = false; | 2668 bool some_case_missing = false; |
| 2592 | 2669 |
| 2593 if (type->Maybe(Type::Null())) { | 2670 if (type->Maybe(Type::Null())) { |
| 2594 if (some_case_handled) if_nil.Or(); | 2671 if (some_case_handled) if_nil.Or(); |
| 2595 if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull()); | 2672 if_nil.If<HCompareObjectEqAndBranch>(value, graph()->GetConstantNull()); |
| 2596 some_case_handled = true; | 2673 some_case_handled = true; |
| 2597 } else { | 2674 } else { |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2642 HInnerAllocatedObject* allocation_memento = Add<HInnerAllocatedObject>( | 2719 HInnerAllocatedObject* allocation_memento = Add<HInnerAllocatedObject>( |
| 2643 previous_object, previous_object_size); | 2720 previous_object, previous_object_size); |
| 2644 AddStoreMapConstant( | 2721 AddStoreMapConstant( |
| 2645 allocation_memento, isolate()->factory()->allocation_memento_map()); | 2722 allocation_memento, isolate()->factory()->allocation_memento_map()); |
| 2646 Add<HStoreNamedField>( | 2723 Add<HStoreNamedField>( |
| 2647 allocation_memento, | 2724 allocation_memento, |
| 2648 HObjectAccess::ForAllocationMementoSite(), | 2725 HObjectAccess::ForAllocationMementoSite(), |
| 2649 allocation_site); | 2726 allocation_site); |
| 2650 if (FLAG_allocation_site_pretenuring) { | 2727 if (FLAG_allocation_site_pretenuring) { |
| 2651 HValue* memento_create_count = Add<HLoadNamedField>( | 2728 HValue* memento_create_count = Add<HLoadNamedField>( |
| 2652 allocation_site, HObjectAccess::ForAllocationSiteOffset( | 2729 allocation_site, static_cast<HValue*>(NULL), |
| 2730 HObjectAccess::ForAllocationSiteOffset( |
| 2653 AllocationSite::kPretenureCreateCountOffset)); | 2731 AllocationSite::kPretenureCreateCountOffset)); |
| 2654 memento_create_count = AddUncasted<HAdd>( | 2732 memento_create_count = AddUncasted<HAdd>( |
| 2655 memento_create_count, graph()->GetConstant1()); | 2733 memento_create_count, graph()->GetConstant1()); |
| 2656 // This smi value is reset to zero after every gc, overflow isn't a problem | 2734 // This smi value is reset to zero after every gc, overflow isn't a problem |
| 2657 // since the counter is bounded by the new space size. | 2735 // since the counter is bounded by the new space size. |
| 2658 memento_create_count->ClearFlag(HValue::kCanOverflow); | 2736 memento_create_count->ClearFlag(HValue::kCanOverflow); |
| 2659 HStoreNamedField* store = Add<HStoreNamedField>( | 2737 HStoreNamedField* store = Add<HStoreNamedField>( |
| 2660 allocation_site, HObjectAccess::ForAllocationSiteOffset( | 2738 allocation_site, HObjectAccess::ForAllocationSiteOffset( |
| 2661 AllocationSite::kPretenureCreateCountOffset), memento_create_count); | 2739 AllocationSite::kPretenureCreateCountOffset), memento_create_count); |
| 2662 // No write barrier needed to store a smi. | 2740 // No write barrier needed to store a smi. |
| 2663 store->SkipWriteBarrier(); | 2741 store->SkipWriteBarrier(); |
| 2664 } | 2742 } |
| 2665 } | 2743 } |
| 2666 | 2744 |
| 2667 | 2745 |
| 2668 HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* closure) { | 2746 HInstruction* HGraphBuilder::BuildGetNativeContext(HValue* closure) { |
| 2669 // Get the global context, then the native context | 2747 // Get the global context, then the native context |
| 2670 HInstruction* context = | 2748 HInstruction* context = |
| 2671 Add<HLoadNamedField>(closure, HObjectAccess::ForFunctionContextPointer()); | 2749 Add<HLoadNamedField>(closure, static_cast<HValue*>(NULL), |
| 2672 HInstruction* global_object = Add<HLoadNamedField>(context, | 2750 HObjectAccess::ForFunctionContextPointer()); |
| 2751 HInstruction* global_object = Add<HLoadNamedField>( |
| 2752 context, static_cast<HValue*>(NULL), |
| 2673 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | 2753 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
| 2674 HObjectAccess access = HObjectAccess::ForJSObjectOffset( | 2754 HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset( |
| 2675 GlobalObject::kNativeContextOffset); | 2755 GlobalObject::kNativeContextOffset); |
| 2676 return Add<HLoadNamedField>(global_object, access); | 2756 return Add<HLoadNamedField>( |
| 2757 global_object, static_cast<HValue*>(NULL), access); |
| 2677 } | 2758 } |
| 2678 | 2759 |
| 2679 | 2760 |
| 2680 HInstruction* HGraphBuilder::BuildGetNativeContext() { | 2761 HInstruction* HGraphBuilder::BuildGetNativeContext() { |
| 2681 // Get the global context, then the native context | 2762 // Get the global context, then the native context |
| 2682 HInstruction* global_object = Add<HGlobalObject>(); | 2763 HValue* global_object = Add<HLoadNamedField>( |
| 2683 HObjectAccess access = HObjectAccess::ForJSObjectOffset( | 2764 context(), static_cast<HValue*>(NULL), |
| 2684 GlobalObject::kNativeContextOffset); | 2765 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
| 2685 return Add<HLoadNamedField>(global_object, access); | 2766 return Add<HLoadNamedField>( |
| 2767 global_object, static_cast<HValue*>(NULL), |
| 2768 HObjectAccess::ForObservableJSObjectOffset( |
| 2769 GlobalObject::kNativeContextOffset)); |
| 2686 } | 2770 } |
| 2687 | 2771 |
| 2688 | 2772 |
| 2689 HInstruction* HGraphBuilder::BuildGetArrayFunction() { | 2773 HInstruction* HGraphBuilder::BuildGetArrayFunction() { |
| 2690 HInstruction* native_context = BuildGetNativeContext(); | 2774 HInstruction* native_context = BuildGetNativeContext(); |
| 2691 HInstruction* index = | 2775 HInstruction* index = |
| 2692 Add<HConstant>(static_cast<int32_t>(Context::ARRAY_FUNCTION_INDEX)); | 2776 Add<HConstant>(static_cast<int32_t>(Context::ARRAY_FUNCTION_INDEX)); |
| 2693 return Add<HLoadKeyed>( | 2777 return Add<HLoadKeyed>( |
| 2694 native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS); | 2778 native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS); |
| 2695 } | 2779 } |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2729 // A constant map is fine. | 2813 // A constant map is fine. |
| 2730 Handle<Map> map(builder()->isolate()->get_initial_js_array_map(kind_), | 2814 Handle<Map> map(builder()->isolate()->get_initial_js_array_map(kind_), |
| 2731 builder()->isolate()); | 2815 builder()->isolate()); |
| 2732 return builder()->Add<HConstant>(map); | 2816 return builder()->Add<HConstant>(map); |
| 2733 } | 2817 } |
| 2734 | 2818 |
| 2735 if (constructor_function_ != NULL && kind_ == GetInitialFastElementsKind()) { | 2819 if (constructor_function_ != NULL && kind_ == GetInitialFastElementsKind()) { |
| 2736 // No need for a context lookup if the kind_ matches the initial | 2820 // No need for a context lookup if the kind_ matches the initial |
| 2737 // map, because we can just load the map in that case. | 2821 // map, because we can just load the map in that case. |
| 2738 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); | 2822 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); |
| 2739 return builder()->AddLoadNamedField(constructor_function_, access); | 2823 return builder()->Add<HLoadNamedField>( |
| 2824 constructor_function_, static_cast<HValue*>(NULL), access); |
| 2740 } | 2825 } |
| 2741 | 2826 |
| 2742 // TODO(mvstanton): we should always have a constructor function if we | 2827 // TODO(mvstanton): we should always have a constructor function if we |
| 2743 // are creating a stub. | 2828 // are creating a stub. |
| 2744 HInstruction* native_context = constructor_function_ != NULL | 2829 HInstruction* native_context = constructor_function_ != NULL |
| 2745 ? builder()->BuildGetNativeContext(constructor_function_) | 2830 ? builder()->BuildGetNativeContext(constructor_function_) |
| 2746 : builder()->BuildGetNativeContext(); | 2831 : builder()->BuildGetNativeContext(); |
| 2747 | 2832 |
| 2748 HInstruction* index = builder()->Add<HConstant>( | 2833 HInstruction* index = builder()->Add<HConstant>( |
| 2749 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX)); | 2834 static_cast<int32_t>(Context::JS_ARRAY_MAPS_INDEX)); |
| 2750 | 2835 |
| 2751 HInstruction* map_array = builder()->Add<HLoadKeyed>( | 2836 HInstruction* map_array = builder()->Add<HLoadKeyed>( |
| 2752 native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS); | 2837 native_context, index, static_cast<HValue*>(NULL), FAST_ELEMENTS); |
| 2753 | 2838 |
| 2754 HInstruction* kind_index = builder()->Add<HConstant>(kind_); | 2839 HInstruction* kind_index = builder()->Add<HConstant>(kind_); |
| 2755 | 2840 |
| 2756 return builder()->Add<HLoadKeyed>( | 2841 return builder()->Add<HLoadKeyed>( |
| 2757 map_array, kind_index, static_cast<HValue*>(NULL), FAST_ELEMENTS); | 2842 map_array, kind_index, static_cast<HValue*>(NULL), FAST_ELEMENTS); |
| 2758 } | 2843 } |
| 2759 | 2844 |
| 2760 | 2845 |
| 2761 HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() { | 2846 HValue* HGraphBuilder::JSArrayBuilder::EmitInternalMapCode() { |
| 2762 // Find the map near the constructor function | 2847 // Find the map near the constructor function |
| 2763 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); | 2848 HObjectAccess access = HObjectAccess::ForPrototypeOrInitialMap(); |
| 2764 return builder()->AddLoadNamedField(constructor_function_, access); | 2849 return builder()->Add<HLoadNamedField>( |
| 2850 constructor_function_, static_cast<HValue*>(NULL), access); |
| 2765 } | 2851 } |
| 2766 | 2852 |
| 2767 | 2853 |
| 2768 HValue* HGraphBuilder::JSArrayBuilder::EstablishAllocationSize( | 2854 HValue* HGraphBuilder::JSArrayBuilder::EstablishAllocationSize( |
| 2769 HValue* length_node) { | 2855 HValue* length_node) { |
| 2770 ASSERT(length_node != NULL); | 2856 ASSERT(length_node != NULL); |
| 2771 | 2857 |
| 2772 int base_size = JSArray::kSize; | 2858 int base_size = JSArray::kSize; |
| 2773 if (mode_ == TRACK_ALLOCATION_SITE) { | 2859 if (mode_ == TRACK_ALLOCATION_SITE) { |
| 2774 base_size += AllocationMemento::kSize; | 2860 base_size += AllocationMemento::kSize; |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2871 | 2957 |
| 2872 | 2958 |
| 2873 HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object, | 2959 HStoreNamedField* HGraphBuilder::AddStoreMapConstant(HValue *object, |
| 2874 Handle<Map> map) { | 2960 Handle<Map> map) { |
| 2875 return Add<HStoreNamedField>(object, HObjectAccess::ForMap(), | 2961 return Add<HStoreNamedField>(object, HObjectAccess::ForMap(), |
| 2876 Add<HConstant>(map)); | 2962 Add<HConstant>(map)); |
| 2877 } | 2963 } |
| 2878 | 2964 |
| 2879 | 2965 |
| 2880 HValue* HGraphBuilder::AddLoadJSBuiltin(Builtins::JavaScript builtin) { | 2966 HValue* HGraphBuilder::AddLoadJSBuiltin(Builtins::JavaScript builtin) { |
| 2881 HGlobalObject* global_object = Add<HGlobalObject>(); | 2967 HValue* global_object = Add<HLoadNamedField>( |
| 2882 HObjectAccess access = HObjectAccess::ForJSObjectOffset( | 2968 context(), static_cast<HValue*>(NULL), |
| 2969 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
| 2970 HObjectAccess access = HObjectAccess::ForObservableJSObjectOffset( |
| 2883 GlobalObject::kBuiltinsOffset); | 2971 GlobalObject::kBuiltinsOffset); |
| 2884 HValue* builtins = Add<HLoadNamedField>(global_object, access); | 2972 HValue* builtins = Add<HLoadNamedField>( |
| 2885 HObjectAccess function_access = HObjectAccess::ForJSObjectOffset( | 2973 global_object, static_cast<HValue*>(NULL), access); |
| 2886 JSBuiltinsObject::OffsetOfFunctionWithId(builtin)); | 2974 HObjectAccess function_access = HObjectAccess::ForObservableJSObjectOffset( |
| 2887 return Add<HLoadNamedField>(builtins, function_access); | 2975 JSBuiltinsObject::OffsetOfFunctionWithId(builtin)); |
| 2976 return Add<HLoadNamedField>( |
| 2977 builtins, static_cast<HValue*>(NULL), function_access); |
| 2888 } | 2978 } |
| 2889 | 2979 |
| 2890 | 2980 |
| 2891 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info) | 2981 HOptimizedGraphBuilder::HOptimizedGraphBuilder(CompilationInfo* info) |
| 2892 : HGraphBuilder(info), | 2982 : HGraphBuilder(info), |
| 2893 function_state_(NULL), | 2983 function_state_(NULL), |
| 2894 initial_function_state_(this, info, NORMAL_RETURN), | 2984 initial_function_state_(this, info, NORMAL_RETURN, 0), |
| 2895 ast_context_(NULL), | 2985 ast_context_(NULL), |
| 2896 break_scope_(NULL), | 2986 break_scope_(NULL), |
| 2897 inlined_count_(0), | 2987 inlined_count_(0), |
| 2898 globals_(10, info->zone()), | 2988 globals_(10, info->zone()), |
| 2899 inline_bailout_(false), | 2989 inline_bailout_(false), |
| 2900 osr_(new(info->zone()) HOsrBuilder(this)) { | 2990 osr_(new(info->zone()) HOsrBuilder(this)) { |
| 2901 // This is not initialized in the initializer list because the | 2991 // This is not initialized in the initializer list because the |
| 2902 // constructor for the initial state relies on function_state_ == NULL | 2992 // constructor for the initial state relies on function_state_ == NULL |
| 2903 // to know it's the initial state. | 2993 // to know it's the initial state. |
| 2904 function_state_= &initial_function_state_; | 2994 function_state_= &initial_function_state_; |
| 2905 InitializeAstVisitor(info->isolate()); | 2995 InitializeAstVisitor(info->zone()); |
| 2906 if (FLAG_emit_opt_code_positions) { | 2996 if (FLAG_hydrogen_track_positions) { |
| 2907 SetSourcePosition(info->shared_info()->start_position()); | 2997 SetSourcePosition(info->shared_info()->start_position()); |
| 2908 } | 2998 } |
| 2909 } | 2999 } |
| 2910 | 3000 |
| 2911 | 3001 |
| 2912 HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first, | 3002 HBasicBlock* HOptimizedGraphBuilder::CreateJoin(HBasicBlock* first, |
| 2913 HBasicBlock* second, | 3003 HBasicBlock* second, |
| 2914 BailoutId join_id) { | 3004 BailoutId join_id) { |
| 2915 if (first == NULL) { | 3005 if (first == NULL) { |
| 2916 return second; | 3006 return second; |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2965 | 3055 |
| 2966 HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry( | 3056 HBasicBlock* HOptimizedGraphBuilder::BuildLoopEntry( |
| 2967 IterationStatement* statement) { | 3057 IterationStatement* statement) { |
| 2968 HBasicBlock* loop_entry = osr()->HasOsrEntryAt(statement) | 3058 HBasicBlock* loop_entry = osr()->HasOsrEntryAt(statement) |
| 2969 ? osr()->BuildOsrLoopEntry(statement) | 3059 ? osr()->BuildOsrLoopEntry(statement) |
| 2970 : BuildLoopEntry(); | 3060 : BuildLoopEntry(); |
| 2971 return loop_entry; | 3061 return loop_entry; |
| 2972 } | 3062 } |
| 2973 | 3063 |
| 2974 | 3064 |
| 2975 void HBasicBlock::FinishExit(HControlInstruction* instruction, int position) { | 3065 void HBasicBlock::FinishExit(HControlInstruction* instruction, |
| 3066 HSourcePosition position) { |
| 2976 Finish(instruction, position); | 3067 Finish(instruction, position); |
| 2977 ClearEnvironment(); | 3068 ClearEnvironment(); |
| 2978 } | 3069 } |
| 2979 | 3070 |
| 2980 | 3071 |
| 2981 HGraph::HGraph(CompilationInfo* info) | 3072 HGraph::HGraph(CompilationInfo* info) |
| 2982 : isolate_(info->isolate()), | 3073 : isolate_(info->isolate()), |
| 2983 next_block_id_(0), | 3074 next_block_id_(0), |
| 2984 entry_block_(NULL), | 3075 entry_block_(NULL), |
| 2985 blocks_(8, info->zone()), | 3076 blocks_(8, info->zone()), |
| 2986 values_(16, info->zone()), | 3077 values_(16, info->zone()), |
| 2987 phi_list_(NULL), | 3078 phi_list_(NULL), |
| 2988 uint32_instructions_(NULL), | 3079 uint32_instructions_(NULL), |
| 2989 osr_(NULL), | 3080 osr_(NULL), |
| 2990 info_(info), | 3081 info_(info), |
| 2991 zone_(info->zone()), | 3082 zone_(info->zone()), |
| 2992 is_recursive_(false), | 3083 is_recursive_(false), |
| 2993 use_optimistic_licm_(false), | 3084 use_optimistic_licm_(false), |
| 2994 depends_on_empty_array_proto_elements_(false), | 3085 depends_on_empty_array_proto_elements_(false), |
| 2995 type_change_checksum_(0), | 3086 type_change_checksum_(0), |
| 2996 maximum_environment_size_(0), | 3087 maximum_environment_size_(0), |
| 2997 no_side_effects_scope_count_(0), | 3088 no_side_effects_scope_count_(0), |
| 2998 disallow_adding_new_values_(false) { | 3089 disallow_adding_new_values_(false), |
| 3090 next_inline_id_(0), |
| 3091 inlined_functions_(5, info->zone()) { |
| 2999 if (info->IsStub()) { | 3092 if (info->IsStub()) { |
| 3000 HydrogenCodeStub* stub = info->code_stub(); | 3093 HydrogenCodeStub* stub = info->code_stub(); |
| 3001 CodeStubInterfaceDescriptor* descriptor = | 3094 CodeStubInterfaceDescriptor* descriptor = |
| 3002 stub->GetInterfaceDescriptor(isolate_); | 3095 stub->GetInterfaceDescriptor(isolate_); |
| 3003 start_environment_ = | 3096 start_environment_ = |
| 3004 new(zone_) HEnvironment(zone_, descriptor->environment_length()); | 3097 new(zone_) HEnvironment(zone_, descriptor->environment_length()); |
| 3005 } else { | 3098 } else { |
| 3099 TraceInlinedFunction(info->shared_info(), HSourcePosition::Unknown()); |
| 3006 start_environment_ = | 3100 start_environment_ = |
| 3007 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); | 3101 new(zone_) HEnvironment(NULL, info->scope(), info->closure(), zone_); |
| 3008 } | 3102 } |
| 3009 start_environment_->set_ast_id(BailoutId::FunctionEntry()); | 3103 start_environment_->set_ast_id(BailoutId::FunctionEntry()); |
| 3010 entry_block_ = CreateBasicBlock(); | 3104 entry_block_ = CreateBasicBlock(); |
| 3011 entry_block_->SetInitialEnvironment(start_environment_); | 3105 entry_block_->SetInitialEnvironment(start_environment_); |
| 3012 } | 3106 } |
| 3013 | 3107 |
| 3014 | 3108 |
| 3015 HBasicBlock* HGraph::CreateBasicBlock() { | 3109 HBasicBlock* HGraph::CreateBasicBlock() { |
| 3016 HBasicBlock* result = new(zone()) HBasicBlock(this); | 3110 HBasicBlock* result = new(zone()) HBasicBlock(this); |
| 3017 blocks_.Add(result, zone()); | 3111 blocks_.Add(result, zone()); |
| 3018 return result; | 3112 return result; |
| 3019 } | 3113 } |
| 3020 | 3114 |
| 3021 | 3115 |
| 3022 void HGraph::FinalizeUniqueness() { | 3116 void HGraph::FinalizeUniqueness() { |
| 3023 DisallowHeapAllocation no_gc; | 3117 DisallowHeapAllocation no_gc; |
| 3024 ASSERT(!OptimizingCompilerThread::IsOptimizerThread(isolate())); | 3118 ASSERT(!OptimizingCompilerThread::IsOptimizerThread(isolate())); |
| 3025 for (int i = 0; i < blocks()->length(); ++i) { | 3119 for (int i = 0; i < blocks()->length(); ++i) { |
| 3026 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) { | 3120 for (HInstructionIterator it(blocks()->at(i)); !it.Done(); it.Advance()) { |
| 3027 it.Current()->FinalizeUniqueness(); | 3121 it.Current()->FinalizeUniqueness(); |
| 3028 } | 3122 } |
| 3029 } | 3123 } |
| 3030 } | 3124 } |
| 3031 | 3125 |
| 3032 | 3126 |
| 3127 int HGraph::TraceInlinedFunction( |
| 3128 Handle<SharedFunctionInfo> shared, |
| 3129 HSourcePosition position) { |
| 3130 if (!FLAG_hydrogen_track_positions) { |
| 3131 return 0; |
| 3132 } |
| 3133 |
| 3134 int id = 0; |
| 3135 for (; id < inlined_functions_.length(); id++) { |
| 3136 if (inlined_functions_[id].shared().is_identical_to(shared)) { |
| 3137 break; |
| 3138 } |
| 3139 } |
| 3140 |
| 3141 if (id == inlined_functions_.length()) { |
| 3142 inlined_functions_.Add(InlinedFunctionInfo(shared), zone()); |
| 3143 |
| 3144 if (!shared->script()->IsUndefined()) { |
| 3145 Handle<Script> script(Script::cast(shared->script())); |
| 3146 if (!script->source()->IsUndefined()) { |
| 3147 CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer()); |
| 3148 PrintF(tracing_scope.file(), |
| 3149 "--- FUNCTION SOURCE (%s) id{%d,%d} ---\n", |
| 3150 shared->DebugName()->ToCString().get(), |
| 3151 info()->optimization_id(), |
| 3152 id); |
| 3153 |
| 3154 { |
| 3155 ConsStringIteratorOp op; |
| 3156 StringCharacterStream stream(String::cast(script->source()), |
| 3157 &op, |
| 3158 shared->start_position()); |
| 3159 // fun->end_position() points to the last character in the stream. We |
| 3160 // need to compensate by adding one to calculate the length. |
| 3161 int source_len = |
| 3162 shared->end_position() - shared->start_position() + 1; |
| 3163 for (int i = 0; i < source_len; i++) { |
| 3164 if (stream.HasMore()) { |
| 3165 PrintF(tracing_scope.file(), "%c", stream.GetNext()); |
| 3166 } |
| 3167 } |
| 3168 } |
| 3169 |
| 3170 PrintF(tracing_scope.file(), "\n--- END ---\n"); |
| 3171 } |
| 3172 } |
| 3173 } |
| 3174 |
| 3175 int inline_id = next_inline_id_++; |
| 3176 |
| 3177 if (inline_id != 0) { |
| 3178 CodeTracer::Scope tracing_scope(isolate()->GetCodeTracer()); |
| 3179 PrintF(tracing_scope.file(), "INLINE (%s) id{%d,%d} AS %d AT ", |
| 3180 shared->DebugName()->ToCString().get(), |
| 3181 info()->optimization_id(), |
| 3182 id, |
| 3183 inline_id); |
| 3184 position.PrintTo(tracing_scope.file()); |
| 3185 PrintF(tracing_scope.file(), "\n"); |
| 3186 } |
| 3187 |
| 3188 return inline_id; |
| 3189 } |
| 3190 |
| 3191 |
| 3192 int HGraph::SourcePositionToScriptPosition(HSourcePosition pos) { |
| 3193 if (!FLAG_hydrogen_track_positions || pos.IsUnknown()) { |
| 3194 return pos.raw(); |
| 3195 } |
| 3196 |
| 3197 return inlined_functions_[pos.inlining_id()].start_position() + |
| 3198 pos.position(); |
| 3199 } |
| 3200 |
| 3201 |
| 3033 // Block ordering was implemented with two mutually recursive methods, | 3202 // Block ordering was implemented with two mutually recursive methods, |
| 3034 // HGraph::Postorder and HGraph::PostorderLoopBlocks. | 3203 // HGraph::Postorder and HGraph::PostorderLoopBlocks. |
| 3035 // The recursion could lead to stack overflow so the algorithm has been | 3204 // The recursion could lead to stack overflow so the algorithm has been |
| 3036 // implemented iteratively. | 3205 // implemented iteratively. |
| 3037 // At a high level the algorithm looks like this: | 3206 // At a high level the algorithm looks like this: |
| 3038 // | 3207 // |
| 3039 // Postorder(block, loop_header) : { | 3208 // Postorder(block, loop_header) : { |
| 3040 // if (block has already been visited or is of another loop) return; | 3209 // if (block has already been visited or is of another loop) return; |
| 3041 // mark block as visited; | 3210 // mark block as visited; |
| 3042 // if (block is a loop header) { | 3211 // if (block is a loop header) { |
| (...skipping 358 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3401 phi_list_->Add(phi, zone()); | 3570 phi_list_->Add(phi, zone()); |
| 3402 } | 3571 } |
| 3403 } | 3572 } |
| 3404 } | 3573 } |
| 3405 | 3574 |
| 3406 | 3575 |
| 3407 // Implementation of utility class to encapsulate the translation state for | 3576 // Implementation of utility class to encapsulate the translation state for |
| 3408 // a (possibly inlined) function. | 3577 // a (possibly inlined) function. |
| 3409 FunctionState::FunctionState(HOptimizedGraphBuilder* owner, | 3578 FunctionState::FunctionState(HOptimizedGraphBuilder* owner, |
| 3410 CompilationInfo* info, | 3579 CompilationInfo* info, |
| 3411 InliningKind inlining_kind) | 3580 InliningKind inlining_kind, |
| 3581 int inlining_id) |
| 3412 : owner_(owner), | 3582 : owner_(owner), |
| 3413 compilation_info_(info), | 3583 compilation_info_(info), |
| 3414 call_context_(NULL), | 3584 call_context_(NULL), |
| 3415 inlining_kind_(inlining_kind), | 3585 inlining_kind_(inlining_kind), |
| 3416 function_return_(NULL), | 3586 function_return_(NULL), |
| 3417 test_context_(NULL), | 3587 test_context_(NULL), |
| 3418 entry_(NULL), | 3588 entry_(NULL), |
| 3419 arguments_object_(NULL), | 3589 arguments_object_(NULL), |
| 3420 arguments_elements_(NULL), | 3590 arguments_elements_(NULL), |
| 3591 inlining_id_(inlining_id), |
| 3592 outer_source_position_(HSourcePosition::Unknown()), |
| 3421 outer_(owner->function_state()) { | 3593 outer_(owner->function_state()) { |
| 3422 if (outer_ != NULL) { | 3594 if (outer_ != NULL) { |
| 3423 // State for an inline function. | 3595 // State for an inline function. |
| 3424 if (owner->ast_context()->IsTest()) { | 3596 if (owner->ast_context()->IsTest()) { |
| 3425 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); | 3597 HBasicBlock* if_true = owner->graph()->CreateBasicBlock(); |
| 3426 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); | 3598 HBasicBlock* if_false = owner->graph()->CreateBasicBlock(); |
| 3427 if_true->MarkAsInlineReturnTarget(owner->current_block()); | 3599 if_true->MarkAsInlineReturnTarget(owner->current_block()); |
| 3428 if_false->MarkAsInlineReturnTarget(owner->current_block()); | 3600 if_false->MarkAsInlineReturnTarget(owner->current_block()); |
| 3429 TestContext* outer_test_context = TestContext::cast(owner->ast_context()); | 3601 TestContext* outer_test_context = TestContext::cast(owner->ast_context()); |
| 3430 Expression* cond = outer_test_context->condition(); | 3602 Expression* cond = outer_test_context->condition(); |
| 3431 // The AstContext constructor pushed on the context stack. This newed | 3603 // The AstContext constructor pushed on the context stack. This newed |
| 3432 // instance is the reason that AstContext can't be BASE_EMBEDDED. | 3604 // instance is the reason that AstContext can't be BASE_EMBEDDED. |
| 3433 test_context_ = new TestContext(owner, cond, if_true, if_false); | 3605 test_context_ = new TestContext(owner, cond, if_true, if_false); |
| 3434 } else { | 3606 } else { |
| 3435 function_return_ = owner->graph()->CreateBasicBlock(); | 3607 function_return_ = owner->graph()->CreateBasicBlock(); |
| 3436 function_return()->MarkAsInlineReturnTarget(owner->current_block()); | 3608 function_return()->MarkAsInlineReturnTarget(owner->current_block()); |
| 3437 } | 3609 } |
| 3438 // Set this after possibly allocating a new TestContext above. | 3610 // Set this after possibly allocating a new TestContext above. |
| 3439 call_context_ = owner->ast_context(); | 3611 call_context_ = owner->ast_context(); |
| 3440 } | 3612 } |
| 3441 | 3613 |
| 3442 // Push on the state stack. | 3614 // Push on the state stack. |
| 3443 owner->set_function_state(this); | 3615 owner->set_function_state(this); |
| 3616 |
| 3617 if (FLAG_hydrogen_track_positions) { |
| 3618 outer_source_position_ = owner->source_position(); |
| 3619 owner->EnterInlinedSource( |
| 3620 info->shared_info()->start_position(), |
| 3621 inlining_id); |
| 3622 owner->SetSourcePosition(info->shared_info()->start_position()); |
| 3623 } |
| 3444 } | 3624 } |
| 3445 | 3625 |
| 3446 | 3626 |
| 3447 FunctionState::~FunctionState() { | 3627 FunctionState::~FunctionState() { |
| 3448 delete test_context_; | 3628 delete test_context_; |
| 3449 owner_->set_function_state(outer_); | 3629 owner_->set_function_state(outer_); |
| 3630 |
| 3631 if (FLAG_hydrogen_track_positions) { |
| 3632 owner_->set_source_position(outer_source_position_); |
| 3633 owner_->EnterInlinedSource( |
| 3634 outer_->compilation_info()->shared_info()->start_position(), |
| 3635 outer_->inlining_id()); |
| 3636 } |
| 3450 } | 3637 } |
| 3451 | 3638 |
| 3452 | 3639 |
| 3453 // Implementation of utility classes to represent an expression's context in | 3640 // Implementation of utility classes to represent an expression's context in |
| 3454 // the AST. | 3641 // the AST. |
| 3455 AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind) | 3642 AstContext::AstContext(HOptimizedGraphBuilder* owner, Expression::Context kind) |
| 3456 : owner_(owner), | 3643 : owner_(owner), |
| 3457 kind_(kind), | 3644 kind_(kind), |
| 3458 outer_(owner->ast_context()), | 3645 outer_(owner->ast_context()), |
| 3459 for_typeof_(false) { | 3646 for_typeof_(false) { |
| (...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3908 | 4095 |
| 3909 #ifdef DEBUG | 4096 #ifdef DEBUG |
| 3910 for (int i = 0; i < block->phis()->length(); i++) { | 4097 for (int i = 0; i < block->phis()->length(); i++) { |
| 3911 HPhi* phi = block->phis()->at(i); | 4098 HPhi* phi = block->phis()->at(i); |
| 3912 ASSERT(phi->ActualValue() == phi); | 4099 ASSERT(phi->ActualValue() == phi); |
| 3913 } | 4100 } |
| 3914 #endif | 4101 #endif |
| 3915 | 4102 |
| 3916 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { | 4103 for (HInstructionIterator it(block); !it.Done(); it.Advance()) { |
| 3917 HInstruction* instruction = it.Current(); | 4104 HInstruction* instruction = it.Current(); |
| 3918 if (instruction->ActualValue() != instruction) { | 4105 if (instruction->ActualValue() == instruction) continue; |
| 4106 if (instruction->CheckFlag(HValue::kIsDead)) { |
| 4107 // The instruction was marked as deleted but left in the graph |
| 4108 // as a control flow dependency point for subsequent |
| 4109 // instructions. |
| 4110 instruction->DeleteAndReplaceWith(instruction->ActualValue()); |
| 4111 } else { |
| 3919 ASSERT(instruction->IsInformativeDefinition()); | 4112 ASSERT(instruction->IsInformativeDefinition()); |
| 3920 if (instruction->IsPurelyInformativeDefinition()) { | 4113 if (instruction->IsPurelyInformativeDefinition()) { |
| 3921 instruction->DeleteAndReplaceWith(instruction->RedefinedOperand()); | 4114 instruction->DeleteAndReplaceWith(instruction->RedefinedOperand()); |
| 3922 } else { | 4115 } else { |
| 3923 instruction->ReplaceAllUsesWith(instruction->ActualValue()); | 4116 instruction->ReplaceAllUsesWith(instruction->ActualValue()); |
| 3924 } | 4117 } |
| 3925 } | 4118 } |
| 3926 } | 4119 } |
| 3927 } | 4120 } |
| 3928 } | 4121 } |
| (...skipping 297 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4226 ZoneList<CaseClause*>* clauses = stmt->cases(); | 4419 ZoneList<CaseClause*>* clauses = stmt->cases(); |
| 4227 int clause_count = clauses->length(); | 4420 int clause_count = clauses->length(); |
| 4228 ZoneList<HBasicBlock*> body_blocks(clause_count, zone()); | 4421 ZoneList<HBasicBlock*> body_blocks(clause_count, zone()); |
| 4229 if (clause_count > kCaseClauseLimit) { | 4422 if (clause_count > kCaseClauseLimit) { |
| 4230 return Bailout(kSwitchStatementTooManyClauses); | 4423 return Bailout(kSwitchStatementTooManyClauses); |
| 4231 } | 4424 } |
| 4232 | 4425 |
| 4233 CHECK_ALIVE(VisitForValue(stmt->tag())); | 4426 CHECK_ALIVE(VisitForValue(stmt->tag())); |
| 4234 Add<HSimulate>(stmt->EntryId()); | 4427 Add<HSimulate>(stmt->EntryId()); |
| 4235 HValue* tag_value = Top(); | 4428 HValue* tag_value = Top(); |
| 4236 Handle<Type> tag_type = stmt->tag()->bounds().lower; | 4429 Type* tag_type = stmt->tag()->bounds().lower; |
| 4237 | 4430 |
| 4238 // 1. Build all the tests, with dangling true branches | 4431 // 1. Build all the tests, with dangling true branches |
| 4239 BailoutId default_id = BailoutId::None(); | 4432 BailoutId default_id = BailoutId::None(); |
| 4240 for (int i = 0; i < clause_count; ++i) { | 4433 for (int i = 0; i < clause_count; ++i) { |
| 4241 CaseClause* clause = clauses->at(i); | 4434 CaseClause* clause = clauses->at(i); |
| 4242 if (clause->is_default()) { | 4435 if (clause->is_default()) { |
| 4243 body_blocks.Add(NULL, zone()); | 4436 body_blocks.Add(NULL, zone()); |
| 4244 if (default_id.IsNone()) default_id = clause->EntryId(); | 4437 if (default_id.IsNone()) default_id = clause->EntryId(); |
| 4245 continue; | 4438 continue; |
| 4246 } | 4439 } |
| 4247 | 4440 |
| 4248 // Generate a compare and branch. | 4441 // Generate a compare and branch. |
| 4249 CHECK_ALIVE(VisitForValue(clause->label())); | 4442 CHECK_ALIVE(VisitForValue(clause->label())); |
| 4250 HValue* label_value = Pop(); | 4443 HValue* label_value = Pop(); |
| 4251 | 4444 |
| 4252 Handle<Type> label_type = clause->label()->bounds().lower; | 4445 Type* label_type = clause->label()->bounds().lower; |
| 4253 Handle<Type> combined_type = clause->compare_type(); | 4446 Type* combined_type = clause->compare_type(); |
| 4254 HControlInstruction* compare = BuildCompareInstruction( | 4447 HControlInstruction* compare = BuildCompareInstruction( |
| 4255 Token::EQ_STRICT, tag_value, label_value, tag_type, label_type, | 4448 Token::EQ_STRICT, tag_value, label_value, tag_type, label_type, |
| 4256 combined_type, stmt->tag()->position(), clause->label()->position(), | 4449 combined_type, |
| 4257 clause->id()); | 4450 ScriptPositionToSourcePosition(stmt->tag()->position()), |
| 4451 ScriptPositionToSourcePosition(clause->label()->position()), |
| 4452 PUSH_BEFORE_SIMULATE, clause->id()); |
| 4258 | 4453 |
| 4259 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); | 4454 HBasicBlock* next_test_block = graph()->CreateBasicBlock(); |
| 4260 HBasicBlock* body_block = graph()->CreateBasicBlock(); | 4455 HBasicBlock* body_block = graph()->CreateBasicBlock(); |
| 4261 body_blocks.Add(body_block, zone()); | 4456 body_blocks.Add(body_block, zone()); |
| 4262 compare->SetSuccessorAt(0, body_block); | 4457 compare->SetSuccessorAt(0, body_block); |
| 4263 compare->SetSuccessorAt(1, next_test_block); | 4458 compare->SetSuccessorAt(1, next_test_block); |
| 4264 FinishCurrentBlock(compare); | 4459 FinishCurrentBlock(compare); |
| 4265 | 4460 |
| 4266 set_current_block(body_block); | 4461 set_current_block(body_block); |
| 4267 Drop(1); // tag_value | 4462 Drop(1); // tag_value |
| (...skipping 399 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4667 set_current_block(join); | 4862 set_current_block(join); |
| 4668 if (join != NULL && !ast_context()->IsEffect()) { | 4863 if (join != NULL && !ast_context()->IsEffect()) { |
| 4669 return ast_context()->ReturnValue(Pop()); | 4864 return ast_context()->ReturnValue(Pop()); |
| 4670 } | 4865 } |
| 4671 } | 4866 } |
| 4672 } | 4867 } |
| 4673 | 4868 |
| 4674 | 4869 |
| 4675 HOptimizedGraphBuilder::GlobalPropertyAccess | 4870 HOptimizedGraphBuilder::GlobalPropertyAccess |
| 4676 HOptimizedGraphBuilder::LookupGlobalProperty( | 4871 HOptimizedGraphBuilder::LookupGlobalProperty( |
| 4677 Variable* var, LookupResult* lookup, bool is_store) { | 4872 Variable* var, LookupResult* lookup, PropertyAccessType access_type) { |
| 4678 if (var->is_this() || !current_info()->has_global_object()) { | 4873 if (var->is_this() || !current_info()->has_global_object()) { |
| 4679 return kUseGeneric; | 4874 return kUseGeneric; |
| 4680 } | 4875 } |
| 4681 Handle<GlobalObject> global(current_info()->global_object()); | 4876 Handle<GlobalObject> global(current_info()->global_object()); |
| 4682 global->Lookup(*var->name(), lookup); | 4877 global->Lookup(*var->name(), lookup); |
| 4683 if (!lookup->IsNormal() || | 4878 if (!lookup->IsNormal() || |
| 4684 (is_store && lookup->IsReadOnly()) || | 4879 (access_type == STORE && lookup->IsReadOnly()) || |
| 4685 lookup->holder() != *global) { | 4880 lookup->holder() != *global) { |
| 4686 return kUseGeneric; | 4881 return kUseGeneric; |
| 4687 } | 4882 } |
| 4688 | 4883 |
| 4689 return kUseCell; | 4884 return kUseCell; |
| 4690 } | 4885 } |
| 4691 | 4886 |
| 4692 | 4887 |
| 4693 HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) { | 4888 HValue* HOptimizedGraphBuilder::BuildContextChainWalk(Variable* var) { |
| 4694 ASSERT(var->IsContextSlot()); | 4889 ASSERT(var->IsContextSlot()); |
| 4695 HValue* context = environment()->context(); | 4890 HValue* context = environment()->context(); |
| 4696 int length = current_info()->scope()->ContextChainLength(var->scope()); | 4891 int length = current_info()->scope()->ContextChainLength(var->scope()); |
| 4697 while (length-- > 0) { | 4892 while (length-- > 0) { |
| 4698 context = Add<HOuterContext>(context); | 4893 context = Add<HLoadNamedField>( |
| 4894 context, static_cast<HValue*>(NULL), |
| 4895 HObjectAccess::ForContextSlot(Context::PREVIOUS_INDEX)); |
| 4699 } | 4896 } |
| 4700 return context; | 4897 return context; |
| 4701 } | 4898 } |
| 4702 | 4899 |
| 4703 | 4900 |
| 4704 void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { | 4901 void HOptimizedGraphBuilder::VisitVariableProxy(VariableProxy* expr) { |
| 4705 if (expr->is_this()) { | 4902 if (expr->is_this()) { |
| 4706 current_info()->set_this_has_uses(true); | 4903 current_info()->set_this_has_uses(true); |
| 4707 } | 4904 } |
| 4708 | 4905 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 4719 // Handle known global constants like 'undefined' specially to avoid a | 4916 // Handle known global constants like 'undefined' specially to avoid a |
| 4720 // load from a global cell for them. | 4917 // load from a global cell for them. |
| 4721 Handle<Object> constant_value = | 4918 Handle<Object> constant_value = |
| 4722 isolate()->factory()->GlobalConstantFor(variable->name()); | 4919 isolate()->factory()->GlobalConstantFor(variable->name()); |
| 4723 if (!constant_value.is_null()) { | 4920 if (!constant_value.is_null()) { |
| 4724 HConstant* instr = New<HConstant>(constant_value); | 4921 HConstant* instr = New<HConstant>(constant_value); |
| 4725 return ast_context()->ReturnInstruction(instr, expr->id()); | 4922 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 4726 } | 4923 } |
| 4727 | 4924 |
| 4728 LookupResult lookup(isolate()); | 4925 LookupResult lookup(isolate()); |
| 4729 GlobalPropertyAccess type = | 4926 GlobalPropertyAccess type = LookupGlobalProperty(variable, &lookup, LOAD); |
| 4730 LookupGlobalProperty(variable, &lookup, false); | |
| 4731 | 4927 |
| 4732 if (type == kUseCell && | 4928 if (type == kUseCell && |
| 4733 current_info()->global_object()->IsAccessCheckNeeded()) { | 4929 current_info()->global_object()->IsAccessCheckNeeded()) { |
| 4734 type = kUseGeneric; | 4930 type = kUseGeneric; |
| 4735 } | 4931 } |
| 4736 | 4932 |
| 4737 if (type == kUseCell) { | 4933 if (type == kUseCell) { |
| 4738 Handle<GlobalObject> global(current_info()->global_object()); | 4934 Handle<GlobalObject> global(current_info()->global_object()); |
| 4739 Handle<PropertyCell> cell(global->GetPropertyCell(&lookup)); | 4935 Handle<PropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 4740 if (cell->type()->IsConstant()) { | 4936 if (cell->type()->IsConstant()) { |
| 4741 cell->AddDependentCompilationInfo(top_info()); | 4937 cell->AddDependentCompilationInfo(top_info()); |
| 4742 Handle<Object> constant_object = cell->type()->AsConstant(); | 4938 Handle<Object> constant_object = cell->type()->AsConstant(); |
| 4743 if (constant_object->IsConsString()) { | 4939 if (constant_object->IsConsString()) { |
| 4744 constant_object = | 4940 constant_object = |
| 4745 FlattenGetString(Handle<String>::cast(constant_object)); | 4941 FlattenGetString(Handle<String>::cast(constant_object)); |
| 4746 } | 4942 } |
| 4747 HConstant* constant = New<HConstant>(constant_object); | 4943 HConstant* constant = New<HConstant>(constant_object); |
| 4748 return ast_context()->ReturnInstruction(constant, expr->id()); | 4944 return ast_context()->ReturnInstruction(constant, expr->id()); |
| 4749 } else { | 4945 } else { |
| 4750 HLoadGlobalCell* instr = | 4946 HLoadGlobalCell* instr = |
| 4751 New<HLoadGlobalCell>(cell, lookup.GetPropertyDetails()); | 4947 New<HLoadGlobalCell>(cell, lookup.GetPropertyDetails()); |
| 4752 return ast_context()->ReturnInstruction(instr, expr->id()); | 4948 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 4753 } | 4949 } |
| 4754 } else { | 4950 } else { |
| 4755 HGlobalObject* global_object = Add<HGlobalObject>(); | 4951 HValue* global_object = Add<HLoadNamedField>( |
| 4952 context(), static_cast<HValue*>(NULL), |
| 4953 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
| 4756 HLoadGlobalGeneric* instr = | 4954 HLoadGlobalGeneric* instr = |
| 4757 New<HLoadGlobalGeneric>(global_object, | 4955 New<HLoadGlobalGeneric>(global_object, |
| 4758 variable->name(), | 4956 variable->name(), |
| 4759 ast_context()->is_for_typeof()); | 4957 ast_context()->is_for_typeof()); |
| 4760 return ast_context()->ReturnInstruction(instr, expr->id()); | 4958 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 4761 } | 4959 } |
| 4762 } | 4960 } |
| 4763 | 4961 |
| 4764 case Variable::PARAMETER: | 4962 case Variable::PARAMETER: |
| 4765 case Variable::LOCAL: { | 4963 case Variable::LOCAL: { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 4800 Handle<JSFunction> closure = function_state()->compilation_info()->closure(); | 4998 Handle<JSFunction> closure = function_state()->compilation_info()->closure(); |
| 4801 Handle<FixedArray> literals(closure->literals()); | 4999 Handle<FixedArray> literals(closure->literals()); |
| 4802 HRegExpLiteral* instr = New<HRegExpLiteral>(literals, | 5000 HRegExpLiteral* instr = New<HRegExpLiteral>(literals, |
| 4803 expr->pattern(), | 5001 expr->pattern(), |
| 4804 expr->flags(), | 5002 expr->flags(), |
| 4805 expr->literal_index()); | 5003 expr->literal_index()); |
| 4806 return ast_context()->ReturnInstruction(instr, expr->id()); | 5004 return ast_context()->ReturnInstruction(instr, expr->id()); |
| 4807 } | 5005 } |
| 4808 | 5006 |
| 4809 | 5007 |
| 4810 static bool CanInlinePropertyAccess(Map* type) { | 5008 static bool CanInlinePropertyAccess(Type* type) { |
| 4811 return type->IsJSObjectMap() && | 5009 if (type->Is(Type::NumberOrString())) return true; |
| 4812 !type->is_dictionary_map() && | 5010 if (!type->IsClass()) return false; |
| 4813 !type->has_named_interceptor(); | 5011 Handle<Map> map = type->AsClass(); |
| 5012 return map->IsJSObjectMap() && |
| 5013 !map->is_dictionary_map() && |
| 5014 !map->has_named_interceptor(); |
| 4814 } | 5015 } |
| 4815 | 5016 |
| 4816 | 5017 |
| 4817 static void LookupInPrototypes(Handle<Map> map, | |
| 4818 Handle<String> name, | |
| 4819 LookupResult* lookup) { | |
| 4820 while (map->prototype()->IsJSObject()) { | |
| 4821 Handle<JSObject> holder(JSObject::cast(map->prototype())); | |
| 4822 map = Handle<Map>(holder->map()); | |
| 4823 if (!CanInlinePropertyAccess(*map)) break; | |
| 4824 map->LookupDescriptor(*holder, *name, lookup); | |
| 4825 if (lookup->IsFound()) return; | |
| 4826 } | |
| 4827 lookup->NotFound(); | |
| 4828 } | |
| 4829 | |
| 4830 | |
| 4831 // Tries to find a JavaScript accessor of the given name in the prototype chain | |
| 4832 // starting at the given map. Return true iff there is one, including the | |
| 4833 // corresponding AccessorPair plus its holder (which could be null when the | |
| 4834 // accessor is found directly in the given map). | |
| 4835 static bool LookupAccessorPair(Handle<Map> map, | |
| 4836 Handle<String> name, | |
| 4837 Handle<AccessorPair>* accessors, | |
| 4838 Handle<JSObject>* holder) { | |
| 4839 Isolate* isolate = map->GetIsolate(); | |
| 4840 LookupResult lookup(isolate); | |
| 4841 | |
| 4842 // Check for a JavaScript accessor directly in the map. | |
| 4843 map->LookupDescriptor(NULL, *name, &lookup); | |
| 4844 if (lookup.IsPropertyCallbacks()) { | |
| 4845 Handle<Object> callback(lookup.GetValueFromMap(*map), isolate); | |
| 4846 if (!callback->IsAccessorPair()) return false; | |
| 4847 *accessors = Handle<AccessorPair>::cast(callback); | |
| 4848 *holder = Handle<JSObject>(); | |
| 4849 return true; | |
| 4850 } | |
| 4851 | |
| 4852 // Everything else, e.g. a field, can't be an accessor call. | |
| 4853 if (lookup.IsFound()) return false; | |
| 4854 | |
| 4855 // Check for a JavaScript accessor somewhere in the proto chain. | |
| 4856 LookupInPrototypes(map, name, &lookup); | |
| 4857 if (lookup.IsPropertyCallbacks()) { | |
| 4858 Handle<Object> callback(lookup.GetValue(), isolate); | |
| 4859 if (!callback->IsAccessorPair()) return false; | |
| 4860 *accessors = Handle<AccessorPair>::cast(callback); | |
| 4861 *holder = Handle<JSObject>(lookup.holder()); | |
| 4862 return true; | |
| 4863 } | |
| 4864 | |
| 4865 // We haven't found a JavaScript accessor anywhere. | |
| 4866 return false; | |
| 4867 } | |
| 4868 | |
| 4869 | |
| 4870 static bool LookupSetter(Handle<Map> map, | |
| 4871 Handle<String> name, | |
| 4872 Handle<JSFunction>* setter, | |
| 4873 Handle<JSObject>* holder) { | |
| 4874 Handle<AccessorPair> accessors; | |
| 4875 if (LookupAccessorPair(map, name, &accessors, holder) && | |
| 4876 accessors->setter()->IsJSFunction()) { | |
| 4877 Handle<JSFunction> func(JSFunction::cast(accessors->setter())); | |
| 4878 CallOptimization call_optimization(func); | |
| 4879 // TODO(dcarney): temporary hack unless crankshaft can handle api calls. | |
| 4880 if (call_optimization.is_simple_api_call()) return false; | |
| 4881 *setter = func; | |
| 4882 return true; | |
| 4883 } | |
| 4884 return false; | |
| 4885 } | |
| 4886 | |
| 4887 | |
| 4888 // Determines whether the given array or object literal boilerplate satisfies | 5018 // Determines whether the given array or object literal boilerplate satisfies |
| 4889 // all limits to be considered for fast deep-copying and computes the total | 5019 // all limits to be considered for fast deep-copying and computes the total |
| 4890 // size of all objects that are part of the graph. | 5020 // size of all objects that are part of the graph. |
| 4891 static bool IsFastLiteral(Handle<JSObject> boilerplate, | 5021 static bool IsFastLiteral(Handle<JSObject> boilerplate, |
| 4892 int max_depth, | 5022 int max_depth, |
| 4893 int* max_properties) { | 5023 int* max_properties) { |
| 4894 if (boilerplate->map()->is_deprecated()) { | 5024 if (boilerplate->map()->is_deprecated()) { |
| 4895 Handle<Object> result = JSObject::TryMigrateInstance(boilerplate); | 5025 Handle<Object> result = JSObject::TryMigrateInstance(boilerplate); |
| 4896 if (result.is_null()) return false; | 5026 if (result.is_null()) return false; |
| 4897 } | 5027 } |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5021 case ObjectLiteral::Property::COMPUTED: | 5151 case ObjectLiteral::Property::COMPUTED: |
| 5022 if (key->value()->IsInternalizedString()) { | 5152 if (key->value()->IsInternalizedString()) { |
| 5023 if (property->emit_store()) { | 5153 if (property->emit_store()) { |
| 5024 CHECK_ALIVE(VisitForValue(value)); | 5154 CHECK_ALIVE(VisitForValue(value)); |
| 5025 HValue* value = Pop(); | 5155 HValue* value = Pop(); |
| 5026 Handle<Map> map = property->GetReceiverType(); | 5156 Handle<Map> map = property->GetReceiverType(); |
| 5027 Handle<String> name = property->key()->AsPropertyName(); | 5157 Handle<String> name = property->key()->AsPropertyName(); |
| 5028 HInstruction* store; | 5158 HInstruction* store; |
| 5029 if (map.is_null()) { | 5159 if (map.is_null()) { |
| 5030 // If we don't know the monomorphic type, do a generic store. | 5160 // If we don't know the monomorphic type, do a generic store. |
| 5031 CHECK_ALIVE(store = BuildStoreNamedGeneric(literal, name, value)); | 5161 CHECK_ALIVE(store = BuildNamedGeneric( |
| 5162 STORE, literal, name, value)); |
| 5032 } else { | 5163 } else { |
| 5033 #if DEBUG | 5164 PropertyAccessInfo info(this, STORE, ToType(map), name); |
| 5034 Handle<JSFunction> setter; | 5165 if (info.CanAccessMonomorphic()) { |
| 5035 Handle<JSObject> holder; | 5166 HValue* checked_literal = BuildCheckMap(literal, map); |
| 5036 ASSERT(!LookupSetter(map, name, &setter, &holder)); | 5167 ASSERT(!info.lookup()->IsPropertyCallbacks()); |
| 5037 #endif | 5168 store = BuildMonomorphicAccess( |
| 5038 CHECK_ALIVE(store = BuildStoreNamedMonomorphic(literal, | 5169 &info, literal, checked_literal, value, |
| 5039 name, | 5170 BailoutId::None(), BailoutId::None()); |
| 5040 value, | 5171 } else { |
| 5041 map)); | 5172 CHECK_ALIVE(store = BuildNamedGeneric( |
| 5173 STORE, literal, name, value)); |
| 5174 } |
| 5042 } | 5175 } |
| 5043 AddInstruction(store); | 5176 AddInstruction(store); |
| 5044 if (store->HasObservableSideEffects()) { | 5177 if (store->HasObservableSideEffects()) { |
| 5045 Add<HSimulate>(key->id(), REMOVABLE_SIMULATE); | 5178 Add<HSimulate>(key->id(), REMOVABLE_SIMULATE); |
| 5046 } | 5179 } |
| 5047 } else { | 5180 } else { |
| 5048 CHECK_ALIVE(VisitForEffect(value)); | 5181 CHECK_ALIVE(VisitForEffect(value)); |
| 5049 } | 5182 } |
| 5050 break; | 5183 break; |
| 5051 } | 5184 } |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5206 } | 5339 } |
| 5207 | 5340 |
| 5208 | 5341 |
| 5209 HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object, | 5342 HCheckMaps* HOptimizedGraphBuilder::AddCheckMap(HValue* object, |
| 5210 Handle<Map> map) { | 5343 Handle<Map> map) { |
| 5211 BuildCheckHeapObject(object); | 5344 BuildCheckHeapObject(object); |
| 5212 return Add<HCheckMaps>(object, map, top_info()); | 5345 return Add<HCheckMaps>(object, map, top_info()); |
| 5213 } | 5346 } |
| 5214 | 5347 |
| 5215 | 5348 |
| 5349 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedField( |
| 5350 PropertyAccessInfo* info, |
| 5351 HValue* checked_object) { |
| 5352 HObjectAccess access = info->access(); |
| 5353 if (access.representation().IsDouble()) { |
| 5354 // Load the heap number. |
| 5355 checked_object = Add<HLoadNamedField>( |
| 5356 checked_object, static_cast<HValue*>(NULL), |
| 5357 access.WithRepresentation(Representation::Tagged())); |
| 5358 checked_object->set_type(HType::HeapNumber()); |
| 5359 // Load the double value from it. |
| 5360 access = HObjectAccess::ForHeapNumberValue(); |
| 5361 } |
| 5362 return New<HLoadNamedField>( |
| 5363 checked_object, static_cast<HValue*>(NULL), access); |
| 5364 } |
| 5365 |
| 5366 |
| 5216 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( | 5367 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedField( |
| 5368 PropertyAccessInfo* info, |
| 5217 HValue* checked_object, | 5369 HValue* checked_object, |
| 5218 Handle<String> name, | 5370 HValue* value) { |
| 5219 HValue* value, | 5371 bool transition_to_field = info->lookup()->IsTransition(); |
| 5220 Handle<Map> map, | 5372 // TODO(verwaest): Move this logic into PropertyAccessInfo. |
| 5221 LookupResult* lookup) { | 5373 HObjectAccess field_access = HObjectAccess::ForField( |
| 5222 ASSERT(lookup->IsFound()); | 5374 info->map(), info->lookup(), info->name()); |
| 5223 // If the property does not exist yet, we have to check that it wasn't made | |
| 5224 // readonly or turned into a setter by some meanwhile modifications on the | |
| 5225 // prototype chain. | |
| 5226 if (!lookup->IsProperty() && map->prototype()->IsJSReceiver()) { | |
| 5227 Object* proto = map->prototype(); | |
| 5228 // First check that the prototype chain isn't affected already. | |
| 5229 LookupResult proto_result(isolate()); | |
| 5230 proto->Lookup(*name, &proto_result); | |
| 5231 if (proto_result.IsProperty()) { | |
| 5232 // If the inherited property could induce readonly-ness, bail out. | |
| 5233 if (proto_result.IsReadOnly() || !proto_result.IsCacheable()) { | |
| 5234 Bailout(kImproperObjectOnPrototypeChainForStore); | |
| 5235 return NULL; | |
| 5236 } | |
| 5237 // We only need to check up to the preexisting property. | |
| 5238 proto = proto_result.holder(); | |
| 5239 } else { | |
| 5240 // Otherwise, find the top prototype. | |
| 5241 while (proto->GetPrototype(isolate())->IsJSObject()) { | |
| 5242 proto = proto->GetPrototype(isolate()); | |
| 5243 } | |
| 5244 ASSERT(proto->GetPrototype(isolate())->IsNull()); | |
| 5245 } | |
| 5246 ASSERT(proto->IsJSObject()); | |
| 5247 BuildCheckPrototypeMaps( | |
| 5248 Handle<JSObject>(JSObject::cast(map->prototype())), | |
| 5249 Handle<JSObject>(JSObject::cast(proto))); | |
| 5250 } | |
| 5251 | |
| 5252 HObjectAccess field_access = HObjectAccess::ForField(map, lookup, name); | |
| 5253 bool transition_to_field = lookup->IsTransitionToField(*map); | |
| 5254 | 5375 |
| 5255 HStoreNamedField *instr; | 5376 HStoreNamedField *instr; |
| 5256 if (FLAG_track_double_fields && field_access.representation().IsDouble()) { | 5377 if (field_access.representation().IsDouble()) { |
| 5257 HObjectAccess heap_number_access = | 5378 HObjectAccess heap_number_access = |
| 5258 field_access.WithRepresentation(Representation::Tagged()); | 5379 field_access.WithRepresentation(Representation::Tagged()); |
| 5259 if (transition_to_field) { | 5380 if (transition_to_field) { |
| 5260 // The store requires a mutable HeapNumber to be allocated. | 5381 // The store requires a mutable HeapNumber to be allocated. |
| 5261 NoObservableSideEffectsScope no_side_effects(this); | 5382 NoObservableSideEffectsScope no_side_effects(this); |
| 5262 HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize); | 5383 HInstruction* heap_number_size = Add<HConstant>(HeapNumber::kSize); |
| 5384 |
| 5385 PretenureFlag pretenure_flag = !FLAG_allocation_site_pretenuring ? |
| 5386 isolate()->heap()->GetPretenureMode() : NOT_TENURED; |
| 5387 |
| 5263 HInstruction* heap_number = Add<HAllocate>(heap_number_size, | 5388 HInstruction* heap_number = Add<HAllocate>(heap_number_size, |
| 5264 HType::HeapNumber(), isolate()->heap()->GetPretenureMode(), | 5389 HType::HeapNumber(), |
| 5390 pretenure_flag, |
| 5265 HEAP_NUMBER_TYPE); | 5391 HEAP_NUMBER_TYPE); |
| 5266 AddStoreMapConstant(heap_number, isolate()->factory()->heap_number_map()); | 5392 AddStoreMapConstant(heap_number, isolate()->factory()->heap_number_map()); |
| 5267 Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(), | 5393 Add<HStoreNamedField>(heap_number, HObjectAccess::ForHeapNumberValue(), |
| 5268 value); | 5394 value); |
| 5269 instr = New<HStoreNamedField>(checked_object->ActualValue(), | 5395 instr = New<HStoreNamedField>(checked_object->ActualValue(), |
| 5270 heap_number_access, | 5396 heap_number_access, |
| 5271 heap_number); | 5397 heap_number); |
| 5272 } else { | 5398 } else { |
| 5273 // Already holds a HeapNumber; load the box and write its value field. | 5399 // Already holds a HeapNumber; load the box and write its value field. |
| 5274 HInstruction* heap_number = Add<HLoadNamedField>(checked_object, | 5400 HInstruction* heap_number = Add<HLoadNamedField>( |
| 5275 heap_number_access); | 5401 checked_object, static_cast<HValue*>(NULL), heap_number_access); |
| 5276 heap_number->set_type(HType::HeapNumber()); | 5402 heap_number->set_type(HType::HeapNumber()); |
| 5277 instr = New<HStoreNamedField>(heap_number, | 5403 instr = New<HStoreNamedField>(heap_number, |
| 5278 HObjectAccess::ForHeapNumberValue(), | 5404 HObjectAccess::ForHeapNumberValue(), |
| 5279 value); | 5405 value, STORE_TO_INITIALIZED_ENTRY); |
| 5280 } | 5406 } |
| 5281 } else { | 5407 } else { |
| 5282 // This is a normal store. | 5408 // This is a normal store. |
| 5283 instr = New<HStoreNamedField>( | 5409 instr = New<HStoreNamedField>( |
| 5284 checked_object->ActualValue(), field_access, value, | 5410 checked_object->ActualValue(), field_access, value, |
| 5285 transition_to_field ? INITIALIZING_STORE : STORE_TO_INITIALIZED_ENTRY); | 5411 transition_to_field ? INITIALIZING_STORE : STORE_TO_INITIALIZED_ENTRY); |
| 5286 } | 5412 } |
| 5287 | 5413 |
| 5288 if (transition_to_field) { | 5414 if (transition_to_field) { |
| 5289 Handle<Map> transition(lookup->GetTransitionMapFromMap(*map)); | 5415 HConstant* transition_constant = Add<HConstant>(info->transition()); |
| 5290 HConstant* transition_constant = Add<HConstant>(transition); | |
| 5291 instr->SetTransition(transition_constant, top_info()); | 5416 instr->SetTransition(transition_constant, top_info()); |
| 5292 // TODO(fschneider): Record the new map type of the object in the IR to | 5417 instr->SetChangesFlag(kMaps); |
| 5293 // enable elimination of redundant checks after the transition store. | |
| 5294 instr->SetGVNFlag(kChangesMaps); | |
| 5295 } | 5418 } |
| 5296 return instr; | 5419 return instr; |
| 5297 } | 5420 } |
| 5298 | 5421 |
| 5299 | 5422 |
| 5300 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedGeneric( | 5423 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatible( |
| 5301 HValue* object, | 5424 PropertyAccessInfo* info) { |
| 5302 Handle<String> name, | 5425 if (!CanInlinePropertyAccess(type_)) return false; |
| 5303 HValue* value) { | |
| 5304 return New<HStoreNamedGeneric>( | |
| 5305 object, | |
| 5306 name, | |
| 5307 value, | |
| 5308 function_strict_mode_flag()); | |
| 5309 } | |
| 5310 | 5426 |
| 5427 // Currently only handle Type::Number as a polymorphic case. |
| 5428 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber |
| 5429 // instruction. |
| 5430 if (type_->Is(Type::Number())) return false; |
| 5311 | 5431 |
| 5312 // Sets the lookup result and returns true if the load/store can be inlined. | 5432 // Values are only compatible for monomorphic load if they all behave the same |
| 5313 static bool ComputeStoreField(Handle<Map> type, | 5433 // regarding value wrappers. |
| 5314 Handle<String> name, | 5434 if (type_->Is(Type::NumberOrString())) { |
| 5315 LookupResult* lookup, | 5435 if (!info->type_->Is(Type::NumberOrString())) return false; |
| 5316 bool lookup_transition = true) { | 5436 } else { |
| 5317 ASSERT(!type->is_observed()); | 5437 if (info->type_->Is(Type::NumberOrString())) return false; |
| 5318 if (!CanInlinePropertyAccess(*type)) { | |
| 5319 lookup->NotFound(); | |
| 5320 return false; | |
| 5321 } | 5438 } |
| 5322 // If we directly find a field, the access can be inlined. | |
| 5323 type->LookupDescriptor(NULL, *name, lookup); | |
| 5324 if (lookup->IsField()) return true; | |
| 5325 | |
| 5326 if (!lookup_transition) return false; | |
| 5327 | |
| 5328 type->LookupTransition(NULL, *name, lookup); | |
| 5329 return lookup->IsTransitionToField(*type) && | |
| 5330 (type->unused_property_fields() > 0); | |
| 5331 } | |
| 5332 | |
| 5333 | |
| 5334 HInstruction* HOptimizedGraphBuilder::BuildStoreNamedMonomorphic( | |
| 5335 HValue* object, | |
| 5336 Handle<String> name, | |
| 5337 HValue* value, | |
| 5338 Handle<Map> map) { | |
| 5339 // Handle a store to a known field. | |
| 5340 LookupResult lookup(isolate()); | |
| 5341 if (ComputeStoreField(map, name, &lookup)) { | |
| 5342 HCheckMaps* checked_object = AddCheckMap(object, map); | |
| 5343 return BuildStoreNamedField(checked_object, name, value, map, &lookup); | |
| 5344 } | |
| 5345 | |
| 5346 // No luck, do a generic store. | |
| 5347 return BuildStoreNamedGeneric(object, name, value); | |
| 5348 } | |
| 5349 | |
| 5350 | |
| 5351 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad( | |
| 5352 PropertyAccessInfo* info) { | |
| 5353 if (!CanInlinePropertyAccess(*map_)) return false; | |
| 5354 | 5439 |
| 5355 if (!LookupDescriptor()) return false; | 5440 if (!LookupDescriptor()) return false; |
| 5356 | 5441 |
| 5357 if (!lookup_.IsFound()) { | 5442 if (!lookup_.IsFound()) { |
| 5358 return (!info->lookup_.IsFound() || info->has_holder()) && | 5443 return (!info->lookup_.IsFound() || info->has_holder()) && |
| 5359 map_->prototype() == info->map_->prototype(); | 5444 map()->prototype() == info->map()->prototype(); |
| 5360 } | 5445 } |
| 5361 | 5446 |
| 5362 // Mismatch if the other access info found the property in the prototype | 5447 // Mismatch if the other access info found the property in the prototype |
| 5363 // chain. | 5448 // chain. |
| 5364 if (info->has_holder()) return false; | 5449 if (info->has_holder()) return false; |
| 5365 | 5450 |
| 5366 if (lookup_.IsPropertyCallbacks()) { | 5451 if (lookup_.IsPropertyCallbacks()) { |
| 5367 return accessor_.is_identical_to(info->accessor_); | 5452 return accessor_.is_identical_to(info->accessor_) && |
| 5453 api_holder_.is_identical_to(info->api_holder_); |
| 5368 } | 5454 } |
| 5369 | 5455 |
| 5370 if (lookup_.IsConstant()) { | 5456 if (lookup_.IsConstant()) { |
| 5371 return constant_.is_identical_to(info->constant_); | 5457 return constant_.is_identical_to(info->constant_); |
| 5372 } | 5458 } |
| 5373 | 5459 |
| 5374 ASSERT(lookup_.IsField()); | 5460 ASSERT(lookup_.IsField()); |
| 5375 if (!info->lookup_.IsField()) return false; | 5461 if (!info->lookup_.IsField()) return false; |
| 5376 | 5462 |
| 5377 Representation r = access_.representation(); | 5463 Representation r = access_.representation(); |
| 5378 if (!info->access_.representation().IsCompatibleForLoad(r)) return false; | 5464 if (IsLoad()) { |
| 5465 if (!info->access_.representation().IsCompatibleForLoad(r)) return false; |
| 5466 } else { |
| 5467 if (!info->access_.representation().IsCompatibleForStore(r)) return false; |
| 5468 } |
| 5379 if (info->access_.offset() != access_.offset()) return false; | 5469 if (info->access_.offset() != access_.offset()) return false; |
| 5380 if (info->access_.IsInobject() != access_.IsInobject()) return false; | 5470 if (info->access_.IsInobject() != access_.IsInobject()) return false; |
| 5381 info->GeneralizeRepresentation(r); | 5471 info->GeneralizeRepresentation(r); |
| 5382 return true; | 5472 return true; |
| 5383 } | 5473 } |
| 5384 | 5474 |
| 5385 | 5475 |
| 5386 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { | 5476 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { |
| 5387 map_->LookupDescriptor(NULL, *name_, &lookup_); | 5477 if (!type_->IsClass()) return true; |
| 5388 return LoadResult(map_); | 5478 map()->LookupDescriptor(NULL, *name_, &lookup_); |
| 5479 return LoadResult(map()); |
| 5389 } | 5480 } |
| 5390 | 5481 |
| 5391 | 5482 |
| 5392 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { | 5483 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { |
| 5484 if (!IsLoad() && lookup_.IsProperty() && |
| 5485 (lookup_.IsReadOnly() || !lookup_.IsCacheable())) { |
| 5486 return false; |
| 5487 } |
| 5488 |
| 5393 if (lookup_.IsField()) { | 5489 if (lookup_.IsField()) { |
| 5394 access_ = HObjectAccess::ForField(map, &lookup_, name_); | 5490 access_ = HObjectAccess::ForField(map, &lookup_, name_); |
| 5395 } else if (lookup_.IsPropertyCallbacks()) { | 5491 } else if (lookup_.IsPropertyCallbacks()) { |
| 5396 Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate()); | 5492 Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate()); |
| 5397 if (!callback->IsAccessorPair()) return false; | 5493 if (!callback->IsAccessorPair()) return false; |
| 5398 Object* getter = Handle<AccessorPair>::cast(callback)->getter(); | 5494 Object* raw_accessor = IsLoad() |
| 5399 if (!getter->IsJSFunction()) return false; | 5495 ? Handle<AccessorPair>::cast(callback)->getter() |
| 5400 Handle<JSFunction> accessor = handle(JSFunction::cast(getter)); | 5496 : Handle<AccessorPair>::cast(callback)->setter(); |
| 5401 CallOptimization call_optimization(accessor); | 5497 if (!raw_accessor->IsJSFunction()) return false; |
| 5402 // TODO(dcarney): temporary hack unless crankshaft can handle api calls. | 5498 Handle<JSFunction> accessor = handle(JSFunction::cast(raw_accessor)); |
| 5403 if (call_optimization.is_simple_api_call()) return false; | 5499 if (accessor->shared()->IsApiFunction()) { |
| 5500 CallOptimization call_optimization(accessor); |
| 5501 if (!call_optimization.is_simple_api_call()) return false; |
| 5502 CallOptimization::HolderLookup holder_lookup; |
| 5503 api_holder_ = call_optimization.LookupHolderOfExpectedType( |
| 5504 map, &holder_lookup); |
| 5505 switch (holder_lookup) { |
| 5506 case CallOptimization::kHolderNotFound: |
| 5507 return false; |
| 5508 case CallOptimization::kHolderIsReceiver: |
| 5509 case CallOptimization::kHolderFound: |
| 5510 break; |
| 5511 } |
| 5512 } |
| 5404 accessor_ = accessor; | 5513 accessor_ = accessor; |
| 5405 } else if (lookup_.IsConstant()) { | 5514 } else if (lookup_.IsConstant()) { |
| 5406 constant_ = handle(lookup_.GetConstantFromMap(*map), isolate()); | 5515 constant_ = handle(lookup_.GetConstantFromMap(*map), isolate()); |
| 5407 } | 5516 } |
| 5408 | 5517 |
| 5409 return true; | 5518 return true; |
| 5410 } | 5519 } |
| 5411 | 5520 |
| 5412 | 5521 |
| 5413 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { | 5522 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { |
| 5414 Handle<Map> map = map_; | 5523 Handle<Map> map = this->map(); |
| 5524 |
| 5415 while (map->prototype()->IsJSObject()) { | 5525 while (map->prototype()->IsJSObject()) { |
| 5416 holder_ = handle(JSObject::cast(map->prototype())); | 5526 holder_ = handle(JSObject::cast(map->prototype())); |
| 5417 if (holder_->map()->is_deprecated()) { | 5527 if (holder_->map()->is_deprecated()) { |
| 5418 JSObject::TryMigrateInstance(holder_); | 5528 JSObject::TryMigrateInstance(holder_); |
| 5419 } | 5529 } |
| 5420 map = Handle<Map>(holder_->map()); | 5530 map = Handle<Map>(holder_->map()); |
| 5421 if (!CanInlinePropertyAccess(*map)) { | 5531 if (!CanInlinePropertyAccess(ToType(map))) { |
| 5422 lookup_.NotFound(); | 5532 lookup_.NotFound(); |
| 5423 return false; | 5533 return false; |
| 5424 } | 5534 } |
| 5425 map->LookupDescriptor(*holder_, *name_, &lookup_); | 5535 map->LookupDescriptor(*holder_, *name_, &lookup_); |
| 5426 if (lookup_.IsFound()) return LoadResult(map); | 5536 if (lookup_.IsFound()) return LoadResult(map); |
| 5427 } | 5537 } |
| 5428 lookup_.NotFound(); | 5538 lookup_.NotFound(); |
| 5429 return true; | 5539 return true; |
| 5430 } | 5540 } |
| 5431 | 5541 |
| 5432 | 5542 |
| 5433 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() { | 5543 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessMonomorphic() { |
| 5434 if (!CanInlinePropertyAccess(*map_)) return IsStringLength(); | 5544 if (!CanInlinePropertyAccess(type_)) return false; |
| 5435 if (IsJSObjectFieldAccessor()) return true; | 5545 if (IsJSObjectFieldAccessor()) return IsLoad(); |
| 5436 if (!LookupDescriptor()) return false; | 5546 if (!LookupDescriptor()) return false; |
| 5437 if (lookup_.IsFound()) return true; | 5547 if (lookup_.IsFound()) { |
| 5438 return LookupInPrototypes(); | 5548 if (IsLoad()) return true; |
| 5549 return !lookup_.IsReadOnly() && lookup_.IsCacheable(); |
| 5550 } |
| 5551 if (!LookupInPrototypes()) return false; |
| 5552 if (IsLoad()) return true; |
| 5553 |
| 5554 if (lookup_.IsPropertyCallbacks()) return true; |
| 5555 Handle<Map> map = this->map(); |
| 5556 map->LookupTransition(NULL, *name_, &lookup_); |
| 5557 if (lookup_.IsTransitionToField() && map->unused_property_fields() > 0) { |
| 5558 return true; |
| 5559 } |
| 5560 return false; |
| 5439 } | 5561 } |
| 5440 | 5562 |
| 5441 | 5563 |
| 5442 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic( | 5564 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanAccessAsMonomorphic( |
| 5443 SmallMapList* types) { | 5565 SmallMapList* types) { |
| 5444 ASSERT(map_.is_identical_to(types->first())); | 5566 ASSERT(type_->Is(ToType(types->first()))); |
| 5445 if (!CanLoadMonomorphic()) return false; | 5567 if (!CanAccessMonomorphic()) return false; |
| 5568 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism); |
| 5446 if (types->length() > kMaxLoadPolymorphism) return false; | 5569 if (types->length() > kMaxLoadPolymorphism) return false; |
| 5447 | 5570 |
| 5448 if (IsStringLength()) { | 5571 HObjectAccess access = HObjectAccess::ForMap(); // bogus default |
| 5572 if (GetJSObjectFieldAccess(&access)) { |
| 5449 for (int i = 1; i < types->length(); ++i) { | 5573 for (int i = 1; i < types->length(); ++i) { |
| 5450 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; | 5574 PropertyAccessInfo test_info( |
| 5575 builder_, access_type_, ToType(types->at(i)), name_); |
| 5576 HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default |
| 5577 if (!test_info.GetJSObjectFieldAccess(&test_access)) return false; |
| 5578 if (!access.Equals(test_access)) return false; |
| 5451 } | 5579 } |
| 5452 return true; | 5580 return true; |
| 5453 } | 5581 } |
| 5454 | 5582 |
| 5455 if (IsArrayLength()) { | 5583 // Currently only handle Type::Number as a polymorphic case. |
| 5456 bool is_fast = IsFastElementsKind(map_->elements_kind()); | 5584 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber |
| 5457 for (int i = 1; i < types->length(); ++i) { | 5585 // instruction. |
| 5458 Handle<Map> test_map = types->at(i); | 5586 if (type_->Is(Type::Number())) return false; |
| 5459 if (test_map->instance_type() != JS_ARRAY_TYPE) return false; | |
| 5460 if (IsFastElementsKind(test_map->elements_kind()) != is_fast) { | |
| 5461 return false; | |
| 5462 } | |
| 5463 } | |
| 5464 return true; | |
| 5465 } | |
| 5466 | 5587 |
| 5467 if (IsJSObjectFieldAccessor()) { | 5588 // Multiple maps cannot transition to the same target map. |
| 5468 InstanceType instance_type = map_->instance_type(); | 5589 ASSERT(!IsLoad() || !lookup_.IsTransition()); |
| 5469 for (int i = 1; i < types->length(); ++i) { | 5590 if (lookup_.IsTransition() && types->length() > 1) return false; |
| 5470 if (types->at(i)->instance_type() != instance_type) return false; | |
| 5471 } | |
| 5472 return true; | |
| 5473 } | |
| 5474 | 5591 |
| 5475 for (int i = 1; i < types->length(); ++i) { | 5592 for (int i = 1; i < types->length(); ++i) { |
| 5476 PropertyAccessInfo test_info(isolate(), types->at(i), name_); | 5593 PropertyAccessInfo test_info( |
| 5477 if (!test_info.IsCompatibleForLoad(this)) return false; | 5594 builder_, access_type_, ToType(types->at(i)), name_); |
| 5595 if (!test_info.IsCompatible(this)) return false; |
| 5478 } | 5596 } |
| 5479 | 5597 |
| 5480 return true; | 5598 return true; |
| 5481 } | 5599 } |
| 5482 | 5600 |
| 5483 | 5601 |
| 5484 HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic( | 5602 static bool NeedsWrappingFor(Type* type, Handle<JSFunction> target) { |
| 5603 return type->Is(Type::NumberOrString()) && |
| 5604 target->shared()->is_classic_mode() && |
| 5605 !target->shared()->native(); |
| 5606 } |
| 5607 |
| 5608 |
| 5609 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicAccess( |
| 5485 PropertyAccessInfo* info, | 5610 PropertyAccessInfo* info, |
| 5486 HValue* object, | 5611 HValue* object, |
| 5487 HInstruction* checked_object, | 5612 HValue* checked_object, |
| 5613 HValue* value, |
| 5488 BailoutId ast_id, | 5614 BailoutId ast_id, |
| 5489 BailoutId return_id, | 5615 BailoutId return_id, |
| 5490 bool can_inline_accessor) { | 5616 bool can_inline_accessor) { |
| 5491 | 5617 |
| 5492 HObjectAccess access = HObjectAccess::ForMap(); // bogus default | 5618 HObjectAccess access = HObjectAccess::ForMap(); // bogus default |
| 5493 if (info->GetJSObjectFieldAccess(&access)) { | 5619 if (info->GetJSObjectFieldAccess(&access)) { |
| 5494 return New<HLoadNamedField>(checked_object, access); | 5620 ASSERT(info->IsLoad()); |
| 5621 return New<HLoadNamedField>(object, checked_object, access); |
| 5495 } | 5622 } |
| 5496 | 5623 |
| 5497 HValue* checked_holder = checked_object; | 5624 HValue* checked_holder = checked_object; |
| 5498 if (info->has_holder()) { | 5625 if (info->has_holder()) { |
| 5499 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype())); | 5626 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype())); |
| 5500 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); | 5627 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); |
| 5501 } | 5628 } |
| 5502 | 5629 |
| 5503 if (!info->lookup()->IsFound()) return graph()->GetConstantUndefined(); | 5630 if (!info->lookup()->IsFound()) { |
| 5631 ASSERT(info->IsLoad()); |
| 5632 return graph()->GetConstantUndefined(); |
| 5633 } |
| 5504 | 5634 |
| 5505 if (info->lookup()->IsField()) { | 5635 if (info->lookup()->IsField()) { |
| 5506 return BuildLoadNamedField(checked_holder, info->access()); | 5636 if (info->IsLoad()) { |
| 5637 return BuildLoadNamedField(info, checked_holder); |
| 5638 } else { |
| 5639 return BuildStoreNamedField(info, checked_object, value); |
| 5640 } |
| 5641 } |
| 5642 |
| 5643 if (info->lookup()->IsTransition()) { |
| 5644 ASSERT(!info->IsLoad()); |
| 5645 return BuildStoreNamedField(info, checked_object, value); |
| 5507 } | 5646 } |
| 5508 | 5647 |
| 5509 if (info->lookup()->IsPropertyCallbacks()) { | 5648 if (info->lookup()->IsPropertyCallbacks()) { |
| 5510 Push(checked_object); | 5649 Push(checked_object); |
| 5511 if (FLAG_inline_accessors && | 5650 int argument_count = 1; |
| 5512 can_inline_accessor && | 5651 if (!info->IsLoad()) { |
| 5513 TryInlineGetter(info->accessor(), ast_id, return_id)) { | 5652 argument_count = 2; |
| 5514 return NULL; | 5653 Push(value); |
| 5515 } | 5654 } |
| 5516 Add<HPushArgument>(Pop()); | 5655 |
| 5517 return BuildCallConstantFunction(info->accessor(), 1); | 5656 if (NeedsWrappingFor(info->type(), info->accessor())) { |
| 5657 HValue* function = Add<HConstant>(info->accessor()); |
| 5658 PushArgumentsFromEnvironment(argument_count); |
| 5659 return New<HCallFunction>(function, argument_count, WRAP_AND_CALL); |
| 5660 } else if (FLAG_inline_accessors && can_inline_accessor) { |
| 5661 bool success = info->IsLoad() |
| 5662 ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id) |
| 5663 : TryInlineSetter( |
| 5664 info->accessor(), info->map(), ast_id, return_id, value); |
| 5665 if (success) return NULL; |
| 5666 } |
| 5667 |
| 5668 PushArgumentsFromEnvironment(argument_count); |
| 5669 return BuildCallConstantFunction(info->accessor(), argument_count); |
| 5518 } | 5670 } |
| 5519 | 5671 |
| 5520 ASSERT(info->lookup()->IsConstant()); | 5672 ASSERT(info->lookup()->IsConstant()); |
| 5521 return New<HConstant>(info->constant()); | 5673 if (info->IsLoad()) { |
| 5674 return New<HConstant>(info->constant()); |
| 5675 } else { |
| 5676 return New<HCheckValue>(value, Handle<JSFunction>::cast(info->constant())); |
| 5677 } |
| 5522 } | 5678 } |
| 5523 | 5679 |
| 5524 | 5680 |
| 5525 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( | 5681 void HOptimizedGraphBuilder::HandlePolymorphicNamedFieldAccess( |
| 5682 PropertyAccessType access_type, |
| 5526 BailoutId ast_id, | 5683 BailoutId ast_id, |
| 5527 BailoutId return_id, | 5684 BailoutId return_id, |
| 5528 HValue* object, | 5685 HValue* object, |
| 5686 HValue* value, |
| 5529 SmallMapList* types, | 5687 SmallMapList* types, |
| 5530 Handle<String> name) { | 5688 Handle<String> name) { |
| 5531 // Something did not match; must use a polymorphic load. | 5689 // Something did not match; must use a polymorphic load. |
| 5532 int count = 0; | 5690 int count = 0; |
| 5533 HBasicBlock* join = NULL; | 5691 HBasicBlock* join = NULL; |
| 5692 HBasicBlock* number_block = NULL; |
| 5693 bool handled_string = false; |
| 5694 |
| 5695 bool handle_smi = false; |
| 5696 STATIC_ASSERT(kMaxLoadPolymorphism == kMaxStorePolymorphism); |
| 5534 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { | 5697 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
| 5535 PropertyAccessInfo info(isolate(), types->at(i), name); | 5698 PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name); |
| 5536 if (info.CanLoadMonomorphic()) { | 5699 if (info.type()->Is(Type::String())) { |
| 5537 if (count == 0) { | 5700 if (handled_string) continue; |
| 5701 handled_string = true; |
| 5702 } |
| 5703 if (info.CanAccessMonomorphic()) { |
| 5704 count++; |
| 5705 if (info.type()->Is(Type::Number())) { |
| 5706 handle_smi = true; |
| 5707 break; |
| 5708 } |
| 5709 } |
| 5710 } |
| 5711 |
| 5712 count = 0; |
| 5713 HControlInstruction* smi_check = NULL; |
| 5714 handled_string = false; |
| 5715 |
| 5716 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
| 5717 PropertyAccessInfo info(this, access_type, ToType(types->at(i)), name); |
| 5718 if (info.type()->Is(Type::String())) { |
| 5719 if (handled_string) continue; |
| 5720 handled_string = true; |
| 5721 } |
| 5722 if (!info.CanAccessMonomorphic()) continue; |
| 5723 |
| 5724 if (count == 0) { |
| 5725 join = graph()->CreateBasicBlock(); |
| 5726 if (handle_smi) { |
| 5727 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
| 5728 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
| 5729 number_block = graph()->CreateBasicBlock(); |
| 5730 smi_check = New<HIsSmiAndBranch>( |
| 5731 object, empty_smi_block, not_smi_block); |
| 5732 FinishCurrentBlock(smi_check); |
| 5733 GotoNoSimulate(empty_smi_block, number_block); |
| 5734 set_current_block(not_smi_block); |
| 5735 } else { |
| 5538 BuildCheckHeapObject(object); | 5736 BuildCheckHeapObject(object); |
| 5539 join = graph()->CreateBasicBlock(); | |
| 5540 } | 5737 } |
| 5541 ++count; | 5738 } |
| 5542 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 5739 ++count; |
| 5543 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 5740 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 5544 HCompareMap* compare = New<HCompareMap>( | 5741 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 5545 object, info.map(), if_true, if_false); | 5742 HUnaryControlInstruction* compare; |
| 5546 FinishCurrentBlock(compare); | |
| 5547 | 5743 |
| 5548 set_current_block(if_true); | 5744 HValue* dependency; |
| 5745 if (info.type()->Is(Type::Number())) { |
| 5746 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
| 5747 compare = New<HCompareMap>(object, heap_number_map, if_true, if_false); |
| 5748 dependency = smi_check; |
| 5749 } else if (info.type()->Is(Type::String())) { |
| 5750 compare = New<HIsStringAndBranch>(object, if_true, if_false); |
| 5751 dependency = compare; |
| 5752 } else { |
| 5753 compare = New<HCompareMap>(object, info.map(), if_true, if_false); |
| 5754 dependency = compare; |
| 5755 } |
| 5756 FinishCurrentBlock(compare); |
| 5549 | 5757 |
| 5550 HInstruction* load = BuildLoadMonomorphic( | 5758 if (info.type()->Is(Type::Number())) { |
| 5551 &info, object, compare, ast_id, return_id, FLAG_polymorphic_inlining); | 5759 GotoNoSimulate(if_true, number_block); |
| 5552 if (load == NULL) { | 5760 if_true = number_block; |
| 5553 if (HasStackOverflow()) return; | 5761 } |
| 5554 } else { | |
| 5555 if (!load->IsLinked()) { | |
| 5556 AddInstruction(load); | |
| 5557 } | |
| 5558 if (!ast_context()->IsEffect()) Push(load); | |
| 5559 } | |
| 5560 | 5762 |
| 5561 if (current_block() != NULL) Goto(join); | 5763 set_current_block(if_true); |
| 5562 set_current_block(if_false); | 5764 |
| 5765 HInstruction* access = BuildMonomorphicAccess( |
| 5766 &info, object, dependency, value, ast_id, |
| 5767 return_id, FLAG_polymorphic_inlining); |
| 5768 |
| 5769 HValue* result = NULL; |
| 5770 switch (access_type) { |
| 5771 case LOAD: |
| 5772 result = access; |
| 5773 break; |
| 5774 case STORE: |
| 5775 result = value; |
| 5776 break; |
| 5563 } | 5777 } |
| 5778 |
| 5779 if (access == NULL) { |
| 5780 if (HasStackOverflow()) return; |
| 5781 } else { |
| 5782 if (!access->IsLinked()) AddInstruction(access); |
| 5783 if (!ast_context()->IsEffect()) Push(result); |
| 5784 } |
| 5785 |
| 5786 if (current_block() != NULL) Goto(join); |
| 5787 set_current_block(if_false); |
| 5564 } | 5788 } |
| 5565 | 5789 |
| 5566 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 5790 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 5567 // know about and do not want to handle ones we've never seen. Otherwise | 5791 // know about and do not want to handle ones we've never seen. Otherwise |
| 5568 // use a generic IC. | 5792 // use a generic IC. |
| 5569 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 5793 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 5570 // Because the deopt may be the only path in the polymorphic load, make sure | 5794 FinishExitWithHardDeoptimization("Uknown map in polymorphic access"); |
| 5571 // that the environment stack matches the depth on deopt that it otherwise | |
| 5572 // would have had after a successful load. | |
| 5573 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); | |
| 5574 FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); | |
| 5575 } else { | 5795 } else { |
| 5576 HInstruction* load = Add<HLoadNamedGeneric>(object, name); | 5796 HInstruction* instr = BuildNamedGeneric(access_type, object, name, value); |
| 5577 if (!ast_context()->IsEffect()) Push(load); | 5797 AddInstruction(instr); |
| 5798 if (!ast_context()->IsEffect()) Push(access_type == LOAD ? instr : value); |
| 5578 | 5799 |
| 5579 if (join != NULL) { | 5800 if (join != NULL) { |
| 5580 Goto(join); | 5801 Goto(join); |
| 5581 } else { | 5802 } else { |
| 5582 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 5803 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 5583 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | 5804 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 5584 return; | 5805 return; |
| 5585 } | 5806 } |
| 5586 } | 5807 } |
| 5587 | 5808 |
| 5588 ASSERT(join != NULL); | 5809 ASSERT(join != NULL); |
| 5589 join->SetJoinId(ast_id); | 5810 if (join->HasPredecessor()) { |
| 5590 set_current_block(join); | 5811 join->SetJoinId(ast_id); |
| 5591 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | 5812 set_current_block(join); |
| 5592 } | 5813 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); |
| 5593 | |
| 5594 | |
| 5595 bool HOptimizedGraphBuilder::TryStorePolymorphicAsMonomorphic( | |
| 5596 BailoutId assignment_id, | |
| 5597 HValue* object, | |
| 5598 HValue* value, | |
| 5599 SmallMapList* types, | |
| 5600 Handle<String> name) { | |
| 5601 // Use monomorphic store if property lookup results in the same field index | |
| 5602 // for all maps. Requires special map check on the set of all handled maps. | |
| 5603 if (types->length() > kMaxStorePolymorphism) return false; | |
| 5604 | |
| 5605 LookupResult lookup(isolate()); | |
| 5606 int count; | |
| 5607 Representation representation = Representation::None(); | |
| 5608 HObjectAccess access = HObjectAccess::ForMap(); // initial value unused. | |
| 5609 for (count = 0; count < types->length(); ++count) { | |
| 5610 Handle<Map> map = types->at(count); | |
| 5611 // Pass false to ignore transitions. | |
| 5612 if (!ComputeStoreField(map, name, &lookup, false)) break; | |
| 5613 ASSERT(!map->is_observed()); | |
| 5614 | |
| 5615 HObjectAccess new_access = HObjectAccess::ForField(map, &lookup, name); | |
| 5616 Representation new_representation = new_access.representation(); | |
| 5617 | |
| 5618 if (count == 0) { | |
| 5619 // First time through the loop; set access and representation. | |
| 5620 access = new_access; | |
| 5621 representation = new_representation; | |
| 5622 } else if (!representation.IsCompatibleForStore(new_representation)) { | |
| 5623 // Representations did not match. | |
| 5624 break; | |
| 5625 } else if (access.offset() != new_access.offset()) { | |
| 5626 // Offsets did not match. | |
| 5627 break; | |
| 5628 } else if (access.IsInobject() != new_access.IsInobject()) { | |
| 5629 // In-objectness did not match. | |
| 5630 break; | |
| 5631 } | |
| 5632 } | |
| 5633 | |
| 5634 if (count != types->length()) return false; | |
| 5635 | |
| 5636 // Everything matched; can use monomorphic store. | |
| 5637 BuildCheckHeapObject(object); | |
| 5638 HCheckMaps* checked_object = Add<HCheckMaps>(object, types); | |
| 5639 HInstruction* store; | |
| 5640 CHECK_ALIVE_OR_RETURN( | |
| 5641 store = BuildStoreNamedField( | |
| 5642 checked_object, name, value, types->at(count - 1), &lookup), | |
| 5643 true); | |
| 5644 if (!ast_context()->IsEffect()) Push(value); | |
| 5645 AddInstruction(store); | |
| 5646 Add<HSimulate>(assignment_id); | |
| 5647 if (!ast_context()->IsEffect()) Drop(1); | |
| 5648 ast_context()->ReturnValue(value); | |
| 5649 return true; | |
| 5650 } | |
| 5651 | |
| 5652 | |
| 5653 void HOptimizedGraphBuilder::HandlePolymorphicStoreNamedField( | |
| 5654 BailoutId assignment_id, | |
| 5655 HValue* object, | |
| 5656 HValue* value, | |
| 5657 SmallMapList* types, | |
| 5658 Handle<String> name) { | |
| 5659 if (TryStorePolymorphicAsMonomorphic( | |
| 5660 assignment_id, object, value, types, name)) { | |
| 5661 return; | |
| 5662 } | |
| 5663 | |
| 5664 // TODO(ager): We should recognize when the prototype chains for different | |
| 5665 // maps are identical. In that case we can avoid repeatedly generating the | |
| 5666 // same prototype map checks. | |
| 5667 int count = 0; | |
| 5668 HBasicBlock* join = NULL; | |
| 5669 for (int i = 0; i < types->length() && count < kMaxStorePolymorphism; ++i) { | |
| 5670 Handle<Map> map = types->at(i); | |
| 5671 LookupResult lookup(isolate()); | |
| 5672 if (ComputeStoreField(map, name, &lookup)) { | |
| 5673 if (count == 0) { | |
| 5674 BuildCheckHeapObject(object); | |
| 5675 join = graph()->CreateBasicBlock(); | |
| 5676 } | |
| 5677 ++count; | |
| 5678 HBasicBlock* if_true = graph()->CreateBasicBlock(); | |
| 5679 HBasicBlock* if_false = graph()->CreateBasicBlock(); | |
| 5680 HCompareMap* compare = New<HCompareMap>(object, map, if_true, if_false); | |
| 5681 FinishCurrentBlock(compare); | |
| 5682 | |
| 5683 set_current_block(if_true); | |
| 5684 HInstruction* instr; | |
| 5685 CHECK_ALIVE(instr = BuildStoreNamedField( | |
| 5686 compare, name, value, map, &lookup)); | |
| 5687 // Goto will add the HSimulate for the store. | |
| 5688 AddInstruction(instr); | |
| 5689 if (!ast_context()->IsEffect()) Push(value); | |
| 5690 Goto(join); | |
| 5691 | |
| 5692 set_current_block(if_false); | |
| 5693 } | |
| 5694 } | |
| 5695 | |
| 5696 // Finish up. Unconditionally deoptimize if we've handled all the maps we | |
| 5697 // know about and do not want to handle ones we've never seen. Otherwise | |
| 5698 // use a generic IC. | |
| 5699 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | |
| 5700 FinishExitWithHardDeoptimization("Unknown map in polymorphic store", join); | |
| 5701 } else { | 5814 } else { |
| 5702 HInstruction* instr = BuildStoreNamedGeneric(object, name, value); | 5815 set_current_block(NULL); |
| 5703 AddInstruction(instr); | |
| 5704 | |
| 5705 if (join != NULL) { | |
| 5706 if (!ast_context()->IsEffect()) { | |
| 5707 Push(value); | |
| 5708 } | |
| 5709 Goto(join); | |
| 5710 } else { | |
| 5711 // The HSimulate for the store should not see the stored value in | |
| 5712 // effect contexts (it is not materialized at expr->id() in the | |
| 5713 // unoptimized code). | |
| 5714 if (instr->HasObservableSideEffects()) { | |
| 5715 if (ast_context()->IsEffect()) { | |
| 5716 Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE); | |
| 5717 } else { | |
| 5718 Push(value); | |
| 5719 Add<HSimulate>(assignment_id, REMOVABLE_SIMULATE); | |
| 5720 Drop(1); | |
| 5721 } | |
| 5722 } | |
| 5723 return ast_context()->ReturnValue(value); | |
| 5724 } | |
| 5725 } | |
| 5726 | |
| 5727 ASSERT(join != NULL); | |
| 5728 join->SetJoinId(assignment_id); | |
| 5729 set_current_block(join); | |
| 5730 if (!ast_context()->IsEffect()) { | |
| 5731 ast_context()->ReturnValue(Pop()); | |
| 5732 } | 5816 } |
| 5733 } | 5817 } |
| 5734 | 5818 |
| 5735 | 5819 |
| 5736 static bool ComputeReceiverTypes(Expression* expr, | 5820 static bool ComputeReceiverTypes(Expression* expr, |
| 5737 HValue* receiver, | 5821 HValue* receiver, |
| 5738 SmallMapList** t) { | 5822 SmallMapList** t, |
| 5823 Zone* zone) { |
| 5739 SmallMapList* types = expr->GetReceiverTypes(); | 5824 SmallMapList* types = expr->GetReceiverTypes(); |
| 5740 *t = types; | 5825 *t = types; |
| 5741 bool monomorphic = expr->IsMonomorphic(); | 5826 bool monomorphic = expr->IsMonomorphic(); |
| 5742 if (types != NULL && receiver->HasMonomorphicJSObjectType()) { | 5827 if (types != NULL && receiver->HasMonomorphicJSObjectType()) { |
| 5743 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); | 5828 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); |
| 5744 types->FilterForPossibleTransitions(root_map); | 5829 types->FilterForPossibleTransitions(root_map); |
| 5745 monomorphic = types->length() == 1; | 5830 monomorphic = types->length() == 1; |
| 5746 } | 5831 } |
| 5747 return monomorphic && CanInlinePropertyAccess(*types->first()); | 5832 return monomorphic && CanInlinePropertyAccess( |
| 5833 IC::MapToType<Type>(types->first(), zone)); |
| 5748 } | 5834 } |
| 5749 | 5835 |
| 5750 | 5836 |
| 5837 static bool AreStringTypes(SmallMapList* types) { |
| 5838 for (int i = 0; i < types->length(); i++) { |
| 5839 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; |
| 5840 } |
| 5841 return true; |
| 5842 } |
| 5843 |
| 5844 |
| 5751 void HOptimizedGraphBuilder::BuildStore(Expression* expr, | 5845 void HOptimizedGraphBuilder::BuildStore(Expression* expr, |
| 5752 Property* prop, | 5846 Property* prop, |
| 5753 BailoutId ast_id, | 5847 BailoutId ast_id, |
| 5754 BailoutId return_id, | 5848 BailoutId return_id, |
| 5755 bool is_uninitialized) { | 5849 bool is_uninitialized) { |
| 5756 HValue* value = environment()->ExpressionStackAt(0); | |
| 5757 | |
| 5758 if (!prop->key()->IsPropertyName()) { | 5850 if (!prop->key()->IsPropertyName()) { |
| 5759 // Keyed store. | 5851 // Keyed store. |
| 5852 HValue* value = environment()->ExpressionStackAt(0); |
| 5760 HValue* key = environment()->ExpressionStackAt(1); | 5853 HValue* key = environment()->ExpressionStackAt(1); |
| 5761 HValue* object = environment()->ExpressionStackAt(2); | 5854 HValue* object = environment()->ExpressionStackAt(2); |
| 5762 bool has_side_effects = false; | 5855 bool has_side_effects = false; |
| 5763 HandleKeyedElementAccess(object, key, value, expr, | 5856 HandleKeyedElementAccess(object, key, value, expr, |
| 5764 true, // is_store | 5857 STORE, &has_side_effects); |
| 5765 &has_side_effects); | |
| 5766 Drop(3); | 5858 Drop(3); |
| 5767 Push(value); | 5859 Push(value); |
| 5768 Add<HSimulate>(return_id, REMOVABLE_SIMULATE); | 5860 Add<HSimulate>(return_id, REMOVABLE_SIMULATE); |
| 5769 return ast_context()->ReturnValue(Pop()); | 5861 return ast_context()->ReturnValue(Pop()); |
| 5770 } | 5862 } |
| 5771 | 5863 |
| 5772 // Named store. | 5864 // Named store. |
| 5773 HValue* object = environment()->ExpressionStackAt(1); | 5865 HValue* value = Pop(); |
| 5774 | 5866 HValue* object = Pop(); |
| 5775 if (is_uninitialized) { | |
| 5776 Add<HDeoptimize>("Insufficient type feedback for property assignment", | |
| 5777 Deoptimizer::SOFT); | |
| 5778 } | |
| 5779 | 5867 |
| 5780 Literal* key = prop->key()->AsLiteral(); | 5868 Literal* key = prop->key()->AsLiteral(); |
| 5781 Handle<String> name = Handle<String>::cast(key->value()); | 5869 Handle<String> name = Handle<String>::cast(key->value()); |
| 5782 ASSERT(!name.is_null()); | 5870 ASSERT(!name.is_null()); |
| 5783 | 5871 |
| 5784 HInstruction* instr = NULL; | 5872 HInstruction* instr = BuildNamedAccess(STORE, ast_id, return_id, expr, |
| 5785 | 5873 object, name, value, is_uninitialized); |
| 5786 SmallMapList* types; | 5874 if (instr == NULL) return; |
| 5787 bool monomorphic = ComputeReceiverTypes(expr, object, &types); | |
| 5788 | |
| 5789 if (monomorphic) { | |
| 5790 Handle<Map> map = types->first(); | |
| 5791 Handle<JSFunction> setter; | |
| 5792 Handle<JSObject> holder; | |
| 5793 if (LookupSetter(map, name, &setter, &holder)) { | |
| 5794 AddCheckConstantFunction(holder, object, map); | |
| 5795 if (FLAG_inline_accessors && | |
| 5796 TryInlineSetter(setter, ast_id, return_id, value)) { | |
| 5797 return; | |
| 5798 } | |
| 5799 Drop(2); | |
| 5800 Add<HPushArgument>(object); | |
| 5801 Add<HPushArgument>(value); | |
| 5802 instr = BuildCallConstantFunction(setter, 2); | |
| 5803 } else { | |
| 5804 Drop(2); | |
| 5805 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, | |
| 5806 name, | |
| 5807 value, | |
| 5808 map)); | |
| 5809 } | |
| 5810 } else if (types != NULL && types->length() > 1) { | |
| 5811 Drop(2); | |
| 5812 return HandlePolymorphicStoreNamedField(ast_id, object, value, types, name); | |
| 5813 } else { | |
| 5814 Drop(2); | |
| 5815 instr = BuildStoreNamedGeneric(object, name, value); | |
| 5816 } | |
| 5817 | 5875 |
| 5818 if (!ast_context()->IsEffect()) Push(value); | 5876 if (!ast_context()->IsEffect()) Push(value); |
| 5819 AddInstruction(instr); | 5877 AddInstruction(instr); |
| 5820 if (instr->HasObservableSideEffects()) { | 5878 if (instr->HasObservableSideEffects()) { |
| 5821 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 5879 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 5822 } | 5880 } |
| 5823 if (!ast_context()->IsEffect()) Drop(1); | 5881 if (!ast_context()->IsEffect()) Drop(1); |
| 5824 return ast_context()->ReturnValue(value); | 5882 return ast_context()->ReturnValue(value); |
| 5825 } | 5883 } |
| 5826 | 5884 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 5839 | 5897 |
| 5840 | 5898 |
| 5841 // Because not every expression has a position and there is not common | 5899 // Because not every expression has a position and there is not common |
| 5842 // superclass of Assignment and CountOperation, we cannot just pass the | 5900 // superclass of Assignment and CountOperation, we cannot just pass the |
| 5843 // owning expression instead of position and ast_id separately. | 5901 // owning expression instead of position and ast_id separately. |
| 5844 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( | 5902 void HOptimizedGraphBuilder::HandleGlobalVariableAssignment( |
| 5845 Variable* var, | 5903 Variable* var, |
| 5846 HValue* value, | 5904 HValue* value, |
| 5847 BailoutId ast_id) { | 5905 BailoutId ast_id) { |
| 5848 LookupResult lookup(isolate()); | 5906 LookupResult lookup(isolate()); |
| 5849 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, true); | 5907 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, STORE); |
| 5850 if (type == kUseCell) { | 5908 if (type == kUseCell) { |
| 5851 Handle<GlobalObject> global(current_info()->global_object()); | 5909 Handle<GlobalObject> global(current_info()->global_object()); |
| 5852 Handle<PropertyCell> cell(global->GetPropertyCell(&lookup)); | 5910 Handle<PropertyCell> cell(global->GetPropertyCell(&lookup)); |
| 5853 if (cell->type()->IsConstant()) { | 5911 if (cell->type()->IsConstant()) { |
| 5854 IfBuilder builder(this); | 5912 Handle<Object> constant = cell->type()->AsConstant(); |
| 5855 HValue* constant = Add<HConstant>(cell->type()->AsConstant()); | 5913 if (value->IsConstant()) { |
| 5856 if (cell->type()->AsConstant()->IsNumber()) { | 5914 HConstant* c_value = HConstant::cast(value); |
| 5857 builder.If<HCompareNumericAndBranch>(value, constant, Token::EQ); | 5915 if (!constant.is_identical_to(c_value->handle(isolate()))) { |
| 5916 Add<HDeoptimize>("Constant global variable assignment", |
| 5917 Deoptimizer::EAGER); |
| 5918 } |
| 5858 } else { | 5919 } else { |
| 5859 builder.If<HCompareObjectEqAndBranch>(value, constant); | 5920 HValue* c_constant = Add<HConstant>(constant); |
| 5921 IfBuilder builder(this); |
| 5922 if (constant->IsNumber()) { |
| 5923 builder.If<HCompareNumericAndBranch>(value, c_constant, Token::EQ); |
| 5924 } else { |
| 5925 builder.If<HCompareObjectEqAndBranch>(value, c_constant); |
| 5926 } |
| 5927 builder.Then(); |
| 5928 builder.Else(); |
| 5929 Add<HDeoptimize>("Constant global variable assignment", |
| 5930 Deoptimizer::EAGER); |
| 5931 builder.End(); |
| 5860 } | 5932 } |
| 5861 builder.Then(); | |
| 5862 builder.Else(); | |
| 5863 Add<HDeoptimize>("Constant global variable assignment", | |
| 5864 Deoptimizer::EAGER); | |
| 5865 builder.End(); | |
| 5866 } | 5933 } |
| 5867 HInstruction* instr = | 5934 HInstruction* instr = |
| 5868 Add<HStoreGlobalCell>(value, cell, lookup.GetPropertyDetails()); | 5935 Add<HStoreGlobalCell>(value, cell, lookup.GetPropertyDetails()); |
| 5869 if (instr->HasObservableSideEffects()) { | 5936 if (instr->HasObservableSideEffects()) { |
| 5870 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 5937 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 5871 } | 5938 } |
| 5872 } else { | 5939 } else { |
| 5873 HGlobalObject* global_object = Add<HGlobalObject>(); | 5940 HValue* global_object = Add<HLoadNamedField>( |
| 5941 context(), static_cast<HValue*>(NULL), |
| 5942 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); |
| 5874 HStoreNamedGeneric* instr = | 5943 HStoreNamedGeneric* instr = |
| 5875 Add<HStoreNamedGeneric>(global_object, var->name(), | 5944 Add<HStoreNamedGeneric>(global_object, var->name(), |
| 5876 value, function_strict_mode_flag()); | 5945 value, function_strict_mode_flag()); |
| 5877 USE(instr); | 5946 USE(instr); |
| 5878 ASSERT(instr->HasObservableSideEffects()); | 5947 ASSERT(instr->HasObservableSideEffects()); |
| 5879 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 5948 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 5880 } | 5949 } |
| 5881 } | 5950 } |
| 5882 | 5951 |
| 5883 | 5952 |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 5969 CHECK_ALIVE(VisitForValue(prop->key())); | 6038 CHECK_ALIVE(VisitForValue(prop->key())); |
| 5970 key = Top(); | 6039 key = Top(); |
| 5971 } | 6040 } |
| 5972 | 6041 |
| 5973 CHECK_ALIVE(PushLoad(prop, object, key)); | 6042 CHECK_ALIVE(PushLoad(prop, object, key)); |
| 5974 | 6043 |
| 5975 CHECK_ALIVE(VisitForValue(expr->value())); | 6044 CHECK_ALIVE(VisitForValue(expr->value())); |
| 5976 HValue* right = Pop(); | 6045 HValue* right = Pop(); |
| 5977 HValue* left = Pop(); | 6046 HValue* left = Pop(); |
| 5978 | 6047 |
| 5979 Push(BuildBinaryOperation(operation, left, right)); | 6048 Push(BuildBinaryOperation(operation, left, right, PUSH_BEFORE_SIMULATE)); |
| 6049 |
| 5980 BuildStore(expr, prop, expr->id(), | 6050 BuildStore(expr, prop, expr->id(), |
| 5981 expr->AssignmentId(), expr->IsUninitialized()); | 6051 expr->AssignmentId(), expr->IsUninitialized()); |
| 5982 } else { | 6052 } else { |
| 5983 return Bailout(kInvalidLhsInCompoundAssignment); | 6053 return Bailout(kInvalidLhsInCompoundAssignment); |
| 5984 } | 6054 } |
| 5985 } | 6055 } |
| 5986 | 6056 |
| 5987 | 6057 |
| 5988 void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { | 6058 void HOptimizedGraphBuilder::VisitAssignment(Assignment* expr) { |
| 5989 ASSERT(!HasStackOverflow()); | 6059 ASSERT(!HasStackOverflow()); |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6120 ASSERT(!HasStackOverflow()); | 6190 ASSERT(!HasStackOverflow()); |
| 6121 ASSERT(current_block() != NULL); | 6191 ASSERT(current_block() != NULL); |
| 6122 ASSERT(current_block()->HasPredecessor()); | 6192 ASSERT(current_block()->HasPredecessor()); |
| 6123 // We don't optimize functions with invalid left-hand sides in | 6193 // We don't optimize functions with invalid left-hand sides in |
| 6124 // assignments, count operations, or for-in. Consequently throw can | 6194 // assignments, count operations, or for-in. Consequently throw can |
| 6125 // currently only occur in an effect context. | 6195 // currently only occur in an effect context. |
| 6126 ASSERT(ast_context()->IsEffect()); | 6196 ASSERT(ast_context()->IsEffect()); |
| 6127 CHECK_ALIVE(VisitForValue(expr->exception())); | 6197 CHECK_ALIVE(VisitForValue(expr->exception())); |
| 6128 | 6198 |
| 6129 HValue* value = environment()->Pop(); | 6199 HValue* value = environment()->Pop(); |
| 6130 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 6200 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); |
| 6131 Add<HThrow>(value); | 6201 Add<HPushArgument>(value); |
| 6202 Add<HCallRuntime>(isolate()->factory()->empty_string(), |
| 6203 Runtime::FunctionForId(Runtime::kThrow), 1); |
| 6132 Add<HSimulate>(expr->id()); | 6204 Add<HSimulate>(expr->id()); |
| 6133 | 6205 |
| 6134 // If the throw definitely exits the function, we can finish with a dummy | 6206 // If the throw definitely exits the function, we can finish with a dummy |
| 6135 // control flow at this point. This is not the case if the throw is inside | 6207 // control flow at this point. This is not the case if the throw is inside |
| 6136 // an inlined function which may be replaced. | 6208 // an inlined function which may be replaced. |
| 6137 if (call_context() == NULL) { | 6209 if (call_context() == NULL) { |
| 6138 FinishExitCurrentBlock(New<HAbnormalExit>()); | 6210 FinishExitCurrentBlock(New<HAbnormalExit>()); |
| 6139 } | 6211 } |
| 6140 } | 6212 } |
| 6141 | 6213 |
| 6142 | 6214 |
| 6143 HLoadNamedField* HGraphBuilder::BuildLoadNamedField(HValue* object, | |
| 6144 HObjectAccess access) { | |
| 6145 if (FLAG_track_double_fields && access.representation().IsDouble()) { | |
| 6146 // load the heap number | |
| 6147 HLoadNamedField* heap_number = Add<HLoadNamedField>( | |
| 6148 object, access.WithRepresentation(Representation::Tagged())); | |
| 6149 heap_number->set_type(HType::HeapNumber()); | |
| 6150 // load the double value from it | |
| 6151 return New<HLoadNamedField>( | |
| 6152 heap_number, HObjectAccess::ForHeapNumberValue()); | |
| 6153 } | |
| 6154 return New<HLoadNamedField>(object, access); | |
| 6155 } | |
| 6156 | |
| 6157 | |
| 6158 HInstruction* HGraphBuilder::AddLoadNamedField(HValue* object, | |
| 6159 HObjectAccess access) { | |
| 6160 return AddInstruction(BuildLoadNamedField(object, access)); | |
| 6161 } | |
| 6162 | |
| 6163 | |
| 6164 HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) { | 6215 HInstruction* HGraphBuilder::AddLoadStringInstanceType(HValue* string) { |
| 6165 if (string->IsConstant()) { | 6216 if (string->IsConstant()) { |
| 6166 HConstant* c_string = HConstant::cast(string); | 6217 HConstant* c_string = HConstant::cast(string); |
| 6167 if (c_string->HasStringValue()) { | 6218 if (c_string->HasStringValue()) { |
| 6168 return Add<HConstant>(c_string->StringValue()->map()->instance_type()); | 6219 return Add<HConstant>(c_string->StringValue()->map()->instance_type()); |
| 6169 } | 6220 } |
| 6170 } | 6221 } |
| 6171 return AddLoadNamedField( | 6222 return Add<HLoadNamedField>( |
| 6172 AddLoadNamedField(string, HObjectAccess::ForMap()), | 6223 Add<HLoadNamedField>(string, static_cast<HValue*>(NULL), |
| 6173 HObjectAccess::ForMapInstanceType()); | 6224 HObjectAccess::ForMap()), |
| 6225 static_cast<HValue*>(NULL), HObjectAccess::ForMapInstanceType()); |
| 6174 } | 6226 } |
| 6175 | 6227 |
| 6176 | 6228 |
| 6177 HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) { | 6229 HInstruction* HGraphBuilder::AddLoadStringLength(HValue* string) { |
| 6178 if (string->IsConstant()) { | 6230 if (string->IsConstant()) { |
| 6179 HConstant* c_string = HConstant::cast(string); | 6231 HConstant* c_string = HConstant::cast(string); |
| 6180 if (c_string->HasStringValue()) { | 6232 if (c_string->HasStringValue()) { |
| 6181 return Add<HConstant>(c_string->StringValue()->length()); | 6233 return Add<HConstant>(c_string->StringValue()->length()); |
| 6182 } | 6234 } |
| 6183 } | 6235 } |
| 6184 return AddLoadNamedField(string, HObjectAccess::ForStringLength()); | 6236 return Add<HLoadNamedField>(string, static_cast<HValue*>(NULL), |
| 6237 HObjectAccess::ForStringLength()); |
| 6185 } | 6238 } |
| 6186 | 6239 |
| 6187 | 6240 |
| 6188 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( | 6241 HInstruction* HOptimizedGraphBuilder::BuildNamedGeneric( |
| 6242 PropertyAccessType access_type, |
| 6189 HValue* object, | 6243 HValue* object, |
| 6190 Handle<String> name, | 6244 Handle<String> name, |
| 6191 Property* expr) { | 6245 HValue* value, |
| 6192 if (expr->IsUninitialized()) { | 6246 bool is_uninitialized) { |
| 6193 Add<HDeoptimize>("Insufficient type feedback for generic named load", | 6247 if (is_uninitialized) { |
| 6248 Add<HDeoptimize>("Insufficient type feedback for generic named access", |
| 6194 Deoptimizer::SOFT); | 6249 Deoptimizer::SOFT); |
| 6195 } | 6250 } |
| 6196 return New<HLoadNamedGeneric>(object, name); | 6251 if (access_type == LOAD) { |
| 6252 return New<HLoadNamedGeneric>(object, name); |
| 6253 } else { |
| 6254 return New<HStoreNamedGeneric>( |
| 6255 object, name, value, function_strict_mode_flag()); |
| 6256 } |
| 6197 } | 6257 } |
| 6198 | 6258 |
| 6199 | 6259 |
| 6200 | 6260 |
| 6201 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 6261 HInstruction* HOptimizedGraphBuilder::BuildKeyedGeneric( |
| 6202 HValue* key) { | 6262 PropertyAccessType access_type, |
| 6203 return New<HLoadKeyedGeneric>(object, key); | 6263 HValue* object, |
| 6264 HValue* key, |
| 6265 HValue* value) { |
| 6266 if (access_type == LOAD) { |
| 6267 return New<HLoadKeyedGeneric>(object, key); |
| 6268 } else { |
| 6269 return New<HStoreKeyedGeneric>( |
| 6270 object, key, value, function_strict_mode_flag()); |
| 6271 } |
| 6204 } | 6272 } |
| 6205 | 6273 |
| 6206 | 6274 |
| 6207 LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) { | 6275 LoadKeyedHoleMode HOptimizedGraphBuilder::BuildKeyedHoleMode(Handle<Map> map) { |
| 6208 // Loads from a "stock" fast holey double arrays can elide the hole check. | 6276 // Loads from a "stock" fast holey double arrays can elide the hole check. |
| 6209 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE; | 6277 LoadKeyedHoleMode load_mode = NEVER_RETURN_HOLE; |
| 6210 if (*map == isolate()->get_initial_js_array_map(FAST_HOLEY_DOUBLE_ELEMENTS) && | 6278 if (*map == isolate()->get_initial_js_array_map(FAST_HOLEY_DOUBLE_ELEMENTS) && |
| 6211 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { | 6279 isolate()->IsFastArrayConstructorPrototypeChainIntact()) { |
| 6212 Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate()); | 6280 Handle<JSObject> prototype(JSObject::cast(map->prototype()), isolate()); |
| 6213 Handle<JSObject> object_prototype = isolate()->initial_object_prototype(); | 6281 Handle<JSObject> object_prototype = isolate()->initial_object_prototype(); |
| 6214 BuildCheckPrototypeMaps(prototype, object_prototype); | 6282 BuildCheckPrototypeMaps(prototype, object_prototype); |
| 6215 load_mode = ALLOW_RETURN_HOLE; | 6283 load_mode = ALLOW_RETURN_HOLE; |
| 6216 graph()->MarkDependsOnEmptyArrayProtoElements(); | 6284 graph()->MarkDependsOnEmptyArrayProtoElements(); |
| 6217 } | 6285 } |
| 6218 | 6286 |
| 6219 return load_mode; | 6287 return load_mode; |
| 6220 } | 6288 } |
| 6221 | 6289 |
| 6222 | 6290 |
| 6223 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( | 6291 HInstruction* HOptimizedGraphBuilder::BuildMonomorphicElementAccess( |
| 6224 HValue* object, | 6292 HValue* object, |
| 6225 HValue* key, | 6293 HValue* key, |
| 6226 HValue* val, | 6294 HValue* val, |
| 6227 HValue* dependency, | 6295 HValue* dependency, |
| 6228 Handle<Map> map, | 6296 Handle<Map> map, |
| 6229 bool is_store, | 6297 PropertyAccessType access_type, |
| 6230 KeyedAccessStoreMode store_mode) { | 6298 KeyedAccessStoreMode store_mode) { |
| 6231 HCheckMaps* checked_object = Add<HCheckMaps>(object, map, top_info(), | 6299 HCheckMaps* checked_object = Add<HCheckMaps>(object, map, top_info(), |
| 6232 dependency); | 6300 dependency); |
| 6233 if (dependency) { | 6301 if (dependency) { |
| 6234 checked_object->ClearGVNFlag(kDependsOnElementsKind); | 6302 checked_object->ClearDependsOnFlag(kElementsKind); |
| 6235 } | 6303 } |
| 6236 | 6304 |
| 6237 if (is_store && map->prototype()->IsJSObject()) { | 6305 if (access_type == STORE && map->prototype()->IsJSObject()) { |
| 6238 // monomorphic stores need a prototype chain check because shape | 6306 // monomorphic stores need a prototype chain check because shape |
| 6239 // changes could allow callbacks on elements in the chain that | 6307 // changes could allow callbacks on elements in the chain that |
| 6240 // aren't compatible with monomorphic keyed stores. | 6308 // aren't compatible with monomorphic keyed stores. |
| 6241 Handle<JSObject> prototype(JSObject::cast(map->prototype())); | 6309 Handle<JSObject> prototype(JSObject::cast(map->prototype())); |
| 6242 Object* holder = map->prototype(); | 6310 Object* holder = map->prototype(); |
| 6243 while (holder->GetPrototype(isolate())->IsJSObject()) { | 6311 while (holder->GetPrototype(isolate())->IsJSObject()) { |
| 6244 holder = holder->GetPrototype(isolate()); | 6312 holder = holder->GetPrototype(isolate()); |
| 6245 } | 6313 } |
| 6246 ASSERT(holder->GetPrototype(isolate())->IsNull()); | 6314 ASSERT(holder->GetPrototype(isolate())->IsNull()); |
| 6247 | 6315 |
| 6248 BuildCheckPrototypeMaps(prototype, | 6316 BuildCheckPrototypeMaps(prototype, |
| 6249 Handle<JSObject>(JSObject::cast(holder))); | 6317 Handle<JSObject>(JSObject::cast(holder))); |
| 6250 } | 6318 } |
| 6251 | 6319 |
| 6252 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); | 6320 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); |
| 6253 return BuildUncheckedMonomorphicElementAccess( | 6321 return BuildUncheckedMonomorphicElementAccess( |
| 6254 checked_object, key, val, | 6322 checked_object, key, val, |
| 6255 map->instance_type() == JS_ARRAY_TYPE, | 6323 map->instance_type() == JS_ARRAY_TYPE, |
| 6256 map->elements_kind(), is_store, | 6324 map->elements_kind(), access_type, |
| 6257 load_mode, store_mode); | 6325 load_mode, store_mode); |
| 6258 } | 6326 } |
| 6259 | 6327 |
| 6260 | 6328 |
| 6261 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( | 6329 HInstruction* HOptimizedGraphBuilder::TryBuildConsolidatedElementLoad( |
| 6262 HValue* object, | 6330 HValue* object, |
| 6263 HValue* key, | 6331 HValue* key, |
| 6264 HValue* val, | 6332 HValue* val, |
| 6265 SmallMapList* maps) { | 6333 SmallMapList* maps) { |
| 6266 // For polymorphic loads of similar elements kinds (i.e. all tagged or all | 6334 // For polymorphic loads of similar elements kinds (i.e. all tagged or all |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6312 HCheckMaps* checked_object = Add<HCheckMaps>(object, maps); | 6380 HCheckMaps* checked_object = Add<HCheckMaps>(object, maps); |
| 6313 // FAST_ELEMENTS is considered more general than FAST_HOLEY_SMI_ELEMENTS. | 6381 // FAST_ELEMENTS is considered more general than FAST_HOLEY_SMI_ELEMENTS. |
| 6314 // If we've seen both, the consolidated load must use FAST_HOLEY_ELEMENTS. | 6382 // If we've seen both, the consolidated load must use FAST_HOLEY_ELEMENTS. |
| 6315 ElementsKind consolidated_elements_kind = has_seen_holey_elements | 6383 ElementsKind consolidated_elements_kind = has_seen_holey_elements |
| 6316 ? GetHoleyElementsKind(most_general_consolidated_map->elements_kind()) | 6384 ? GetHoleyElementsKind(most_general_consolidated_map->elements_kind()) |
| 6317 : most_general_consolidated_map->elements_kind(); | 6385 : most_general_consolidated_map->elements_kind(); |
| 6318 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( | 6386 HInstruction* instr = BuildUncheckedMonomorphicElementAccess( |
| 6319 checked_object, key, val, | 6387 checked_object, key, val, |
| 6320 most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE, | 6388 most_general_consolidated_map->instance_type() == JS_ARRAY_TYPE, |
| 6321 consolidated_elements_kind, | 6389 consolidated_elements_kind, |
| 6322 false, NEVER_RETURN_HOLE, STANDARD_STORE); | 6390 LOAD, NEVER_RETURN_HOLE, STANDARD_STORE); |
| 6323 return instr; | 6391 return instr; |
| 6324 } | 6392 } |
| 6325 | 6393 |
| 6326 | 6394 |
| 6327 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( | 6395 HValue* HOptimizedGraphBuilder::HandlePolymorphicElementAccess( |
| 6328 HValue* object, | 6396 HValue* object, |
| 6329 HValue* key, | 6397 HValue* key, |
| 6330 HValue* val, | 6398 HValue* val, |
| 6331 SmallMapList* maps, | 6399 SmallMapList* maps, |
| 6332 bool is_store, | 6400 PropertyAccessType access_type, |
| 6333 KeyedAccessStoreMode store_mode, | 6401 KeyedAccessStoreMode store_mode, |
| 6334 bool* has_side_effects) { | 6402 bool* has_side_effects) { |
| 6335 *has_side_effects = false; | 6403 *has_side_effects = false; |
| 6336 BuildCheckHeapObject(object); | 6404 BuildCheckHeapObject(object); |
| 6337 | 6405 |
| 6338 if (!is_store) { | 6406 if (access_type == LOAD) { |
| 6339 HInstruction* consolidated_load = | 6407 HInstruction* consolidated_load = |
| 6340 TryBuildConsolidatedElementLoad(object, key, val, maps); | 6408 TryBuildConsolidatedElementLoad(object, key, val, maps); |
| 6341 if (consolidated_load != NULL) { | 6409 if (consolidated_load != NULL) { |
| 6342 *has_side_effects |= consolidated_load->HasObservableSideEffects(); | 6410 *has_side_effects |= consolidated_load->HasObservableSideEffects(); |
| 6343 return consolidated_load; | 6411 return consolidated_load; |
| 6344 } | 6412 } |
| 6345 } | 6413 } |
| 6346 | 6414 |
| 6347 // Elements_kind transition support. | 6415 // Elements_kind transition support. |
| 6348 MapHandleList transition_target(maps->length()); | 6416 MapHandleList transition_target(maps->length()); |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6381 } | 6449 } |
| 6382 | 6450 |
| 6383 // If only one map is left after transitioning, handle this case | 6451 // If only one map is left after transitioning, handle this case |
| 6384 // monomorphically. | 6452 // monomorphically. |
| 6385 ASSERT(untransitionable_maps.length() >= 1); | 6453 ASSERT(untransitionable_maps.length() >= 1); |
| 6386 if (untransitionable_maps.length() == 1) { | 6454 if (untransitionable_maps.length() == 1) { |
| 6387 Handle<Map> untransitionable_map = untransitionable_maps[0]; | 6455 Handle<Map> untransitionable_map = untransitionable_maps[0]; |
| 6388 HInstruction* instr = NULL; | 6456 HInstruction* instr = NULL; |
| 6389 if (untransitionable_map->has_slow_elements_kind() || | 6457 if (untransitionable_map->has_slow_elements_kind() || |
| 6390 !untransitionable_map->IsJSObjectMap()) { | 6458 !untransitionable_map->IsJSObjectMap()) { |
| 6391 instr = AddInstruction(is_store ? BuildStoreKeyedGeneric(object, key, val) | 6459 instr = AddInstruction(BuildKeyedGeneric(access_type, object, key, val)); |
| 6392 : BuildLoadKeyedGeneric(object, key)); | |
| 6393 } else { | 6460 } else { |
| 6394 instr = BuildMonomorphicElementAccess( | 6461 instr = BuildMonomorphicElementAccess( |
| 6395 object, key, val, transition, untransitionable_map, is_store, | 6462 object, key, val, transition, untransitionable_map, access_type, |
| 6396 store_mode); | 6463 store_mode); |
| 6397 } | 6464 } |
| 6398 *has_side_effects |= instr->HasObservableSideEffects(); | 6465 *has_side_effects |= instr->HasObservableSideEffects(); |
| 6399 return is_store ? NULL : instr; | 6466 return access_type == STORE ? NULL : instr; |
| 6400 } | 6467 } |
| 6401 | 6468 |
| 6402 HBasicBlock* join = graph()->CreateBasicBlock(); | 6469 HBasicBlock* join = graph()->CreateBasicBlock(); |
| 6403 | 6470 |
| 6404 for (int i = 0; i < untransitionable_maps.length(); ++i) { | 6471 for (int i = 0; i < untransitionable_maps.length(); ++i) { |
| 6405 Handle<Map> map = untransitionable_maps[i]; | 6472 Handle<Map> map = untransitionable_maps[i]; |
| 6406 if (!map->IsJSObjectMap()) continue; | 6473 if (!map->IsJSObjectMap()) continue; |
| 6407 ElementsKind elements_kind = map->elements_kind(); | 6474 ElementsKind elements_kind = map->elements_kind(); |
| 6408 HBasicBlock* this_map = graph()->CreateBasicBlock(); | 6475 HBasicBlock* this_map = graph()->CreateBasicBlock(); |
| 6409 HBasicBlock* other_map = graph()->CreateBasicBlock(); | 6476 HBasicBlock* other_map = graph()->CreateBasicBlock(); |
| 6410 HCompareMap* mapcompare = | 6477 HCompareMap* mapcompare = |
| 6411 New<HCompareMap>(object, map, this_map, other_map); | 6478 New<HCompareMap>(object, map, this_map, other_map); |
| 6412 FinishCurrentBlock(mapcompare); | 6479 FinishCurrentBlock(mapcompare); |
| 6413 | 6480 |
| 6414 set_current_block(this_map); | 6481 set_current_block(this_map); |
| 6415 HInstruction* access = NULL; | 6482 HInstruction* access = NULL; |
| 6416 if (IsDictionaryElementsKind(elements_kind)) { | 6483 if (IsDictionaryElementsKind(elements_kind)) { |
| 6417 access = is_store | 6484 access = AddInstruction(BuildKeyedGeneric(access_type, object, key, val)); |
| 6418 ? AddInstruction(BuildStoreKeyedGeneric(object, key, val)) | |
| 6419 : AddInstruction(BuildLoadKeyedGeneric(object, key)); | |
| 6420 } else { | 6485 } else { |
| 6421 ASSERT(IsFastElementsKind(elements_kind) || | 6486 ASSERT(IsFastElementsKind(elements_kind) || |
| 6422 IsExternalArrayElementsKind(elements_kind)); | 6487 IsExternalArrayElementsKind(elements_kind)); |
| 6423 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); | 6488 LoadKeyedHoleMode load_mode = BuildKeyedHoleMode(map); |
| 6424 // Happily, mapcompare is a checked object. | 6489 // Happily, mapcompare is a checked object. |
| 6425 access = BuildUncheckedMonomorphicElementAccess( | 6490 access = BuildUncheckedMonomorphicElementAccess( |
| 6426 mapcompare, key, val, | 6491 mapcompare, key, val, |
| 6427 map->instance_type() == JS_ARRAY_TYPE, | 6492 map->instance_type() == JS_ARRAY_TYPE, |
| 6428 elements_kind, is_store, | 6493 elements_kind, access_type, |
| 6429 load_mode, | 6494 load_mode, |
| 6430 store_mode); | 6495 store_mode); |
| 6431 } | 6496 } |
| 6432 *has_side_effects |= access->HasObservableSideEffects(); | 6497 *has_side_effects |= access->HasObservableSideEffects(); |
| 6433 // The caller will use has_side_effects and add a correct Simulate. | 6498 // The caller will use has_side_effects and add a correct Simulate. |
| 6434 access->SetFlag(HValue::kHasNoObservableSideEffects); | 6499 access->SetFlag(HValue::kHasNoObservableSideEffects); |
| 6435 if (!is_store) { | 6500 if (access_type == LOAD) { |
| 6436 Push(access); | 6501 Push(access); |
| 6437 } | 6502 } |
| 6438 NoObservableSideEffectsScope scope(this); | 6503 NoObservableSideEffectsScope scope(this); |
| 6439 GotoNoSimulate(join); | 6504 GotoNoSimulate(join); |
| 6440 set_current_block(other_map); | 6505 set_current_block(other_map); |
| 6441 } | 6506 } |
| 6442 | 6507 |
| 6508 // Ensure that we visited at least one map above that goes to join. This is |
| 6509 // necessary because FinishExitWithHardDeoptimization does an AbnormalExit |
| 6510 // rather than joining the join block. If this becomes an issue, insert a |
| 6511 // generic access in the case length() == 0. |
| 6512 ASSERT(join->predecessors()->length() > 0); |
| 6443 // Deopt if none of the cases matched. | 6513 // Deopt if none of the cases matched. |
| 6444 NoObservableSideEffectsScope scope(this); | 6514 NoObservableSideEffectsScope scope(this); |
| 6445 FinishExitWithHardDeoptimization("Unknown map in polymorphic element access", | 6515 FinishExitWithHardDeoptimization("Unknown map in polymorphic element access"); |
| 6446 join); | |
| 6447 set_current_block(join); | 6516 set_current_block(join); |
| 6448 return is_store ? NULL : Pop(); | 6517 return access_type == STORE ? NULL : Pop(); |
| 6449 } | 6518 } |
| 6450 | 6519 |
| 6451 | 6520 |
| 6452 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( | 6521 HValue* HOptimizedGraphBuilder::HandleKeyedElementAccess( |
| 6453 HValue* obj, | 6522 HValue* obj, |
| 6454 HValue* key, | 6523 HValue* key, |
| 6455 HValue* val, | 6524 HValue* val, |
| 6456 Expression* expr, | 6525 Expression* expr, |
| 6457 bool is_store, | 6526 PropertyAccessType access_type, |
| 6458 bool* has_side_effects) { | 6527 bool* has_side_effects) { |
| 6459 ASSERT(!expr->IsPropertyName()); | 6528 ASSERT(!expr->IsPropertyName()); |
| 6460 HInstruction* instr = NULL; | 6529 HInstruction* instr = NULL; |
| 6461 | 6530 |
| 6462 SmallMapList* types; | 6531 SmallMapList* types; |
| 6463 bool monomorphic = ComputeReceiverTypes(expr, obj, &types); | 6532 bool monomorphic = ComputeReceiverTypes(expr, obj, &types, zone()); |
| 6464 | 6533 |
| 6465 bool force_generic = false; | 6534 bool force_generic = false; |
| 6466 if (is_store && (monomorphic || (types != NULL && !types->is_empty()))) { | 6535 if (access_type == STORE && |
| 6536 (monomorphic || (types != NULL && !types->is_empty()))) { |
| 6467 // Stores can't be mono/polymorphic if their prototype chain has dictionary | 6537 // Stores can't be mono/polymorphic if their prototype chain has dictionary |
| 6468 // elements. However a receiver map that has dictionary elements itself | 6538 // elements. However a receiver map that has dictionary elements itself |
| 6469 // should be left to normal mono/poly behavior (the other maps may benefit | 6539 // should be left to normal mono/poly behavior (the other maps may benefit |
| 6470 // from highly optimized stores). | 6540 // from highly optimized stores). |
| 6471 for (int i = 0; i < types->length(); i++) { | 6541 for (int i = 0; i < types->length(); i++) { |
| 6472 Handle<Map> current_map = types->at(i); | 6542 Handle<Map> current_map = types->at(i); |
| 6473 if (current_map->DictionaryElementsInPrototypeChainOnly()) { | 6543 if (current_map->DictionaryElementsInPrototypeChainOnly()) { |
| 6474 force_generic = true; | 6544 force_generic = true; |
| 6475 monomorphic = false; | 6545 monomorphic = false; |
| 6476 break; | 6546 break; |
| 6477 } | 6547 } |
| 6478 } | 6548 } |
| 6479 } | 6549 } |
| 6480 | 6550 |
| 6481 if (monomorphic) { | 6551 if (monomorphic) { |
| 6482 Handle<Map> map = types->first(); | 6552 Handle<Map> map = types->first(); |
| 6483 if (map->has_slow_elements_kind()) { | 6553 if (map->has_slow_elements_kind() || !map->IsJSObjectMap()) { |
| 6484 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) | 6554 instr = AddInstruction(BuildKeyedGeneric(access_type, obj, key, val)); |
| 6485 : BuildLoadKeyedGeneric(obj, key); | |
| 6486 AddInstruction(instr); | |
| 6487 } else { | 6555 } else { |
| 6488 BuildCheckHeapObject(obj); | 6556 BuildCheckHeapObject(obj); |
| 6489 instr = BuildMonomorphicElementAccess( | 6557 instr = BuildMonomorphicElementAccess( |
| 6490 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); | 6558 obj, key, val, NULL, map, access_type, expr->GetStoreMode()); |
| 6491 } | 6559 } |
| 6492 } else if (!force_generic && (types != NULL && !types->is_empty())) { | 6560 } else if (!force_generic && (types != NULL && !types->is_empty())) { |
| 6493 return HandlePolymorphicElementAccess( | 6561 return HandlePolymorphicElementAccess( |
| 6494 obj, key, val, types, is_store, | 6562 obj, key, val, types, access_type, |
| 6495 expr->GetStoreMode(), has_side_effects); | 6563 expr->GetStoreMode(), has_side_effects); |
| 6496 } else { | 6564 } else { |
| 6497 if (is_store) { | 6565 if (access_type == STORE) { |
| 6498 if (expr->IsAssignment() && | 6566 if (expr->IsAssignment() && |
| 6499 expr->AsAssignment()->HasNoTypeInformation()) { | 6567 expr->AsAssignment()->HasNoTypeInformation()) { |
| 6500 Add<HDeoptimize>("Insufficient type feedback for keyed store", | 6568 Add<HDeoptimize>("Insufficient type feedback for keyed store", |
| 6501 Deoptimizer::SOFT); | 6569 Deoptimizer::SOFT); |
| 6502 } | 6570 } |
| 6503 instr = BuildStoreKeyedGeneric(obj, key, val); | |
| 6504 } else { | 6571 } else { |
| 6505 if (expr->AsProperty()->HasNoTypeInformation()) { | 6572 if (expr->AsProperty()->HasNoTypeInformation()) { |
| 6506 Add<HDeoptimize>("Insufficient type feedback for keyed load", | 6573 Add<HDeoptimize>("Insufficient type feedback for keyed load", |
| 6507 Deoptimizer::SOFT); | 6574 Deoptimizer::SOFT); |
| 6508 } | 6575 } |
| 6509 instr = BuildLoadKeyedGeneric(obj, key); | |
| 6510 } | 6576 } |
| 6511 AddInstruction(instr); | 6577 instr = AddInstruction(BuildKeyedGeneric(access_type, obj, key, val)); |
| 6512 } | 6578 } |
| 6513 *has_side_effects = instr->HasObservableSideEffects(); | 6579 *has_side_effects = instr->HasObservableSideEffects(); |
| 6514 return instr; | 6580 return instr; |
| 6515 } | 6581 } |
| 6516 | 6582 |
| 6517 | 6583 |
| 6518 HInstruction* HOptimizedGraphBuilder::BuildStoreKeyedGeneric( | |
| 6519 HValue* object, | |
| 6520 HValue* key, | |
| 6521 HValue* value) { | |
| 6522 return New<HStoreKeyedGeneric>( | |
| 6523 object, | |
| 6524 key, | |
| 6525 value, | |
| 6526 function_strict_mode_flag()); | |
| 6527 } | |
| 6528 | |
| 6529 | |
| 6530 void HOptimizedGraphBuilder::EnsureArgumentsArePushedForAccess() { | 6584 void HOptimizedGraphBuilder::EnsureArgumentsArePushedForAccess() { |
| 6531 // Outermost function already has arguments on the stack. | 6585 // Outermost function already has arguments on the stack. |
| 6532 if (function_state()->outer() == NULL) return; | 6586 if (function_state()->outer() == NULL) return; |
| 6533 | 6587 |
| 6534 if (function_state()->arguments_pushed()) return; | 6588 if (function_state()->arguments_pushed()) return; |
| 6535 | 6589 |
| 6536 // Push arguments when entering inlined function. | 6590 // Push arguments when entering inlined function. |
| 6537 HEnterInlined* entry = function_state()->entry(); | 6591 HEnterInlined* entry = function_state()->entry(); |
| 6538 entry->set_arguments_pushed(); | 6592 entry->set_arguments_pushed(); |
| 6539 | 6593 |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 6597 HInstruction* length = Add<HConstant>(argument_count); | 6651 HInstruction* length = Add<HConstant>(argument_count); |
| 6598 HInstruction* checked_key = Add<HBoundsCheck>(key, length); | 6652 HInstruction* checked_key = Add<HBoundsCheck>(key, length); |
| 6599 result = New<HAccessArgumentsAt>(elements, length, checked_key); | 6653 result = New<HAccessArgumentsAt>(elements, length, checked_key); |
| 6600 } | 6654 } |
| 6601 } | 6655 } |
| 6602 ast_context()->ReturnInstruction(result, expr->id()); | 6656 ast_context()->ReturnInstruction(result, expr->id()); |
| 6603 return true; | 6657 return true; |
| 6604 } | 6658 } |
| 6605 | 6659 |
| 6606 | 6660 |
| 6661 HInstruction* HOptimizedGraphBuilder::BuildNamedAccess( |
| 6662 PropertyAccessType access, |
| 6663 BailoutId ast_id, |
| 6664 BailoutId return_id, |
| 6665 Expression* expr, |
| 6666 HValue* object, |
| 6667 Handle<String> name, |
| 6668 HValue* value, |
| 6669 bool is_uninitialized) { |
| 6670 SmallMapList* types; |
| 6671 ComputeReceiverTypes(expr, object, &types, zone()); |
| 6672 ASSERT(types != NULL); |
| 6673 |
| 6674 if (types->length() > 0) { |
| 6675 PropertyAccessInfo info(this, access, ToType(types->first()), name); |
| 6676 if (!info.CanAccessAsMonomorphic(types)) { |
| 6677 HandlePolymorphicNamedFieldAccess( |
| 6678 access, ast_id, return_id, object, value, types, name); |
| 6679 return NULL; |
| 6680 } |
| 6681 |
| 6682 HValue* checked_object; |
| 6683 // Type::Number() is only supported by polymorphic load/call handling. |
| 6684 ASSERT(!info.type()->Is(Type::Number())); |
| 6685 BuildCheckHeapObject(object); |
| 6686 if (AreStringTypes(types)) { |
| 6687 checked_object = |
| 6688 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); |
| 6689 } else { |
| 6690 checked_object = Add<HCheckMaps>(object, types); |
| 6691 } |
| 6692 return BuildMonomorphicAccess( |
| 6693 &info, object, checked_object, value, ast_id, return_id); |
| 6694 } |
| 6695 |
| 6696 return BuildNamedGeneric(access, object, name, value, is_uninitialized); |
| 6697 } |
| 6698 |
| 6699 |
| 6607 void HOptimizedGraphBuilder::PushLoad(Property* expr, | 6700 void HOptimizedGraphBuilder::PushLoad(Property* expr, |
| 6608 HValue* object, | 6701 HValue* object, |
| 6609 HValue* key) { | 6702 HValue* key) { |
| 6610 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); | 6703 ValueContext for_value(this, ARGUMENTS_NOT_ALLOWED); |
| 6611 Push(object); | 6704 Push(object); |
| 6612 if (key != NULL) Push(key); | 6705 if (key != NULL) Push(key); |
| 6613 BuildLoad(expr, expr->LoadId()); | 6706 BuildLoad(expr, expr->LoadId()); |
| 6614 } | 6707 } |
| 6615 | 6708 |
| 6616 | 6709 |
| 6617 static bool AreStringTypes(SmallMapList* types) { | |
| 6618 for (int i = 0; i < types->length(); i++) { | |
| 6619 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; | |
| 6620 } | |
| 6621 return true; | |
| 6622 } | |
| 6623 | |
| 6624 | |
| 6625 void HOptimizedGraphBuilder::BuildLoad(Property* expr, | 6710 void HOptimizedGraphBuilder::BuildLoad(Property* expr, |
| 6626 BailoutId ast_id) { | 6711 BailoutId ast_id) { |
| 6627 HInstruction* instr = NULL; | 6712 HInstruction* instr = NULL; |
| 6628 if (expr->IsStringAccess()) { | 6713 if (expr->IsStringAccess()) { |
| 6629 HValue* index = Pop(); | 6714 HValue* index = Pop(); |
| 6630 HValue* string = Pop(); | 6715 HValue* string = Pop(); |
| 6631 HInstruction* char_code = BuildStringCharCodeAt(string, index); | 6716 HInstruction* char_code = BuildStringCharCodeAt(string, index); |
| 6632 AddInstruction(char_code); | 6717 AddInstruction(char_code); |
| 6633 instr = NewUncasted<HStringCharFromCode>(char_code); | 6718 instr = NewUncasted<HStringCharFromCode>(char_code); |
| 6634 | 6719 |
| 6635 } else if (expr->IsFunctionPrototype()) { | 6720 } else if (expr->IsFunctionPrototype()) { |
| 6636 HValue* function = Pop(); | 6721 HValue* function = Pop(); |
| 6637 BuildCheckHeapObject(function); | 6722 BuildCheckHeapObject(function); |
| 6638 instr = New<HLoadFunctionPrototype>(function); | 6723 instr = New<HLoadFunctionPrototype>(function); |
| 6639 | 6724 |
| 6640 } else if (expr->key()->IsPropertyName()) { | 6725 } else if (expr->key()->IsPropertyName()) { |
| 6641 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 6726 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
| 6642 HValue* object = Pop(); | 6727 HValue* object = Pop(); |
| 6643 | 6728 |
| 6644 SmallMapList* types; | 6729 instr = BuildNamedAccess(LOAD, ast_id, expr->LoadId(), expr, |
| 6645 ComputeReceiverTypes(expr, object, &types); | 6730 object, name, NULL, expr->IsUninitialized()); |
| 6646 ASSERT(types != NULL); | 6731 if (instr == NULL) return; |
| 6647 | 6732 if (instr->IsLinked()) return ast_context()->ReturnValue(instr); |
| 6648 if (types->length() > 0) { | |
| 6649 PropertyAccessInfo info(isolate(), types->first(), name); | |
| 6650 if (!info.CanLoadAsMonomorphic(types)) { | |
| 6651 return HandlePolymorphicLoadNamedField( | |
| 6652 ast_id, expr->LoadId(), object, types, name); | |
| 6653 } | |
| 6654 | |
| 6655 BuildCheckHeapObject(object); | |
| 6656 HInstruction* checked_object; | |
| 6657 if (AreStringTypes(types)) { | |
| 6658 checked_object = | |
| 6659 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); | |
| 6660 } else { | |
| 6661 checked_object = Add<HCheckMaps>(object, types); | |
| 6662 } | |
| 6663 instr = BuildLoadMonomorphic( | |
| 6664 &info, object, checked_object, ast_id, expr->LoadId()); | |
| 6665 if (instr == NULL) return; | |
| 6666 if (instr->IsLinked()) return ast_context()->ReturnValue(instr); | |
| 6667 } else { | |
| 6668 instr = BuildLoadNamedGeneric(object, name, expr); | |
| 6669 } | |
| 6670 | 6733 |
| 6671 } else { | 6734 } else { |
| 6672 HValue* key = Pop(); | 6735 HValue* key = Pop(); |
| 6673 HValue* obj = Pop(); | 6736 HValue* obj = Pop(); |
| 6674 | 6737 |
| 6675 bool has_side_effects = false; | 6738 bool has_side_effects = false; |
| 6676 HValue* load = HandleKeyedElementAccess( | 6739 HValue* load = HandleKeyedElementAccess( |
| 6677 obj, key, NULL, expr, | 6740 obj, key, NULL, expr, LOAD, &has_side_effects); |
| 6678 false, // is_store | |
| 6679 &has_side_effects); | |
| 6680 if (has_side_effects) { | 6741 if (has_side_effects) { |
| 6681 if (ast_context()->IsEffect()) { | 6742 if (ast_context()->IsEffect()) { |
| 6682 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 6743 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 6683 } else { | 6744 } else { |
| 6684 Push(load); | 6745 Push(load); |
| 6685 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); | 6746 Add<HSimulate>(ast_id, REMOVABLE_SIMULATE); |
| 6686 Drop(1); | 6747 Drop(1); |
| 6687 } | 6748 } |
| 6688 } | 6749 } |
| 6689 return ast_context()->ReturnValue(load); | 6750 return ast_context()->ReturnValue(load); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 6715 | 6776 |
| 6716 if (constant->map()->CanOmitMapChecks()) { | 6777 if (constant->map()->CanOmitMapChecks()) { |
| 6717 constant->map()->AddDependentCompilationInfo( | 6778 constant->map()->AddDependentCompilationInfo( |
| 6718 DependentCode::kPrototypeCheckGroup, info); | 6779 DependentCode::kPrototypeCheckGroup, info); |
| 6719 return constant_value; | 6780 return constant_value; |
| 6720 } | 6781 } |
| 6721 | 6782 |
| 6722 AddInstruction(constant_value); | 6783 AddInstruction(constant_value); |
| 6723 HCheckMaps* check = | 6784 HCheckMaps* check = |
| 6724 Add<HCheckMaps>(constant_value, handle(constant->map()), info); | 6785 Add<HCheckMaps>(constant_value, handle(constant->map()), info); |
| 6725 check->ClearGVNFlag(kDependsOnElementsKind); | 6786 check->ClearDependsOnFlag(kElementsKind); |
| 6726 return check; | 6787 return check; |
| 6727 } | 6788 } |
| 6728 | 6789 |
| 6729 | 6790 |
| 6730 HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype, | 6791 HInstruction* HGraphBuilder::BuildCheckPrototypeMaps(Handle<JSObject> prototype, |
| 6731 Handle<JSObject> holder) { | 6792 Handle<JSObject> holder) { |
| 6732 while (!prototype.is_identical_to(holder)) { | 6793 while (!prototype.is_identical_to(holder)) { |
| 6733 BuildConstantMapCheck(prototype, top_info()); | 6794 BuildConstantMapCheck(prototype, top_info()); |
| 6734 prototype = handle(JSObject::cast(prototype->GetPrototype())); | 6795 prototype = handle(JSObject::cast(prototype->GetPrototype())); |
| 6735 } | 6796 } |
| 6736 | 6797 |
| 6737 HInstruction* checked_object = BuildConstantMapCheck(prototype, top_info()); | 6798 HInstruction* checked_object = BuildConstantMapCheck(prototype, top_info()); |
| 6738 if (!checked_object->IsLinked()) AddInstruction(checked_object); | 6799 if (!checked_object->IsLinked()) AddInstruction(checked_object); |
| 6739 return checked_object; | 6800 return checked_object; |
| 6740 } | 6801 } |
| 6741 | 6802 |
| 6742 | 6803 |
| 6743 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, | 6804 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, |
| 6744 Handle<Map> receiver_map) { | 6805 Handle<Map> receiver_map) { |
| 6745 if (!holder.is_null()) { | 6806 if (!holder.is_null()) { |
| 6746 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); | 6807 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); |
| 6747 BuildCheckPrototypeMaps(prototype, holder); | 6808 BuildCheckPrototypeMaps(prototype, holder); |
| 6748 } | 6809 } |
| 6749 } | 6810 } |
| 6750 | 6811 |
| 6751 | 6812 |
| 6752 void HOptimizedGraphBuilder::AddCheckConstantFunction( | |
| 6753 Handle<JSObject> holder, | |
| 6754 HValue* receiver, | |
| 6755 Handle<Map> receiver_map) { | |
| 6756 // Constant functions have the nice property that the map will change if they | |
| 6757 // are overwritten. Therefore it is enough to check the map of the holder and | |
| 6758 // its prototypes. | |
| 6759 AddCheckMap(receiver, receiver_map); | |
| 6760 AddCheckPrototypeMaps(holder, receiver_map); | |
| 6761 } | |
| 6762 | |
| 6763 | |
| 6764 HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall( | 6813 HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall( |
| 6765 HValue* fun, int argument_count, bool pass_argument_count) { | 6814 HValue* fun, int argument_count, bool pass_argument_count) { |
| 6766 return New<HCallJSFunction>( | 6815 return New<HCallJSFunction>( |
| 6767 fun, argument_count, pass_argument_count); | 6816 fun, argument_count, pass_argument_count); |
| 6768 } | 6817 } |
| 6769 | 6818 |
| 6770 | 6819 |
| 6771 HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall( | 6820 HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall( |
| 6772 HValue* fun, HValue* context, | 6821 HValue* fun, HValue* context, |
| 6773 int argument_count, HValue* expected_param_count) { | 6822 int argument_count, HValue* expected_param_count) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 6794 // For constant functions, we try to avoid calling the | 6843 // For constant functions, we try to avoid calling the |
| 6795 // argument adaptor and instead call the function directly | 6844 // argument adaptor and instead call the function directly |
| 6796 int formal_parameter_count = jsfun->shared()->formal_parameter_count(); | 6845 int formal_parameter_count = jsfun->shared()->formal_parameter_count(); |
| 6797 bool dont_adapt_arguments = | 6846 bool dont_adapt_arguments = |
| 6798 (formal_parameter_count == | 6847 (formal_parameter_count == |
| 6799 SharedFunctionInfo::kDontAdaptArgumentsSentinel); | 6848 SharedFunctionInfo::kDontAdaptArgumentsSentinel); |
| 6800 int arity = argument_count - 1; | 6849 int arity = argument_count - 1; |
| 6801 bool can_invoke_directly = | 6850 bool can_invoke_directly = |
| 6802 dont_adapt_arguments || formal_parameter_count == arity; | 6851 dont_adapt_arguments || formal_parameter_count == arity; |
| 6803 if (can_invoke_directly) { | 6852 if (can_invoke_directly) { |
| 6853 if (jsfun.is_identical_to(current_info()->closure())) { |
| 6854 graph()->MarkRecursive(); |
| 6855 } |
| 6804 return NewPlainFunctionCall(target, argument_count, dont_adapt_arguments); | 6856 return NewPlainFunctionCall(target, argument_count, dont_adapt_arguments); |
| 6805 } else { | 6857 } else { |
| 6806 HValue* param_count_value = Add<HConstant>(formal_parameter_count); | 6858 HValue* param_count_value = Add<HConstant>(formal_parameter_count); |
| 6807 HValue* context = Add<HLoadNamedField>(target, | 6859 HValue* context = Add<HLoadNamedField>( |
| 6860 target, static_cast<HValue*>(NULL), |
| 6808 HObjectAccess::ForFunctionContextPointer()); | 6861 HObjectAccess::ForFunctionContextPointer()); |
| 6809 return NewArgumentAdaptorCall(target, context, | 6862 return NewArgumentAdaptorCall(target, context, |
| 6810 argument_count, param_count_value); | 6863 argument_count, param_count_value); |
| 6811 } | 6864 } |
| 6812 UNREACHABLE(); | 6865 UNREACHABLE(); |
| 6813 return NULL; | 6866 return NULL; |
| 6814 } | 6867 } |
| 6815 | 6868 |
| 6816 | 6869 |
| 6817 HInstruction* HOptimizedGraphBuilder::NewCallNamed( | |
| 6818 Handle<String> name, int argument_count) { | |
| 6819 CallInterfaceDescriptor* descriptor = | |
| 6820 isolate()->call_descriptor(Isolate::NamedCall); | |
| 6821 HValue* op_vals[] = { context(), Add<HConstant>(name) }; | |
| 6822 int arity = argument_count - 1; | |
| 6823 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity); | |
| 6824 | |
| 6825 return New<HCallWithDescriptor>( | |
| 6826 Add<HConstant>(ic), argument_count, descriptor, | |
| 6827 Vector<HValue*>(op_vals, descriptor->environment_length())); | |
| 6828 } | |
| 6829 | |
| 6830 | |
| 6831 HInstruction* HOptimizedGraphBuilder::NewCallKeyed( | |
| 6832 HValue* key, int argument_count) { | |
| 6833 CallInterfaceDescriptor* descriptor = | |
| 6834 isolate()->call_descriptor(Isolate::KeyedCall); | |
| 6835 HValue* op_vals[] = { context(), key }; | |
| 6836 int arity = argument_count - 1; | |
| 6837 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(arity); | |
| 6838 | |
| 6839 return New<HCallWithDescriptor>( | |
| 6840 Add<HConstant>(ic), argument_count, descriptor, | |
| 6841 Vector<HValue*>(op_vals, descriptor->environment_length())); | |
| 6842 } | |
| 6843 | |
| 6844 class FunctionSorter { | |
| 6845 public: | |
| 6846 FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { } | |
| 6847 FunctionSorter(int index, int ticks, int ast_length, int src_length) | |
| 6848 : index_(index), | |
| 6849 ticks_(ticks), | |
| 6850 ast_length_(ast_length), | |
| 6851 src_length_(src_length) { } | |
| 6852 | |
| 6853 int index() const { return index_; } | |
| 6854 int ticks() const { return ticks_; } | |
| 6855 int ast_length() const { return ast_length_; } | |
| 6856 int src_length() const { return src_length_; } | |
| 6857 | |
| 6858 private: | |
| 6859 int index_; | |
| 6860 int ticks_; | |
| 6861 int ast_length_; | |
| 6862 int src_length_; | |
| 6863 }; | |
| 6864 | |
| 6865 | |
| 6866 inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) { | |
| 6867 int diff = lhs.ticks() - rhs.ticks(); | |
| 6868 if (diff != 0) return diff > 0; | |
| 6869 diff = lhs.ast_length() - rhs.ast_length(); | |
| 6870 if (diff != 0) return diff < 0; | |
| 6871 return lhs.src_length() < rhs.src_length(); | |
| 6872 } | |
| 6873 | |
| 6874 | |
| 6875 bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic( | |
| 6876 Call* expr, | |
| 6877 HValue* receiver, | |
| 6878 SmallMapList* types, | |
| 6879 Handle<String> name) { | |
| 6880 if (types->length() > kMaxCallPolymorphism) return false; | |
| 6881 | |
| 6882 PropertyAccessInfo info(isolate(), types->at(0), name); | |
| 6883 if (!info.CanLoadAsMonomorphic(types)) return false; | |
| 6884 if (!expr->ComputeTarget(info.map(), name)) return false; | |
| 6885 | |
| 6886 BuildCheckHeapObject(receiver); | |
| 6887 Add<HCheckMaps>(receiver, types); | |
| 6888 AddCheckPrototypeMaps(expr->holder(), info.map()); | |
| 6889 if (FLAG_trace_inlining) { | |
| 6890 Handle<JSFunction> caller = current_info()->closure(); | |
| 6891 SmartArrayPointer<char> caller_name = | |
| 6892 caller->shared()->DebugName()->ToCString(); | |
| 6893 PrintF("Trying to inline the polymorphic call to %s from %s\n", | |
| 6894 name->ToCString().get(), caller_name.get()); | |
| 6895 } | |
| 6896 | |
| 6897 if (!TryInlineCall(expr)) { | |
| 6898 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | |
| 6899 HInstruction* call = BuildCallConstantFunction( | |
| 6900 expr->target(), argument_count); | |
| 6901 PushArgumentsFromEnvironment(argument_count); | |
| 6902 AddInstruction(call); | |
| 6903 if (!ast_context()->IsEffect()) Push(call); | |
| 6904 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | |
| 6905 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | |
| 6906 } | |
| 6907 | |
| 6908 return true; | |
| 6909 } | |
| 6910 | |
| 6911 | |
| 6912 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( | 6870 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
| 6913 Call* expr, | 6871 Call* expr, |
| 6914 HValue* receiver, | 6872 HValue* receiver, |
| 6915 SmallMapList* types, | 6873 SmallMapList* types, |
| 6916 Handle<String> name) { | 6874 Handle<String> name) { |
| 6917 if (TryCallPolymorphicAsMonomorphic(expr, receiver, types, name)) return; | |
| 6918 | |
| 6919 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 6875 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
| 6920 HBasicBlock* join = NULL; | 6876 int order[kMaxCallPolymorphism]; |
| 6921 FunctionSorter order[kMaxCallPolymorphism]; | |
| 6922 int ordered_functions = 0; | |
| 6923 | |
| 6924 Handle<Map> initial_string_map( | |
| 6925 isolate()->native_context()->string_function()->initial_map()); | |
| 6926 Handle<Map> string_marker_map( | |
| 6927 JSObject::cast(initial_string_map->prototype())->map()); | |
| 6928 Handle<Map> initial_number_map( | |
| 6929 isolate()->native_context()->number_function()->initial_map()); | |
| 6930 Handle<Map> number_marker_map( | |
| 6931 JSObject::cast(initial_number_map->prototype())->map()); | |
| 6932 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); | |
| 6933 | 6877 |
| 6934 bool handle_smi = false; | 6878 bool handle_smi = false; |
| 6879 bool handled_string = false; |
| 6880 int ordered_functions = 0; |
| 6935 | 6881 |
| 6936 for (int i = 0; | 6882 for (int i = 0; |
| 6937 i < types->length() && ordered_functions < kMaxCallPolymorphism; | 6883 i < types->length() && ordered_functions < kMaxCallPolymorphism; |
| 6938 ++i) { | 6884 ++i) { |
| 6939 Handle<Map> map = types->at(i); | 6885 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); |
| 6940 if (expr->ComputeTarget(map, name)) { | 6886 if (info.CanAccessMonomorphic() && |
| 6941 if (map.is_identical_to(number_marker_map)) handle_smi = true; | 6887 info.lookup()->IsConstant() && |
| 6942 order[ordered_functions++] = | 6888 info.constant()->IsJSFunction()) { |
| 6943 FunctionSorter(i, | 6889 if (info.type()->Is(Type::String())) { |
| 6944 expr->target()->shared()->profiler_ticks(), | 6890 if (handled_string) continue; |
| 6945 InliningAstSize(expr->target()), | 6891 handled_string = true; |
| 6946 expr->target()->shared()->SourceSize()); | 6892 } |
| 6893 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); |
| 6894 if (info.type()->Is(Type::Number())) { |
| 6895 handle_smi = true; |
| 6896 } |
| 6897 expr->set_target(target); |
| 6898 order[ordered_functions++] = i; |
| 6947 } | 6899 } |
| 6948 } | 6900 } |
| 6949 | 6901 |
| 6950 std::sort(order, order + ordered_functions); | |
| 6951 | |
| 6952 HBasicBlock* number_block = NULL; | 6902 HBasicBlock* number_block = NULL; |
| 6903 HBasicBlock* join = NULL; |
| 6904 handled_string = false; |
| 6905 int count = 0; |
| 6953 | 6906 |
| 6954 for (int fn = 0; fn < ordered_functions; ++fn) { | 6907 for (int fn = 0; fn < ordered_functions; ++fn) { |
| 6955 int i = order[fn].index(); | 6908 int i = order[fn]; |
| 6956 Handle<Map> map = types->at(i); | 6909 PropertyAccessInfo info(this, LOAD, ToType(types->at(i)), name); |
| 6957 if (fn == 0) { | 6910 if (info.type()->Is(Type::String())) { |
| 6911 if (handled_string) continue; |
| 6912 handled_string = true; |
| 6913 } |
| 6914 // Reloads the target. |
| 6915 info.CanAccessMonomorphic(); |
| 6916 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); |
| 6917 |
| 6918 expr->set_target(target); |
| 6919 if (count == 0) { |
| 6958 // Only needed once. | 6920 // Only needed once. |
| 6959 join = graph()->CreateBasicBlock(); | 6921 join = graph()->CreateBasicBlock(); |
| 6960 if (handle_smi) { | 6922 if (handle_smi) { |
| 6961 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); | 6923 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
| 6962 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); | 6924 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
| 6963 number_block = graph()->CreateBasicBlock(); | 6925 number_block = graph()->CreateBasicBlock(); |
| 6964 FinishCurrentBlock(New<HIsSmiAndBranch>( | 6926 FinishCurrentBlock(New<HIsSmiAndBranch>( |
| 6965 receiver, empty_smi_block, not_smi_block)); | 6927 receiver, empty_smi_block, not_smi_block)); |
| 6966 Goto(empty_smi_block, number_block); | 6928 GotoNoSimulate(empty_smi_block, number_block); |
| 6967 set_current_block(not_smi_block); | 6929 set_current_block(not_smi_block); |
| 6968 } else { | 6930 } else { |
| 6969 BuildCheckHeapObject(receiver); | 6931 BuildCheckHeapObject(receiver); |
| 6970 } | 6932 } |
| 6971 } | 6933 } |
| 6934 ++count; |
| 6972 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 6935 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 6973 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 6936 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 6974 HUnaryControlInstruction* compare; | 6937 HUnaryControlInstruction* compare; |
| 6975 | 6938 |
| 6976 if (handle_smi && map.is_identical_to(number_marker_map)) { | 6939 Handle<Map> map = info.map(); |
| 6940 if (info.type()->Is(Type::Number())) { |
| 6941 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
| 6977 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); | 6942 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); |
| 6978 map = initial_number_map; | 6943 } else if (info.type()->Is(Type::String())) { |
| 6979 expr->set_number_check( | |
| 6980 Handle<JSObject>(JSObject::cast(map->prototype()))); | |
| 6981 } else if (map.is_identical_to(string_marker_map)) { | |
| 6982 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); | 6944 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); |
| 6983 map = initial_string_map; | |
| 6984 expr->set_string_check( | |
| 6985 Handle<JSObject>(JSObject::cast(map->prototype()))); | |
| 6986 } else { | 6945 } else { |
| 6987 compare = New<HCompareMap>(receiver, map, if_true, if_false); | 6946 compare = New<HCompareMap>(receiver, map, if_true, if_false); |
| 6988 expr->set_map_check(); | 6947 } |
| 6948 FinishCurrentBlock(compare); |
| 6949 |
| 6950 if (info.type()->Is(Type::Number())) { |
| 6951 GotoNoSimulate(if_true, number_block); |
| 6952 if_true = number_block; |
| 6989 } | 6953 } |
| 6990 | 6954 |
| 6991 FinishCurrentBlock(compare); | |
| 6992 | |
| 6993 if (expr->check_type() == NUMBER_CHECK) { | |
| 6994 Goto(if_true, number_block); | |
| 6995 if_true = number_block; | |
| 6996 number_block->SetJoinId(expr->id()); | |
| 6997 } | |
| 6998 set_current_block(if_true); | 6955 set_current_block(if_true); |
| 6999 | 6956 |
| 7000 expr->ComputeTarget(map, name); | 6957 AddCheckPrototypeMaps(info.holder(), map); |
| 7001 AddCheckPrototypeMaps(expr->holder(), map); | 6958 |
| 7002 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 6959 HValue* function = Add<HConstant>(expr->target()); |
| 6960 environment()->SetExpressionStackAt(0, function); |
| 6961 Push(receiver); |
| 6962 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 6963 bool needs_wrapping = NeedsWrappingFor(info.type(), target); |
| 6964 bool try_inline = FLAG_polymorphic_inlining && !needs_wrapping; |
| 6965 if (FLAG_trace_inlining && try_inline) { |
| 7003 Handle<JSFunction> caller = current_info()->closure(); | 6966 Handle<JSFunction> caller = current_info()->closure(); |
| 7004 SmartArrayPointer<char> caller_name = | 6967 SmartArrayPointer<char> caller_name = |
| 7005 caller->shared()->DebugName()->ToCString(); | 6968 caller->shared()->DebugName()->ToCString(); |
| 7006 PrintF("Trying to inline the polymorphic call to %s from %s\n", | 6969 PrintF("Trying to inline the polymorphic call to %s from %s\n", |
| 7007 name->ToCString().get(), | 6970 name->ToCString().get(), |
| 7008 caller_name.get()); | 6971 caller_name.get()); |
| 7009 } | 6972 } |
| 7010 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { | 6973 if (try_inline && TryInlineCall(expr)) { |
| 7011 // Trying to inline will signal that we should bailout from the | 6974 // Trying to inline will signal that we should bailout from the |
| 7012 // entire compilation by setting stack overflow on the visitor. | 6975 // entire compilation by setting stack overflow on the visitor. |
| 7013 if (HasStackOverflow()) return; | 6976 if (HasStackOverflow()) return; |
| 7014 } else { | 6977 } else { |
| 7015 HInstruction* call = BuildCallConstantFunction( | 6978 // Since HWrapReceiver currently cannot actually wrap numbers and strings, |
| 7016 expr->target(), argument_count); | 6979 // use the regular CallFunctionStub for method calls to wrap the receiver. |
| 6980 // TODO(verwaest): Support creation of value wrappers directly in |
| 6981 // HWrapReceiver. |
| 6982 HInstruction* call = needs_wrapping |
| 6983 ? NewUncasted<HCallFunction>( |
| 6984 function, argument_count, WRAP_AND_CALL) |
| 6985 : BuildCallConstantFunction(target, argument_count); |
| 7017 PushArgumentsFromEnvironment(argument_count); | 6986 PushArgumentsFromEnvironment(argument_count); |
| 7018 AddInstruction(call); | 6987 AddInstruction(call); |
| 6988 Drop(1); // Drop the function. |
| 7019 if (!ast_context()->IsEffect()) Push(call); | 6989 if (!ast_context()->IsEffect()) Push(call); |
| 7020 } | 6990 } |
| 7021 | 6991 |
| 7022 if (current_block() != NULL) Goto(join); | 6992 if (current_block() != NULL) Goto(join); |
| 7023 set_current_block(if_false); | 6993 set_current_block(if_false); |
| 7024 } | 6994 } |
| 7025 | 6995 |
| 7026 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 6996 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
| 7027 // know about and do not want to handle ones we've never seen. Otherwise | 6997 // know about and do not want to handle ones we've never seen. Otherwise |
| 7028 // use a generic IC. | 6998 // use a generic IC. |
| 7029 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { | 6999 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { |
| 7030 // Because the deopt may be the only path in the polymorphic call, make sure | 7000 FinishExitWithHardDeoptimization("Unknown map in polymorphic call"); |
| 7031 // that the environment stack matches the depth on deopt that it otherwise | |
| 7032 // would have had after a successful call. | |
| 7033 Drop(argument_count); | |
| 7034 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); | |
| 7035 FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); | |
| 7036 } else { | 7001 } else { |
| 7037 HInstruction* call = NewCallNamed(name, argument_count); | 7002 Property* prop = expr->expression()->AsProperty(); |
| 7003 HInstruction* function = BuildNamedGeneric( |
| 7004 LOAD, receiver, name, NULL, prop->IsUninitialized()); |
| 7005 AddInstruction(function); |
| 7006 Push(function); |
| 7007 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
| 7008 |
| 7009 environment()->SetExpressionStackAt(1, function); |
| 7010 environment()->SetExpressionStackAt(0, receiver); |
| 7011 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7012 |
| 7013 CallFunctionFlags flags = receiver->type().IsJSObject() |
| 7014 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; |
| 7015 HInstruction* call = New<HCallFunction>( |
| 7016 function, argument_count, flags); |
| 7017 |
| 7038 PushArgumentsFromEnvironment(argument_count); | 7018 PushArgumentsFromEnvironment(argument_count); |
| 7039 | 7019 |
| 7020 Drop(1); // Function. |
| 7021 |
| 7040 if (join != NULL) { | 7022 if (join != NULL) { |
| 7041 AddInstruction(call); | 7023 AddInstruction(call); |
| 7042 if (!ast_context()->IsEffect()) Push(call); | 7024 if (!ast_context()->IsEffect()) Push(call); |
| 7043 Goto(join); | 7025 Goto(join); |
| 7044 } else { | 7026 } else { |
| 7045 return ast_context()->ReturnInstruction(call, expr->id()); | 7027 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7046 } | 7028 } |
| 7047 } | 7029 } |
| 7048 | 7030 |
| 7049 // We assume that control flow is always live after an expression. So | 7031 // We assume that control flow is always live after an expression. So |
| (...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7116 int nodes_added = target_shared->ast_node_count(); | 7098 int nodes_added = target_shared->ast_node_count(); |
| 7117 return nodes_added; | 7099 return nodes_added; |
| 7118 } | 7100 } |
| 7119 | 7101 |
| 7120 | 7102 |
| 7121 bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, | 7103 bool HOptimizedGraphBuilder::TryInline(Handle<JSFunction> target, |
| 7122 int arguments_count, | 7104 int arguments_count, |
| 7123 HValue* implicit_return_value, | 7105 HValue* implicit_return_value, |
| 7124 BailoutId ast_id, | 7106 BailoutId ast_id, |
| 7125 BailoutId return_id, | 7107 BailoutId return_id, |
| 7126 InliningKind inlining_kind) { | 7108 InliningKind inlining_kind, |
| 7109 HSourcePosition position) { |
| 7127 int nodes_added = InliningAstSize(target); | 7110 int nodes_added = InliningAstSize(target); |
| 7128 if (nodes_added == kNotInlinable) return false; | 7111 if (nodes_added == kNotInlinable) return false; |
| 7129 | 7112 |
| 7130 Handle<JSFunction> caller = current_info()->closure(); | 7113 Handle<JSFunction> caller = current_info()->closure(); |
| 7131 | 7114 |
| 7132 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { | 7115 if (nodes_added > Min(FLAG_max_inlined_nodes, kUnlimitedMaxInlinedNodes)) { |
| 7133 TraceInline(target, caller, "target AST is too large [early]"); | 7116 TraceInline(target, caller, "target AST is too large [early]"); |
| 7134 return false; | 7117 return false; |
| 7135 } | 7118 } |
| 7136 | 7119 |
| (...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7248 } | 7231 } |
| 7249 | 7232 |
| 7250 // ---------------------------------------------------------------- | 7233 // ---------------------------------------------------------------- |
| 7251 // After this point, we've made a decision to inline this function (so | 7234 // After this point, we've made a decision to inline this function (so |
| 7252 // TryInline should always return true). | 7235 // TryInline should always return true). |
| 7253 | 7236 |
| 7254 // Type-check the inlined function. | 7237 // Type-check the inlined function. |
| 7255 ASSERT(target_shared->has_deoptimization_support()); | 7238 ASSERT(target_shared->has_deoptimization_support()); |
| 7256 AstTyper::Run(&target_info); | 7239 AstTyper::Run(&target_info); |
| 7257 | 7240 |
| 7241 int function_id = graph()->TraceInlinedFunction(target_shared, position); |
| 7242 |
| 7258 // Save the pending call context. Set up new one for the inlined function. | 7243 // Save the pending call context. Set up new one for the inlined function. |
| 7259 // The function state is new-allocated because we need to delete it | 7244 // The function state is new-allocated because we need to delete it |
| 7260 // in two different places. | 7245 // in two different places. |
| 7261 FunctionState* target_state = new FunctionState( | 7246 FunctionState* target_state = new FunctionState( |
| 7262 this, &target_info, inlining_kind); | 7247 this, &target_info, inlining_kind, function_id); |
| 7263 | 7248 |
| 7264 HConstant* undefined = graph()->GetConstantUndefined(); | 7249 HConstant* undefined = graph()->GetConstantUndefined(); |
| 7265 | 7250 |
| 7266 HEnvironment* inner_env = | 7251 HEnvironment* inner_env = |
| 7267 environment()->CopyForInlining(target, | 7252 environment()->CopyForInlining(target, |
| 7268 arguments_count, | 7253 arguments_count, |
| 7269 function, | 7254 function, |
| 7270 undefined, | 7255 undefined, |
| 7271 function_state()->inlining_kind()); | 7256 function_state()->inlining_kind()); |
| 7272 | 7257 |
| (...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 7393 function_return()->SetJoinId(ast_id); | 7378 function_return()->SetJoinId(ast_id); |
| 7394 set_current_block(function_return()); | 7379 set_current_block(function_return()); |
| 7395 } else { | 7380 } else { |
| 7396 set_current_block(NULL); | 7381 set_current_block(NULL); |
| 7397 } | 7382 } |
| 7398 delete target_state; | 7383 delete target_state; |
| 7399 return true; | 7384 return true; |
| 7400 } | 7385 } |
| 7401 | 7386 |
| 7402 | 7387 |
| 7403 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr, bool drop_extra) { | 7388 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) { |
| 7404 return TryInline(expr->target(), | 7389 return TryInline(expr->target(), |
| 7405 expr->arguments()->length(), | 7390 expr->arguments()->length(), |
| 7406 NULL, | 7391 NULL, |
| 7407 expr->id(), | 7392 expr->id(), |
| 7408 expr->ReturnId(), | 7393 expr->ReturnId(), |
| 7409 drop_extra ? DROP_EXTRA_ON_RETURN : NORMAL_RETURN); | 7394 NORMAL_RETURN, |
| 7395 ScriptPositionToSourcePosition(expr->position())); |
| 7410 } | 7396 } |
| 7411 | 7397 |
| 7412 | 7398 |
| 7413 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, | 7399 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, |
| 7414 HValue* implicit_return_value) { | 7400 HValue* implicit_return_value) { |
| 7415 return TryInline(expr->target(), | 7401 return TryInline(expr->target(), |
| 7416 expr->arguments()->length(), | 7402 expr->arguments()->length(), |
| 7417 implicit_return_value, | 7403 implicit_return_value, |
| 7418 expr->id(), | 7404 expr->id(), |
| 7419 expr->ReturnId(), | 7405 expr->ReturnId(), |
| 7420 CONSTRUCT_CALL_RETURN); | 7406 CONSTRUCT_CALL_RETURN, |
| 7407 ScriptPositionToSourcePosition(expr->position())); |
| 7421 } | 7408 } |
| 7422 | 7409 |
| 7423 | 7410 |
| 7424 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, | 7411 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, |
| 7412 Handle<Map> receiver_map, |
| 7425 BailoutId ast_id, | 7413 BailoutId ast_id, |
| 7426 BailoutId return_id) { | 7414 BailoutId return_id) { |
| 7415 if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true; |
| 7427 return TryInline(getter, | 7416 return TryInline(getter, |
| 7428 0, | 7417 0, |
| 7429 NULL, | 7418 NULL, |
| 7430 ast_id, | 7419 ast_id, |
| 7431 return_id, | 7420 return_id, |
| 7432 GETTER_CALL_RETURN); | 7421 GETTER_CALL_RETURN, |
| 7422 source_position()); |
| 7433 } | 7423 } |
| 7434 | 7424 |
| 7435 | 7425 |
| 7436 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, | 7426 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, |
| 7427 Handle<Map> receiver_map, |
| 7437 BailoutId id, | 7428 BailoutId id, |
| 7438 BailoutId assignment_id, | 7429 BailoutId assignment_id, |
| 7439 HValue* implicit_return_value) { | 7430 HValue* implicit_return_value) { |
| 7431 if (TryInlineApiSetter(setter, receiver_map, id)) return true; |
| 7440 return TryInline(setter, | 7432 return TryInline(setter, |
| 7441 1, | 7433 1, |
| 7442 implicit_return_value, | 7434 implicit_return_value, |
| 7443 id, assignment_id, | 7435 id, assignment_id, |
| 7444 SETTER_CALL_RETURN); | 7436 SETTER_CALL_RETURN, |
| 7437 source_position()); |
| 7445 } | 7438 } |
| 7446 | 7439 |
| 7447 | 7440 |
| 7448 bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, | 7441 bool HOptimizedGraphBuilder::TryInlineApply(Handle<JSFunction> function, |
| 7449 Call* expr, | 7442 Call* expr, |
| 7450 int arguments_count) { | 7443 int arguments_count) { |
| 7451 return TryInline(function, | 7444 return TryInline(function, |
| 7452 arguments_count, | 7445 arguments_count, |
| 7453 NULL, | 7446 NULL, |
| 7454 expr->id(), | 7447 expr->id(), |
| 7455 expr->ReturnId(), | 7448 expr->ReturnId(), |
| 7456 NORMAL_RETURN); | 7449 NORMAL_RETURN, |
| 7450 ScriptPositionToSourcePosition(expr->position())); |
| 7457 } | 7451 } |
| 7458 | 7452 |
| 7459 | 7453 |
| 7460 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, | 7454 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { |
| 7461 bool drop_extra) { | |
| 7462 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 7455 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
| 7463 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 7456 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 7464 switch (id) { | 7457 switch (id) { |
| 7465 case kMathExp: | 7458 case kMathExp: |
| 7466 if (!FLAG_fast_math) break; | 7459 if (!FLAG_fast_math) break; |
| 7467 // Fall through if FLAG_fast_math. | 7460 // Fall through if FLAG_fast_math. |
| 7468 case kMathRound: | 7461 case kMathRound: |
| 7469 case kMathFloor: | 7462 case kMathFloor: |
| 7470 case kMathAbs: | 7463 case kMathAbs: |
| 7471 case kMathSqrt: | 7464 case kMathSqrt: |
| 7472 case kMathLog: | 7465 case kMathLog: |
| 7466 case kMathClz32: |
| 7473 if (expr->arguments()->length() == 1) { | 7467 if (expr->arguments()->length() == 1) { |
| 7474 HValue* argument = Pop(); | 7468 HValue* argument = Pop(); |
| 7475 Drop(1); // Receiver. | 7469 Drop(2); // Receiver and function. |
| 7476 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); | 7470 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
| 7477 if (drop_extra) Drop(1); // Optionally drop the function. | |
| 7478 ast_context()->ReturnInstruction(op, expr->id()); | 7471 ast_context()->ReturnInstruction(op, expr->id()); |
| 7479 return true; | 7472 return true; |
| 7480 } | 7473 } |
| 7481 break; | 7474 break; |
| 7482 case kMathImul: | 7475 case kMathImul: |
| 7483 if (expr->arguments()->length() == 2) { | 7476 if (expr->arguments()->length() == 2) { |
| 7484 HValue* right = Pop(); | 7477 HValue* right = Pop(); |
| 7485 HValue* left = Pop(); | 7478 HValue* left = Pop(); |
| 7486 Drop(1); // Receiver. | 7479 Drop(2); // Receiver and function. |
| 7487 HInstruction* op = HMul::NewImul(zone(), context(), left, right); | 7480 HInstruction* op = HMul::NewImul(zone(), context(), left, right); |
| 7488 if (drop_extra) Drop(1); // Optionally drop the function. | |
| 7489 ast_context()->ReturnInstruction(op, expr->id()); | 7481 ast_context()->ReturnInstruction(op, expr->id()); |
| 7490 return true; | 7482 return true; |
| 7491 } | 7483 } |
| 7492 break; | 7484 break; |
| 7493 default: | 7485 default: |
| 7494 // Not supported for inlining yet. | 7486 // Not supported for inlining yet. |
| 7495 break; | 7487 break; |
| 7496 } | 7488 } |
| 7497 return false; | 7489 return false; |
| 7498 } | 7490 } |
| 7499 | 7491 |
| 7500 | 7492 |
| 7501 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( | 7493 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
| 7502 Call* expr, | 7494 Call* expr, |
| 7503 HValue* receiver, | 7495 HValue* receiver, |
| 7504 Handle<Map> receiver_map, | 7496 Handle<Map> receiver_map) { |
| 7505 CheckType check_type) { | |
| 7506 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); | |
| 7507 // Try to inline calls like Math.* as operations in the calling function. | 7497 // Try to inline calls like Math.* as operations in the calling function. |
| 7508 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 7498 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
| 7509 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 7499 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
| 7510 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 7500 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 7511 switch (id) { | 7501 switch (id) { |
| 7512 case kStringCharCodeAt: | 7502 case kStringCharCodeAt: |
| 7513 case kStringCharAt: | 7503 case kStringCharAt: |
| 7514 if (argument_count == 2 && check_type == STRING_CHECK) { | 7504 if (argument_count == 2) { |
| 7515 HValue* index = Pop(); | 7505 HValue* index = Pop(); |
| 7516 HValue* string = Pop(); | 7506 HValue* string = Pop(); |
| 7517 ASSERT(!expr->holder().is_null()); | 7507 Drop(1); // Function. |
| 7518 BuildCheckPrototypeMaps(Call::GetPrototypeForPrimitiveCheck( | |
| 7519 STRING_CHECK, expr->holder()->GetIsolate()), | |
| 7520 expr->holder()); | |
| 7521 HInstruction* char_code = | 7508 HInstruction* char_code = |
| 7522 BuildStringCharCodeAt(string, index); | 7509 BuildStringCharCodeAt(string, index); |
| 7523 if (id == kStringCharCodeAt) { | 7510 if (id == kStringCharCodeAt) { |
| 7524 ast_context()->ReturnInstruction(char_code, expr->id()); | 7511 ast_context()->ReturnInstruction(char_code, expr->id()); |
| 7525 return true; | 7512 return true; |
| 7526 } | 7513 } |
| 7527 AddInstruction(char_code); | 7514 AddInstruction(char_code); |
| 7528 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code); | 7515 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code); |
| 7529 ast_context()->ReturnInstruction(result, expr->id()); | 7516 ast_context()->ReturnInstruction(result, expr->id()); |
| 7530 return true; | 7517 return true; |
| 7531 } | 7518 } |
| 7532 break; | 7519 break; |
| 7533 case kStringFromCharCode: | 7520 case kStringFromCharCode: |
| 7534 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { | 7521 if (argument_count == 2) { |
| 7535 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
| 7536 HValue* argument = Pop(); | 7522 HValue* argument = Pop(); |
| 7537 Drop(1); // Receiver. | 7523 Drop(2); // Receiver and function. |
| 7538 HInstruction* result = NewUncasted<HStringCharFromCode>(argument); | 7524 HInstruction* result = NewUncasted<HStringCharFromCode>(argument); |
| 7539 ast_context()->ReturnInstruction(result, expr->id()); | 7525 ast_context()->ReturnInstruction(result, expr->id()); |
| 7540 return true; | 7526 return true; |
| 7541 } | 7527 } |
| 7542 break; | 7528 break; |
| 7543 case kMathExp: | 7529 case kMathExp: |
| 7544 if (!FLAG_fast_math) break; | 7530 if (!FLAG_fast_math) break; |
| 7545 // Fall through if FLAG_fast_math. | 7531 // Fall through if FLAG_fast_math. |
| 7546 case kMathRound: | 7532 case kMathRound: |
| 7547 case kMathFloor: | 7533 case kMathFloor: |
| 7548 case kMathAbs: | 7534 case kMathAbs: |
| 7549 case kMathSqrt: | 7535 case kMathSqrt: |
| 7550 case kMathLog: | 7536 case kMathLog: |
| 7551 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { | 7537 case kMathClz32: |
| 7552 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | 7538 if (argument_count == 2) { |
| 7553 HValue* argument = Pop(); | 7539 HValue* argument = Pop(); |
| 7554 Drop(1); // Receiver. | 7540 Drop(2); // Receiver and function. |
| 7555 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); | 7541 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
| 7556 ast_context()->ReturnInstruction(op, expr->id()); | 7542 ast_context()->ReturnInstruction(op, expr->id()); |
| 7557 return true; | 7543 return true; |
| 7558 } | 7544 } |
| 7559 break; | 7545 break; |
| 7560 case kMathPow: | 7546 case kMathPow: |
| 7561 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { | 7547 if (argument_count == 3) { |
| 7562 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
| 7563 HValue* right = Pop(); | 7548 HValue* right = Pop(); |
| 7564 HValue* left = Pop(); | 7549 HValue* left = Pop(); |
| 7565 Pop(); // Pop receiver. | 7550 Drop(2); // Receiver and function. |
| 7566 HInstruction* result = NULL; | 7551 HInstruction* result = NULL; |
| 7567 // Use sqrt() if exponent is 0.5 or -0.5. | 7552 // Use sqrt() if exponent is 0.5 or -0.5. |
| 7568 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { | 7553 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
| 7569 double exponent = HConstant::cast(right)->DoubleValue(); | 7554 double exponent = HConstant::cast(right)->DoubleValue(); |
| 7570 if (exponent == 0.5) { | 7555 if (exponent == 0.5) { |
| 7571 result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf); | 7556 result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf); |
| 7572 } else if (exponent == -0.5) { | 7557 } else if (exponent == -0.5) { |
| 7573 HValue* one = graph()->GetConstant1(); | 7558 HValue* one = graph()->GetConstant1(); |
| 7574 HInstruction* sqrt = AddUncasted<HUnaryMathOperation>( | 7559 HInstruction* sqrt = AddUncasted<HUnaryMathOperation>( |
| 7575 left, kMathPowHalf); | 7560 left, kMathPowHalf); |
| 7576 // MathPowHalf doesn't have side effects so there's no need for | 7561 // MathPowHalf doesn't have side effects so there's no need for |
| 7577 // an environment simulation here. | 7562 // an environment simulation here. |
| 7578 ASSERT(!sqrt->HasObservableSideEffects()); | 7563 ASSERT(!sqrt->HasObservableSideEffects()); |
| 7579 result = NewUncasted<HDiv>(one, sqrt); | 7564 result = NewUncasted<HDiv>(one, sqrt); |
| 7580 } else if (exponent == 2.0) { | 7565 } else if (exponent == 2.0) { |
| 7581 result = NewUncasted<HMul>(left, left); | 7566 result = NewUncasted<HMul>(left, left); |
| 7582 } | 7567 } |
| 7583 } | 7568 } |
| 7584 | 7569 |
| 7585 if (result == NULL) { | 7570 if (result == NULL) { |
| 7586 result = NewUncasted<HPower>(left, right); | 7571 result = NewUncasted<HPower>(left, right); |
| 7587 } | 7572 } |
| 7588 ast_context()->ReturnInstruction(result, expr->id()); | 7573 ast_context()->ReturnInstruction(result, expr->id()); |
| 7589 return true; | 7574 return true; |
| 7590 } | 7575 } |
| 7591 break; | 7576 break; |
| 7592 case kMathMax: | 7577 case kMathMax: |
| 7593 case kMathMin: | 7578 case kMathMin: |
| 7594 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { | 7579 if (argument_count == 3) { |
| 7595 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
| 7596 HValue* right = Pop(); | 7580 HValue* right = Pop(); |
| 7597 HValue* left = Pop(); | 7581 HValue* left = Pop(); |
| 7598 Drop(1); // Receiver. | 7582 Drop(2); // Receiver and function. |
| 7599 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin | 7583 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin |
| 7600 : HMathMinMax::kMathMax; | 7584 : HMathMinMax::kMathMax; |
| 7601 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); | 7585 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); |
| 7602 ast_context()->ReturnInstruction(result, expr->id()); | 7586 ast_context()->ReturnInstruction(result, expr->id()); |
| 7603 return true; | 7587 return true; |
| 7604 } | 7588 } |
| 7605 break; | 7589 break; |
| 7606 case kMathImul: | 7590 case kMathImul: |
| 7607 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { | 7591 if (argument_count == 3) { |
| 7608 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
| 7609 HValue* right = Pop(); | 7592 HValue* right = Pop(); |
| 7610 HValue* left = Pop(); | 7593 HValue* left = Pop(); |
| 7611 Drop(1); // Receiver. | 7594 Drop(2); // Receiver and function. |
| 7612 HInstruction* result = HMul::NewImul(zone(), context(), left, right); | 7595 HInstruction* result = HMul::NewImul(zone(), context(), left, right); |
| 7613 ast_context()->ReturnInstruction(result, expr->id()); | 7596 ast_context()->ReturnInstruction(result, expr->id()); |
| 7614 return true; | 7597 return true; |
| 7615 } | 7598 } |
| 7616 break; | 7599 break; |
| 7600 case kArrayPop: { |
| 7601 if (receiver_map.is_null()) return false; |
| 7602 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; |
| 7603 ElementsKind elements_kind = receiver_map->elements_kind(); |
| 7604 if (!IsFastElementsKind(elements_kind)) return false; |
| 7605 |
| 7606 Drop(expr->arguments()->length()); |
| 7607 HValue* result; |
| 7608 HValue* reduced_length; |
| 7609 HValue* receiver = Pop(); |
| 7610 |
| 7611 HValue* checked_object = AddCheckMap(receiver, receiver_map); |
| 7612 HValue* length = Add<HLoadNamedField>( |
| 7613 checked_object, static_cast<HValue*>(NULL), |
| 7614 HObjectAccess::ForArrayLength(elements_kind)); |
| 7615 |
| 7616 Drop(1); // Function. |
| 7617 |
| 7618 { NoObservableSideEffectsScope scope(this); |
| 7619 IfBuilder length_checker(this); |
| 7620 |
| 7621 HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>( |
| 7622 length, graph()->GetConstant0(), Token::EQ); |
| 7623 length_checker.Then(); |
| 7624 |
| 7625 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); |
| 7626 |
| 7627 length_checker.Else(); |
| 7628 HValue* elements = AddLoadElements(checked_object); |
| 7629 // Ensure that we aren't popping from a copy-on-write array. |
| 7630 if (IsFastSmiOrObjectElementsKind(elements_kind)) { |
| 7631 elements = BuildCopyElementsOnWrite(checked_object, elements, |
| 7632 elements_kind, length); |
| 7633 } |
| 7634 reduced_length = AddUncasted<HSub>(length, graph()->GetConstant1()); |
| 7635 result = AddElementAccess(elements, reduced_length, NULL, |
| 7636 bounds_check, elements_kind, LOAD); |
| 7637 Factory* factory = isolate()->factory(); |
| 7638 double nan_double = FixedDoubleArray::hole_nan_as_double(); |
| 7639 HValue* hole = IsFastSmiOrObjectElementsKind(elements_kind) |
| 7640 ? Add<HConstant>(factory->the_hole_value()) |
| 7641 : Add<HConstant>(nan_double); |
| 7642 if (IsFastSmiOrObjectElementsKind(elements_kind)) { |
| 7643 elements_kind = FAST_HOLEY_ELEMENTS; |
| 7644 } |
| 7645 AddElementAccess( |
| 7646 elements, reduced_length, hole, bounds_check, elements_kind, STORE); |
| 7647 Add<HStoreNamedField>( |
| 7648 checked_object, HObjectAccess::ForArrayLength(elements_kind), |
| 7649 reduced_length, STORE_TO_INITIALIZED_ENTRY); |
| 7650 |
| 7651 if (!ast_context()->IsEffect()) Push(result); |
| 7652 |
| 7653 length_checker.End(); |
| 7654 } |
| 7655 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top(); |
| 7656 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
| 7657 if (!ast_context()->IsEffect()) Drop(1); |
| 7658 |
| 7659 ast_context()->ReturnValue(result); |
| 7660 return true; |
| 7661 } |
| 7662 case kArrayPush: { |
| 7663 if (receiver_map.is_null()) return false; |
| 7664 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; |
| 7665 ElementsKind elements_kind = receiver_map->elements_kind(); |
| 7666 if (!IsFastElementsKind(elements_kind)) return false; |
| 7667 |
| 7668 HValue* op_vals[] = { |
| 7669 context(), |
| 7670 // Receiver. |
| 7671 environment()->ExpressionStackAt(expr->arguments()->length()) |
| 7672 }; |
| 7673 |
| 7674 const int argc = expr->arguments()->length(); |
| 7675 // Includes receiver. |
| 7676 PushArgumentsFromEnvironment(argc + 1); |
| 7677 |
| 7678 CallInterfaceDescriptor* descriptor = |
| 7679 isolate()->call_descriptor(Isolate::CallHandler); |
| 7680 |
| 7681 ArrayPushStub stub(receiver_map->elements_kind(), argc); |
| 7682 Handle<Code> code = stub.GetCode(isolate()); |
| 7683 HConstant* code_value = Add<HConstant>(code); |
| 7684 |
| 7685 ASSERT((sizeof(op_vals) / kPointerSize) == |
| 7686 descriptor->environment_length()); |
| 7687 |
| 7688 HInstruction* call = New<HCallWithDescriptor>( |
| 7689 code_value, argc + 1, descriptor, |
| 7690 Vector<HValue*>(op_vals, descriptor->environment_length())); |
| 7691 Drop(1); // Drop function. |
| 7692 ast_context()->ReturnInstruction(call, expr->id()); |
| 7693 return true; |
| 7694 } |
| 7617 default: | 7695 default: |
| 7618 // Not yet supported for inlining. | 7696 // Not yet supported for inlining. |
| 7619 break; | 7697 break; |
| 7620 } | 7698 } |
| 7621 return false; | 7699 return false; |
| 7622 } | 7700 } |
| 7623 | 7701 |
| 7624 | 7702 |
| 7703 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, |
| 7704 HValue* receiver) { |
| 7705 Handle<JSFunction> function = expr->target(); |
| 7706 int argc = expr->arguments()->length(); |
| 7707 SmallMapList receiver_maps; |
| 7708 return TryInlineApiCall(function, |
| 7709 receiver, |
| 7710 &receiver_maps, |
| 7711 argc, |
| 7712 expr->id(), |
| 7713 kCallApiFunction); |
| 7714 } |
| 7715 |
| 7716 |
| 7717 bool HOptimizedGraphBuilder::TryInlineApiMethodCall( |
| 7718 Call* expr, |
| 7719 HValue* receiver, |
| 7720 SmallMapList* receiver_maps) { |
| 7721 Handle<JSFunction> function = expr->target(); |
| 7722 int argc = expr->arguments()->length(); |
| 7723 return TryInlineApiCall(function, |
| 7724 receiver, |
| 7725 receiver_maps, |
| 7726 argc, |
| 7727 expr->id(), |
| 7728 kCallApiMethod); |
| 7729 } |
| 7730 |
| 7731 |
| 7732 bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<JSFunction> function, |
| 7733 Handle<Map> receiver_map, |
| 7734 BailoutId ast_id) { |
| 7735 SmallMapList receiver_maps(1, zone()); |
| 7736 receiver_maps.Add(receiver_map, zone()); |
| 7737 return TryInlineApiCall(function, |
| 7738 NULL, // Receiver is on expression stack. |
| 7739 &receiver_maps, |
| 7740 0, |
| 7741 ast_id, |
| 7742 kCallApiGetter); |
| 7743 } |
| 7744 |
| 7745 |
| 7746 bool HOptimizedGraphBuilder::TryInlineApiSetter(Handle<JSFunction> function, |
| 7747 Handle<Map> receiver_map, |
| 7748 BailoutId ast_id) { |
| 7749 SmallMapList receiver_maps(1, zone()); |
| 7750 receiver_maps.Add(receiver_map, zone()); |
| 7751 return TryInlineApiCall(function, |
| 7752 NULL, // Receiver is on expression stack. |
| 7753 &receiver_maps, |
| 7754 1, |
| 7755 ast_id, |
| 7756 kCallApiSetter); |
| 7757 } |
| 7758 |
| 7759 |
| 7760 bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function, |
| 7761 HValue* receiver, |
| 7762 SmallMapList* receiver_maps, |
| 7763 int argc, |
| 7764 BailoutId ast_id, |
| 7765 ApiCallType call_type) { |
| 7766 CallOptimization optimization(function); |
| 7767 if (!optimization.is_simple_api_call()) return false; |
| 7768 Handle<Map> holder_map; |
| 7769 if (call_type == kCallApiFunction) { |
| 7770 // Cannot embed a direct reference to the global proxy map |
| 7771 // as it maybe dropped on deserialization. |
| 7772 CHECK(!Serializer::enabled()); |
| 7773 ASSERT_EQ(0, receiver_maps->length()); |
| 7774 receiver_maps->Add(handle( |
| 7775 function->context()->global_object()->global_receiver()->map()), |
| 7776 zone()); |
| 7777 } |
| 7778 CallOptimization::HolderLookup holder_lookup = |
| 7779 CallOptimization::kHolderNotFound; |
| 7780 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( |
| 7781 receiver_maps->first(), &holder_lookup); |
| 7782 if (holder_lookup == CallOptimization::kHolderNotFound) return false; |
| 7783 |
| 7784 if (FLAG_trace_inlining) { |
| 7785 PrintF("Inlining api function "); |
| 7786 function->ShortPrint(); |
| 7787 PrintF("\n"); |
| 7788 } |
| 7789 |
| 7790 bool drop_extra = false; |
| 7791 bool is_store = false; |
| 7792 switch (call_type) { |
| 7793 case kCallApiFunction: |
| 7794 case kCallApiMethod: |
| 7795 // Need to check that none of the receiver maps could have changed. |
| 7796 Add<HCheckMaps>(receiver, receiver_maps); |
| 7797 // Need to ensure the chain between receiver and api_holder is intact. |
| 7798 if (holder_lookup == CallOptimization::kHolderFound) { |
| 7799 AddCheckPrototypeMaps(api_holder, receiver_maps->first()); |
| 7800 } else { |
| 7801 ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); |
| 7802 } |
| 7803 // Includes receiver. |
| 7804 PushArgumentsFromEnvironment(argc + 1); |
| 7805 // Drop function after call. |
| 7806 drop_extra = true; |
| 7807 break; |
| 7808 case kCallApiGetter: |
| 7809 // Receiver and prototype chain cannot have changed. |
| 7810 ASSERT_EQ(0, argc); |
| 7811 ASSERT_EQ(NULL, receiver); |
| 7812 // Receiver is on expression stack. |
| 7813 receiver = Pop(); |
| 7814 Add<HPushArgument>(receiver); |
| 7815 break; |
| 7816 case kCallApiSetter: |
| 7817 { |
| 7818 is_store = true; |
| 7819 // Receiver and prototype chain cannot have changed. |
| 7820 ASSERT_EQ(1, argc); |
| 7821 ASSERT_EQ(NULL, receiver); |
| 7822 // Receiver and value are on expression stack. |
| 7823 HValue* value = Pop(); |
| 7824 receiver = Pop(); |
| 7825 Add<HPushArgument>(receiver); |
| 7826 Add<HPushArgument>(value); |
| 7827 break; |
| 7828 } |
| 7829 } |
| 7830 |
| 7831 HValue* holder = NULL; |
| 7832 switch (holder_lookup) { |
| 7833 case CallOptimization::kHolderFound: |
| 7834 holder = Add<HConstant>(api_holder); |
| 7835 break; |
| 7836 case CallOptimization::kHolderIsReceiver: |
| 7837 holder = receiver; |
| 7838 break; |
| 7839 case CallOptimization::kHolderNotFound: |
| 7840 UNREACHABLE(); |
| 7841 break; |
| 7842 } |
| 7843 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
| 7844 Handle<Object> call_data_obj(api_call_info->data(), isolate()); |
| 7845 bool call_data_is_undefined = call_data_obj->IsUndefined(); |
| 7846 HValue* call_data = Add<HConstant>(call_data_obj); |
| 7847 ApiFunction fun(v8::ToCData<Address>(api_call_info->callback())); |
| 7848 ExternalReference ref = ExternalReference(&fun, |
| 7849 ExternalReference::DIRECT_API_CALL, |
| 7850 isolate()); |
| 7851 HValue* api_function_address = Add<HConstant>(ExternalReference(ref)); |
| 7852 |
| 7853 HValue* op_vals[] = { |
| 7854 Add<HConstant>(function), |
| 7855 call_data, |
| 7856 holder, |
| 7857 api_function_address, |
| 7858 context() |
| 7859 }; |
| 7860 |
| 7861 CallInterfaceDescriptor* descriptor = |
| 7862 isolate()->call_descriptor(Isolate::ApiFunctionCall); |
| 7863 |
| 7864 CallApiFunctionStub stub(is_store, call_data_is_undefined, argc); |
| 7865 Handle<Code> code = stub.GetCode(isolate()); |
| 7866 HConstant* code_value = Add<HConstant>(code); |
| 7867 |
| 7868 ASSERT((sizeof(op_vals) / kPointerSize) == |
| 7869 descriptor->environment_length()); |
| 7870 |
| 7871 HInstruction* call = New<HCallWithDescriptor>( |
| 7872 code_value, argc + 1, descriptor, |
| 7873 Vector<HValue*>(op_vals, descriptor->environment_length())); |
| 7874 |
| 7875 if (drop_extra) Drop(1); // Drop function. |
| 7876 ast_context()->ReturnInstruction(call, ast_id); |
| 7877 return true; |
| 7878 } |
| 7879 |
| 7880 |
| 7625 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { | 7881 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
| 7626 Expression* callee = expr->expression(); | 7882 ASSERT(expr->expression()->IsProperty()); |
| 7627 Property* prop = callee->AsProperty(); | |
| 7628 ASSERT(prop != NULL); | |
| 7629 | 7883 |
| 7630 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { | 7884 if (!expr->IsMonomorphic()) { |
| 7631 return false; | 7885 return false; |
| 7632 } | 7886 } |
| 7633 Handle<Map> function_map = expr->GetReceiverTypes()->first(); | 7887 Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
| 7634 if (function_map->instance_type() != JS_FUNCTION_TYPE || | 7888 if (function_map->instance_type() != JS_FUNCTION_TYPE || |
| 7635 !expr->target()->shared()->HasBuiltinFunctionId() || | 7889 !expr->target()->shared()->HasBuiltinFunctionId() || |
| 7636 expr->target()->shared()->builtin_function_id() != kFunctionApply) { | 7890 expr->target()->shared()->builtin_function_id() != kFunctionApply) { |
| 7637 return false; | 7891 return false; |
| 7638 } | 7892 } |
| 7639 | 7893 |
| 7640 if (current_info()->scope()->arguments() == NULL) return false; | 7894 if (current_info()->scope()->arguments() == NULL) return false; |
| 7641 | 7895 |
| 7642 ZoneList<Expression*>* args = expr->arguments(); | 7896 ZoneList<Expression*>* args = expr->arguments(); |
| 7643 if (args->length() != 2) return false; | 7897 if (args->length() != 2) return false; |
| 7644 | 7898 |
| 7645 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 7899 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
| 7646 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; | 7900 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
| 7647 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); | 7901 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); |
| 7648 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; | 7902 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
| 7649 | 7903 |
| 7650 // Found pattern f.apply(receiver, arguments). | 7904 // Found pattern f.apply(receiver, arguments). |
| 7651 CHECK_ALIVE_OR_RETURN(VisitForValue(prop->obj()), true); | |
| 7652 HValue* function = Top(); | |
| 7653 | |
| 7654 AddCheckConstantFunction(expr->holder(), function, function_map); | |
| 7655 | |
| 7656 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); | 7905 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); |
| 7657 HValue* receiver = Pop(); | 7906 HValue* receiver = Pop(); // receiver |
| 7658 | 7907 HValue* function = Pop(); // f |
| 7659 Drop(1); // Pop the function. | 7908 Drop(1); // apply |
| 7660 | 7909 |
| 7661 if (function_state()->outer() == NULL) { | 7910 if (function_state()->outer() == NULL) { |
| 7662 HInstruction* elements = Add<HArgumentsElements>(false); | 7911 HInstruction* elements = Add<HArgumentsElements>(false); |
| 7663 HInstruction* length = Add<HArgumentsLength>(elements); | 7912 HInstruction* length = Add<HArgumentsLength>(elements); |
| 7664 HValue* wrapped_receiver = BuildWrapReceiver(receiver, function); | 7913 HValue* wrapped_receiver = BuildWrapReceiver(receiver, function); |
| 7665 HInstruction* result = New<HApplyArguments>(function, | 7914 HInstruction* result = New<HApplyArguments>(function, |
| 7666 wrapped_receiver, | 7915 wrapped_receiver, |
| 7667 length, | 7916 length, |
| 7668 elements); | 7917 elements); |
| 7669 ast_context()->ReturnInstruction(result, expr->id()); | 7918 ast_context()->ReturnInstruction(result, expr->id()); |
| 7670 return true; | 7919 return true; |
| 7671 } else { | 7920 } else { |
| 7672 // We are inside inlined function and we know exactly what is inside | 7921 // We are inside inlined function and we know exactly what is inside |
| 7673 // arguments object. But we need to be able to materialize at deopt. | 7922 // arguments object. But we need to be able to materialize at deopt. |
| 7674 ASSERT_EQ(environment()->arguments_environment()->parameter_count(), | 7923 ASSERT_EQ(environment()->arguments_environment()->parameter_count(), |
| 7675 function_state()->entry()->arguments_object()->arguments_count()); | 7924 function_state()->entry()->arguments_object()->arguments_count()); |
| 7676 HArgumentsObject* args = function_state()->entry()->arguments_object(); | 7925 HArgumentsObject* args = function_state()->entry()->arguments_object(); |
| 7677 const ZoneList<HValue*>* arguments_values = args->arguments_values(); | 7926 const ZoneList<HValue*>* arguments_values = args->arguments_values(); |
| 7678 int arguments_count = arguments_values->length(); | 7927 int arguments_count = arguments_values->length(); |
| 7928 Push(function); |
| 7679 Push(BuildWrapReceiver(receiver, function)); | 7929 Push(BuildWrapReceiver(receiver, function)); |
| 7680 for (int i = 1; i < arguments_count; i++) { | 7930 for (int i = 1; i < arguments_count; i++) { |
| 7681 Push(arguments_values->at(i)); | 7931 Push(arguments_values->at(i)); |
| 7682 } | 7932 } |
| 7683 | 7933 |
| 7684 Handle<JSFunction> known_function; | 7934 Handle<JSFunction> known_function; |
| 7685 if (function->IsConstant() && | 7935 if (function->IsConstant() && |
| 7686 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { | 7936 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
| 7687 known_function = Handle<JSFunction>::cast( | 7937 known_function = Handle<JSFunction>::cast( |
| 7688 HConstant::cast(function)->handle(isolate())); | 7938 HConstant::cast(function)->handle(isolate())); |
| 7689 int args_count = arguments_count - 1; // Excluding receiver. | 7939 int args_count = arguments_count - 1; // Excluding receiver. |
| 7690 if (TryInlineApply(known_function, expr, args_count)) return true; | 7940 if (TryInlineApply(known_function, expr, args_count)) return true; |
| 7691 } | 7941 } |
| 7692 | 7942 |
| 7693 Drop(arguments_count - 1); | 7943 PushArgumentsFromEnvironment(arguments_count); |
| 7694 Push(Add<HPushArgument>(Pop())); | 7944 HInvokeFunction* call = New<HInvokeFunction>( |
| 7695 for (int i = 1; i < arguments_count; i++) { | 7945 function, known_function, arguments_count); |
| 7696 Push(Add<HPushArgument>(arguments_values->at(i))); | 7946 Drop(1); // Function. |
| 7697 } | |
| 7698 | |
| 7699 HInvokeFunction* call = New<HInvokeFunction>(function, | |
| 7700 known_function, | |
| 7701 arguments_count); | |
| 7702 Drop(arguments_count); | |
| 7703 ast_context()->ReturnInstruction(call, expr->id()); | 7947 ast_context()->ReturnInstruction(call, expr->id()); |
| 7704 return true; | 7948 return true; |
| 7705 } | 7949 } |
| 7706 } | 7950 } |
| 7707 | 7951 |
| 7708 | 7952 |
| 7709 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, | 7953 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, |
| 7710 Handle<JSFunction> target) { | 7954 Handle<JSFunction> target) { |
| 7711 SharedFunctionInfo* shared = target->shared(); | 7955 SharedFunctionInfo* shared = target->shared(); |
| 7712 if (shared->is_classic_mode() && !shared->native()) { | 7956 if (shared->is_classic_mode() && !shared->native()) { |
| 7713 HValue* context = Add<HLoadNamedField>( | 7957 // Cannot embed a direct reference to the global proxy |
| 7714 function, | 7958 // as is it dropped on deserialization. |
| 7715 HObjectAccess::ForJSObjectOffset(JSFunction::kContextOffset)); | 7959 CHECK(!Serializer::enabled()); |
| 7716 HValue* global_object = Add<HLoadNamedField>( | 7960 Handle<JSObject> global_receiver( |
| 7717 context, | 7961 target->context()->global_object()->global_receiver()); |
| 7718 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | 7962 return Add<HConstant>(global_receiver); |
| 7719 return Add<HLoadNamedField>( | |
| 7720 global_object, | |
| 7721 HObjectAccess::ForJSObjectOffset( | |
| 7722 GlobalObject::kGlobalReceiverOffset)); | |
| 7723 } | 7963 } |
| 7724 return graph()->GetConstantUndefined(); | 7964 return graph()->GetConstantUndefined(); |
| 7725 } | 7965 } |
| 7726 | 7966 |
| 7727 | 7967 |
| 7728 void HOptimizedGraphBuilder::VisitCall(Call* expr) { | 7968 void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
| 7729 ASSERT(!HasStackOverflow()); | 7969 ASSERT(!HasStackOverflow()); |
| 7730 ASSERT(current_block() != NULL); | 7970 ASSERT(current_block() != NULL); |
| 7731 ASSERT(current_block()->HasPredecessor()); | 7971 ASSERT(current_block()->HasPredecessor()); |
| 7732 Expression* callee = expr->expression(); | 7972 Expression* callee = expr->expression(); |
| 7733 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 7973 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
| 7734 HInstruction* call = NULL; | 7974 HInstruction* call = NULL; |
| 7735 | 7975 |
| 7736 Property* prop = callee->AsProperty(); | 7976 Property* prop = callee->AsProperty(); |
| 7737 if (prop != NULL) { | 7977 if (prop != NULL) { |
| 7738 if (!prop->key()->IsPropertyName()) { | 7978 CHECK_ALIVE(VisitForValue(prop->obj())); |
| 7739 // Keyed function call. | 7979 HValue* receiver = Top(); |
| 7740 CHECK_ALIVE(VisitForValue(prop->obj())); | |
| 7741 CHECK_ALIVE(VisitForValue(prop->key())); | |
| 7742 | 7980 |
| 7743 // Push receiver and key like the non-optimized code generator expects it. | 7981 SmallMapList* types; |
| 7744 HValue* key = Pop(); | 7982 ComputeReceiverTypes(expr, receiver, &types, zone()); |
| 7745 HValue* receiver = Pop(); | |
| 7746 Push(key); | |
| 7747 Push(Add<HPushArgument>(receiver)); | |
| 7748 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | |
| 7749 | 7983 |
| 7750 if (expr->IsMonomorphic()) { | 7984 if (prop->key()->IsPropertyName() && types->length() > 0) { |
| 7751 BuildCheckHeapObject(receiver); | 7985 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
| 7752 ElementsKind kind = expr->KeyedArrayCallIsHoley() | 7986 PropertyAccessInfo info(this, LOAD, ToType(types->first()), name); |
| 7753 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS; | 7987 if (!info.CanAccessAsMonomorphic(types)) { |
| 7754 | 7988 HandlePolymorphicCallNamed(expr, receiver, types, name); |
| 7755 Handle<Map> map(isolate()->get_initial_js_array_map(kind)); | 7989 return; |
| 7756 | |
| 7757 HValue* function = BuildMonomorphicElementAccess( | |
| 7758 receiver, key, NULL, NULL, map, false, STANDARD_STORE); | |
| 7759 | |
| 7760 call = New<HCallFunction>(function, argument_count); | |
| 7761 } else { | |
| 7762 call = NewCallKeyed(key, argument_count); | |
| 7763 } | 7990 } |
| 7764 Drop(argument_count + 1); // 1 is the key. | |
| 7765 return ast_context()->ReturnInstruction(call, expr->id()); | |
| 7766 } | 7991 } |
| 7767 | 7992 |
| 7768 // Named function call. | 7993 HValue* key = NULL; |
| 7769 if (TryCallApply(expr)) return; | 7994 if (!prop->key()->IsPropertyName()) { |
| 7770 | 7995 CHECK_ALIVE(VisitForValue(prop->key())); |
| 7771 CHECK_ALIVE(VisitForValue(prop->obj())); | 7996 key = Pop(); |
| 7772 CHECK_ALIVE(VisitExpressions(expr->arguments())); | |
| 7773 | |
| 7774 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | |
| 7775 HValue* receiver = | |
| 7776 environment()->ExpressionStackAt(expr->arguments()->length()); | |
| 7777 | |
| 7778 SmallMapList* types; | |
| 7779 bool was_monomorphic = expr->IsMonomorphic(); | |
| 7780 bool monomorphic = ComputeReceiverTypes(expr, receiver, &types); | |
| 7781 if (!was_monomorphic && monomorphic) { | |
| 7782 monomorphic = expr->ComputeTarget(types->first(), name); | |
| 7783 } | 7997 } |
| 7784 | 7998 |
| 7785 if (monomorphic) { | 7999 CHECK_ALIVE(PushLoad(prop, receiver, key)); |
| 7786 Handle<Map> map = types->first(); | 8000 HValue* function = Pop(); |
| 7787 if (TryInlineBuiltinMethodCall(expr, receiver, map, expr->check_type())) { | 8001 |
| 8002 if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); |
| 8003 |
| 8004 // Push the function under the receiver. |
| 8005 environment()->SetExpressionStackAt(0, function); |
| 8006 |
| 8007 Push(receiver); |
| 8008 |
| 8009 if (function->IsConstant() && |
| 8010 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
| 8011 Handle<JSFunction> known_function = Handle<JSFunction>::cast( |
| 8012 HConstant::cast(function)->handle(isolate())); |
| 8013 expr->set_target(known_function); |
| 8014 |
| 8015 if (TryCallApply(expr)) return; |
| 8016 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 8017 |
| 8018 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); |
| 8019 if (TryInlineBuiltinMethodCall(expr, receiver, map)) { |
| 7788 if (FLAG_trace_inlining) { | 8020 if (FLAG_trace_inlining) { |
| 7789 PrintF("Inlining builtin "); | 8021 PrintF("Inlining builtin "); |
| 7790 expr->target()->ShortPrint(); | 8022 known_function->ShortPrint(); |
| 7791 PrintF("\n"); | 8023 PrintF("\n"); |
| 7792 } | 8024 } |
| 7793 return; | 8025 return; |
| 7794 } | 8026 } |
| 8027 if (TryInlineApiMethodCall(expr, receiver, types)) return; |
| 7795 | 8028 |
| 7796 if (CallStubCompiler::HasCustomCallGenerator(expr->target()) || | 8029 // Wrap the receiver if necessary. |
| 7797 expr->check_type() != RECEIVER_MAP_CHECK) { | 8030 if (NeedsWrappingFor(ToType(types->first()), known_function)) { |
| 7798 // When the target has a custom call IC generator, use the IC, | 8031 // Since HWrapReceiver currently cannot actually wrap numbers and |
| 7799 // because it is likely to generate better code. Also use the IC | 8032 // strings, use the regular CallFunctionStub for method calls to wrap |
| 7800 // when a primitive receiver check is required. | 8033 // the receiver. |
| 7801 call = NewCallNamed(name, argument_count); | 8034 // TODO(verwaest): Support creation of value wrappers directly in |
| 7802 PushArgumentsFromEnvironment(argument_count); | 8035 // HWrapReceiver. |
| 8036 call = New<HCallFunction>( |
| 8037 function, argument_count, WRAP_AND_CALL); |
| 8038 } else if (TryInlineCall(expr)) { |
| 8039 return; |
| 7803 } else { | 8040 } else { |
| 7804 AddCheckConstantFunction(expr->holder(), receiver, map); | 8041 call = BuildCallConstantFunction(known_function, argument_count); |
| 7805 | |
| 7806 if (TryInlineCall(expr)) return; | |
| 7807 call = BuildCallConstantFunction(expr->target(), argument_count); | |
| 7808 PushArgumentsFromEnvironment(argument_count); | |
| 7809 } | 8042 } |
| 7810 } else if (types != NULL && types->length() > 1) { | |
| 7811 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | |
| 7812 HandlePolymorphicCallNamed(expr, receiver, types, name); | |
| 7813 return; | |
| 7814 | 8043 |
| 7815 } else { | 8044 } else { |
| 7816 call = NewCallNamed(name, argument_count); | 8045 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7817 PushArgumentsFromEnvironment(argument_count); | 8046 CallFunctionFlags flags = receiver->type().IsJSObject() |
| 8047 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; |
| 8048 call = New<HCallFunction>(function, argument_count, flags); |
| 7818 } | 8049 } |
| 8050 PushArgumentsFromEnvironment(argument_count); |
| 8051 |
| 7819 } else { | 8052 } else { |
| 7820 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 8053 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
| 7821 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { | 8054 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { |
| 7822 return Bailout(kPossibleDirectCallToEval); | 8055 return Bailout(kPossibleDirectCallToEval); |
| 7823 } | 8056 } |
| 7824 | 8057 |
| 7825 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); | 8058 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); |
| 7826 if (global_call) { | 8059 if (global_call) { |
| 7827 Variable* var = proxy->var(); | 8060 Variable* var = proxy->var(); |
| 7828 bool known_global_function = false; | 8061 bool known_global_function = false; |
| 7829 // If there is a global property cell for the name at compile time and | 8062 // If there is a global property cell for the name at compile time and |
| 7830 // access check is not enabled we assume that the function will not change | 8063 // access check is not enabled we assume that the function will not change |
| 7831 // and generate optimized code for calling the function. | 8064 // and generate optimized code for calling the function. |
| 7832 LookupResult lookup(isolate()); | 8065 LookupResult lookup(isolate()); |
| 7833 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); | 8066 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, LOAD); |
| 7834 if (type == kUseCell && | 8067 if (type == kUseCell && |
| 7835 !current_info()->global_object()->IsAccessCheckNeeded()) { | 8068 !current_info()->global_object()->IsAccessCheckNeeded()) { |
| 7836 Handle<GlobalObject> global(current_info()->global_object()); | 8069 Handle<GlobalObject> global(current_info()->global_object()); |
| 7837 known_global_function = expr->ComputeGlobalTarget(global, &lookup); | 8070 known_global_function = expr->ComputeGlobalTarget(global, &lookup); |
| 7838 } | 8071 } |
| 8072 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 8073 HValue* function = Top(); |
| 7839 if (known_global_function) { | 8074 if (known_global_function) { |
| 7840 // Push the global object instead of the global receiver because | 8075 Add<HCheckValue>(function, expr->target()); |
| 7841 // code generated by the full code generator expects it. | |
| 7842 HGlobalObject* global_object = Add<HGlobalObject>(); | |
| 7843 Push(global_object); | |
| 7844 | 8076 |
| 8077 // Placeholder for the receiver. |
| 8078 Push(graph()->GetConstantUndefined()); |
| 7845 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8079 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7846 | 8080 |
| 7847 CHECK_ALIVE(VisitForValue(expr->expression())); | |
| 7848 HValue* function = Pop(); | |
| 7849 Add<HCheckValue>(function, expr->target()); | |
| 7850 | |
| 7851 // Patch the global object on the stack by the expected receiver. | 8081 // Patch the global object on the stack by the expected receiver. |
| 7852 HValue* receiver = ImplicitReceiverFor(function, expr->target()); | 8082 HValue* receiver = ImplicitReceiverFor(function, expr->target()); |
| 7853 const int receiver_index = argument_count - 1; | 8083 const int receiver_index = argument_count - 1; |
| 7854 environment()->SetExpressionStackAt(receiver_index, receiver); | 8084 environment()->SetExpressionStackAt(receiver_index, receiver); |
| 7855 | 8085 |
| 7856 if (TryInlineBuiltinFunctionCall(expr, false)) { // Nothing to drop. | 8086 if (TryInlineBuiltinFunctionCall(expr)) { |
| 7857 if (FLAG_trace_inlining) { | 8087 if (FLAG_trace_inlining) { |
| 7858 PrintF("Inlining builtin "); | 8088 PrintF("Inlining builtin "); |
| 7859 expr->target()->ShortPrint(); | 8089 expr->target()->ShortPrint(); |
| 7860 PrintF("\n"); | 8090 PrintF("\n"); |
| 7861 } | 8091 } |
| 7862 return; | 8092 return; |
| 7863 } | 8093 } |
| 8094 if (TryInlineApiFunctionCall(expr, receiver)) return; |
| 7864 if (TryInlineCall(expr)) return; | 8095 if (TryInlineCall(expr)) return; |
| 7865 | 8096 |
| 7866 if (expr->target().is_identical_to(current_info()->closure())) { | 8097 PushArgumentsFromEnvironment(argument_count); |
| 7867 graph()->MarkRecursive(); | 8098 call = BuildCallConstantFunction(expr->target(), argument_count); |
| 7868 } | |
| 7869 | |
| 7870 if (CallStubCompiler::HasCustomCallGenerator(expr->target())) { | |
| 7871 // We're about to install a contextual IC, which expects the global | |
| 7872 // object as receiver rather than the global proxy. | |
| 7873 HGlobalObject* global_object = Add<HGlobalObject>(); | |
| 7874 const int receiver_index = argument_count - 1; | |
| 7875 environment()->SetExpressionStackAt(receiver_index, global_object); | |
| 7876 // When the target has a custom call IC generator, use the IC, | |
| 7877 // because it is likely to generate better code. | |
| 7878 call = NewCallNamed(var->name(), argument_count); | |
| 7879 PushArgumentsFromEnvironment(argument_count); | |
| 7880 } else { | |
| 7881 call = BuildCallConstantFunction(expr->target(), argument_count); | |
| 7882 PushArgumentsFromEnvironment(argument_count); | |
| 7883 } | |
| 7884 } else { | 8099 } else { |
| 7885 HGlobalObject* receiver = Add<HGlobalObject>(); | 8100 Push(Add<HPushArgument>(graph()->GetConstantUndefined())); |
| 7886 Push(Add<HPushArgument>(receiver)); | |
| 7887 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 8101 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| 7888 | 8102 call = New<HCallFunction>(function, argument_count); |
| 7889 call = NewCallNamed(var->name(), argument_count); | |
| 7890 Drop(argument_count); | 8103 Drop(argument_count); |
| 7891 } | 8104 } |
| 7892 | 8105 |
| 7893 } else if (expr->IsMonomorphic()) { | 8106 } else if (expr->IsMonomorphic()) { |
| 7894 // The function is on the stack in the unoptimized code during | 8107 // The function is on the stack in the unoptimized code during |
| 7895 // evaluation of the arguments. | 8108 // evaluation of the arguments. |
| 7896 CHECK_ALIVE(VisitForValue(expr->expression())); | 8109 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 7897 HValue* function = Top(); | 8110 HValue* function = Top(); |
| 7898 | 8111 |
| 7899 Add<HCheckValue>(function, expr->target()); | 8112 Add<HCheckValue>(function, expr->target()); |
| 7900 | 8113 |
| 7901 HValue* receiver = ImplicitReceiverFor(function, expr->target()); | 8114 Push(graph()->GetConstantUndefined()); |
| 7902 Push(receiver); | |
| 7903 | |
| 7904 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8115 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7905 | 8116 |
| 7906 if (TryInlineBuiltinFunctionCall(expr, true)) { // Drop the function. | 8117 HValue* receiver = ImplicitReceiverFor(function, expr->target()); |
| 8118 const int receiver_index = argument_count - 1; |
| 8119 environment()->SetExpressionStackAt(receiver_index, receiver); |
| 8120 |
| 8121 if (TryInlineBuiltinFunctionCall(expr)) { |
| 7907 if (FLAG_trace_inlining) { | 8122 if (FLAG_trace_inlining) { |
| 7908 PrintF("Inlining builtin "); | 8123 PrintF("Inlining builtin "); |
| 7909 expr->target()->ShortPrint(); | 8124 expr->target()->ShortPrint(); |
| 7910 PrintF("\n"); | 8125 PrintF("\n"); |
| 7911 } | 8126 } |
| 7912 return; | 8127 return; |
| 7913 } | 8128 } |
| 8129 if (TryInlineApiFunctionCall(expr, receiver)) return; |
| 7914 | 8130 |
| 7915 if (TryInlineCall(expr, true)) { // Drop function from environment. | 8131 if (TryInlineCall(expr)) return; |
| 7916 return; | 8132 |
| 7917 } else { | 8133 call = PreProcessCall(New<HInvokeFunction>( |
| 7918 call = PreProcessCall(New<HInvokeFunction>(function, expr->target(), | 8134 function, expr->target(), argument_count)); |
| 7919 argument_count)); | |
| 7920 Drop(1); // The function. | |
| 7921 } | |
| 7922 | 8135 |
| 7923 } else { | 8136 } else { |
| 7924 CHECK_ALIVE(VisitForValue(expr->expression())); | 8137 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 7925 HValue* function = Top(); | 8138 HValue* function = Top(); |
| 7926 HValue* receiver = graph()->GetConstantUndefined(); | 8139 HValue* receiver = graph()->GetConstantUndefined(); |
| 7927 Push(Add<HPushArgument>(receiver)); | 8140 Push(Add<HPushArgument>(receiver)); |
| 7928 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 8141 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
| 7929 call = New<HCallFunction>( | 8142 call = New<HCallFunction>(function, argument_count); |
| 7930 function, argument_count, NORMAL_CONTEXTUAL_CALL); | 8143 Drop(argument_count); |
| 7931 Drop(argument_count + 1); | |
| 7932 } | 8144 } |
| 7933 } | 8145 } |
| 7934 | 8146 |
| 8147 Drop(1); // Drop the function. |
| 7935 return ast_context()->ReturnInstruction(call, expr->id()); | 8148 return ast_context()->ReturnInstruction(call, expr->id()); |
| 7936 } | 8149 } |
| 7937 | 8150 |
| 7938 | 8151 |
| 7939 void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { | 8152 void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { |
| 7940 NoObservableSideEffectsScope no_effects(this); | 8153 NoObservableSideEffectsScope no_effects(this); |
| 7941 | 8154 |
| 7942 int argument_count = expr->arguments()->length(); | 8155 int argument_count = expr->arguments()->length(); |
| 7943 // We should at least have the constructor on the expression stack. | 8156 // We should at least have the constructor on the expression stack. |
| 7944 HValue* constructor = environment()->ExpressionStackAt(argument_count); | 8157 HValue* constructor = environment()->ExpressionStackAt(argument_count); |
| 7945 | 8158 |
| 7946 ElementsKind kind = expr->elements_kind(); | 8159 ElementsKind kind = expr->elements_kind(); |
| 7947 Handle<Cell> cell = expr->allocation_info_cell(); | 8160 Handle<AllocationSite> site = expr->allocation_site(); |
| 7948 Handle<AllocationSite> site(AllocationSite::cast(cell->value())); | 8161 ASSERT(!site.is_null()); |
| 7949 | 8162 |
| 7950 // Register on the site for deoptimization if the transition feedback changes. | 8163 // Register on the site for deoptimization if the transition feedback changes. |
| 7951 AllocationSite::AddDependentCompilationInfo( | 8164 AllocationSite::AddDependentCompilationInfo( |
| 7952 site, AllocationSite::TRANSITIONS, top_info()); | 8165 site, AllocationSite::TRANSITIONS, top_info()); |
| 7953 HInstruction* site_instruction = Add<HConstant>(site); | 8166 HInstruction* site_instruction = Add<HConstant>(site); |
| 7954 | 8167 |
| 7955 // In the single constant argument case, we may have to adjust elements kind | 8168 // In the single constant argument case, we may have to adjust elements kind |
| 7956 // to avoid creating a packed non-empty array. | 8169 // to avoid creating a packed non-empty array. |
| 7957 if (argument_count == 1 && !IsHoleyElementsKind(kind)) { | 8170 if (argument_count == 1 && !IsHoleyElementsKind(kind)) { |
| 7958 HValue* argument = environment()->Top(); | 8171 HValue* argument = environment()->Top(); |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8005 // Checks whether allocation using the given constructor can be inlined. | 8218 // Checks whether allocation using the given constructor can be inlined. |
| 8006 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { | 8219 static bool IsAllocationInlineable(Handle<JSFunction> constructor) { |
| 8007 return constructor->has_initial_map() && | 8220 return constructor->has_initial_map() && |
| 8008 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && | 8221 constructor->initial_map()->instance_type() == JS_OBJECT_TYPE && |
| 8009 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && | 8222 constructor->initial_map()->instance_size() < HAllocate::kMaxInlineSize && |
| 8010 constructor->initial_map()->InitialPropertiesLength() == 0; | 8223 constructor->initial_map()->InitialPropertiesLength() == 0; |
| 8011 } | 8224 } |
| 8012 | 8225 |
| 8013 | 8226 |
| 8014 bool HOptimizedGraphBuilder::IsCallNewArrayInlineable(CallNew* expr) { | 8227 bool HOptimizedGraphBuilder::IsCallNewArrayInlineable(CallNew* expr) { |
| 8015 bool inline_ok = false; | |
| 8016 Handle<JSFunction> caller = current_info()->closure(); | 8228 Handle<JSFunction> caller = current_info()->closure(); |
| 8017 Handle<JSFunction> target(isolate()->global_context()->array_function(), | 8229 Handle<JSFunction> target(isolate()->native_context()->array_function(), |
| 8018 isolate()); | 8230 isolate()); |
| 8019 int argument_count = expr->arguments()->length(); | 8231 int argument_count = expr->arguments()->length(); |
| 8020 // We should have the function plus array arguments on the environment stack. | 8232 // We should have the function plus array arguments on the environment stack. |
| 8021 ASSERT(environment()->length() >= (argument_count + 1)); | 8233 ASSERT(environment()->length() >= (argument_count + 1)); |
| 8022 Handle<Cell> cell = expr->allocation_info_cell(); | 8234 Handle<AllocationSite> site = expr->allocation_site(); |
| 8023 AllocationSite* site = AllocationSite::cast(cell->value()); | 8235 ASSERT(!site.is_null()); |
| 8236 |
| 8237 bool inline_ok = false; |
| 8024 if (site->CanInlineCall()) { | 8238 if (site->CanInlineCall()) { |
| 8025 // We also want to avoid inlining in certain 1 argument scenarios. | 8239 // We also want to avoid inlining in certain 1 argument scenarios. |
| 8026 if (argument_count == 1) { | 8240 if (argument_count == 1) { |
| 8027 HValue* argument = Top(); | 8241 HValue* argument = Top(); |
| 8028 if (argument->IsConstant()) { | 8242 if (argument->IsConstant()) { |
| 8029 // Do not inline if the constant length argument is not a smi or | 8243 // Do not inline if the constant length argument is not a smi or |
| 8030 // outside the valid range for a fast array. | 8244 // outside the valid range for a fast array. |
| 8031 HConstant* constant_argument = HConstant::cast(argument); | 8245 HConstant* constant_argument = HConstant::cast(argument); |
| 8032 if (constant_argument->HasSmiValue()) { | 8246 if (constant_argument->HasSmiValue()) { |
| 8033 int value = constant_argument->Integer32Value(); | 8247 int value = constant_argument->Integer32Value(); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 8052 TraceInline(target, caller, NULL); | 8266 TraceInline(target, caller, NULL); |
| 8053 } | 8267 } |
| 8054 return inline_ok; | 8268 return inline_ok; |
| 8055 } | 8269 } |
| 8056 | 8270 |
| 8057 | 8271 |
| 8058 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { | 8272 void HOptimizedGraphBuilder::VisitCallNew(CallNew* expr) { |
| 8059 ASSERT(!HasStackOverflow()); | 8273 ASSERT(!HasStackOverflow()); |
| 8060 ASSERT(current_block() != NULL); | 8274 ASSERT(current_block() != NULL); |
| 8061 ASSERT(current_block()->HasPredecessor()); | 8275 ASSERT(current_block()->HasPredecessor()); |
| 8062 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 8276 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); |
| 8063 int argument_count = expr->arguments()->length() + 1; // Plus constructor. | 8277 int argument_count = expr->arguments()->length() + 1; // Plus constructor. |
| 8064 Factory* factory = isolate()->factory(); | 8278 Factory* factory = isolate()->factory(); |
| 8065 | 8279 |
| 8066 // The constructor function is on the stack in the unoptimized code | 8280 // The constructor function is on the stack in the unoptimized code |
| 8067 // during evaluation of the arguments. | 8281 // during evaluation of the arguments. |
| 8068 CHECK_ALIVE(VisitForValue(expr->expression())); | 8282 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 8069 HValue* function = Top(); | 8283 HValue* function = Top(); |
| 8070 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8284 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 8071 | 8285 |
| 8072 if (FLAG_inline_construct && | 8286 if (FLAG_inline_construct && |
| (...skipping 10 matching lines...) Expand all Loading... |
| 8083 | 8297 |
| 8084 // Calculate instance size from initial map of constructor. | 8298 // Calculate instance size from initial map of constructor. |
| 8085 ASSERT(constructor->has_initial_map()); | 8299 ASSERT(constructor->has_initial_map()); |
| 8086 Handle<Map> initial_map(constructor->initial_map()); | 8300 Handle<Map> initial_map(constructor->initial_map()); |
| 8087 int instance_size = initial_map->instance_size(); | 8301 int instance_size = initial_map->instance_size(); |
| 8088 ASSERT(initial_map->InitialPropertiesLength() == 0); | 8302 ASSERT(initial_map->InitialPropertiesLength() == 0); |
| 8089 | 8303 |
| 8090 // Allocate an instance of the implicit receiver object. | 8304 // Allocate an instance of the implicit receiver object. |
| 8091 HValue* size_in_bytes = Add<HConstant>(instance_size); | 8305 HValue* size_in_bytes = Add<HConstant>(instance_size); |
| 8092 PretenureFlag pretenure_flag = | 8306 PretenureFlag pretenure_flag = |
| 8093 (FLAG_pretenuring_call_new && | 8307 (FLAG_pretenuring_call_new && !FLAG_allocation_site_pretenuring) ? |
| 8094 isolate()->heap()->GetPretenureMode() == TENURED) | 8308 isolate()->heap()->GetPretenureMode() : NOT_TENURED; |
| 8095 ? TENURED : NOT_TENURED; | |
| 8096 HAllocate* receiver = | 8309 HAllocate* receiver = |
| 8097 Add<HAllocate>(size_in_bytes, HType::JSObject(), pretenure_flag, | 8310 Add<HAllocate>(size_in_bytes, HType::JSObject(), pretenure_flag, |
| 8098 JS_OBJECT_TYPE); | 8311 JS_OBJECT_TYPE); |
| 8099 receiver->set_known_initial_map(initial_map); | 8312 receiver->set_known_initial_map(initial_map); |
| 8100 | 8313 |
| 8101 // Load the initial map from the constructor. | 8314 // Load the initial map from the constructor. |
| 8102 HValue* constructor_value = Add<HConstant>(constructor); | 8315 HValue* constructor_value = Add<HConstant>(constructor); |
| 8103 HValue* initial_map_value = | 8316 HValue* initial_map_value = |
| 8104 Add<HLoadNamedField>(constructor_value, HObjectAccess::ForJSObjectOffset( | 8317 Add<HLoadNamedField>(constructor_value, static_cast<HValue*>(NULL), |
| 8105 JSFunction::kPrototypeOrInitialMapOffset)); | 8318 HObjectAccess::ForMapAndOffset( |
| 8319 handle(constructor->map()), |
| 8320 JSFunction::kPrototypeOrInitialMapOffset)); |
| 8106 | 8321 |
| 8107 // Initialize map and fields of the newly allocated object. | 8322 // Initialize map and fields of the newly allocated object. |
| 8108 { NoObservableSideEffectsScope no_effects(this); | 8323 { NoObservableSideEffectsScope no_effects(this); |
| 8109 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); | 8324 ASSERT(initial_map->instance_type() == JS_OBJECT_TYPE); |
| 8110 Add<HStoreNamedField>(receiver, | 8325 Add<HStoreNamedField>(receiver, |
| 8111 HObjectAccess::ForJSObjectOffset(JSObject::kMapOffset), | 8326 HObjectAccess::ForMapAndOffset(initial_map, JSObject::kMapOffset), |
| 8112 initial_map_value); | 8327 initial_map_value); |
| 8113 HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array()); | 8328 HValue* empty_fixed_array = Add<HConstant>(factory->empty_fixed_array()); |
| 8114 Add<HStoreNamedField>(receiver, | 8329 Add<HStoreNamedField>(receiver, |
| 8115 HObjectAccess::ForJSObjectOffset(JSObject::kPropertiesOffset), | 8330 HObjectAccess::ForMapAndOffset(initial_map, |
| 8331 JSObject::kPropertiesOffset), |
| 8116 empty_fixed_array); | 8332 empty_fixed_array); |
| 8117 Add<HStoreNamedField>(receiver, | 8333 Add<HStoreNamedField>(receiver, |
| 8118 HObjectAccess::ForJSObjectOffset(JSObject::kElementsOffset), | 8334 HObjectAccess::ForMapAndOffset(initial_map, |
| 8335 JSObject::kElementsOffset), |
| 8119 empty_fixed_array); | 8336 empty_fixed_array); |
| 8120 if (initial_map->inobject_properties() != 0) { | 8337 if (initial_map->inobject_properties() != 0) { |
| 8121 HConstant* undefined = graph()->GetConstantUndefined(); | 8338 HConstant* undefined = graph()->GetConstantUndefined(); |
| 8122 for (int i = 0; i < initial_map->inobject_properties(); i++) { | 8339 for (int i = 0; i < initial_map->inobject_properties(); i++) { |
| 8123 int property_offset = JSObject::kHeaderSize + i * kPointerSize; | 8340 int property_offset = initial_map->GetInObjectPropertyOffset(i); |
| 8124 Add<HStoreNamedField>(receiver, | 8341 Add<HStoreNamedField>(receiver, |
| 8125 HObjectAccess::ForJSObjectOffset(property_offset), | 8342 HObjectAccess::ForMapAndOffset(initial_map, property_offset), |
| 8126 undefined); | 8343 undefined); |
| 8127 } | 8344 } |
| 8128 } | 8345 } |
| 8129 } | 8346 } |
| 8130 | 8347 |
| 8131 // Replace the constructor function with a newly allocated receiver using | 8348 // Replace the constructor function with a newly allocated receiver using |
| 8132 // the index of the receiver from the top of the expression stack. | 8349 // the index of the receiver from the top of the expression stack. |
| 8133 const int receiver_index = argument_count - 1; | 8350 const int receiver_index = argument_count - 1; |
| 8134 ASSERT(environment()->ExpressionStackAt(receiver_index) == function); | 8351 ASSERT(environment()->ExpressionStackAt(receiver_index) == function); |
| 8135 environment()->SetExpressionStackAt(receiver_index, receiver); | 8352 environment()->SetExpressionStackAt(receiver_index, receiver); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 8150 receiver->DeleteAndReplaceWith(NULL); | 8367 receiver->DeleteAndReplaceWith(NULL); |
| 8151 check->DeleteAndReplaceWith(NULL); | 8368 check->DeleteAndReplaceWith(NULL); |
| 8152 environment()->SetExpressionStackAt(receiver_index, function); | 8369 environment()->SetExpressionStackAt(receiver_index, function); |
| 8153 HInstruction* call = | 8370 HInstruction* call = |
| 8154 PreProcessCall(New<HCallNew>(function, argument_count)); | 8371 PreProcessCall(New<HCallNew>(function, argument_count)); |
| 8155 return ast_context()->ReturnInstruction(call, expr->id()); | 8372 return ast_context()->ReturnInstruction(call, expr->id()); |
| 8156 } else { | 8373 } else { |
| 8157 // The constructor function is both an operand to the instruction and an | 8374 // The constructor function is both an operand to the instruction and an |
| 8158 // argument to the construct call. | 8375 // argument to the construct call. |
| 8159 Handle<JSFunction> array_function( | 8376 Handle<JSFunction> array_function( |
| 8160 isolate()->global_context()->array_function(), isolate()); | 8377 isolate()->native_context()->array_function(), isolate()); |
| 8161 bool use_call_new_array = expr->target().is_identical_to(array_function); | 8378 bool use_call_new_array = expr->target().is_identical_to(array_function); |
| 8162 Handle<Cell> cell = expr->allocation_info_cell(); | |
| 8163 if (use_call_new_array && IsCallNewArrayInlineable(expr)) { | 8379 if (use_call_new_array && IsCallNewArrayInlineable(expr)) { |
| 8164 // Verify we are still calling the array function for our native context. | 8380 // Verify we are still calling the array function for our native context. |
| 8165 Add<HCheckValue>(function, array_function); | 8381 Add<HCheckValue>(function, array_function); |
| 8166 BuildInlinedCallNewArray(expr); | 8382 BuildInlinedCallNewArray(expr); |
| 8167 return; | 8383 return; |
| 8168 } | 8384 } |
| 8169 | 8385 |
| 8170 HBinaryCall* call; | 8386 HBinaryCall* call; |
| 8171 if (use_call_new_array) { | 8387 if (use_call_new_array) { |
| 8172 Add<HCheckValue>(function, array_function); | 8388 Add<HCheckValue>(function, array_function); |
| 8173 call = New<HCallNewArray>(function, argument_count, cell, | 8389 call = New<HCallNewArray>(function, argument_count, |
| 8174 expr->elements_kind()); | 8390 expr->elements_kind()); |
| 8175 } else { | 8391 } else { |
| 8176 call = New<HCallNew>(function, argument_count); | 8392 call = New<HCallNew>(function, argument_count); |
| 8177 } | 8393 } |
| 8178 PreProcessCall(call); | 8394 PreProcessCall(call); |
| 8179 return ast_context()->ReturnInstruction(call, expr->id()); | 8395 return ast_context()->ReturnInstruction(call, expr->id()); |
| 8180 } | 8396 } |
| 8181 } | 8397 } |
| 8182 | 8398 |
| 8183 | 8399 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 8201 void HGraphBuilder::BuildArrayBufferViewInitialization( | 8417 void HGraphBuilder::BuildArrayBufferViewInitialization( |
| 8202 HValue* obj, | 8418 HValue* obj, |
| 8203 HValue* buffer, | 8419 HValue* buffer, |
| 8204 HValue* byte_offset, | 8420 HValue* byte_offset, |
| 8205 HValue* byte_length) { | 8421 HValue* byte_length) { |
| 8206 | 8422 |
| 8207 for (int offset = ViewClass::kSize; | 8423 for (int offset = ViewClass::kSize; |
| 8208 offset < ViewClass::kSizeWithInternalFields; | 8424 offset < ViewClass::kSizeWithInternalFields; |
| 8209 offset += kPointerSize) { | 8425 offset += kPointerSize) { |
| 8210 Add<HStoreNamedField>(obj, | 8426 Add<HStoreNamedField>(obj, |
| 8211 HObjectAccess::ForJSObjectOffset(offset), | 8427 HObjectAccess::ForObservableJSObjectOffset(offset), |
| 8212 Add<HConstant>(static_cast<int32_t>(0))); | 8428 graph()->GetConstant0()); |
| 8213 } | 8429 } |
| 8214 | 8430 |
| 8215 Add<HStoreNamedField>( | 8431 Add<HStoreNamedField>( |
| 8216 obj, | 8432 obj, |
| 8217 HObjectAccess::ForJSArrayBufferViewBuffer(), buffer); | 8433 HObjectAccess::ForJSArrayBufferViewBuffer(), buffer); |
| 8218 Add<HStoreNamedField>( | 8434 Add<HStoreNamedField>( |
| 8219 obj, | 8435 obj, |
| 8220 HObjectAccess::ForJSArrayBufferViewByteOffset(), | 8436 HObjectAccess::ForJSArrayBufferViewByteOffset(), |
| 8221 byte_offset); | 8437 byte_offset); |
| 8222 Add<HStoreNamedField>( | 8438 Add<HStoreNamedField>( |
| 8223 obj, | 8439 obj, |
| 8224 HObjectAccess::ForJSArrayBufferViewByteLength(), | 8440 HObjectAccess::ForJSArrayBufferViewByteLength(), |
| 8225 byte_length); | 8441 byte_length); |
| 8226 | 8442 |
| 8227 HObjectAccess weak_first_view_access = | 8443 HObjectAccess weak_first_view_access = |
| 8228 HObjectAccess::ForJSArrayBufferWeakFirstView(); | 8444 HObjectAccess::ForJSArrayBufferWeakFirstView(); |
| 8229 Add<HStoreNamedField>(obj, | 8445 Add<HStoreNamedField>(obj, |
| 8230 HObjectAccess::ForJSArrayBufferViewWeakNext(), | 8446 HObjectAccess::ForJSArrayBufferViewWeakNext(), |
| 8231 Add<HLoadNamedField>(buffer, weak_first_view_access)); | 8447 Add<HLoadNamedField>(buffer, static_cast<HValue*>(NULL), |
| 8232 Add<HStoreNamedField>(buffer, weak_first_view_access, obj); | 8448 weak_first_view_access)); |
| 8449 Add<HStoreNamedField>( |
| 8450 buffer, weak_first_view_access, obj); |
| 8233 } | 8451 } |
| 8234 | 8452 |
| 8235 | 8453 |
| 8236 void HOptimizedGraphBuilder::VisitDataViewInitialize( | 8454 void HOptimizedGraphBuilder::VisitDataViewInitialize( |
| 8237 CallRuntime* expr) { | 8455 CallRuntime* expr) { |
| 8238 ZoneList<Expression*>* arguments = expr->arguments(); | 8456 ZoneList<Expression*>* arguments = expr->arguments(); |
| 8239 | 8457 |
| 8240 NoObservableSideEffectsScope scope(this); | 8458 NoObservableSideEffectsScope scope(this); |
| 8241 ASSERT(arguments->length()== 4); | 8459 ASSERT(arguments->length()== 4); |
| 8242 CHECK_ALIVE(VisitForValue(arguments->at(0))); | 8460 CHECK_ALIVE(VisitForValue(arguments->at(0))); |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8303 | 8521 |
| 8304 if (!is_zero_byte_offset) { | 8522 if (!is_zero_byte_offset) { |
| 8305 byte_offset_smi.If<HIsSmiAndBranch>(byte_offset); | 8523 byte_offset_smi.If<HIsSmiAndBranch>(byte_offset); |
| 8306 byte_offset_smi.Then(); | 8524 byte_offset_smi.Then(); |
| 8307 } | 8525 } |
| 8308 | 8526 |
| 8309 { // byte_offset is Smi. | 8527 { // byte_offset is Smi. |
| 8310 BuildArrayBufferViewInitialization<JSTypedArray>( | 8528 BuildArrayBufferViewInitialization<JSTypedArray>( |
| 8311 obj, buffer, byte_offset, byte_length); | 8529 obj, buffer, byte_offset, byte_length); |
| 8312 | 8530 |
| 8313 ExternalArrayType array_type = kExternalByteArray; // Bogus initialization. | 8531 ExternalArrayType array_type = kExternalInt8Array; // Bogus initialization. |
| 8314 size_t element_size = 1; // Bogus initialization. | 8532 size_t element_size = 1; // Bogus initialization. |
| 8315 Runtime::ArrayIdToTypeAndSize(array_id, &array_type, &element_size); | 8533 Runtime::ArrayIdToTypeAndSize(array_id, &array_type, &element_size); |
| 8316 | 8534 |
| 8317 HInstruction* length = AddUncasted<HDiv>(byte_length, | 8535 HInstruction* length = AddUncasted<HDiv>(byte_length, |
| 8318 Add<HConstant>(static_cast<int32_t>(element_size))); | 8536 Add<HConstant>(static_cast<int32_t>(element_size))); |
| 8319 | 8537 |
| 8320 Add<HStoreNamedField>(obj, | 8538 Add<HStoreNamedField>(obj, |
| 8321 HObjectAccess::ForJSTypedArrayLength(), | 8539 HObjectAccess::ForJSTypedArrayLength(), |
| 8322 length); | 8540 length); |
| 8323 | 8541 |
| 8542 Handle<Map> external_array_map( |
| 8543 isolate()->heap()->MapForExternalArrayType(array_type)); |
| 8544 |
| 8324 HValue* elements = | 8545 HValue* elements = |
| 8325 Add<HAllocate>( | 8546 Add<HAllocate>( |
| 8326 Add<HConstant>(ExternalArray::kAlignedSize), | 8547 Add<HConstant>(ExternalArray::kAlignedSize), |
| 8327 HType::JSArray(), | 8548 HType::JSArray(), |
| 8328 NOT_TENURED, | 8549 NOT_TENURED, |
| 8329 static_cast<InstanceType>(FIRST_EXTERNAL_ARRAY_TYPE + array_type)); | 8550 external_array_map->instance_type()); |
| 8330 | 8551 |
| 8331 Handle<Map> external_array_map( | 8552 AddStoreMapConstant(elements, external_array_map); |
| 8332 isolate()->heap()->MapForExternalArrayType(array_type)); | |
| 8333 Add<HStoreNamedField>(elements, | |
| 8334 HObjectAccess::ForMap(), | |
| 8335 Add<HConstant>(external_array_map)); | |
| 8336 | 8553 |
| 8337 HValue* backing_store = Add<HLoadNamedField>( | 8554 HValue* backing_store = Add<HLoadNamedField>( |
| 8338 buffer, HObjectAccess::ForJSArrayBufferBackingStore()); | 8555 buffer, static_cast<HValue*>(NULL), |
| 8556 HObjectAccess::ForJSArrayBufferBackingStore()); |
| 8339 | 8557 |
| 8340 HValue* typed_array_start; | 8558 HValue* typed_array_start; |
| 8341 if (is_zero_byte_offset) { | 8559 if (is_zero_byte_offset) { |
| 8342 typed_array_start = backing_store; | 8560 typed_array_start = backing_store; |
| 8343 } else { | 8561 } else { |
| 8344 HInstruction* external_pointer = | 8562 HInstruction* external_pointer = |
| 8345 AddUncasted<HAdd>(backing_store, byte_offset); | 8563 AddUncasted<HAdd>(backing_store, byte_offset); |
| 8346 // Arguments are checked prior to call to TypedArrayInitialize, | 8564 // Arguments are checked prior to call to TypedArrayInitialize, |
| 8347 // including byte_offset. | 8565 // including byte_offset. |
| 8348 external_pointer->ClearFlag(HValue::kCanOverflow); | 8566 external_pointer->ClearFlag(HValue::kCanOverflow); |
| (...skipping 187 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8536 CreateJoin(materialize_false, materialize_true, expr->id()); | 8754 CreateJoin(materialize_false, materialize_true, expr->id()); |
| 8537 set_current_block(join); | 8755 set_current_block(join); |
| 8538 if (join != NULL) return ast_context()->ReturnValue(Pop()); | 8756 if (join != NULL) return ast_context()->ReturnValue(Pop()); |
| 8539 } | 8757 } |
| 8540 | 8758 |
| 8541 | 8759 |
| 8542 HInstruction* HOptimizedGraphBuilder::BuildIncrement( | 8760 HInstruction* HOptimizedGraphBuilder::BuildIncrement( |
| 8543 bool returns_original_input, | 8761 bool returns_original_input, |
| 8544 CountOperation* expr) { | 8762 CountOperation* expr) { |
| 8545 // The input to the count operation is on top of the expression stack. | 8763 // The input to the count operation is on top of the expression stack. |
| 8546 Handle<Type> info = expr->type(); | 8764 Representation rep = Representation::FromType(expr->type()); |
| 8547 Representation rep = Representation::FromType(info); | |
| 8548 if (rep.IsNone() || rep.IsTagged()) { | 8765 if (rep.IsNone() || rep.IsTagged()) { |
| 8549 rep = Representation::Smi(); | 8766 rep = Representation::Smi(); |
| 8550 } | 8767 } |
| 8551 | 8768 |
| 8552 if (returns_original_input) { | 8769 if (returns_original_input) { |
| 8553 // We need an explicit HValue representing ToNumber(input). The | 8770 // We need an explicit HValue representing ToNumber(input). The |
| 8554 // actual HChange instruction we need is (sometimes) added in a later | 8771 // actual HChange instruction we need is (sometimes) added in a later |
| 8555 // phase, so it is not available now to be used as an input to HAdd and | 8772 // phase, so it is not available now to be used as an input to HAdd and |
| 8556 // as the return value. | 8773 // as the return value. |
| 8557 HInstruction* number_input = AddUncasted<HForceRepresentation>(Pop(), rep); | 8774 HInstruction* number_input = AddUncasted<HForceRepresentation>(Pop(), rep); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8592 if (key != NULL) Push(key); | 8809 if (key != NULL) Push(key); |
| 8593 Push(value); | 8810 Push(value); |
| 8594 BuildStore(expr, prop, ast_id, return_id); | 8811 BuildStore(expr, prop, ast_id, return_id); |
| 8595 } | 8812 } |
| 8596 | 8813 |
| 8597 | 8814 |
| 8598 void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { | 8815 void HOptimizedGraphBuilder::VisitCountOperation(CountOperation* expr) { |
| 8599 ASSERT(!HasStackOverflow()); | 8816 ASSERT(!HasStackOverflow()); |
| 8600 ASSERT(current_block() != NULL); | 8817 ASSERT(current_block() != NULL); |
| 8601 ASSERT(current_block()->HasPredecessor()); | 8818 ASSERT(current_block()->HasPredecessor()); |
| 8602 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 8819 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); |
| 8603 Expression* target = expr->expression(); | 8820 Expression* target = expr->expression(); |
| 8604 VariableProxy* proxy = target->AsVariableProxy(); | 8821 VariableProxy* proxy = target->AsVariableProxy(); |
| 8605 Property* prop = target->AsProperty(); | 8822 Property* prop = target->AsProperty(); |
| 8606 if (proxy == NULL && prop == NULL) { | 8823 if (proxy == NULL && prop == NULL) { |
| 8607 return Bailout(kInvalidLhsInCountOperation); | 8824 return Bailout(kInvalidLhsInCountOperation); |
| 8608 } | 8825 } |
| 8609 | 8826 |
| 8610 // Match the full code generator stack by simulating an extra stack | 8827 // Match the full code generator stack by simulating an extra stack |
| 8611 // element for postfix operations in a non-effect context. The return | 8828 // element for postfix operations in a non-effect context. The return |
| 8612 // value is ToNumber(input). | 8829 // value is ToNumber(input). |
| (...skipping 175 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 8788 if (right_const->HasInteger32Value() && | 9005 if (right_const->HasInteger32Value() && |
| 8789 (right_const->Integer32Value() & 0x1f) != 0) { | 9006 (right_const->Integer32Value() & 0x1f) != 0) { |
| 8790 return false; | 9007 return false; |
| 8791 } | 9008 } |
| 8792 } | 9009 } |
| 8793 return true; | 9010 return true; |
| 8794 } | 9011 } |
| 8795 | 9012 |
| 8796 | 9013 |
| 8797 HValue* HGraphBuilder::EnforceNumberType(HValue* number, | 9014 HValue* HGraphBuilder::EnforceNumberType(HValue* number, |
| 8798 Handle<Type> expected) { | 9015 Type* expected) { |
| 8799 if (expected->Is(Type::Smi())) { | 9016 if (expected->Is(Type::Smi())) { |
| 8800 return AddUncasted<HForceRepresentation>(number, Representation::Smi()); | 9017 return AddUncasted<HForceRepresentation>(number, Representation::Smi()); |
| 8801 } | 9018 } |
| 8802 if (expected->Is(Type::Signed32())) { | 9019 if (expected->Is(Type::Signed32())) { |
| 8803 return AddUncasted<HForceRepresentation>(number, | 9020 return AddUncasted<HForceRepresentation>(number, |
| 8804 Representation::Integer32()); | 9021 Representation::Integer32()); |
| 8805 } | 9022 } |
| 8806 return number; | 9023 return number; |
| 8807 } | 9024 } |
| 8808 | 9025 |
| 8809 | 9026 |
| 8810 HValue* HGraphBuilder::TruncateToNumber(HValue* value, Handle<Type>* expected) { | 9027 HValue* HGraphBuilder::TruncateToNumber(HValue* value, Type** expected) { |
| 8811 if (value->IsConstant()) { | 9028 if (value->IsConstant()) { |
| 8812 HConstant* constant = HConstant::cast(value); | 9029 HConstant* constant = HConstant::cast(value); |
| 8813 Maybe<HConstant*> number = constant->CopyToTruncatedNumber(zone()); | 9030 Maybe<HConstant*> number = constant->CopyToTruncatedNumber(zone()); |
| 8814 if (number.has_value) { | 9031 if (number.has_value) { |
| 8815 *expected = Type::Number(isolate()); | 9032 *expected = Type::Number(zone()); |
| 8816 return AddInstruction(number.value); | 9033 return AddInstruction(number.value); |
| 8817 } | 9034 } |
| 8818 } | 9035 } |
| 8819 | 9036 |
| 8820 // We put temporary values on the stack, which don't correspond to anything | 9037 // We put temporary values on the stack, which don't correspond to anything |
| 8821 // in baseline code. Since nothing is observable we avoid recording those | 9038 // in baseline code. Since nothing is observable we avoid recording those |
| 8822 // pushes with a NoObservableSideEffectsScope. | 9039 // pushes with a NoObservableSideEffectsScope. |
| 8823 NoObservableSideEffectsScope no_effects(this); | 9040 NoObservableSideEffectsScope no_effects(this); |
| 8824 | 9041 |
| 8825 Handle<Type> expected_type = *expected; | 9042 Type* expected_type = *expected; |
| 8826 | 9043 |
| 8827 // Separate the number type from the rest. | 9044 // Separate the number type from the rest. |
| 8828 Handle<Type> expected_obj = Type::Intersect( | 9045 Type* expected_obj = |
| 8829 expected_type, Type::NonNumber(isolate()), isolate()); | 9046 Type::Intersect(expected_type, Type::NonNumber(zone()), zone()); |
| 8830 Handle<Type> expected_number = Type::Intersect( | 9047 Type* expected_number = |
| 8831 expected_type, Type::Number(isolate()), isolate()); | 9048 Type::Intersect(expected_type, Type::Number(zone()), zone()); |
| 8832 | 9049 |
| 8833 // We expect to get a number. | 9050 // We expect to get a number. |
| 8834 // (We need to check first, since Type::None->Is(Type::Any()) == true. | 9051 // (We need to check first, since Type::None->Is(Type::Any()) == true. |
| 8835 if (expected_obj->Is(Type::None())) { | 9052 if (expected_obj->Is(Type::None())) { |
| 8836 ASSERT(!expected_number->Is(Type::None())); | 9053 ASSERT(!expected_number->Is(Type::None(zone()))); |
| 8837 return value; | 9054 return value; |
| 8838 } | 9055 } |
| 8839 | 9056 |
| 8840 if (expected_obj->Is(Type::Undefined())) { | 9057 if (expected_obj->Is(Type::Undefined(zone()))) { |
| 8841 // This is already done by HChange. | 9058 // This is already done by HChange. |
| 8842 *expected = Type::Union( | 9059 *expected = Type::Union(expected_number, Type::Double(zone()), zone()); |
| 8843 expected_number, Type::Double(isolate()), isolate()); | |
| 8844 return value; | 9060 return value; |
| 8845 } | 9061 } |
| 8846 | 9062 |
| 8847 return value; | 9063 return value; |
| 8848 } | 9064 } |
| 8849 | 9065 |
| 8850 | 9066 |
| 8851 HValue* HOptimizedGraphBuilder::BuildBinaryOperation( | 9067 HValue* HOptimizedGraphBuilder::BuildBinaryOperation( |
| 8852 BinaryOperation* expr, | 9068 BinaryOperation* expr, |
| 8853 HValue* left, | 9069 HValue* left, |
| 8854 HValue* right) { | 9070 HValue* right, |
| 8855 Handle<Type> left_type = expr->left()->bounds().lower; | 9071 PushBeforeSimulateBehavior push_sim_result) { |
| 8856 Handle<Type> right_type = expr->right()->bounds().lower; | 9072 Type* left_type = expr->left()->bounds().lower; |
| 8857 Handle<Type> result_type = expr->bounds().lower; | 9073 Type* right_type = expr->right()->bounds().lower; |
| 9074 Type* result_type = expr->bounds().lower; |
| 8858 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); | 9075 Maybe<int> fixed_right_arg = expr->fixed_right_arg(); |
| 8859 Handle<AllocationSite> allocation_site = expr->allocation_site(); | 9076 Handle<AllocationSite> allocation_site = expr->allocation_site(); |
| 8860 | 9077 |
| 9078 PretenureFlag pretenure_flag = !FLAG_allocation_site_pretenuring ? |
| 9079 isolate()->heap()->GetPretenureMode() : NOT_TENURED; |
| 9080 |
| 8861 HAllocationMode allocation_mode = | 9081 HAllocationMode allocation_mode = |
| 8862 FLAG_allocation_site_pretenuring | 9082 FLAG_allocation_site_pretenuring |
| 8863 ? (allocation_site.is_null() | 9083 ? (allocation_site.is_null() |
| 8864 ? HAllocationMode(NOT_TENURED) | 9084 ? HAllocationMode(NOT_TENURED) |
| 8865 : HAllocationMode(allocation_site)) | 9085 : HAllocationMode(allocation_site)) |
| 8866 : HAllocationMode(isolate()->heap()->GetPretenureMode()); | 9086 : HAllocationMode(pretenure_flag); |
| 8867 | 9087 |
| 8868 HValue* result = HGraphBuilder::BuildBinaryOperation( | 9088 HValue* result = HGraphBuilder::BuildBinaryOperation( |
| 8869 expr->op(), left, right, left_type, right_type, result_type, | 9089 expr->op(), left, right, left_type, right_type, result_type, |
| 8870 fixed_right_arg, allocation_mode); | 9090 fixed_right_arg, allocation_mode); |
| 8871 // Add a simulate after instructions with observable side effects, and | 9091 // Add a simulate after instructions with observable side effects, and |
| 8872 // after phis, which are the result of BuildBinaryOperation when we | 9092 // after phis, which are the result of BuildBinaryOperation when we |
| 8873 // inlined some complex subgraph. | 9093 // inlined some complex subgraph. |
| 8874 if (result->HasObservableSideEffects() || result->IsPhi()) { | 9094 if (result->HasObservableSideEffects() || result->IsPhi()) { |
| 8875 Push(result); | 9095 if (push_sim_result == PUSH_BEFORE_SIMULATE) { |
| 8876 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 9096 Push(result); |
| 8877 Drop(1); | 9097 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
| 9098 Drop(1); |
| 9099 } else { |
| 9100 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
| 9101 } |
| 8878 } | 9102 } |
| 8879 return result; | 9103 return result; |
| 8880 } | 9104 } |
| 8881 | 9105 |
| 8882 | 9106 |
| 8883 HValue* HGraphBuilder::BuildBinaryOperation( | 9107 HValue* HGraphBuilder::BuildBinaryOperation( |
| 8884 Token::Value op, | 9108 Token::Value op, |
| 8885 HValue* left, | 9109 HValue* left, |
| 8886 HValue* right, | 9110 HValue* right, |
| 8887 Handle<Type> left_type, | 9111 Type* left_type, |
| 8888 Handle<Type> right_type, | 9112 Type* right_type, |
| 8889 Handle<Type> result_type, | 9113 Type* result_type, |
| 8890 Maybe<int> fixed_right_arg, | 9114 Maybe<int> fixed_right_arg, |
| 8891 HAllocationMode allocation_mode) { | 9115 HAllocationMode allocation_mode) { |
| 8892 | 9116 |
| 8893 Representation left_rep = Representation::FromType(left_type); | 9117 Representation left_rep = Representation::FromType(left_type); |
| 8894 Representation right_rep = Representation::FromType(right_type); | 9118 Representation right_rep = Representation::FromType(right_type); |
| 8895 | 9119 |
| 8896 bool maybe_string_add = op == Token::ADD && | 9120 bool maybe_string_add = op == Token::ADD && |
| 8897 (left_type->Maybe(Type::String()) || | 9121 (left_type->Maybe(Type::String()) || |
| 8898 right_type->Maybe(Type::String())); | 9122 right_type->Maybe(Type::String())); |
| 8899 | 9123 |
| 8900 if (left_type->Is(Type::None())) { | 9124 if (left_type->Is(Type::None())) { |
| 8901 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", | 9125 Add<HDeoptimize>("Insufficient type feedback for LHS of binary operation", |
| 8902 Deoptimizer::SOFT); | 9126 Deoptimizer::SOFT); |
| 8903 // TODO(rossberg): we should be able to get rid of non-continuous | 9127 // TODO(rossberg): we should be able to get rid of non-continuous |
| 8904 // defaults. | 9128 // defaults. |
| 8905 left_type = Type::Any(isolate()); | 9129 left_type = Type::Any(zone()); |
| 8906 } else { | 9130 } else { |
| 8907 if (!maybe_string_add) left = TruncateToNumber(left, &left_type); | 9131 if (!maybe_string_add) left = TruncateToNumber(left, &left_type); |
| 8908 left_rep = Representation::FromType(left_type); | 9132 left_rep = Representation::FromType(left_type); |
| 8909 } | 9133 } |
| 8910 | 9134 |
| 8911 if (right_type->Is(Type::None())) { | 9135 if (right_type->Is(Type::None())) { |
| 8912 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", | 9136 Add<HDeoptimize>("Insufficient type feedback for RHS of binary operation", |
| 8913 Deoptimizer::SOFT); | 9137 Deoptimizer::SOFT); |
| 8914 right_type = Type::Any(isolate()); | 9138 right_type = Type::Any(zone()); |
| 8915 } else { | 9139 } else { |
| 8916 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); | 9140 if (!maybe_string_add) right = TruncateToNumber(right, &right_type); |
| 8917 right_rep = Representation::FromType(right_type); | 9141 right_rep = Representation::FromType(right_type); |
| 8918 } | 9142 } |
| 8919 | 9143 |
| 8920 // Special case for string addition here. | 9144 // Special case for string addition here. |
| 8921 if (op == Token::ADD && | 9145 if (op == Token::ADD && |
| 8922 (left_type->Is(Type::String()) || right_type->Is(Type::String()))) { | 9146 (left_type->Is(Type::String()) || right_type->Is(Type::String()))) { |
| 8923 // Validate type feedback for left argument. | 9147 // Validate type feedback for left argument. |
| 8924 if (left_type->Is(Type::String())) { | 9148 if (left_type->Is(Type::String())) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 8947 ASSERT(left_type->Is(Type::String())); | 9171 ASSERT(left_type->Is(Type::String())); |
| 8948 right = BuildNumberToString(right, right_type); | 9172 right = BuildNumberToString(right, right_type); |
| 8949 } else if (!right_type->Is(Type::String())) { | 9173 } else if (!right_type->Is(Type::String())) { |
| 8950 ASSERT(left_type->Is(Type::String())); | 9174 ASSERT(left_type->Is(Type::String())); |
| 8951 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT); | 9175 HValue* function = AddLoadJSBuiltin(Builtins::STRING_ADD_LEFT); |
| 8952 Add<HPushArgument>(left); | 9176 Add<HPushArgument>(left); |
| 8953 Add<HPushArgument>(right); | 9177 Add<HPushArgument>(right); |
| 8954 return AddUncasted<HInvokeFunction>(function, 2); | 9178 return AddUncasted<HInvokeFunction>(function, 2); |
| 8955 } | 9179 } |
| 8956 | 9180 |
| 8957 // Inline the string addition into the stub when creating allocation | 9181 // Fast path for empty constant strings. |
| 8958 // mementos to gather allocation site feedback. | 9182 if (left->IsConstant() && |
| 8959 if (graph()->info()->IsStub() && | 9183 HConstant::cast(left)->HasStringValue() && |
| 8960 allocation_mode.CreateAllocationMementos()) { | 9184 HConstant::cast(left)->StringValue()->length() == 0) { |
| 8961 return BuildStringAdd(left, right, allocation_mode); | 9185 return right; |
| 9186 } |
| 9187 if (right->IsConstant() && |
| 9188 HConstant::cast(right)->HasStringValue() && |
| 9189 HConstant::cast(right)->StringValue()->length() == 0) { |
| 9190 return left; |
| 8962 } | 9191 } |
| 8963 | 9192 |
| 8964 // Register the dependent code with the allocation site. | 9193 // Register the dependent code with the allocation site. |
| 8965 if (!allocation_mode.feedback_site().is_null()) { | 9194 if (!allocation_mode.feedback_site().is_null()) { |
| 8966 ASSERT(!graph()->info()->IsStub()); | 9195 ASSERT(!graph()->info()->IsStub()); |
| 8967 Handle<AllocationSite> site(allocation_mode.feedback_site()); | 9196 Handle<AllocationSite> site(allocation_mode.feedback_site()); |
| 8968 AllocationSite::AddDependentCompilationInfo( | 9197 AllocationSite::AddDependentCompilationInfo( |
| 8969 site, AllocationSite::TENURING, top_info()); | 9198 site, AllocationSite::TENURING, top_info()); |
| 8970 } | 9199 } |
| 8971 | 9200 |
| 8972 // Inline string addition if we know that we'll create a cons string. | 9201 // Inline the string addition into the stub when creating allocation |
| 8973 if (left->IsConstant()) { | 9202 // mementos to gather allocation site feedback, or if we can statically |
| 8974 HConstant* c_left = HConstant::cast(left); | 9203 // infer that we're going to create a cons string. |
| 8975 if (c_left->HasStringValue()) { | 9204 if ((graph()->info()->IsStub() && |
| 8976 int c_left_length = c_left->StringValue()->length(); | 9205 allocation_mode.CreateAllocationMementos()) || |
| 8977 if (c_left_length == 0) { | 9206 (left->IsConstant() && |
| 8978 return right; | 9207 HConstant::cast(left)->HasStringValue() && |
| 8979 } else if (c_left_length + 1 >= ConsString::kMinLength) { | 9208 HConstant::cast(left)->StringValue()->length() + 1 >= |
| 8980 return BuildStringAdd(left, right, allocation_mode); | 9209 ConsString::kMinLength) || |
| 8981 } | 9210 (right->IsConstant() && |
| 8982 } | 9211 HConstant::cast(right)->HasStringValue() && |
| 8983 } | 9212 HConstant::cast(right)->StringValue()->length() + 1 >= |
| 8984 if (right->IsConstant()) { | 9213 ConsString::kMinLength)) { |
| 8985 HConstant* c_right = HConstant::cast(right); | 9214 return BuildStringAdd(left, right, allocation_mode); |
| 8986 if (c_right->HasStringValue()) { | |
| 8987 int c_right_length = c_right->StringValue()->length(); | |
| 8988 if (c_right_length == 0) { | |
| 8989 return left; | |
| 8990 } else if (c_right_length + 1 >= ConsString::kMinLength) { | |
| 8991 return BuildStringAdd(left, right, allocation_mode); | |
| 8992 } | |
| 8993 } | |
| 8994 } | 9215 } |
| 8995 | 9216 |
| 8996 // Fallback to using the string add stub. | 9217 // Fallback to using the string add stub. |
| 8997 return AddUncasted<HStringAdd>( | 9218 return AddUncasted<HStringAdd>( |
| 8998 left, right, allocation_mode.GetPretenureMode(), | 9219 left, right, allocation_mode.GetPretenureMode(), |
| 8999 STRING_ADD_CHECK_NONE, allocation_mode.feedback_site()); | 9220 STRING_ADD_CHECK_NONE, allocation_mode.feedback_site()); |
| 9000 } | 9221 } |
| 9001 | 9222 |
| 9002 if (graph()->info()->IsStub()) { | 9223 if (graph()->info()->IsStub()) { |
| 9003 left = EnforceNumberType(left, left_type); | 9224 left = EnforceNumberType(left, left_type); |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9170 eval_right->SetJoinId(expr->RightId()); | 9391 eval_right->SetJoinId(expr->RightId()); |
| 9171 set_current_block(eval_right); | 9392 set_current_block(eval_right); |
| 9172 Visit(expr->right()); | 9393 Visit(expr->right()); |
| 9173 } | 9394 } |
| 9174 | 9395 |
| 9175 } else if (ast_context()->IsValue()) { | 9396 } else if (ast_context()->IsValue()) { |
| 9176 CHECK_ALIVE(VisitForValue(expr->left())); | 9397 CHECK_ALIVE(VisitForValue(expr->left())); |
| 9177 ASSERT(current_block() != NULL); | 9398 ASSERT(current_block() != NULL); |
| 9178 HValue* left_value = Top(); | 9399 HValue* left_value = Top(); |
| 9179 | 9400 |
| 9180 if (left_value->IsConstant()) { | 9401 // Short-circuit left values that always evaluate to the same boolean value. |
| 9181 HConstant* left_constant = HConstant::cast(left_value); | 9402 if (expr->left()->ToBooleanIsTrue() || expr->left()->ToBooleanIsFalse()) { |
| 9182 if ((is_logical_and && left_constant->BooleanValue()) || | 9403 // l (evals true) && r -> r |
| 9183 (!is_logical_and && !left_constant->BooleanValue())) { | 9404 // l (evals true) || r -> l |
| 9184 Drop(1); // left_value. | 9405 // l (evals false) && r -> l |
| 9406 // l (evals false) || r -> r |
| 9407 if (is_logical_and == expr->left()->ToBooleanIsTrue()) { |
| 9408 Drop(1); |
| 9185 CHECK_ALIVE(VisitForValue(expr->right())); | 9409 CHECK_ALIVE(VisitForValue(expr->right())); |
| 9186 } | 9410 } |
| 9187 return ast_context()->ReturnValue(Pop()); | 9411 return ast_context()->ReturnValue(Pop()); |
| 9188 } | 9412 } |
| 9189 | 9413 |
| 9190 // We need an extra block to maintain edge-split form. | 9414 // We need an extra block to maintain edge-split form. |
| 9191 HBasicBlock* empty_block = graph()->CreateBasicBlock(); | 9415 HBasicBlock* empty_block = graph()->CreateBasicBlock(); |
| 9192 HBasicBlock* eval_right = graph()->CreateBasicBlock(); | 9416 HBasicBlock* eval_right = graph()->CreateBasicBlock(); |
| 9193 ToBooleanStub::Types expected(expr->left()->to_boolean_types()); | 9417 ToBooleanStub::Types expected(expr->left()->to_boolean_types()); |
| 9194 HBranch* test = is_logical_and | 9418 HBranch* test = is_logical_and |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9247 } | 9471 } |
| 9248 } | 9472 } |
| 9249 | 9473 |
| 9250 | 9474 |
| 9251 void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) { | 9475 void HOptimizedGraphBuilder::VisitArithmeticExpression(BinaryOperation* expr) { |
| 9252 CHECK_ALIVE(VisitForValue(expr->left())); | 9476 CHECK_ALIVE(VisitForValue(expr->left())); |
| 9253 CHECK_ALIVE(VisitForValue(expr->right())); | 9477 CHECK_ALIVE(VisitForValue(expr->right())); |
| 9254 SetSourcePosition(expr->position()); | 9478 SetSourcePosition(expr->position()); |
| 9255 HValue* right = Pop(); | 9479 HValue* right = Pop(); |
| 9256 HValue* left = Pop(); | 9480 HValue* left = Pop(); |
| 9257 HValue* result = BuildBinaryOperation(expr, left, right); | 9481 HValue* result = |
| 9258 if (FLAG_emit_opt_code_positions && result->IsBinaryOperation()) { | 9482 BuildBinaryOperation(expr, left, right, |
| 9483 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE |
| 9484 : PUSH_BEFORE_SIMULATE); |
| 9485 if (FLAG_hydrogen_track_positions && result->IsBinaryOperation()) { |
| 9259 HBinaryOperation::cast(result)->SetOperandPositions( | 9486 HBinaryOperation::cast(result)->SetOperandPositions( |
| 9260 zone(), expr->left()->position(), expr->right()->position()); | 9487 zone(), |
| 9488 ScriptPositionToSourcePosition(expr->left()->position()), |
| 9489 ScriptPositionToSourcePosition(expr->right()->position())); |
| 9261 } | 9490 } |
| 9262 return ast_context()->ReturnValue(result); | 9491 return ast_context()->ReturnValue(result); |
| 9263 } | 9492 } |
| 9264 | 9493 |
| 9265 | 9494 |
| 9266 void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, | 9495 void HOptimizedGraphBuilder::HandleLiteralCompareTypeof(CompareOperation* expr, |
| 9267 Expression* sub_expr, | 9496 Expression* sub_expr, |
| 9268 Handle<String> check) { | 9497 Handle<String> check) { |
| 9269 CHECK_ALIVE(VisitForTypeOf(sub_expr)); | 9498 CHECK_ALIVE(VisitForTypeOf(sub_expr)); |
| 9270 SetSourcePosition(expr->position()); | 9499 SetSourcePosition(expr->position()); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 9284 (right->IsConstant() && | 9513 (right->IsConstant() && |
| 9285 HConstant::cast(right)->handle(isolate)->IsBoolean())); | 9514 HConstant::cast(right)->handle(isolate)->IsBoolean())); |
| 9286 } | 9515 } |
| 9287 | 9516 |
| 9288 | 9517 |
| 9289 void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { | 9518 void HOptimizedGraphBuilder::VisitCompareOperation(CompareOperation* expr) { |
| 9290 ASSERT(!HasStackOverflow()); | 9519 ASSERT(!HasStackOverflow()); |
| 9291 ASSERT(current_block() != NULL); | 9520 ASSERT(current_block() != NULL); |
| 9292 ASSERT(current_block()->HasPredecessor()); | 9521 ASSERT(current_block()->HasPredecessor()); |
| 9293 | 9522 |
| 9294 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 9523 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); |
| 9295 | 9524 |
| 9296 // Check for a few fast cases. The AST visiting behavior must be in sync | 9525 // Check for a few fast cases. The AST visiting behavior must be in sync |
| 9297 // with the full codegen: We don't push both left and right values onto | 9526 // with the full codegen: We don't push both left and right values onto |
| 9298 // the expression stack when one side is a special-case literal. | 9527 // the expression stack when one side is a special-case literal. |
| 9299 Expression* sub_expr = NULL; | 9528 Expression* sub_expr = NULL; |
| 9300 Handle<String> check; | 9529 Handle<String> check; |
| 9301 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { | 9530 if (expr->IsLiteralCompareTypeof(&sub_expr, &check)) { |
| 9302 return HandleLiteralCompareTypeof(expr, sub_expr, check); | 9531 return HandleLiteralCompareTypeof(expr, sub_expr, check); |
| 9303 } | 9532 } |
| 9304 if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) { | 9533 if (expr->IsLiteralCompareUndefined(&sub_expr, isolate())) { |
| 9305 return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue); | 9534 return HandleLiteralCompareNil(expr, sub_expr, kUndefinedValue); |
| 9306 } | 9535 } |
| 9307 if (expr->IsLiteralCompareNull(&sub_expr)) { | 9536 if (expr->IsLiteralCompareNull(&sub_expr)) { |
| 9308 return HandleLiteralCompareNil(expr, sub_expr, kNullValue); | 9537 return HandleLiteralCompareNil(expr, sub_expr, kNullValue); |
| 9309 } | 9538 } |
| 9310 | 9539 |
| 9311 if (IsClassOfTest(expr)) { | 9540 if (IsClassOfTest(expr)) { |
| 9312 CallRuntime* call = expr->left()->AsCallRuntime(); | 9541 CallRuntime* call = expr->left()->AsCallRuntime(); |
| 9313 ASSERT(call->arguments()->length() == 1); | 9542 ASSERT(call->arguments()->length() == 1); |
| 9314 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 9543 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 9315 HValue* value = Pop(); | 9544 HValue* value = Pop(); |
| 9316 Literal* literal = expr->right()->AsLiteral(); | 9545 Literal* literal = expr->right()->AsLiteral(); |
| 9317 Handle<String> rhs = Handle<String>::cast(literal->value()); | 9546 Handle<String> rhs = Handle<String>::cast(literal->value()); |
| 9318 HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs); | 9547 HClassOfTestAndBranch* instr = New<HClassOfTestAndBranch>(value, rhs); |
| 9319 return ast_context()->ReturnControl(instr, expr->id()); | 9548 return ast_context()->ReturnControl(instr, expr->id()); |
| 9320 } | 9549 } |
| 9321 | 9550 |
| 9322 Handle<Type> left_type = expr->left()->bounds().lower; | 9551 Type* left_type = expr->left()->bounds().lower; |
| 9323 Handle<Type> right_type = expr->right()->bounds().lower; | 9552 Type* right_type = expr->right()->bounds().lower; |
| 9324 Handle<Type> combined_type = expr->combined_type(); | 9553 Type* combined_type = expr->combined_type(); |
| 9325 | 9554 |
| 9326 CHECK_ALIVE(VisitForValue(expr->left())); | 9555 CHECK_ALIVE(VisitForValue(expr->left())); |
| 9327 CHECK_ALIVE(VisitForValue(expr->right())); | 9556 CHECK_ALIVE(VisitForValue(expr->right())); |
| 9328 | 9557 |
| 9329 if (FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 9558 if (FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); |
| 9330 | 9559 |
| 9331 HValue* right = Pop(); | 9560 HValue* right = Pop(); |
| 9332 HValue* left = Pop(); | 9561 HValue* left = Pop(); |
| 9333 Token::Value op = expr->op(); | 9562 Token::Value op = expr->op(); |
| 9334 | 9563 |
| 9335 if (IsLiteralCompareBool(isolate(), left, op, right)) { | 9564 if (IsLiteralCompareBool(isolate(), left, op, right)) { |
| 9336 HCompareObjectEqAndBranch* result = | 9565 HCompareObjectEqAndBranch* result = |
| 9337 New<HCompareObjectEqAndBranch>(left, right); | 9566 New<HCompareObjectEqAndBranch>(left, right); |
| 9338 return ast_context()->ReturnControl(result, expr->id()); | 9567 return ast_context()->ReturnControl(result, expr->id()); |
| 9339 } | 9568 } |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9379 } else if (op == Token::IN) { | 9608 } else if (op == Token::IN) { |
| 9380 HValue* function = AddLoadJSBuiltin(Builtins::IN); | 9609 HValue* function = AddLoadJSBuiltin(Builtins::IN); |
| 9381 Add<HPushArgument>(left); | 9610 Add<HPushArgument>(left); |
| 9382 Add<HPushArgument>(right); | 9611 Add<HPushArgument>(right); |
| 9383 // TODO(olivf) InvokeFunction produces a check for the parameter count, | 9612 // TODO(olivf) InvokeFunction produces a check for the parameter count, |
| 9384 // even though we are certain to pass the correct number of arguments here. | 9613 // even though we are certain to pass the correct number of arguments here. |
| 9385 HInstruction* result = New<HInvokeFunction>(function, 2); | 9614 HInstruction* result = New<HInvokeFunction>(function, 2); |
| 9386 return ast_context()->ReturnInstruction(result, expr->id()); | 9615 return ast_context()->ReturnInstruction(result, expr->id()); |
| 9387 } | 9616 } |
| 9388 | 9617 |
| 9618 PushBeforeSimulateBehavior push_behavior = |
| 9619 ast_context()->IsEffect() ? NO_PUSH_BEFORE_SIMULATE |
| 9620 : PUSH_BEFORE_SIMULATE; |
| 9389 HControlInstruction* compare = BuildCompareInstruction( | 9621 HControlInstruction* compare = BuildCompareInstruction( |
| 9390 op, left, right, left_type, right_type, combined_type, | 9622 op, left, right, left_type, right_type, combined_type, |
| 9391 expr->left()->position(), expr->right()->position(), expr->id()); | 9623 ScriptPositionToSourcePosition(expr->left()->position()), |
| 9624 ScriptPositionToSourcePosition(expr->right()->position()), |
| 9625 push_behavior, expr->id()); |
| 9392 if (compare == NULL) return; // Bailed out. | 9626 if (compare == NULL) return; // Bailed out. |
| 9393 return ast_context()->ReturnControl(compare, expr->id()); | 9627 return ast_context()->ReturnControl(compare, expr->id()); |
| 9394 } | 9628 } |
| 9395 | 9629 |
| 9396 | 9630 |
| 9397 HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction( | 9631 HControlInstruction* HOptimizedGraphBuilder::BuildCompareInstruction( |
| 9398 Token::Value op, | 9632 Token::Value op, |
| 9399 HValue* left, | 9633 HValue* left, |
| 9400 HValue* right, | 9634 HValue* right, |
| 9401 Handle<Type> left_type, | 9635 Type* left_type, |
| 9402 Handle<Type> right_type, | 9636 Type* right_type, |
| 9403 Handle<Type> combined_type, | 9637 Type* combined_type, |
| 9404 int left_position, | 9638 HSourcePosition left_position, |
| 9405 int right_position, | 9639 HSourcePosition right_position, |
| 9640 PushBeforeSimulateBehavior push_sim_result, |
| 9406 BailoutId bailout_id) { | 9641 BailoutId bailout_id) { |
| 9407 // Cases handled below depend on collected type feedback. They should | 9642 // Cases handled below depend on collected type feedback. They should |
| 9408 // soft deoptimize when there is no type feedback. | 9643 // soft deoptimize when there is no type feedback. |
| 9409 if (combined_type->Is(Type::None())) { | 9644 if (combined_type->Is(Type::None())) { |
| 9410 Add<HDeoptimize>("Insufficient type feedback for combined type " | 9645 Add<HDeoptimize>("Insufficient type feedback for combined type " |
| 9411 "of binary operation", | 9646 "of binary operation", |
| 9412 Deoptimizer::SOFT); | 9647 Deoptimizer::SOFT); |
| 9413 combined_type = left_type = right_type = Type::Any(isolate()); | 9648 combined_type = left_type = right_type = Type::Any(zone()); |
| 9414 } | 9649 } |
| 9415 | 9650 |
| 9416 Representation left_rep = Representation::FromType(left_type); | 9651 Representation left_rep = Representation::FromType(left_type); |
| 9417 Representation right_rep = Representation::FromType(right_type); | 9652 Representation right_rep = Representation::FromType(right_type); |
| 9418 Representation combined_rep = Representation::FromType(combined_type); | 9653 Representation combined_rep = Representation::FromType(combined_type); |
| 9419 | 9654 |
| 9420 if (combined_type->Is(Type::Receiver())) { | 9655 if (combined_type->Is(Type::Receiver())) { |
| 9421 if (Token::IsEqualityOp(op)) { | 9656 if (Token::IsEqualityOp(op)) { |
| 9422 // Can we get away with map check and not instance type check? | 9657 // Can we get away with map check and not instance type check? |
| 9423 HValue* operand_to_check = | 9658 HValue* operand_to_check = |
| 9424 left->block()->block_id() < right->block()->block_id() ? left : right; | 9659 left->block()->block_id() < right->block()->block_id() ? left : right; |
| 9425 if (combined_type->IsClass()) { | 9660 if (combined_type->IsClass()) { |
| 9426 Handle<Map> map = combined_type->AsClass(); | 9661 Handle<Map> map = combined_type->AsClass(); |
| 9427 AddCheckMap(operand_to_check, map); | 9662 AddCheckMap(operand_to_check, map); |
| 9428 HCompareObjectEqAndBranch* result = | 9663 HCompareObjectEqAndBranch* result = |
| 9429 New<HCompareObjectEqAndBranch>(left, right); | 9664 New<HCompareObjectEqAndBranch>(left, right); |
| 9430 if (FLAG_emit_opt_code_positions) { | 9665 if (FLAG_hydrogen_track_positions) { |
| 9431 result->set_operand_position(zone(), 0, left_position); | 9666 result->set_operand_position(zone(), 0, left_position); |
| 9432 result->set_operand_position(zone(), 1, right_position); | 9667 result->set_operand_position(zone(), 1, right_position); |
| 9433 } | 9668 } |
| 9434 return result; | 9669 return result; |
| 9435 } else { | 9670 } else { |
| 9436 BuildCheckHeapObject(operand_to_check); | 9671 BuildCheckHeapObject(operand_to_check); |
| 9437 Add<HCheckInstanceType>(operand_to_check, | 9672 Add<HCheckInstanceType>(operand_to_check, |
| 9438 HCheckInstanceType::IS_SPEC_OBJECT); | 9673 HCheckInstanceType::IS_SPEC_OBJECT); |
| 9439 HCompareObjectEqAndBranch* result = | 9674 HCompareObjectEqAndBranch* result = |
| 9440 New<HCompareObjectEqAndBranch>(left, right); | 9675 New<HCompareObjectEqAndBranch>(left, right); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 9460 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING); | 9695 Add<HCheckInstanceType>(right, HCheckInstanceType::IS_STRING); |
| 9461 HStringCompareAndBranch* result = | 9696 HStringCompareAndBranch* result = |
| 9462 New<HStringCompareAndBranch>(left, right, op); | 9697 New<HStringCompareAndBranch>(left, right, op); |
| 9463 return result; | 9698 return result; |
| 9464 } else { | 9699 } else { |
| 9465 if (combined_rep.IsTagged() || combined_rep.IsNone()) { | 9700 if (combined_rep.IsTagged() || combined_rep.IsNone()) { |
| 9466 HCompareGeneric* result = Add<HCompareGeneric>(left, right, op); | 9701 HCompareGeneric* result = Add<HCompareGeneric>(left, right, op); |
| 9467 result->set_observed_input_representation(1, left_rep); | 9702 result->set_observed_input_representation(1, left_rep); |
| 9468 result->set_observed_input_representation(2, right_rep); | 9703 result->set_observed_input_representation(2, right_rep); |
| 9469 if (result->HasObservableSideEffects()) { | 9704 if (result->HasObservableSideEffects()) { |
| 9470 Push(result); | 9705 if (push_sim_result == PUSH_BEFORE_SIMULATE) { |
| 9471 AddSimulate(bailout_id, REMOVABLE_SIMULATE); | 9706 Push(result); |
| 9472 Drop(1); | 9707 AddSimulate(bailout_id, REMOVABLE_SIMULATE); |
| 9708 Drop(1); |
| 9709 } else { |
| 9710 AddSimulate(bailout_id, REMOVABLE_SIMULATE); |
| 9711 } |
| 9473 } | 9712 } |
| 9474 // TODO(jkummerow): Can we make this more efficient? | 9713 // TODO(jkummerow): Can we make this more efficient? |
| 9475 HBranch* branch = New<HBranch>(result); | 9714 HBranch* branch = New<HBranch>(result); |
| 9476 return branch; | 9715 return branch; |
| 9477 } else { | 9716 } else { |
| 9478 HCompareNumericAndBranch* result = | 9717 HCompareNumericAndBranch* result = |
| 9479 New<HCompareNumericAndBranch>(left, right, op); | 9718 New<HCompareNumericAndBranch>(left, right, op); |
| 9480 result->set_observed_input_representation(left_rep, right_rep); | 9719 result->set_observed_input_representation(left_rep, right_rep); |
| 9481 if (FLAG_emit_opt_code_positions) { | 9720 if (FLAG_hydrogen_track_positions) { |
| 9482 result->SetOperandPositions(zone(), left_position, right_position); | 9721 result->SetOperandPositions(zone(), left_position, right_position); |
| 9483 } | 9722 } |
| 9484 return result; | 9723 return result; |
| 9485 } | 9724 } |
| 9486 } | 9725 } |
| 9487 } | 9726 } |
| 9488 | 9727 |
| 9489 | 9728 |
| 9490 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, | 9729 void HOptimizedGraphBuilder::HandleLiteralCompareNil(CompareOperation* expr, |
| 9491 Expression* sub_expr, | 9730 Expression* sub_expr, |
| 9492 NilValue nil) { | 9731 NilValue nil) { |
| 9493 ASSERT(!HasStackOverflow()); | 9732 ASSERT(!HasStackOverflow()); |
| 9494 ASSERT(current_block() != NULL); | 9733 ASSERT(current_block() != NULL); |
| 9495 ASSERT(current_block()->HasPredecessor()); | 9734 ASSERT(current_block()->HasPredecessor()); |
| 9496 ASSERT(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT); | 9735 ASSERT(expr->op() == Token::EQ || expr->op() == Token::EQ_STRICT); |
| 9497 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 9736 if (!FLAG_hydrogen_track_positions) SetSourcePosition(expr->position()); |
| 9498 CHECK_ALIVE(VisitForValue(sub_expr)); | 9737 CHECK_ALIVE(VisitForValue(sub_expr)); |
| 9499 HValue* value = Pop(); | 9738 HValue* value = Pop(); |
| 9500 if (expr->op() == Token::EQ_STRICT) { | 9739 if (expr->op() == Token::EQ_STRICT) { |
| 9501 HConstant* nil_constant = nil == kNullValue | 9740 HConstant* nil_constant = nil == kNullValue |
| 9502 ? graph()->GetConstantNull() | 9741 ? graph()->GetConstantNull() |
| 9503 : graph()->GetConstantUndefined(); | 9742 : graph()->GetConstantUndefined(); |
| 9504 HCompareObjectEqAndBranch* instr = | 9743 HCompareObjectEqAndBranch* instr = |
| 9505 New<HCompareObjectEqAndBranch>(value, nil_constant); | 9744 New<HCompareObjectEqAndBranch>(value, nil_constant); |
| 9506 return ast_context()->ReturnControl(instr, expr->id()); | 9745 return ast_context()->ReturnControl(instr, expr->id()); |
| 9507 } else { | 9746 } else { |
| 9508 ASSERT_EQ(Token::EQ, expr->op()); | 9747 ASSERT_EQ(Token::EQ, expr->op()); |
| 9509 Handle<Type> type = expr->combined_type()->Is(Type::None()) | 9748 Type* type = expr->combined_type()->Is(Type::None()) |
| 9510 ? Type::Any(isolate_) : expr->combined_type(); | 9749 ? Type::Any(zone()) : expr->combined_type(); |
| 9511 HIfContinuation continuation; | 9750 HIfContinuation continuation; |
| 9512 BuildCompareNil(value, type, &continuation); | 9751 BuildCompareNil(value, type, &continuation); |
| 9513 return ast_context()->ReturnContinuation(&continuation, expr->id()); | 9752 return ast_context()->ReturnContinuation(&continuation, expr->id()); |
| 9514 } | 9753 } |
| 9515 } | 9754 } |
| 9516 | 9755 |
| 9517 | 9756 |
| 9518 HInstruction* HOptimizedGraphBuilder::BuildThisFunction() { | 9757 HInstruction* HOptimizedGraphBuilder::BuildThisFunction() { |
| 9519 // If we share optimized code between different closures, the | 9758 // If we share optimized code between different closures, the |
| 9520 // this-function is not a constant, except inside an inlined body. | 9759 // this-function is not a constant, except inside an inlined body. |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9554 | 9793 |
| 9555 Handle<FixedArrayBase> elements(boilerplate_object->elements()); | 9794 Handle<FixedArrayBase> elements(boilerplate_object->elements()); |
| 9556 int elements_size = (elements->length() > 0 && | 9795 int elements_size = (elements->length() > 0 && |
| 9557 elements->map() != isolate()->heap()->fixed_cow_array_map()) ? | 9796 elements->map() != isolate()->heap()->fixed_cow_array_map()) ? |
| 9558 elements->Size() : 0; | 9797 elements->Size() : 0; |
| 9559 | 9798 |
| 9560 HInstruction* object_elements = NULL; | 9799 HInstruction* object_elements = NULL; |
| 9561 if (elements_size > 0) { | 9800 if (elements_size > 0) { |
| 9562 HValue* object_elements_size = Add<HConstant>(elements_size); | 9801 HValue* object_elements_size = Add<HConstant>(elements_size); |
| 9563 if (boilerplate_object->HasFastDoubleElements()) { | 9802 if (boilerplate_object->HasFastDoubleElements()) { |
| 9803 // Allocation folding will not be able to fold |object| and |
| 9804 // |object_elements| together if they are pre-tenured. |
| 9805 if (pretenure_flag == TENURED) { |
| 9806 HConstant* empty_fixed_array = Add<HConstant>( |
| 9807 isolate()->factory()->empty_fixed_array()); |
| 9808 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), |
| 9809 empty_fixed_array); |
| 9810 } |
| 9564 object_elements = Add<HAllocate>(object_elements_size, HType::JSObject(), | 9811 object_elements = Add<HAllocate>(object_elements_size, HType::JSObject(), |
| 9565 pretenure_flag, FIXED_DOUBLE_ARRAY_TYPE, site_context->current()); | 9812 pretenure_flag, FIXED_DOUBLE_ARRAY_TYPE, site_context->current()); |
| 9566 } else { | 9813 } else { |
| 9567 object_elements = Add<HAllocate>(object_elements_size, HType::JSObject(), | 9814 object_elements = Add<HAllocate>(object_elements_size, HType::JSObject(), |
| 9568 pretenure_flag, FIXED_ARRAY_TYPE, site_context->current()); | 9815 pretenure_flag, FIXED_ARRAY_TYPE, site_context->current()); |
| 9569 } | 9816 } |
| 9570 } | 9817 } |
| 9571 BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements); | 9818 BuildInitElementsInObjectHeader(boilerplate_object, object, object_elements); |
| 9572 | 9819 |
| 9573 // Copy object elements if non-COW. | 9820 // Copy object elements if non-COW. |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 9627 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), | 9874 Add<HStoreNamedField>(object, HObjectAccess::ForElementsPointer(), |
| 9628 object_elements); | 9875 object_elements); |
| 9629 } | 9876 } |
| 9630 | 9877 |
| 9631 | 9878 |
| 9632 void HOptimizedGraphBuilder::BuildEmitInObjectProperties( | 9879 void HOptimizedGraphBuilder::BuildEmitInObjectProperties( |
| 9633 Handle<JSObject> boilerplate_object, | 9880 Handle<JSObject> boilerplate_object, |
| 9634 HInstruction* object, | 9881 HInstruction* object, |
| 9635 AllocationSiteUsageContext* site_context, | 9882 AllocationSiteUsageContext* site_context, |
| 9636 PretenureFlag pretenure_flag) { | 9883 PretenureFlag pretenure_flag) { |
| 9637 Handle<DescriptorArray> descriptors( | 9884 Handle<Map> boilerplate_map(boilerplate_object->map()); |
| 9638 boilerplate_object->map()->instance_descriptors()); | 9885 Handle<DescriptorArray> descriptors(boilerplate_map->instance_descriptors()); |
| 9639 int limit = boilerplate_object->map()->NumberOfOwnDescriptors(); | 9886 int limit = boilerplate_map->NumberOfOwnDescriptors(); |
| 9640 | 9887 |
| 9641 int copied_fields = 0; | 9888 int copied_fields = 0; |
| 9642 for (int i = 0; i < limit; i++) { | 9889 for (int i = 0; i < limit; i++) { |
| 9643 PropertyDetails details = descriptors->GetDetails(i); | 9890 PropertyDetails details = descriptors->GetDetails(i); |
| 9644 if (details.type() != FIELD) continue; | 9891 if (details.type() != FIELD) continue; |
| 9645 copied_fields++; | 9892 copied_fields++; |
| 9646 int index = descriptors->GetFieldIndex(i); | 9893 int index = descriptors->GetFieldIndex(i); |
| 9647 int property_offset = boilerplate_object->GetInObjectPropertyOffset(index); | 9894 int property_offset = boilerplate_object->GetInObjectPropertyOffset(index); |
| 9648 Handle<Name> name(descriptors->GetKey(i)); | 9895 Handle<Name> name(descriptors->GetKey(i)); |
| 9649 Handle<Object> value = | 9896 Handle<Object> value = |
| 9650 Handle<Object>(boilerplate_object->InObjectPropertyAt(index), | 9897 Handle<Object>(boilerplate_object->InObjectPropertyAt(index), |
| 9651 isolate()); | 9898 isolate()); |
| 9652 | 9899 |
| 9653 // The access for the store depends on the type of the boilerplate. | 9900 // The access for the store depends on the type of the boilerplate. |
| 9654 HObjectAccess access = boilerplate_object->IsJSArray() ? | 9901 HObjectAccess access = boilerplate_object->IsJSArray() ? |
| 9655 HObjectAccess::ForJSArrayOffset(property_offset) : | 9902 HObjectAccess::ForJSArrayOffset(property_offset) : |
| 9656 HObjectAccess::ForJSObjectOffset(property_offset); | 9903 HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset); |
| 9657 | 9904 |
| 9658 if (value->IsJSObject()) { | 9905 if (value->IsJSObject()) { |
| 9659 Handle<JSObject> value_object = Handle<JSObject>::cast(value); | 9906 Handle<JSObject> value_object = Handle<JSObject>::cast(value); |
| 9660 Handle<AllocationSite> current_site = site_context->EnterNewScope(); | 9907 Handle<AllocationSite> current_site = site_context->EnterNewScope(); |
| 9661 HInstruction* result = | 9908 HInstruction* result = |
| 9662 BuildFastLiteral(value_object, site_context); | 9909 BuildFastLiteral(value_object, site_context); |
| 9663 site_context->ExitScope(current_site, value_object); | 9910 site_context->ExitScope(current_site, value_object); |
| 9664 Add<HStoreNamedField>(object, access, result); | 9911 Add<HStoreNamedField>(object, access, result); |
| 9665 } else { | 9912 } else { |
| 9666 Representation representation = details.representation(); | 9913 Representation representation = details.representation(); |
| 9667 HInstruction* value_instruction; | 9914 HInstruction* value_instruction; |
| 9668 | 9915 |
| 9669 if (representation.IsDouble()) { | 9916 if (representation.IsDouble()) { |
| 9670 // Allocate a HeapNumber box and store the value into it. | 9917 // Allocate a HeapNumber box and store the value into it. |
| 9671 HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize); | 9918 HValue* heap_number_constant = Add<HConstant>(HeapNumber::kSize); |
| 9672 // This heap number alloc does not have a corresponding | 9919 // This heap number alloc does not have a corresponding |
| 9673 // AllocationSite. That is okay because | 9920 // AllocationSite. That is okay because |
| 9674 // 1) it's a child object of another object with a valid allocation site | 9921 // 1) it's a child object of another object with a valid allocation site |
| 9675 // 2) we can just use the mode of the parent object for pretenuring | 9922 // 2) we can just use the mode of the parent object for pretenuring |
| 9676 HInstruction* double_box = | 9923 HInstruction* double_box = |
| 9677 Add<HAllocate>(heap_number_constant, HType::HeapNumber(), | 9924 Add<HAllocate>(heap_number_constant, HType::HeapNumber(), |
| 9678 pretenure_flag, HEAP_NUMBER_TYPE); | 9925 pretenure_flag, HEAP_NUMBER_TYPE); |
| 9679 AddStoreMapConstant(double_box, | 9926 AddStoreMapConstant(double_box, |
| 9680 isolate()->factory()->heap_number_map()); | 9927 isolate()->factory()->heap_number_map()); |
| 9681 Add<HStoreNamedField>(double_box, HObjectAccess::ForHeapNumberValue(), | 9928 Add<HStoreNamedField>(double_box, HObjectAccess::ForHeapNumberValue(), |
| 9682 Add<HConstant>(value)); | 9929 Add<HConstant>(value)); |
| 9683 value_instruction = double_box; | 9930 value_instruction = double_box; |
| 9684 } else if (representation.IsSmi() && value->IsUninitialized()) { | 9931 } else if (representation.IsSmi()) { |
| 9685 value_instruction = graph()->GetConstant0(); | 9932 value_instruction = value->IsUninitialized() |
| 9933 ? graph()->GetConstant0() |
| 9934 : Add<HConstant>(value); |
| 9935 // Ensure that value is stored as smi. |
| 9936 access = access.WithRepresentation(representation); |
| 9686 } else { | 9937 } else { |
| 9687 value_instruction = Add<HConstant>(value); | 9938 value_instruction = Add<HConstant>(value); |
| 9688 } | 9939 } |
| 9689 | 9940 |
| 9690 Add<HStoreNamedField>(object, access, value_instruction); | 9941 Add<HStoreNamedField>(object, access, value_instruction); |
| 9691 } | 9942 } |
| 9692 } | 9943 } |
| 9693 | 9944 |
| 9694 int inobject_properties = boilerplate_object->map()->inobject_properties(); | 9945 int inobject_properties = boilerplate_object->map()->inobject_properties(); |
| 9695 HInstruction* value_instruction = | 9946 HInstruction* value_instruction = |
| 9696 Add<HConstant>(isolate()->factory()->one_pointer_filler_map()); | 9947 Add<HConstant>(isolate()->factory()->one_pointer_filler_map()); |
| 9697 for (int i = copied_fields; i < inobject_properties; i++) { | 9948 for (int i = copied_fields; i < inobject_properties; i++) { |
| 9698 ASSERT(boilerplate_object->IsJSObject()); | 9949 ASSERT(boilerplate_object->IsJSObject()); |
| 9699 int property_offset = boilerplate_object->GetInObjectPropertyOffset(i); | 9950 int property_offset = boilerplate_object->GetInObjectPropertyOffset(i); |
| 9700 HObjectAccess access = HObjectAccess::ForJSObjectOffset(property_offset); | 9951 HObjectAccess access = |
| 9952 HObjectAccess::ForMapAndOffset(boilerplate_map, property_offset); |
| 9701 Add<HStoreNamedField>(object, access, value_instruction); | 9953 Add<HStoreNamedField>(object, access, value_instruction); |
| 9702 } | 9954 } |
| 9703 } | 9955 } |
| 9704 | 9956 |
| 9705 | 9957 |
| 9706 void HOptimizedGraphBuilder::BuildEmitElements( | 9958 void HOptimizedGraphBuilder::BuildEmitElements( |
| 9707 Handle<JSObject> boilerplate_object, | 9959 Handle<JSObject> boilerplate_object, |
| 9708 Handle<FixedArrayBase> elements, | 9960 Handle<FixedArrayBase> elements, |
| 9709 HValue* object_elements, | 9961 HValue* object_elements, |
| 9710 AllocationSiteUsageContext* site_context) { | 9962 AllocationSiteUsageContext* site_context) { |
| (...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10068 void HOptimizedGraphBuilder::GenerateClassOf(CallRuntime* call) { | 10320 void HOptimizedGraphBuilder::GenerateClassOf(CallRuntime* call) { |
| 10069 // The special form detected by IsClassOfTest is detected before we get here | 10321 // The special form detected by IsClassOfTest is detected before we get here |
| 10070 // and does not cause a bailout. | 10322 // and does not cause a bailout. |
| 10071 return Bailout(kInlinedRuntimeFunctionClassOf); | 10323 return Bailout(kInlinedRuntimeFunctionClassOf); |
| 10072 } | 10324 } |
| 10073 | 10325 |
| 10074 | 10326 |
| 10075 void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) { | 10327 void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) { |
| 10076 ASSERT(call->arguments()->length() == 1); | 10328 ASSERT(call->arguments()->length() == 1); |
| 10077 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10329 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10078 HValue* value = Pop(); | 10330 HValue* object = Pop(); |
| 10079 HValueOf* result = New<HValueOf>(value); | 10331 |
| 10080 return ast_context()->ReturnInstruction(result, call->id()); | 10332 IfBuilder if_objectisvalue(this); |
| 10333 HValue* objectisvalue = if_objectisvalue.If<HHasInstanceTypeAndBranch>( |
| 10334 object, JS_VALUE_TYPE); |
| 10335 if_objectisvalue.Then(); |
| 10336 { |
| 10337 // Return the actual value. |
| 10338 Push(Add<HLoadNamedField>( |
| 10339 object, objectisvalue, |
| 10340 HObjectAccess::ForObservableJSObjectOffset( |
| 10341 JSValue::kValueOffset))); |
| 10342 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10343 } |
| 10344 if_objectisvalue.Else(); |
| 10345 { |
| 10346 // If the object is not a value return the object. |
| 10347 Push(object); |
| 10348 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10349 } |
| 10350 if_objectisvalue.End(); |
| 10351 return ast_context()->ReturnValue(Pop()); |
| 10081 } | 10352 } |
| 10082 | 10353 |
| 10083 | 10354 |
| 10084 void HOptimizedGraphBuilder::GenerateDateField(CallRuntime* call) { | 10355 void HOptimizedGraphBuilder::GenerateDateField(CallRuntime* call) { |
| 10085 ASSERT(call->arguments()->length() == 2); | 10356 ASSERT(call->arguments()->length() == 2); |
| 10086 ASSERT_NE(NULL, call->arguments()->at(1)->AsLiteral()); | 10357 ASSERT_NE(NULL, call->arguments()->at(1)->AsLiteral()); |
| 10087 Smi* index = Smi::cast(*(call->arguments()->at(1)->AsLiteral()->value())); | 10358 Smi* index = Smi::cast(*(call->arguments()->at(1)->AsLiteral()->value())); |
| 10088 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10359 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10089 HValue* date = Pop(); | 10360 HValue* date = Pop(); |
| 10090 HDateField* result = New<HDateField>(date, index); | 10361 HDateField* result = New<HDateField>(date, index); |
| 10091 return ast_context()->ReturnInstruction(result, call->id()); | 10362 return ast_context()->ReturnInstruction(result, call->id()); |
| 10092 } | 10363 } |
| 10093 | 10364 |
| 10094 | 10365 |
| 10095 void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar( | 10366 void HOptimizedGraphBuilder::GenerateOneByteSeqStringSetChar( |
| 10096 CallRuntime* call) { | 10367 CallRuntime* call) { |
| 10097 ASSERT(call->arguments()->length() == 3); | 10368 ASSERT(call->arguments()->length() == 3); |
| 10098 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10369 // We need to follow the evaluation order of full codegen. |
| 10099 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 10370 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 10100 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); | 10371 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); |
| 10372 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10373 HValue* string = Pop(); |
| 10101 HValue* value = Pop(); | 10374 HValue* value = Pop(); |
| 10102 HValue* index = Pop(); | 10375 HValue* index = Pop(); |
| 10103 HValue* string = Pop(); | |
| 10104 Add<HSeqStringSetChar>(String::ONE_BYTE_ENCODING, string, | 10376 Add<HSeqStringSetChar>(String::ONE_BYTE_ENCODING, string, |
| 10105 index, value); | 10377 index, value); |
| 10106 Add<HSimulate>(call->id(), FIXED_SIMULATE); | 10378 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10107 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 10379 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 10108 } | 10380 } |
| 10109 | 10381 |
| 10110 | 10382 |
| 10111 void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar( | 10383 void HOptimizedGraphBuilder::GenerateTwoByteSeqStringSetChar( |
| 10112 CallRuntime* call) { | 10384 CallRuntime* call) { |
| 10113 ASSERT(call->arguments()->length() == 3); | 10385 ASSERT(call->arguments()->length() == 3); |
| 10114 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10386 // We need to follow the evaluation order of full codegen. |
| 10115 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 10387 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 10116 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); | 10388 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); |
| 10389 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10390 HValue* string = Pop(); |
| 10117 HValue* value = Pop(); | 10391 HValue* value = Pop(); |
| 10118 HValue* index = Pop(); | 10392 HValue* index = Pop(); |
| 10119 HValue* string = Pop(); | |
| 10120 Add<HSeqStringSetChar>(String::TWO_BYTE_ENCODING, string, | 10393 Add<HSeqStringSetChar>(String::TWO_BYTE_ENCODING, string, |
| 10121 index, value); | 10394 index, value); |
| 10122 Add<HSimulate>(call->id(), FIXED_SIMULATE); | 10395 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10123 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); | 10396 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 10124 } | 10397 } |
| 10125 | 10398 |
| 10126 | 10399 |
| 10127 void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) { | 10400 void HOptimizedGraphBuilder::GenerateSetValueOf(CallRuntime* call) { |
| 10128 ASSERT(call->arguments()->length() == 2); | 10401 ASSERT(call->arguments()->length() == 2); |
| 10129 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10402 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10130 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 10403 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 10131 HValue* value = Pop(); | 10404 HValue* value = Pop(); |
| 10132 HValue* object = Pop(); | 10405 HValue* object = Pop(); |
| 10133 // Check if object is a not a smi. | |
| 10134 HBasicBlock* if_smi = graph()->CreateBasicBlock(); | |
| 10135 HBasicBlock* if_heap_object = graph()->CreateBasicBlock(); | |
| 10136 HBasicBlock* join = graph()->CreateBasicBlock(); | |
| 10137 FinishCurrentBlock(New<HIsSmiAndBranch>(object, if_smi, if_heap_object)); | |
| 10138 Goto(if_smi, join); | |
| 10139 | 10406 |
| 10140 // Check if object is a JSValue. | 10407 // Check if object is a JSValue. |
| 10141 set_current_block(if_heap_object); | 10408 IfBuilder if_objectisvalue(this); |
| 10142 HHasInstanceTypeAndBranch* typecheck = | 10409 if_objectisvalue.If<HHasInstanceTypeAndBranch>(object, JS_VALUE_TYPE); |
| 10143 New<HHasInstanceTypeAndBranch>(object, JS_VALUE_TYPE); | 10410 if_objectisvalue.Then(); |
| 10144 HBasicBlock* if_js_value = graph()->CreateBasicBlock(); | 10411 { |
| 10145 HBasicBlock* not_js_value = graph()->CreateBasicBlock(); | 10412 // Create in-object property store to kValueOffset. |
| 10146 typecheck->SetSuccessorAt(0, if_js_value); | 10413 Add<HStoreNamedField>(object, |
| 10147 typecheck->SetSuccessorAt(1, not_js_value); | 10414 HObjectAccess::ForObservableJSObjectOffset(JSValue::kValueOffset), |
| 10148 FinishCurrentBlock(typecheck); | 10415 value); |
| 10149 Goto(not_js_value, join); | 10416 if (!ast_context()->IsEffect()) { |
| 10150 | 10417 Push(value); |
| 10151 // Create in-object property store to kValueOffset. | 10418 } |
| 10152 set_current_block(if_js_value); | 10419 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10153 Add<HStoreNamedField>(object, | 10420 } |
| 10154 HObjectAccess::ForJSObjectOffset(JSValue::kValueOffset), value); | 10421 if_objectisvalue.Else(); |
| 10155 Goto(if_js_value, join); | 10422 { |
| 10156 join->SetJoinId(call->id()); | 10423 // Nothing to do in this case. |
| 10157 set_current_block(join); | 10424 if (!ast_context()->IsEffect()) { |
| 10425 Push(value); |
| 10426 } |
| 10427 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10428 } |
| 10429 if_objectisvalue.End(); |
| 10430 if (!ast_context()->IsEffect()) { |
| 10431 Drop(1); |
| 10432 } |
| 10158 return ast_context()->ReturnValue(value); | 10433 return ast_context()->ReturnValue(value); |
| 10159 } | 10434 } |
| 10160 | 10435 |
| 10161 | 10436 |
| 10162 // Fast support for charCodeAt(n). | 10437 // Fast support for charCodeAt(n). |
| 10163 void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) { | 10438 void HOptimizedGraphBuilder::GenerateStringCharCodeAt(CallRuntime* call) { |
| 10164 ASSERT(call->arguments()->length() == 2); | 10439 ASSERT(call->arguments()->length() == 2); |
| 10165 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10440 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10166 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 10441 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 10167 HValue* index = Pop(); | 10442 HValue* index = Pop(); |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10252 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 10527 CHECK_ALIVE(VisitArgumentList(call->arguments())); |
| 10253 HCallStub* result = New<HCallStub>(CodeStub::RegExpExec, 4); | 10528 HCallStub* result = New<HCallStub>(CodeStub::RegExpExec, 4); |
| 10254 Drop(4); | 10529 Drop(4); |
| 10255 return ast_context()->ReturnInstruction(result, call->id()); | 10530 return ast_context()->ReturnInstruction(result, call->id()); |
| 10256 } | 10531 } |
| 10257 | 10532 |
| 10258 | 10533 |
| 10259 // Construct a RegExp exec result with two in-object properties. | 10534 // Construct a RegExp exec result with two in-object properties. |
| 10260 void HOptimizedGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) { | 10535 void HOptimizedGraphBuilder::GenerateRegExpConstructResult(CallRuntime* call) { |
| 10261 ASSERT_EQ(3, call->arguments()->length()); | 10536 ASSERT_EQ(3, call->arguments()->length()); |
| 10262 CHECK_ALIVE(VisitArgumentList(call->arguments())); | 10537 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10263 HCallStub* result = New<HCallStub>(CodeStub::RegExpConstructResult, 3); | 10538 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 10264 Drop(3); | 10539 CHECK_ALIVE(VisitForValue(call->arguments()->at(2))); |
| 10265 return ast_context()->ReturnInstruction(result, call->id()); | 10540 HValue* input = Pop(); |
| 10541 HValue* index = Pop(); |
| 10542 HValue* length = Pop(); |
| 10543 HValue* result = BuildRegExpConstructResult(length, index, input); |
| 10544 return ast_context()->ReturnValue(result); |
| 10266 } | 10545 } |
| 10267 | 10546 |
| 10268 | 10547 |
| 10269 // Support for fast native caches. | 10548 // Support for fast native caches. |
| 10270 void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) { | 10549 void HOptimizedGraphBuilder::GenerateGetFromCache(CallRuntime* call) { |
| 10271 return Bailout(kInlinedRuntimeFunctionGetFromCache); | 10550 return Bailout(kInlinedRuntimeFunctionGetFromCache); |
| 10272 } | 10551 } |
| 10273 | 10552 |
| 10274 | 10553 |
| 10275 // Fast support for number to string. | 10554 // Fast support for number to string. |
| 10276 void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) { | 10555 void HOptimizedGraphBuilder::GenerateNumberToString(CallRuntime* call) { |
| 10277 ASSERT_EQ(1, call->arguments()->length()); | 10556 ASSERT_EQ(1, call->arguments()->length()); |
| 10278 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10557 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10279 HValue* number = Pop(); | 10558 HValue* number = Pop(); |
| 10280 HValue* result = BuildNumberToString(number, Type::Number(isolate())); | 10559 HValue* result = BuildNumberToString(number, Type::Any(zone())); |
| 10281 return ast_context()->ReturnValue(result); | 10560 return ast_context()->ReturnValue(result); |
| 10282 } | 10561 } |
| 10283 | 10562 |
| 10284 | 10563 |
| 10285 // Fast call for custom callbacks. | 10564 // Fast call for custom callbacks. |
| 10286 void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) { | 10565 void HOptimizedGraphBuilder::GenerateCallFunction(CallRuntime* call) { |
| 10287 // 1 ~ The function to call is not itself an argument to the call. | 10566 // 1 ~ The function to call is not itself an argument to the call. |
| 10288 int arg_count = call->arguments()->length() - 1; | 10567 int arg_count = call->arguments()->length() - 1; |
| 10289 ASSERT(arg_count >= 1); // There's always at least a receiver. | 10568 ASSERT(arg_count >= 1); // There's always at least a receiver. |
| 10290 | 10569 |
| 10291 for (int i = 0; i < arg_count; ++i) { | 10570 for (int i = 0; i < arg_count; ++i) { |
| 10292 CHECK_ALIVE(VisitArgument(call->arguments()->at(i))); | 10571 CHECK_ALIVE(VisitArgument(call->arguments()->at(i))); |
| 10293 } | 10572 } |
| 10294 CHECK_ALIVE(VisitForValue(call->arguments()->last())); | 10573 CHECK_ALIVE(VisitForValue(call->arguments()->last())); |
| 10295 | 10574 |
| 10296 HValue* function = Pop(); | 10575 HValue* function = Pop(); |
| 10297 | 10576 |
| 10298 // Branch for function proxies, or other non-functions. | 10577 IfBuilder if_is_jsfunction(this); |
| 10299 HHasInstanceTypeAndBranch* typecheck = | 10578 if_is_jsfunction.If<HHasInstanceTypeAndBranch>(function, JS_FUNCTION_TYPE); |
| 10300 New<HHasInstanceTypeAndBranch>(function, JS_FUNCTION_TYPE); | |
| 10301 HBasicBlock* if_jsfunction = graph()->CreateBasicBlock(); | |
| 10302 HBasicBlock* if_nonfunction = graph()->CreateBasicBlock(); | |
| 10303 HBasicBlock* join = graph()->CreateBasicBlock(); | |
| 10304 typecheck->SetSuccessorAt(0, if_jsfunction); | |
| 10305 typecheck->SetSuccessorAt(1, if_nonfunction); | |
| 10306 FinishCurrentBlock(typecheck); | |
| 10307 | 10579 |
| 10308 set_current_block(if_jsfunction); | 10580 if_is_jsfunction.Then(); |
| 10309 HInstruction* invoke_result = Add<HInvokeFunction>(function, arg_count); | 10581 { |
| 10310 Drop(arg_count); | 10582 HInstruction* invoke_result = |
| 10311 Push(invoke_result); | 10583 Add<HInvokeFunction>(function, arg_count); |
| 10312 Goto(if_jsfunction, join); | 10584 Drop(arg_count); |
| 10585 if (!ast_context()->IsEffect()) { |
| 10586 Push(invoke_result); |
| 10587 } |
| 10588 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10589 } |
| 10313 | 10590 |
| 10314 set_current_block(if_nonfunction); | 10591 if_is_jsfunction.Else(); |
| 10315 HInstruction* call_result = Add<HCallFunction>(function, arg_count); | 10592 { |
| 10316 Drop(arg_count); | 10593 HInstruction* call_result = |
| 10317 Push(call_result); | 10594 Add<HCallFunction>(function, arg_count); |
| 10318 Goto(if_nonfunction, join); | 10595 Drop(arg_count); |
| 10596 if (!ast_context()->IsEffect()) { |
| 10597 Push(call_result); |
| 10598 } |
| 10599 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10600 } |
| 10601 if_is_jsfunction.End(); |
| 10319 | 10602 |
| 10320 set_current_block(join); | 10603 if (ast_context()->IsEffect()) { |
| 10321 join->SetJoinId(call->id()); | 10604 // EffectContext::ReturnValue ignores the value, so we can just pass |
| 10322 return ast_context()->ReturnValue(Pop()); | 10605 // 'undefined' (as we do not have the call result anymore). |
| 10606 return ast_context()->ReturnValue(graph()->GetConstantUndefined()); |
| 10607 } else { |
| 10608 return ast_context()->ReturnValue(Pop()); |
| 10609 } |
| 10323 } | 10610 } |
| 10324 | 10611 |
| 10325 | 10612 |
| 10326 // Fast call to math functions. | 10613 // Fast call to math functions. |
| 10327 void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) { | 10614 void HOptimizedGraphBuilder::GenerateMathPow(CallRuntime* call) { |
| 10328 ASSERT_EQ(2, call->arguments()->length()); | 10615 ASSERT_EQ(2, call->arguments()->length()); |
| 10329 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10616 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10330 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); | 10617 CHECK_ALIVE(VisitForValue(call->arguments()->at(1))); |
| 10331 HValue* right = Pop(); | 10618 HValue* right = Pop(); |
| 10332 HValue* left = Pop(); | 10619 HValue* left = Pop(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 10346 | 10633 |
| 10347 void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) { | 10634 void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) { |
| 10348 ASSERT(call->arguments()->length() == 1); | 10635 ASSERT(call->arguments()->length() == 1); |
| 10349 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10636 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10350 HValue* value = Pop(); | 10637 HValue* value = Pop(); |
| 10351 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt); | 10638 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt); |
| 10352 return ast_context()->ReturnInstruction(result, call->id()); | 10639 return ast_context()->ReturnInstruction(result, call->id()); |
| 10353 } | 10640 } |
| 10354 | 10641 |
| 10355 | 10642 |
| 10356 // Check whether two RegExps are equivalent | |
| 10357 void HOptimizedGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) { | |
| 10358 return Bailout(kInlinedRuntimeFunctionIsRegExpEquivalent); | |
| 10359 } | |
| 10360 | |
| 10361 | |
| 10362 void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { | 10643 void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { |
| 10363 ASSERT(call->arguments()->length() == 1); | 10644 ASSERT(call->arguments()->length() == 1); |
| 10364 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10645 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
| 10365 HValue* value = Pop(); | 10646 HValue* value = Pop(); |
| 10366 HGetCachedArrayIndex* result = New<HGetCachedArrayIndex>(value); | 10647 HGetCachedArrayIndex* result = New<HGetCachedArrayIndex>(value); |
| 10367 return ast_context()->ReturnInstruction(result, call->id()); | 10648 return ast_context()->ReturnInstruction(result, call->id()); |
| 10368 } | 10649 } |
| 10369 | 10650 |
| 10370 | 10651 |
| 10371 void HOptimizedGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { | 10652 void HOptimizedGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { |
| (...skipping 312 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10684 PrintTo(&trace); | 10965 PrintTo(&trace); |
| 10685 PrintF("%s", trace.ToCString().get()); | 10966 PrintF("%s", trace.ToCString().get()); |
| 10686 } | 10967 } |
| 10687 | 10968 |
| 10688 | 10969 |
| 10689 void HTracer::TraceCompilation(CompilationInfo* info) { | 10970 void HTracer::TraceCompilation(CompilationInfo* info) { |
| 10690 Tag tag(this, "compilation"); | 10971 Tag tag(this, "compilation"); |
| 10691 if (info->IsOptimizing()) { | 10972 if (info->IsOptimizing()) { |
| 10692 Handle<String> name = info->function()->debug_name(); | 10973 Handle<String> name = info->function()->debug_name(); |
| 10693 PrintStringProperty("name", name->ToCString().get()); | 10974 PrintStringProperty("name", name->ToCString().get()); |
| 10694 PrintStringProperty("method", name->ToCString().get()); | 10975 PrintIndent(); |
| 10976 trace_.Add("method \"%s:%d\"\n", |
| 10977 name->ToCString().get(), |
| 10978 info->optimization_id()); |
| 10695 } else { | 10979 } else { |
| 10696 CodeStub::Major major_key = info->code_stub()->MajorKey(); | 10980 CodeStub::Major major_key = info->code_stub()->MajorKey(); |
| 10697 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); | 10981 PrintStringProperty("name", CodeStub::MajorName(major_key, false)); |
| 10698 PrintStringProperty("method", "stub"); | 10982 PrintStringProperty("method", "stub"); |
| 10699 } | 10983 } |
| 10700 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); | 10984 PrintLongProperty("date", static_cast<int64_t>(OS::TimeCurrentMillis())); |
| 10701 } | 10985 } |
| 10702 | 10986 |
| 10703 | 10987 |
| 10704 void HTracer::TraceLithium(const char* name, LChunk* chunk) { | 10988 void HTracer::TraceLithium(const char* name, LChunk* chunk) { |
| (...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 10798 trace_.Add(" "); | 11082 trace_.Add(" "); |
| 10799 phi->PrintTo(&trace_); | 11083 phi->PrintTo(&trace_); |
| 10800 trace_.Add("\n"); | 11084 trace_.Add("\n"); |
| 10801 } | 11085 } |
| 10802 } | 11086 } |
| 10803 | 11087 |
| 10804 { | 11088 { |
| 10805 Tag HIR_tag(this, "HIR"); | 11089 Tag HIR_tag(this, "HIR"); |
| 10806 for (HInstructionIterator it(current); !it.Done(); it.Advance()) { | 11090 for (HInstructionIterator it(current); !it.Done(); it.Advance()) { |
| 10807 HInstruction* instruction = it.Current(); | 11091 HInstruction* instruction = it.Current(); |
| 10808 int bci = FLAG_emit_opt_code_positions && instruction->has_position() ? | |
| 10809 instruction->position() : 0; | |
| 10810 int uses = instruction->UseCount(); | 11092 int uses = instruction->UseCount(); |
| 10811 PrintIndent(); | 11093 PrintIndent(); |
| 10812 trace_.Add("%d %d ", bci, uses); | 11094 trace_.Add("0 %d ", uses); |
| 10813 instruction->PrintNameTo(&trace_); | 11095 instruction->PrintNameTo(&trace_); |
| 10814 trace_.Add(" "); | 11096 trace_.Add(" "); |
| 10815 instruction->PrintTo(&trace_); | 11097 instruction->PrintTo(&trace_); |
| 11098 if (FLAG_hydrogen_track_positions && |
| 11099 instruction->has_position() && |
| 11100 instruction->position().raw() != 0) { |
| 11101 const HSourcePosition pos = instruction->position(); |
| 11102 trace_.Add(" pos:"); |
| 11103 if (pos.inlining_id() != 0) { |
| 11104 trace_.Add("%d_", pos.inlining_id()); |
| 11105 } |
| 11106 trace_.Add("%d", pos.position()); |
| 11107 } |
| 10816 trace_.Add(" <|@\n"); | 11108 trace_.Add(" <|@\n"); |
| 10817 } | 11109 } |
| 10818 } | 11110 } |
| 10819 | 11111 |
| 10820 | 11112 |
| 10821 if (chunk != NULL) { | 11113 if (chunk != NULL) { |
| 10822 Tag LIR_tag(this, "LIR"); | 11114 Tag LIR_tag(this, "LIR"); |
| 10823 int first_index = current->first_instruction_index(); | 11115 int first_index = current->first_instruction_index(); |
| 10824 int last_index = current->last_instruction_index(); | 11116 int last_index = current->last_instruction_index(); |
| 10825 if (first_index != -1 && last_index != -1) { | 11117 if (first_index != -1 && last_index != -1) { |
| (...skipping 180 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 11006 if (ShouldProduceTraceOutput()) { | 11298 if (ShouldProduceTraceOutput()) { |
| 11007 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 11299 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
| 11008 } | 11300 } |
| 11009 | 11301 |
| 11010 #ifdef DEBUG | 11302 #ifdef DEBUG |
| 11011 graph_->Verify(false); // No full verify. | 11303 graph_->Verify(false); // No full verify. |
| 11012 #endif | 11304 #endif |
| 11013 } | 11305 } |
| 11014 | 11306 |
| 11015 } } // namespace v8::internal | 11307 } } // namespace v8::internal |
| OLD | NEW |