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 209 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
220 it.Current()->RegisterPredecessor(this); | 220 it.Current()->RegisterPredecessor(this); |
221 } | 221 } |
222 } | 222 } |
223 | 223 |
224 | 224 |
225 void HBasicBlock::Goto(HBasicBlock* block, | 225 void HBasicBlock::Goto(HBasicBlock* block, |
226 int position, | 226 int position, |
227 FunctionState* state, | 227 FunctionState* state, |
228 bool add_simulate) { | 228 bool add_simulate) { |
229 bool drop_extra = state != NULL && | 229 bool drop_extra = state != NULL && |
230 state->inlining_kind() == DROP_EXTRA_ON_RETURN; | 230 state->inlining_kind() == NORMAL_RETURN; |
231 | 231 |
232 if (block->IsInlineReturnTarget()) { | 232 if (block->IsInlineReturnTarget()) { |
233 HEnvironment* env = last_environment(); | 233 HEnvironment* env = last_environment(); |
234 int argument_count = env->arguments_environment()->parameter_count(); | 234 int argument_count = env->arguments_environment()->parameter_count(); |
235 AddInstruction(new(zone()) | 235 AddInstruction(new(zone()) |
236 HLeaveInlined(state->entry(), argument_count), | 236 HLeaveInlined(state->entry(), argument_count), |
237 position); | 237 position); |
238 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); | 238 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); |
239 } | 239 } |
240 | 240 |
241 if (add_simulate) AddNewSimulate(BailoutId::None(), position); | 241 if (add_simulate) AddNewSimulate(BailoutId::None(), position); |
242 HGoto* instr = new(zone()) HGoto(block); | 242 HGoto* instr = new(zone()) HGoto(block); |
243 Finish(instr, position); | 243 Finish(instr, position); |
244 } | 244 } |
245 | 245 |
246 | 246 |
247 void HBasicBlock::AddLeaveInlined(HValue* return_value, | 247 void HBasicBlock::AddLeaveInlined(HValue* return_value, |
248 FunctionState* state, | 248 FunctionState* state, |
249 int position) { | 249 int position) { |
250 HBasicBlock* target = state->function_return(); | 250 HBasicBlock* target = state->function_return(); |
251 bool drop_extra = state->inlining_kind() == DROP_EXTRA_ON_RETURN; | 251 bool drop_extra = state->inlining_kind() == NORMAL_RETURN; |
252 | 252 |
253 ASSERT(target->IsInlineReturnTarget()); | 253 ASSERT(target->IsInlineReturnTarget()); |
254 ASSERT(return_value != NULL); | 254 ASSERT(return_value != NULL); |
255 HEnvironment* env = last_environment(); | 255 HEnvironment* env = last_environment(); |
256 int argument_count = env->arguments_environment()->parameter_count(); | 256 int argument_count = env->arguments_environment()->parameter_count(); |
257 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count), | 257 AddInstruction(new(zone()) HLeaveInlined(state->entry(), argument_count), |
258 position); | 258 position); |
259 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); | 259 UpdateEnvironment(last_environment()->DiscardInlined(drop_extra)); |
260 last_environment()->Push(return_value); | 260 last_environment()->Push(return_value); |
261 AddNewSimulate(BailoutId::None(), position); | 261 AddNewSimulate(BailoutId::None(), position); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
297 bool HBasicBlock::Dominates(HBasicBlock* other) const { | 297 bool HBasicBlock::Dominates(HBasicBlock* other) const { |
298 HBasicBlock* current = other->dominator(); | 298 HBasicBlock* current = other->dominator(); |
299 while (current != NULL) { | 299 while (current != NULL) { |
300 if (current == this) return true; | 300 if (current == this) return true; |
301 current = current->dominator(); | 301 current = current->dominator(); |
302 } | 302 } |
303 return false; | 303 return false; |
304 } | 304 } |
305 | 305 |
306 | 306 |
| 307 bool HBasicBlock::EqualToOrDominates(HBasicBlock* other) const { |
| 308 if (this == other) return true; |
| 309 return Dominates(other); |
| 310 } |
| 311 |
| 312 |
307 int HBasicBlock::LoopNestingDepth() const { | 313 int HBasicBlock::LoopNestingDepth() const { |
308 const HBasicBlock* current = this; | 314 const HBasicBlock* current = this; |
309 int result = (current->IsLoopHeader()) ? 1 : 0; | 315 int result = (current->IsLoopHeader()) ? 1 : 0; |
310 while (current->parent_loop_header() != NULL) { | 316 while (current->parent_loop_header() != NULL) { |
311 current = current->parent_loop_header(); | 317 current = current->parent_loop_header(); |
312 result++; | 318 result++; |
313 } | 319 } |
314 return result; | 320 return result; |
315 } | 321 } |
316 | 322 |
(...skipping 965 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1282 !HConstant::cast(string)->HasStringValue()); | 1288 !HConstant::cast(string)->HasStringValue()); |
1283 BuildCheckHeapObject(string); | 1289 BuildCheckHeapObject(string); |
1284 return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING); | 1290 return Add<HCheckInstanceType>(string, HCheckInstanceType::IS_STRING); |
1285 } | 1291 } |
1286 return string; | 1292 return string; |
1287 } | 1293 } |
1288 | 1294 |
1289 | 1295 |
1290 HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) { | 1296 HValue* HGraphBuilder::BuildWrapReceiver(HValue* object, HValue* function) { |
1291 if (object->type().IsJSObject()) return object; | 1297 if (object->type().IsJSObject()) return object; |
| 1298 if (function->IsConstant() && |
| 1299 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
| 1300 Handle<JSFunction> f = Handle<JSFunction>::cast( |
| 1301 HConstant::cast(function)->handle(isolate())); |
| 1302 SharedFunctionInfo* shared = f->shared(); |
| 1303 if (!shared->is_classic_mode() || shared->native()) return object; |
| 1304 } |
1292 return Add<HWrapReceiver>(object, function); | 1305 return Add<HWrapReceiver>(object, function); |
1293 } | 1306 } |
1294 | 1307 |
1295 | 1308 |
1296 HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, | 1309 HValue* HGraphBuilder::BuildCheckForCapacityGrow(HValue* object, |
1297 HValue* elements, | 1310 HValue* elements, |
1298 ElementsKind kind, | 1311 ElementsKind kind, |
1299 HValue* length, | 1312 HValue* length, |
1300 HValue* key, | 1313 HValue* key, |
1301 bool is_js_array, | 1314 bool is_js_array, |
(...skipping 3617 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4919 Handle<JSFunction> closure = function_state()->compilation_info()->closure(); | 4932 Handle<JSFunction> closure = function_state()->compilation_info()->closure(); |
4920 Handle<FixedArray> literals(closure->literals()); | 4933 Handle<FixedArray> literals(closure->literals()); |
4921 HRegExpLiteral* instr = New<HRegExpLiteral>(literals, | 4934 HRegExpLiteral* instr = New<HRegExpLiteral>(literals, |
4922 expr->pattern(), | 4935 expr->pattern(), |
4923 expr->flags(), | 4936 expr->flags(), |
4924 expr->literal_index()); | 4937 expr->literal_index()); |
4925 return ast_context()->ReturnInstruction(instr, expr->id()); | 4938 return ast_context()->ReturnInstruction(instr, expr->id()); |
4926 } | 4939 } |
4927 | 4940 |
4928 | 4941 |
4929 static bool CanInlinePropertyAccess(Map* type) { | 4942 static bool CanInlinePropertyAccess(Handle<HeapType> type) { |
4930 return type->IsJSObjectMap() && | 4943 if (type->Is(HeapType::NumberOrString())) return true; |
4931 !type->is_dictionary_map() && | 4944 if (!type->IsClass()) return false; |
4932 !type->has_named_interceptor(); | 4945 Handle<Map> map = type->AsClass(); |
| 4946 return map->IsJSObjectMap() && |
| 4947 !map->is_dictionary_map() && |
| 4948 !map->has_named_interceptor(); |
4933 } | 4949 } |
4934 | 4950 |
4935 | 4951 |
4936 static void LookupInPrototypes(Handle<Map> map, | 4952 static void LookupInPrototypes(Handle<Map> map, |
4937 Handle<String> name, | 4953 Handle<String> name, |
4938 LookupResult* lookup) { | 4954 LookupResult* lookup) { |
4939 while (map->prototype()->IsJSObject()) { | 4955 while (map->prototype()->IsJSObject()) { |
4940 Handle<JSObject> holder(JSObject::cast(map->prototype())); | 4956 Handle<JSObject> holder(JSObject::cast(map->prototype())); |
4941 map = Handle<Map>(holder->map()); | 4957 map = handle(holder->map()); |
4942 if (!CanInlinePropertyAccess(*map)) break; | 4958 if (!CanInlinePropertyAccess(IC::MapToType(map))) break; |
4943 map->LookupDescriptor(*holder, *name, lookup); | 4959 map->LookupDescriptor(*holder, *name, lookup); |
4944 if (lookup->IsFound()) return; | 4960 if (lookup->IsFound()) return; |
4945 } | 4961 } |
4946 lookup->NotFound(); | 4962 lookup->NotFound(); |
4947 } | 4963 } |
4948 | 4964 |
4949 | 4965 |
4950 // Tries to find a JavaScript accessor of the given name in the prototype chain | 4966 // Tries to find a JavaScript accessor of the given name in the prototype chain |
4951 // starting at the given map. Return true iff there is one, including the | 4967 // starting at the given map. Return true iff there is one, including the |
4952 // corresponding AccessorPair plus its holder (which could be null when the | 4968 // corresponding AccessorPair plus its holder (which could be null when the |
(...skipping 480 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5433 function_strict_mode_flag()); | 5449 function_strict_mode_flag()); |
5434 } | 5450 } |
5435 | 5451 |
5436 | 5452 |
5437 // Sets the lookup result and returns true if the load/store can be inlined. | 5453 // Sets the lookup result and returns true if the load/store can be inlined. |
5438 static bool ComputeStoreField(Handle<Map> type, | 5454 static bool ComputeStoreField(Handle<Map> type, |
5439 Handle<String> name, | 5455 Handle<String> name, |
5440 LookupResult* lookup, | 5456 LookupResult* lookup, |
5441 bool lookup_transition = true) { | 5457 bool lookup_transition = true) { |
5442 ASSERT(!type->is_observed()); | 5458 ASSERT(!type->is_observed()); |
5443 if (!CanInlinePropertyAccess(*type)) { | 5459 if (!CanInlinePropertyAccess(IC::MapToType(type))) { |
5444 lookup->NotFound(); | 5460 lookup->NotFound(); |
5445 return false; | 5461 return false; |
5446 } | 5462 } |
5447 // If we directly find a field, the access can be inlined. | 5463 // If we directly find a field, the access can be inlined. |
5448 type->LookupDescriptor(NULL, *name, lookup); | 5464 type->LookupDescriptor(NULL, *name, lookup); |
5449 if (lookup->IsField()) return true; | 5465 if (lookup->IsField()) return true; |
5450 | 5466 |
5451 if (!lookup_transition) return false; | 5467 if (!lookup_transition) return false; |
5452 | 5468 |
5453 type->LookupTransition(NULL, *name, lookup); | 5469 type->LookupTransition(NULL, *name, lookup); |
(...skipping 14 matching lines...) Expand all Loading... |
5468 return BuildStoreNamedField(checked_object, name, value, map, &lookup); | 5484 return BuildStoreNamedField(checked_object, name, value, map, &lookup); |
5469 } | 5485 } |
5470 | 5486 |
5471 // No luck, do a generic store. | 5487 // No luck, do a generic store. |
5472 return BuildStoreNamedGeneric(object, name, value); | 5488 return BuildStoreNamedGeneric(object, name, value); |
5473 } | 5489 } |
5474 | 5490 |
5475 | 5491 |
5476 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad( | 5492 bool HOptimizedGraphBuilder::PropertyAccessInfo::IsCompatibleForLoad( |
5477 PropertyAccessInfo* info) { | 5493 PropertyAccessInfo* info) { |
5478 if (!CanInlinePropertyAccess(*map_)) return false; | 5494 if (!CanInlinePropertyAccess(type_)) return false; |
| 5495 |
| 5496 // Currently only handle HeapType::Number as a polymorphic case. |
| 5497 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber |
| 5498 // instruction. |
| 5499 if (type_->Is(HeapType::Number())) return false; |
| 5500 |
| 5501 // Values are only compatible for monomorphic load if they all behave the same |
| 5502 // regarding value wrappers. |
| 5503 if (type_->Is(HeapType::NumberOrString())) { |
| 5504 if (!info->type_->Is(HeapType::NumberOrString())) return false; |
| 5505 } else { |
| 5506 if (info->type_->Is(HeapType::NumberOrString())) return false; |
| 5507 } |
5479 | 5508 |
5480 if (!LookupDescriptor()) return false; | 5509 if (!LookupDescriptor()) return false; |
5481 | 5510 |
5482 if (!lookup_.IsFound()) { | 5511 if (!lookup_.IsFound()) { |
5483 return (!info->lookup_.IsFound() || info->has_holder()) && | 5512 return (!info->lookup_.IsFound() || info->has_holder()) && |
5484 map_->prototype() == info->map_->prototype(); | 5513 map()->prototype() == info->map()->prototype(); |
5485 } | 5514 } |
5486 | 5515 |
5487 // Mismatch if the other access info found the property in the prototype | 5516 // Mismatch if the other access info found the property in the prototype |
5488 // chain. | 5517 // chain. |
5489 if (info->has_holder()) return false; | 5518 if (info->has_holder()) return false; |
5490 | 5519 |
5491 if (lookup_.IsPropertyCallbacks()) { | 5520 if (lookup_.IsPropertyCallbacks()) { |
5492 return accessor_.is_identical_to(info->accessor_); | 5521 return accessor_.is_identical_to(info->accessor_); |
5493 } | 5522 } |
5494 | 5523 |
5495 if (lookup_.IsConstant()) { | 5524 if (lookup_.IsConstant()) { |
5496 return constant_.is_identical_to(info->constant_); | 5525 return constant_.is_identical_to(info->constant_); |
5497 } | 5526 } |
5498 | 5527 |
5499 ASSERT(lookup_.IsField()); | 5528 ASSERT(lookup_.IsField()); |
5500 if (!info->lookup_.IsField()) return false; | 5529 if (!info->lookup_.IsField()) return false; |
5501 | 5530 |
5502 Representation r = access_.representation(); | 5531 Representation r = access_.representation(); |
5503 if (!info->access_.representation().IsCompatibleForLoad(r)) return false; | 5532 if (!info->access_.representation().IsCompatibleForLoad(r)) return false; |
5504 if (info->access_.offset() != access_.offset()) return false; | 5533 if (info->access_.offset() != access_.offset()) return false; |
5505 if (info->access_.IsInobject() != access_.IsInobject()) return false; | 5534 if (info->access_.IsInobject() != access_.IsInobject()) return false; |
5506 info->GeneralizeRepresentation(r); | 5535 info->GeneralizeRepresentation(r); |
5507 return true; | 5536 return true; |
5508 } | 5537 } |
5509 | 5538 |
5510 | 5539 |
5511 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { | 5540 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupDescriptor() { |
5512 map_->LookupDescriptor(NULL, *name_, &lookup_); | 5541 if (!type_->IsClass()) return true; |
5513 return LoadResult(map_); | 5542 map()->LookupDescriptor(NULL, *name_, &lookup_); |
| 5543 return LoadResult(map()); |
5514 } | 5544 } |
5515 | 5545 |
5516 | 5546 |
5517 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { | 5547 bool HOptimizedGraphBuilder::PropertyAccessInfo::LoadResult(Handle<Map> map) { |
5518 if (lookup_.IsField()) { | 5548 if (lookup_.IsField()) { |
5519 access_ = HObjectAccess::ForField(map, &lookup_, name_); | 5549 access_ = HObjectAccess::ForField(map, &lookup_, name_); |
5520 } else if (lookup_.IsPropertyCallbacks()) { | 5550 } else if (lookup_.IsPropertyCallbacks()) { |
5521 Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate()); | 5551 Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate()); |
5522 if (!callback->IsAccessorPair()) return false; | 5552 if (!callback->IsAccessorPair()) return false; |
5523 Object* getter = Handle<AccessorPair>::cast(callback)->getter(); | 5553 Object* getter = Handle<AccessorPair>::cast(callback)->getter(); |
5524 if (!getter->IsJSFunction()) return false; | 5554 if (!getter->IsJSFunction()) return false; |
5525 Handle<JSFunction> accessor = handle(JSFunction::cast(getter)); | 5555 Handle<JSFunction> accessor = handle(JSFunction::cast(getter)); |
5526 CallOptimization call_optimization(accessor); | 5556 CallOptimization call_optimization(accessor); |
5527 // TODO(dcarney): temporary hack unless crankshaft can handle api calls. | 5557 // TODO(dcarney): temporary hack unless crankshaft can handle api calls. |
5528 if (call_optimization.is_simple_api_call()) return false; | 5558 if (call_optimization.is_simple_api_call()) return false; |
5529 accessor_ = accessor; | 5559 accessor_ = accessor; |
5530 } else if (lookup_.IsConstant()) { | 5560 } else if (lookup_.IsConstant()) { |
5531 constant_ = handle(lookup_.GetConstantFromMap(*map), isolate()); | 5561 constant_ = handle(lookup_.GetConstantFromMap(*map), isolate()); |
5532 } | 5562 } |
5533 | 5563 |
5534 return true; | 5564 return true; |
5535 } | 5565 } |
5536 | 5566 |
5537 | 5567 |
5538 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { | 5568 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { |
5539 Handle<Map> map = map_; | 5569 Handle<Map> map = this->map(); |
| 5570 |
5540 while (map->prototype()->IsJSObject()) { | 5571 while (map->prototype()->IsJSObject()) { |
5541 holder_ = handle(JSObject::cast(map->prototype())); | 5572 holder_ = handle(JSObject::cast(map->prototype())); |
5542 if (holder_->map()->is_deprecated()) { | 5573 if (holder_->map()->is_deprecated()) { |
5543 JSObject::TryMigrateInstance(holder_); | 5574 JSObject::TryMigrateInstance(holder_); |
5544 } | 5575 } |
5545 map = Handle<Map>(holder_->map()); | 5576 map = Handle<Map>(holder_->map()); |
5546 if (!CanInlinePropertyAccess(*map)) { | 5577 if (!CanInlinePropertyAccess(IC::MapToType(map))) { |
5547 lookup_.NotFound(); | 5578 lookup_.NotFound(); |
5548 return false; | 5579 return false; |
5549 } | 5580 } |
5550 map->LookupDescriptor(*holder_, *name_, &lookup_); | 5581 map->LookupDescriptor(*holder_, *name_, &lookup_); |
5551 if (lookup_.IsFound()) return LoadResult(map); | 5582 if (lookup_.IsFound()) return LoadResult(map); |
5552 } | 5583 } |
5553 lookup_.NotFound(); | 5584 lookup_.NotFound(); |
5554 return true; | 5585 return true; |
5555 } | 5586 } |
5556 | 5587 |
5557 | 5588 |
5558 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() { | 5589 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadMonomorphic() { |
5559 if (!CanInlinePropertyAccess(*map_)) return IsStringLength(); | 5590 if (!CanInlinePropertyAccess(type_)) return false; |
5560 if (IsJSObjectFieldAccessor()) return true; | 5591 if (IsJSObjectFieldAccessor()) return true; |
5561 if (!LookupDescriptor()) return false; | 5592 if (!LookupDescriptor()) return false; |
5562 if (lookup_.IsFound()) return true; | 5593 if (lookup_.IsFound()) return true; |
5563 return LookupInPrototypes(); | 5594 return LookupInPrototypes(); |
5564 } | 5595 } |
5565 | 5596 |
5566 | 5597 |
5567 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic( | 5598 bool HOptimizedGraphBuilder::PropertyAccessInfo::CanLoadAsMonomorphic( |
5568 SmallMapList* types) { | 5599 SmallMapList* types) { |
5569 ASSERT(map_.is_identical_to(types->first())); | 5600 ASSERT(type_->Is(IC::MapToType(types->first()))); |
5570 if (!CanLoadMonomorphic()) return false; | 5601 if (!CanLoadMonomorphic()) return false; |
5571 if (types->length() > kMaxLoadPolymorphism) return false; | 5602 if (types->length() > kMaxLoadPolymorphism) return false; |
5572 | 5603 |
5573 if (IsStringLength()) { | |
5574 for (int i = 1; i < types->length(); ++i) { | |
5575 if (types->at(i)->instance_type() >= FIRST_NONSTRING_TYPE) return false; | |
5576 } | |
5577 return true; | |
5578 } | |
5579 | |
5580 if (IsArrayLength()) { | 5604 if (IsArrayLength()) { |
5581 bool is_fast = IsFastElementsKind(map_->elements_kind()); | 5605 bool is_fast = IsFastElementsKind(map()->elements_kind()); |
5582 for (int i = 1; i < types->length(); ++i) { | 5606 for (int i = 1; i < types->length(); ++i) { |
5583 Handle<Map> test_map = types->at(i); | 5607 Handle<Map> test_map = types->at(i); |
5584 if (test_map->instance_type() != JS_ARRAY_TYPE) return false; | 5608 if (test_map->instance_type() != JS_ARRAY_TYPE) return false; |
5585 if (IsFastElementsKind(test_map->elements_kind()) != is_fast) { | 5609 if (IsFastElementsKind(test_map->elements_kind()) != is_fast) { |
5586 return false; | 5610 return false; |
5587 } | 5611 } |
5588 } | 5612 } |
5589 return true; | 5613 return true; |
5590 } | 5614 } |
5591 | 5615 |
5592 if (IsJSObjectFieldAccessor()) { | 5616 HObjectAccess access = HObjectAccess::ForMap(); // bogus default |
5593 InstanceType instance_type = map_->instance_type(); | 5617 if (GetJSObjectFieldAccess(&access)) { |
5594 for (int i = 1; i < types->length(); ++i) { | 5618 for (int i = 1; i < types->length(); ++i) { |
5595 if (types->at(i)->instance_type() != instance_type) return false; | 5619 PropertyAccessInfo test_info( |
| 5620 builder_, IC::MapToType(types->at(i)), name_); |
| 5621 HObjectAccess test_access = HObjectAccess::ForMap(); // bogus default |
| 5622 if (!test_info.GetJSObjectFieldAccess(&test_access)) return false; |
| 5623 if (!access.Equals(test_access)) return false; |
5596 } | 5624 } |
5597 return true; | 5625 return true; |
5598 } | 5626 } |
5599 | 5627 |
| 5628 // Currently only handle HeapType::Number as a polymorphic case. |
| 5629 // TODO(verwaest): Support monomorphic handling of numbers with a HCheckNumber |
| 5630 // instruction. |
| 5631 if (type_->Is(HeapType::Number())) return false; |
| 5632 |
5600 for (int i = 1; i < types->length(); ++i) { | 5633 for (int i = 1; i < types->length(); ++i) { |
5601 PropertyAccessInfo test_info(isolate(), types->at(i), name_); | 5634 PropertyAccessInfo test_info(builder_, IC::MapToType(types->at(i)), name_); |
5602 if (!test_info.IsCompatibleForLoad(this)) return false; | 5635 if (!test_info.IsCompatibleForLoad(this)) return false; |
5603 } | 5636 } |
5604 | 5637 |
5605 return true; | 5638 return true; |
5606 } | 5639 } |
5607 | 5640 |
5608 | 5641 |
| 5642 static bool NeedsWrappingFor(Handle<HeapType> type, Handle<JSFunction> target) { |
| 5643 return type->Is(HeapType::NumberOrString()) && |
| 5644 target->shared()->is_classic_mode() && |
| 5645 !target->shared()->native(); |
| 5646 } |
| 5647 |
| 5648 |
5609 HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic( | 5649 HInstruction* HOptimizedGraphBuilder::BuildLoadMonomorphic( |
5610 PropertyAccessInfo* info, | 5650 PropertyAccessInfo* info, |
5611 HValue* object, | 5651 HValue* object, |
5612 HInstruction* checked_object, | 5652 HValue* checked_object, |
5613 BailoutId ast_id, | 5653 BailoutId ast_id, |
5614 BailoutId return_id, | 5654 BailoutId return_id, |
5615 bool can_inline_accessor) { | 5655 bool can_inline_accessor) { |
5616 | 5656 |
5617 HObjectAccess access = HObjectAccess::ForMap(); // bogus default | 5657 HObjectAccess access = HObjectAccess::ForMap(); // bogus default |
5618 if (info->GetJSObjectFieldAccess(&access)) { | 5658 if (info->GetJSObjectFieldAccess(&access)) { |
5619 return New<HLoadNamedField>( | 5659 return New<HLoadNamedField>( |
5620 checked_object, static_cast<HValue*>(NULL), access); | 5660 checked_object, static_cast<HValue*>(NULL), access); |
5621 } | 5661 } |
5622 | 5662 |
5623 HValue* checked_holder = checked_object; | 5663 HValue* checked_holder = checked_object; |
5624 if (info->has_holder()) { | 5664 if (info->has_holder()) { |
5625 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype())); | 5665 Handle<JSObject> prototype(JSObject::cast(info->map()->prototype())); |
5626 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); | 5666 checked_holder = BuildCheckPrototypeMaps(prototype, info->holder()); |
5627 } | 5667 } |
5628 | 5668 |
5629 if (!info->lookup()->IsFound()) return graph()->GetConstantUndefined(); | 5669 if (!info->lookup()->IsFound()) return graph()->GetConstantUndefined(); |
5630 | 5670 |
5631 if (info->lookup()->IsField()) { | 5671 if (info->lookup()->IsField()) { |
5632 return BuildLoadNamedField(checked_holder, info->access()); | 5672 return BuildLoadNamedField(checked_holder, info->access()); |
5633 } | 5673 } |
5634 | 5674 |
5635 if (info->lookup()->IsPropertyCallbacks()) { | 5675 if (info->lookup()->IsPropertyCallbacks()) { |
5636 Push(checked_object); | 5676 if (NeedsWrappingFor(info->type(), info->accessor())) { |
5637 if (FLAG_inline_accessors && | 5677 HValue* function = Add<HConstant>(info->accessor()); |
5638 can_inline_accessor && | 5678 Add<HPushArgument>(checked_object); |
5639 TryInlineGetter(info->accessor(), ast_id, return_id)) { | 5679 return New<HCallFunction>(function, 1, WRAP_AND_CALL); |
5640 return NULL; | 5680 } else { |
| 5681 Push(checked_object); |
| 5682 if (FLAG_inline_accessors && |
| 5683 can_inline_accessor && |
| 5684 TryInlineGetter(info->accessor(), ast_id, return_id)) { |
| 5685 return NULL; |
| 5686 } |
| 5687 Add<HPushArgument>(Pop()); |
| 5688 return BuildCallConstantFunction(info->accessor(), 1); |
5641 } | 5689 } |
5642 Add<HPushArgument>(Pop()); | |
5643 return BuildCallConstantFunction(info->accessor(), 1); | |
5644 } | 5690 } |
5645 | 5691 |
5646 ASSERT(info->lookup()->IsConstant()); | 5692 ASSERT(info->lookup()->IsConstant()); |
5647 return New<HConstant>(info->constant()); | 5693 return New<HConstant>(info->constant()); |
5648 } | 5694 } |
5649 | 5695 |
5650 | 5696 |
5651 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( | 5697 void HOptimizedGraphBuilder::HandlePolymorphicLoadNamedField( |
5652 BailoutId ast_id, | 5698 BailoutId ast_id, |
5653 BailoutId return_id, | 5699 BailoutId return_id, |
5654 HValue* object, | 5700 HValue* object, |
5655 SmallMapList* types, | 5701 SmallMapList* types, |
5656 Handle<String> name) { | 5702 Handle<String> name) { |
5657 // Something did not match; must use a polymorphic load. | 5703 // Something did not match; must use a polymorphic load. |
5658 int count = 0; | 5704 int count = 0; |
5659 HBasicBlock* join = NULL; | 5705 HBasicBlock* join = NULL; |
| 5706 HBasicBlock* number_block = NULL; |
| 5707 bool handled_string = false; |
| 5708 |
| 5709 bool handle_smi = false; |
5660 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { | 5710 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
5661 PropertyAccessInfo info(isolate(), types->at(i), name); | 5711 PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name); |
| 5712 if (info.type()->Is(HeapType::String())) { |
| 5713 if (handled_string) continue; |
| 5714 handled_string = true; |
| 5715 } |
5662 if (info.CanLoadMonomorphic()) { | 5716 if (info.CanLoadMonomorphic()) { |
5663 if (count == 0) { | 5717 count++; |
5664 BuildCheckHeapObject(object); | 5718 if (info.type()->Is(HeapType::Number())) { |
5665 join = graph()->CreateBasicBlock(); | 5719 handle_smi = true; |
| 5720 break; |
5666 } | 5721 } |
5667 ++count; | |
5668 HBasicBlock* if_true = graph()->CreateBasicBlock(); | |
5669 HBasicBlock* if_false = graph()->CreateBasicBlock(); | |
5670 HCompareMap* compare = New<HCompareMap>( | |
5671 object, info.map(), if_true, if_false); | |
5672 FinishCurrentBlock(compare); | |
5673 | |
5674 set_current_block(if_true); | |
5675 | |
5676 HInstruction* load = BuildLoadMonomorphic( | |
5677 &info, object, compare, ast_id, return_id, FLAG_polymorphic_inlining); | |
5678 if (load == NULL) { | |
5679 if (HasStackOverflow()) return; | |
5680 } else { | |
5681 if (!load->IsLinked()) { | |
5682 AddInstruction(load); | |
5683 } | |
5684 if (!ast_context()->IsEffect()) Push(load); | |
5685 } | |
5686 | |
5687 if (current_block() != NULL) Goto(join); | |
5688 set_current_block(if_false); | |
5689 } | 5722 } |
5690 } | 5723 } |
5691 | 5724 |
| 5725 count = 0; |
| 5726 HControlInstruction* smi_check = NULL; |
| 5727 handled_string = false; |
| 5728 |
| 5729 for (int i = 0; i < types->length() && count < kMaxLoadPolymorphism; ++i) { |
| 5730 PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name); |
| 5731 if (info.type()->Is(HeapType::String())) { |
| 5732 if (handled_string) continue; |
| 5733 handled_string = true; |
| 5734 } |
| 5735 if (!info.CanLoadMonomorphic()) continue; |
| 5736 |
| 5737 if (count == 0) { |
| 5738 join = graph()->CreateBasicBlock(); |
| 5739 if (handle_smi) { |
| 5740 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
| 5741 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
| 5742 number_block = graph()->CreateBasicBlock(); |
| 5743 smi_check = New<HIsSmiAndBranch>( |
| 5744 object, empty_smi_block, not_smi_block); |
| 5745 FinishCurrentBlock(smi_check); |
| 5746 Goto(empty_smi_block, number_block); |
| 5747 set_current_block(not_smi_block); |
| 5748 } else { |
| 5749 BuildCheckHeapObject(object); |
| 5750 } |
| 5751 } |
| 5752 ++count; |
| 5753 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
| 5754 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
| 5755 HUnaryControlInstruction* compare; |
| 5756 |
| 5757 HValue* dependency; |
| 5758 if (info.type()->Is(HeapType::Number())) { |
| 5759 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
| 5760 compare = New<HCompareMap>(object, heap_number_map, if_true, if_false); |
| 5761 dependency = smi_check; |
| 5762 } else if (info.type()->Is(HeapType::String())) { |
| 5763 compare = New<HIsStringAndBranch>(object, if_true, if_false); |
| 5764 dependency = compare; |
| 5765 } else { |
| 5766 compare = New<HCompareMap>(object, info.map(), if_true, if_false); |
| 5767 dependency = compare; |
| 5768 } |
| 5769 FinishCurrentBlock(compare); |
| 5770 |
| 5771 if (info.type()->Is(HeapType::Number())) { |
| 5772 Goto(if_true, number_block); |
| 5773 if_true = number_block; |
| 5774 number_block->SetJoinId(ast_id); |
| 5775 } |
| 5776 |
| 5777 set_current_block(if_true); |
| 5778 |
| 5779 HInstruction* load = BuildLoadMonomorphic( |
| 5780 &info, object, dependency, ast_id, |
| 5781 return_id, FLAG_polymorphic_inlining); |
| 5782 if (load == NULL) { |
| 5783 if (HasStackOverflow()) return; |
| 5784 } else { |
| 5785 if (!load->IsLinked()) { |
| 5786 AddInstruction(load); |
| 5787 } |
| 5788 if (!ast_context()->IsEffect()) Push(load); |
| 5789 } |
| 5790 |
| 5791 if (current_block() != NULL) Goto(join); |
| 5792 set_current_block(if_false); |
| 5793 } |
| 5794 |
5692 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 5795 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
5693 // know about and do not want to handle ones we've never seen. Otherwise | 5796 // know about and do not want to handle ones we've never seen. Otherwise |
5694 // use a generic IC. | 5797 // use a generic IC. |
5695 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { | 5798 if (count == types->length() && FLAG_deoptimize_uncommon_cases) { |
5696 // Because the deopt may be the only path in the polymorphic load, make sure | 5799 // Because the deopt may be the only path in the polymorphic load, make sure |
5697 // that the environment stack matches the depth on deopt that it otherwise | 5800 // that the environment stack matches the depth on deopt that it otherwise |
5698 // would have had after a successful load. | 5801 // would have had after a successful load. |
5699 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); | 5802 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); |
5700 FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); | 5803 FinishExitWithHardDeoptimization("Unknown map in polymorphic load", join); |
5701 } else { | 5804 } else { |
(...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5863 HValue* receiver, | 5966 HValue* receiver, |
5864 SmallMapList** t) { | 5967 SmallMapList** t) { |
5865 SmallMapList* types = expr->GetReceiverTypes(); | 5968 SmallMapList* types = expr->GetReceiverTypes(); |
5866 *t = types; | 5969 *t = types; |
5867 bool monomorphic = expr->IsMonomorphic(); | 5970 bool monomorphic = expr->IsMonomorphic(); |
5868 if (types != NULL && receiver->HasMonomorphicJSObjectType()) { | 5971 if (types != NULL && receiver->HasMonomorphicJSObjectType()) { |
5869 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); | 5972 Map* root_map = receiver->GetMonomorphicJSObjectMap()->FindRootMap(); |
5870 types->FilterForPossibleTransitions(root_map); | 5973 types->FilterForPossibleTransitions(root_map); |
5871 monomorphic = types->length() == 1; | 5974 monomorphic = types->length() == 1; |
5872 } | 5975 } |
5873 return monomorphic && CanInlinePropertyAccess(*types->first()); | 5976 return monomorphic && CanInlinePropertyAccess(IC::MapToType(types->first())); |
5874 } | 5977 } |
5875 | 5978 |
5876 | 5979 |
5877 void HOptimizedGraphBuilder::BuildStore(Expression* expr, | 5980 void HOptimizedGraphBuilder::BuildStore(Expression* expr, |
5878 Property* prop, | 5981 Property* prop, |
5879 BailoutId ast_id, | 5982 BailoutId ast_id, |
5880 BailoutId return_id, | 5983 BailoutId return_id, |
5881 bool is_uninitialized) { | 5984 bool is_uninitialized) { |
5882 HValue* value = environment()->ExpressionStackAt(0); | 5985 HValue* value = environment()->ExpressionStackAt(0); |
5883 | 5986 |
(...skipping 26 matching lines...) Expand all Loading... |
5910 HInstruction* instr = NULL; | 6013 HInstruction* instr = NULL; |
5911 | 6014 |
5912 SmallMapList* types; | 6015 SmallMapList* types; |
5913 bool monomorphic = ComputeReceiverTypes(expr, object, &types); | 6016 bool monomorphic = ComputeReceiverTypes(expr, object, &types); |
5914 | 6017 |
5915 if (monomorphic) { | 6018 if (monomorphic) { |
5916 Handle<Map> map = types->first(); | 6019 Handle<Map> map = types->first(); |
5917 Handle<JSFunction> setter; | 6020 Handle<JSFunction> setter; |
5918 Handle<JSObject> holder; | 6021 Handle<JSObject> holder; |
5919 if (LookupSetter(map, name, &setter, &holder)) { | 6022 if (LookupSetter(map, name, &setter, &holder)) { |
5920 AddCheckConstantFunction(holder, object, map); | 6023 AddCheckMap(object, map); |
5921 if (FLAG_inline_accessors && | 6024 AddCheckPrototypeMaps(holder, map); |
5922 TryInlineSetter(setter, ast_id, return_id, value)) { | 6025 bool needs_wrapping = NeedsWrappingFor(IC::MapToType(map), setter); |
| 6026 bool try_inline = FLAG_inline_accessors && !needs_wrapping; |
| 6027 if (try_inline && TryInlineSetter(setter, ast_id, return_id, value)) { |
5923 return; | 6028 return; |
5924 } | 6029 } |
5925 Drop(2); | 6030 Drop(2); |
5926 Add<HPushArgument>(object); | 6031 Add<HPushArgument>(object); |
5927 Add<HPushArgument>(value); | 6032 Add<HPushArgument>(value); |
5928 instr = BuildCallConstantFunction(setter, 2); | 6033 if (needs_wrapping) { |
| 6034 HValue* function = Add<HConstant>(setter); |
| 6035 instr = New<HCallFunction>(function, 2, WRAP_AND_CALL); |
| 6036 } else { |
| 6037 instr = BuildCallConstantFunction(setter, 2); |
| 6038 } |
5929 } else { | 6039 } else { |
5930 Drop(2); | 6040 Drop(2); |
5931 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, | 6041 CHECK_ALIVE(instr = BuildStoreNamedMonomorphic(object, |
5932 name, | 6042 name, |
5933 value, | 6043 value, |
5934 map)); | 6044 map)); |
5935 } | 6045 } |
5936 } else if (types != NULL && types->length() > 1) { | 6046 } else if (types != NULL && types->length() > 1) { |
5937 Drop(2); | 6047 Drop(2); |
5938 return HandlePolymorphicStoreNamedField(ast_id, object, value, types, name); | 6048 return HandlePolymorphicStoreNamedField(ast_id, object, value, types, name); |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6249 ASSERT(current_block() != NULL); | 6359 ASSERT(current_block() != NULL); |
6250 ASSERT(current_block()->HasPredecessor()); | 6360 ASSERT(current_block()->HasPredecessor()); |
6251 // We don't optimize functions with invalid left-hand sides in | 6361 // We don't optimize functions with invalid left-hand sides in |
6252 // assignments, count operations, or for-in. Consequently throw can | 6362 // assignments, count operations, or for-in. Consequently throw can |
6253 // currently only occur in an effect context. | 6363 // currently only occur in an effect context. |
6254 ASSERT(ast_context()->IsEffect()); | 6364 ASSERT(ast_context()->IsEffect()); |
6255 CHECK_ALIVE(VisitForValue(expr->exception())); | 6365 CHECK_ALIVE(VisitForValue(expr->exception())); |
6256 | 6366 |
6257 HValue* value = environment()->Pop(); | 6367 HValue* value = environment()->Pop(); |
6258 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); | 6368 if (!FLAG_emit_opt_code_positions) SetSourcePosition(expr->position()); |
6259 Add<HThrow>(value); | 6369 Add<HPushArgument>(value); |
| 6370 Add<HCallRuntime>(isolate()->factory()->empty_string(), |
| 6371 Runtime::FunctionForId(Runtime::kThrow), 1); |
6260 Add<HSimulate>(expr->id()); | 6372 Add<HSimulate>(expr->id()); |
6261 | 6373 |
6262 // If the throw definitely exits the function, we can finish with a dummy | 6374 // If the throw definitely exits the function, we can finish with a dummy |
6263 // control flow at this point. This is not the case if the throw is inside | 6375 // control flow at this point. This is not the case if the throw is inside |
6264 // an inlined function which may be replaced. | 6376 // an inlined function which may be replaced. |
6265 if (call_context() == NULL) { | 6377 if (call_context() == NULL) { |
6266 FinishExitCurrentBlock(New<HAbnormalExit>()); | 6378 FinishExitCurrentBlock(New<HAbnormalExit>()); |
6267 } | 6379 } |
6268 } | 6380 } |
6269 | 6381 |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6312 } | 6424 } |
6313 } | 6425 } |
6314 return AddLoadNamedField(string, HObjectAccess::ForStringLength()); | 6426 return AddLoadNamedField(string, HObjectAccess::ForStringLength()); |
6315 } | 6427 } |
6316 | 6428 |
6317 | 6429 |
6318 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( | 6430 HInstruction* HOptimizedGraphBuilder::BuildLoadNamedGeneric( |
6319 HValue* object, | 6431 HValue* object, |
6320 Handle<String> name, | 6432 Handle<String> name, |
6321 Property* expr) { | 6433 Property* expr) { |
6322 if (expr->IsUninitialized()) { | 6434 if (!expr->IsForCall() && expr->IsUninitialized()) { |
6323 Add<HDeoptimize>("Insufficient type feedback for generic named load", | 6435 Add<HDeoptimize>("Insufficient type feedback for generic named load", |
6324 Deoptimizer::SOFT); | 6436 Deoptimizer::SOFT); |
6325 } | 6437 } |
6326 return New<HLoadNamedGeneric>(object, name); | 6438 return New<HLoadNamedGeneric>(object, name); |
6327 } | 6439 } |
6328 | 6440 |
6329 | 6441 |
6330 | 6442 |
6331 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object, | 6443 HInstruction* HOptimizedGraphBuilder::BuildLoadKeyedGeneric(HValue* object, |
6332 HValue* key) { | 6444 HValue* key) { |
(...skipping 270 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6603 if (current_map->DictionaryElementsInPrototypeChainOnly()) { | 6715 if (current_map->DictionaryElementsInPrototypeChainOnly()) { |
6604 force_generic = true; | 6716 force_generic = true; |
6605 monomorphic = false; | 6717 monomorphic = false; |
6606 break; | 6718 break; |
6607 } | 6719 } |
6608 } | 6720 } |
6609 } | 6721 } |
6610 | 6722 |
6611 if (monomorphic) { | 6723 if (monomorphic) { |
6612 Handle<Map> map = types->first(); | 6724 Handle<Map> map = types->first(); |
6613 if (map->has_slow_elements_kind()) { | 6725 if (map->has_slow_elements_kind() || !map->IsJSObjectMap()) { |
6614 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) | 6726 instr = is_store ? BuildStoreKeyedGeneric(obj, key, val) |
6615 : BuildLoadKeyedGeneric(obj, key); | 6727 : BuildLoadKeyedGeneric(obj, key); |
6616 AddInstruction(instr); | 6728 AddInstruction(instr); |
6617 } else { | 6729 } else { |
6618 BuildCheckHeapObject(obj); | 6730 BuildCheckHeapObject(obj); |
6619 instr = BuildMonomorphicElementAccess( | 6731 instr = BuildMonomorphicElementAccess( |
6620 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); | 6732 obj, key, val, NULL, map, is_store, expr->GetStoreMode()); |
6621 } | 6733 } |
6622 } else if (!force_generic && (types != NULL && !types->is_empty())) { | 6734 } else if (!force_generic && (types != NULL && !types->is_empty())) { |
6623 return HandlePolymorphicElementAccess( | 6735 return HandlePolymorphicElementAccess( |
(...skipping 145 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6769 | 6881 |
6770 } else if (expr->key()->IsPropertyName()) { | 6882 } else if (expr->key()->IsPropertyName()) { |
6771 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); | 6883 Handle<String> name = expr->key()->AsLiteral()->AsPropertyName(); |
6772 HValue* object = Pop(); | 6884 HValue* object = Pop(); |
6773 | 6885 |
6774 SmallMapList* types; | 6886 SmallMapList* types; |
6775 ComputeReceiverTypes(expr, object, &types); | 6887 ComputeReceiverTypes(expr, object, &types); |
6776 ASSERT(types != NULL); | 6888 ASSERT(types != NULL); |
6777 | 6889 |
6778 if (types->length() > 0) { | 6890 if (types->length() > 0) { |
6779 PropertyAccessInfo info(isolate(), types->first(), name); | 6891 PropertyAccessInfo info(this, IC::MapToType(types->first()), name); |
6780 if (!info.CanLoadAsMonomorphic(types)) { | 6892 if (!info.CanLoadAsMonomorphic(types)) { |
6781 return HandlePolymorphicLoadNamedField( | 6893 return HandlePolymorphicLoadNamedField( |
6782 ast_id, expr->LoadId(), object, types, name); | 6894 ast_id, expr->LoadId(), object, types, name); |
6783 } | 6895 } |
6784 | 6896 |
| 6897 HValue* checked_object; |
| 6898 // HeapType::Number() is only supported by polymorphic load/call handling. |
| 6899 ASSERT(!info.type()->Is(HeapType::Number())); |
6785 BuildCheckHeapObject(object); | 6900 BuildCheckHeapObject(object); |
6786 HInstruction* checked_object; | |
6787 if (AreStringTypes(types)) { | 6901 if (AreStringTypes(types)) { |
6788 checked_object = | 6902 checked_object = |
6789 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); | 6903 Add<HCheckInstanceType>(object, HCheckInstanceType::IS_STRING); |
6790 } else { | 6904 } else { |
6791 checked_object = Add<HCheckMaps>(object, types); | 6905 checked_object = Add<HCheckMaps>(object, types); |
6792 } | 6906 } |
6793 instr = BuildLoadMonomorphic( | 6907 instr = BuildLoadMonomorphic( |
6794 &info, object, checked_object, ast_id, expr->LoadId()); | 6908 &info, object, checked_object, ast_id, expr->LoadId()); |
6795 if (instr == NULL) return; | 6909 if (instr == NULL) return; |
6796 if (instr->IsLinked()) return ast_context()->ReturnValue(instr); | 6910 if (instr->IsLinked()) return ast_context()->ReturnValue(instr); |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
6872 | 6986 |
6873 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, | 6987 void HOptimizedGraphBuilder::AddCheckPrototypeMaps(Handle<JSObject> holder, |
6874 Handle<Map> receiver_map) { | 6988 Handle<Map> receiver_map) { |
6875 if (!holder.is_null()) { | 6989 if (!holder.is_null()) { |
6876 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); | 6990 Handle<JSObject> prototype(JSObject::cast(receiver_map->prototype())); |
6877 BuildCheckPrototypeMaps(prototype, holder); | 6991 BuildCheckPrototypeMaps(prototype, holder); |
6878 } | 6992 } |
6879 } | 6993 } |
6880 | 6994 |
6881 | 6995 |
6882 void HOptimizedGraphBuilder::AddCheckConstantFunction( | |
6883 Handle<JSObject> holder, | |
6884 HValue* receiver, | |
6885 Handle<Map> receiver_map) { | |
6886 // Constant functions have the nice property that the map will change if they | |
6887 // are overwritten. Therefore it is enough to check the map of the holder and | |
6888 // its prototypes. | |
6889 AddCheckMap(receiver, receiver_map); | |
6890 AddCheckPrototypeMaps(holder, receiver_map); | |
6891 } | |
6892 | |
6893 | |
6894 HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall( | 6996 HInstruction* HOptimizedGraphBuilder::NewPlainFunctionCall( |
6895 HValue* fun, int argument_count, bool pass_argument_count) { | 6997 HValue* fun, int argument_count, bool pass_argument_count) { |
6896 return New<HCallJSFunction>( | 6998 return New<HCallJSFunction>( |
6897 fun, argument_count, pass_argument_count); | 6999 fun, argument_count, pass_argument_count); |
6898 } | 7000 } |
6899 | 7001 |
6900 | 7002 |
6901 HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall( | 7003 HInstruction* HOptimizedGraphBuilder::NewArgumentAdaptorCall( |
6902 HValue* fun, HValue* context, | 7004 HValue* fun, HValue* context, |
6903 int argument_count, HValue* expected_param_count) { | 7005 int argument_count, HValue* expected_param_count) { |
(...skipping 20 matching lines...) Expand all Loading... |
6924 // For constant functions, we try to avoid calling the | 7026 // For constant functions, we try to avoid calling the |
6925 // argument adaptor and instead call the function directly | 7027 // argument adaptor and instead call the function directly |
6926 int formal_parameter_count = jsfun->shared()->formal_parameter_count(); | 7028 int formal_parameter_count = jsfun->shared()->formal_parameter_count(); |
6927 bool dont_adapt_arguments = | 7029 bool dont_adapt_arguments = |
6928 (formal_parameter_count == | 7030 (formal_parameter_count == |
6929 SharedFunctionInfo::kDontAdaptArgumentsSentinel); | 7031 SharedFunctionInfo::kDontAdaptArgumentsSentinel); |
6930 int arity = argument_count - 1; | 7032 int arity = argument_count - 1; |
6931 bool can_invoke_directly = | 7033 bool can_invoke_directly = |
6932 dont_adapt_arguments || formal_parameter_count == arity; | 7034 dont_adapt_arguments || formal_parameter_count == arity; |
6933 if (can_invoke_directly) { | 7035 if (can_invoke_directly) { |
| 7036 if (jsfun.is_identical_to(current_info()->closure())) { |
| 7037 graph()->MarkRecursive(); |
| 7038 } |
6934 return NewPlainFunctionCall(target, argument_count, dont_adapt_arguments); | 7039 return NewPlainFunctionCall(target, argument_count, dont_adapt_arguments); |
6935 } else { | 7040 } else { |
6936 HValue* param_count_value = Add<HConstant>(formal_parameter_count); | 7041 HValue* param_count_value = Add<HConstant>(formal_parameter_count); |
6937 HValue* context = Add<HLoadNamedField>( | 7042 HValue* context = Add<HLoadNamedField>( |
6938 target, static_cast<HValue*>(NULL), | 7043 target, static_cast<HValue*>(NULL), |
6939 HObjectAccess::ForFunctionContextPointer()); | 7044 HObjectAccess::ForFunctionContextPointer()); |
6940 return NewArgumentAdaptorCall(target, context, | 7045 return NewArgumentAdaptorCall(target, context, |
6941 argument_count, param_count_value); | 7046 argument_count, param_count_value); |
6942 } | 7047 } |
6943 UNREACHABLE(); | 7048 UNREACHABLE(); |
6944 return NULL; | 7049 return NULL; |
6945 } | 7050 } |
6946 | 7051 |
6947 | 7052 |
6948 HInstruction* HOptimizedGraphBuilder::NewCallNamed( | |
6949 Handle<String> name, int argument_count) { | |
6950 CallInterfaceDescriptor* descriptor = | |
6951 isolate()->call_descriptor(Isolate::NamedCall); | |
6952 HValue* op_vals[] = { context(), Add<HConstant>(name) }; | |
6953 int arity = argument_count - 1; | |
6954 Handle<Code> ic = isolate()->stub_cache()->ComputeCallInitialize(arity); | |
6955 | |
6956 return New<HCallWithDescriptor>( | |
6957 Add<HConstant>(ic), argument_count, descriptor, | |
6958 Vector<HValue*>(op_vals, descriptor->environment_length())); | |
6959 } | |
6960 | |
6961 | |
6962 HInstruction* HOptimizedGraphBuilder::NewCallKeyed( | |
6963 HValue* key, int argument_count) { | |
6964 CallInterfaceDescriptor* descriptor = | |
6965 isolate()->call_descriptor(Isolate::KeyedCall); | |
6966 HValue* op_vals[] = { context(), key }; | |
6967 int arity = argument_count - 1; | |
6968 Handle<Code> ic = isolate()->stub_cache()->ComputeKeyedCallInitialize(arity); | |
6969 | |
6970 return New<HCallWithDescriptor>( | |
6971 Add<HConstant>(ic), argument_count, descriptor, | |
6972 Vector<HValue*>(op_vals, descriptor->environment_length())); | |
6973 } | |
6974 | |
6975 class FunctionSorter { | 7053 class FunctionSorter { |
6976 public: | 7054 public: |
6977 FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { } | 7055 FunctionSorter() : index_(0), ticks_(0), ast_length_(0), src_length_(0) { } |
6978 FunctionSorter(int index, int ticks, int ast_length, int src_length) | 7056 FunctionSorter(int index, int ticks, int ast_length, int src_length) |
6979 : index_(index), | 7057 : index_(index), |
6980 ticks_(ticks), | 7058 ticks_(ticks), |
6981 ast_length_(ast_length), | 7059 ast_length_(ast_length), |
6982 src_length_(src_length) { } | 7060 src_length_(src_length) { } |
6983 | 7061 |
6984 int index() const { return index_; } | 7062 int index() const { return index_; } |
(...skipping 11 matching lines...) Expand all Loading... |
6996 | 7074 |
6997 inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) { | 7075 inline bool operator<(const FunctionSorter& lhs, const FunctionSorter& rhs) { |
6998 int diff = lhs.ticks() - rhs.ticks(); | 7076 int diff = lhs.ticks() - rhs.ticks(); |
6999 if (diff != 0) return diff > 0; | 7077 if (diff != 0) return diff > 0; |
7000 diff = lhs.ast_length() - rhs.ast_length(); | 7078 diff = lhs.ast_length() - rhs.ast_length(); |
7001 if (diff != 0) return diff < 0; | 7079 if (diff != 0) return diff < 0; |
7002 return lhs.src_length() < rhs.src_length(); | 7080 return lhs.src_length() < rhs.src_length(); |
7003 } | 7081 } |
7004 | 7082 |
7005 | 7083 |
7006 bool HOptimizedGraphBuilder::TryCallPolymorphicAsMonomorphic( | |
7007 Call* expr, | |
7008 HValue* receiver, | |
7009 SmallMapList* types, | |
7010 Handle<String> name) { | |
7011 if (types->length() > kMaxCallPolymorphism) return false; | |
7012 | |
7013 PropertyAccessInfo info(isolate(), types->at(0), name); | |
7014 if (!info.CanLoadAsMonomorphic(types)) return false; | |
7015 if (!expr->ComputeTarget(info.map(), name)) return false; | |
7016 | |
7017 BuildCheckHeapObject(receiver); | |
7018 Add<HCheckMaps>(receiver, types); | |
7019 AddCheckPrototypeMaps(expr->holder(), info.map()); | |
7020 if (FLAG_trace_inlining) { | |
7021 Handle<JSFunction> caller = current_info()->closure(); | |
7022 SmartArrayPointer<char> caller_name = | |
7023 caller->shared()->DebugName()->ToCString(); | |
7024 PrintF("Trying to inline the polymorphic call to %s from %s\n", | |
7025 name->ToCString().get(), caller_name.get()); | |
7026 } | |
7027 | |
7028 if (!TryInlineCall(expr)) { | |
7029 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | |
7030 HInstruction* call = BuildCallConstantFunction( | |
7031 expr->target(), argument_count); | |
7032 PushArgumentsFromEnvironment(argument_count); | |
7033 AddInstruction(call); | |
7034 if (!ast_context()->IsEffect()) Push(call); | |
7035 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | |
7036 if (!ast_context()->IsEffect()) ast_context()->ReturnValue(Pop()); | |
7037 } | |
7038 | |
7039 return true; | |
7040 } | |
7041 | |
7042 | |
7043 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( | 7084 void HOptimizedGraphBuilder::HandlePolymorphicCallNamed( |
7044 Call* expr, | 7085 Call* expr, |
7045 HValue* receiver, | 7086 HValue* receiver, |
7046 SmallMapList* types, | 7087 SmallMapList* types, |
7047 Handle<String> name) { | 7088 Handle<String> name) { |
7048 if (TryCallPolymorphicAsMonomorphic(expr, receiver, types, name)) return; | |
7049 | |
7050 int argument_count = expr->arguments()->length() + 1; // Includes receiver. | 7089 int argument_count = expr->arguments()->length() + 1; // Includes receiver. |
7051 HBasicBlock* join = NULL; | |
7052 FunctionSorter order[kMaxCallPolymorphism]; | 7090 FunctionSorter order[kMaxCallPolymorphism]; |
7053 int ordered_functions = 0; | |
7054 | |
7055 Handle<Map> initial_string_map( | |
7056 isolate()->native_context()->string_function()->initial_map()); | |
7057 Handle<Map> string_marker_map( | |
7058 JSObject::cast(initial_string_map->prototype())->map()); | |
7059 Handle<Map> initial_number_map( | |
7060 isolate()->native_context()->number_function()->initial_map()); | |
7061 Handle<Map> number_marker_map( | |
7062 JSObject::cast(initial_number_map->prototype())->map()); | |
7063 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); | |
7064 | 7091 |
7065 bool handle_smi = false; | 7092 bool handle_smi = false; |
| 7093 bool handled_string = false; |
| 7094 int ordered_functions = 0; |
7066 | 7095 |
7067 for (int i = 0; | 7096 for (int i = 0; |
7068 i < types->length() && ordered_functions < kMaxCallPolymorphism; | 7097 i < types->length() && ordered_functions < kMaxCallPolymorphism; |
7069 ++i) { | 7098 ++i) { |
7070 Handle<Map> map = types->at(i); | 7099 PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name); |
7071 if (expr->ComputeTarget(map, name)) { | 7100 if (info.CanLoadMonomorphic() && |
7072 if (map.is_identical_to(number_marker_map)) handle_smi = true; | 7101 info.lookup()->IsConstant() && |
| 7102 info.constant()->IsJSFunction()) { |
| 7103 if (info.type()->Is(HeapType::String())) { |
| 7104 if (handled_string) continue; |
| 7105 handled_string = true; |
| 7106 } |
| 7107 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); |
| 7108 if (info.type()->Is(HeapType::Number())) { |
| 7109 handle_smi = true; |
| 7110 } |
| 7111 expr->set_target(target); |
7073 order[ordered_functions++] = | 7112 order[ordered_functions++] = |
7074 FunctionSorter(i, | 7113 FunctionSorter(i, |
7075 expr->target()->shared()->profiler_ticks(), | 7114 expr->target()->shared()->profiler_ticks(), |
7076 InliningAstSize(expr->target()), | 7115 InliningAstSize(expr->target()), |
7077 expr->target()->shared()->SourceSize()); | 7116 expr->target()->shared()->SourceSize()); |
7078 } | 7117 } |
7079 } | 7118 } |
7080 | 7119 |
7081 std::sort(order, order + ordered_functions); | 7120 std::sort(order, order + ordered_functions); |
7082 | 7121 |
7083 HBasicBlock* number_block = NULL; | 7122 HBasicBlock* number_block = NULL; |
| 7123 HBasicBlock* join = NULL; |
| 7124 handled_string = false; |
| 7125 int count = 0; |
7084 | 7126 |
7085 for (int fn = 0; fn < ordered_functions; ++fn) { | 7127 for (int fn = 0; fn < ordered_functions; ++fn) { |
7086 int i = order[fn].index(); | 7128 int i = order[fn].index(); |
7087 Handle<Map> map = types->at(i); | 7129 PropertyAccessInfo info(this, IC::MapToType(types->at(i)), name); |
7088 if (fn == 0) { | 7130 if (info.type()->Is(HeapType::String())) { |
| 7131 if (handled_string) continue; |
| 7132 handled_string = true; |
| 7133 } |
| 7134 // Reloads the target. |
| 7135 info.CanLoadMonomorphic(); |
| 7136 Handle<JSFunction> target = Handle<JSFunction>::cast(info.constant()); |
| 7137 |
| 7138 expr->set_target(target); |
| 7139 if (count == 0) { |
7089 // Only needed once. | 7140 // Only needed once. |
7090 join = graph()->CreateBasicBlock(); | 7141 join = graph()->CreateBasicBlock(); |
7091 if (handle_smi) { | 7142 if (handle_smi) { |
7092 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); | 7143 HBasicBlock* empty_smi_block = graph()->CreateBasicBlock(); |
7093 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); | 7144 HBasicBlock* not_smi_block = graph()->CreateBasicBlock(); |
7094 number_block = graph()->CreateBasicBlock(); | 7145 number_block = graph()->CreateBasicBlock(); |
7095 FinishCurrentBlock(New<HIsSmiAndBranch>( | 7146 FinishCurrentBlock(New<HIsSmiAndBranch>( |
7096 receiver, empty_smi_block, not_smi_block)); | 7147 receiver, empty_smi_block, not_smi_block)); |
7097 Goto(empty_smi_block, number_block); | 7148 Goto(empty_smi_block, number_block); |
7098 set_current_block(not_smi_block); | 7149 set_current_block(not_smi_block); |
7099 } else { | 7150 } else { |
7100 BuildCheckHeapObject(receiver); | 7151 BuildCheckHeapObject(receiver); |
7101 } | 7152 } |
7102 } | 7153 } |
| 7154 ++count; |
7103 HBasicBlock* if_true = graph()->CreateBasicBlock(); | 7155 HBasicBlock* if_true = graph()->CreateBasicBlock(); |
7104 HBasicBlock* if_false = graph()->CreateBasicBlock(); | 7156 HBasicBlock* if_false = graph()->CreateBasicBlock(); |
7105 HUnaryControlInstruction* compare; | 7157 HUnaryControlInstruction* compare; |
7106 | 7158 |
7107 if (handle_smi && map.is_identical_to(number_marker_map)) { | 7159 Handle<Map> map = info.map(); |
| 7160 if (info.type()->Is(HeapType::Number())) { |
| 7161 Handle<Map> heap_number_map = isolate()->factory()->heap_number_map(); |
7108 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); | 7162 compare = New<HCompareMap>(receiver, heap_number_map, if_true, if_false); |
7109 map = initial_number_map; | 7163 } else if (info.type()->Is(HeapType::String())) { |
7110 expr->set_number_check( | |
7111 Handle<JSObject>(JSObject::cast(map->prototype()))); | |
7112 } else if (map.is_identical_to(string_marker_map)) { | |
7113 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); | 7164 compare = New<HIsStringAndBranch>(receiver, if_true, if_false); |
7114 map = initial_string_map; | |
7115 expr->set_string_check( | |
7116 Handle<JSObject>(JSObject::cast(map->prototype()))); | |
7117 } else { | 7165 } else { |
7118 compare = New<HCompareMap>(receiver, map, if_true, if_false); | 7166 compare = New<HCompareMap>(receiver, map, if_true, if_false); |
7119 expr->set_map_check(); | |
7120 } | 7167 } |
7121 | |
7122 FinishCurrentBlock(compare); | 7168 FinishCurrentBlock(compare); |
7123 | 7169 |
7124 if (expr->check_type() == NUMBER_CHECK) { | 7170 if (info.type()->Is(HeapType::Number())) { |
7125 Goto(if_true, number_block); | 7171 Goto(if_true, number_block); |
7126 if_true = number_block; | 7172 if_true = number_block; |
7127 number_block->SetJoinId(expr->id()); | 7173 number_block->SetJoinId(expr->id()); |
7128 } | 7174 } |
| 7175 |
7129 set_current_block(if_true); | 7176 set_current_block(if_true); |
7130 | 7177 |
7131 expr->ComputeTarget(map, name); | 7178 AddCheckPrototypeMaps(info.holder(), map); |
7132 AddCheckPrototypeMaps(expr->holder(), map); | 7179 |
7133 if (FLAG_trace_inlining && FLAG_polymorphic_inlining) { | 7180 HValue* function = Add<HConstant>(expr->target()); |
| 7181 environment()->SetExpressionStackAt(0, function); |
| 7182 Push(receiver); |
| 7183 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7184 bool needs_wrapping = NeedsWrappingFor(info.type(), target); |
| 7185 bool try_inline = FLAG_polymorphic_inlining && !needs_wrapping; |
| 7186 if (FLAG_trace_inlining && try_inline) { |
7134 Handle<JSFunction> caller = current_info()->closure(); | 7187 Handle<JSFunction> caller = current_info()->closure(); |
7135 SmartArrayPointer<char> caller_name = | 7188 SmartArrayPointer<char> caller_name = |
7136 caller->shared()->DebugName()->ToCString(); | 7189 caller->shared()->DebugName()->ToCString(); |
7137 PrintF("Trying to inline the polymorphic call to %s from %s\n", | 7190 PrintF("Trying to inline the polymorphic call to %s from %s\n", |
7138 name->ToCString().get(), | 7191 name->ToCString().get(), |
7139 caller_name.get()); | 7192 caller_name.get()); |
7140 } | 7193 } |
7141 if (FLAG_polymorphic_inlining && TryInlineCall(expr)) { | 7194 if (try_inline && TryInlineCall(expr)) { |
7142 // Trying to inline will signal that we should bailout from the | 7195 // Trying to inline will signal that we should bailout from the |
7143 // entire compilation by setting stack overflow on the visitor. | 7196 // entire compilation by setting stack overflow on the visitor. |
7144 if (HasStackOverflow()) return; | 7197 if (HasStackOverflow()) return; |
7145 } else { | 7198 } else { |
7146 HInstruction* call = BuildCallConstantFunction( | 7199 // Since HWrapReceiver currently cannot actually wrap numbers and strings, |
7147 expr->target(), argument_count); | 7200 // use the regular CallFunctionStub for method calls to wrap the receiver. |
| 7201 // TODO(verwaest): Support creation of value wrappers directly in |
| 7202 // HWrapReceiver. |
| 7203 HInstruction* call = needs_wrapping |
| 7204 ? NewUncasted<HCallFunction>( |
| 7205 function, argument_count, WRAP_AND_CALL) |
| 7206 : BuildCallConstantFunction(target, argument_count); |
7148 PushArgumentsFromEnvironment(argument_count); | 7207 PushArgumentsFromEnvironment(argument_count); |
7149 AddInstruction(call); | 7208 AddInstruction(call); |
| 7209 Drop(1); // Drop the function. |
7150 if (!ast_context()->IsEffect()) Push(call); | 7210 if (!ast_context()->IsEffect()) Push(call); |
7151 } | 7211 } |
7152 | 7212 |
7153 if (current_block() != NULL) Goto(join); | 7213 if (current_block() != NULL) Goto(join); |
7154 set_current_block(if_false); | 7214 set_current_block(if_false); |
7155 } | 7215 } |
7156 | 7216 |
7157 // Finish up. Unconditionally deoptimize if we've handled all the maps we | 7217 // Finish up. Unconditionally deoptimize if we've handled all the maps we |
7158 // know about and do not want to handle ones we've never seen. Otherwise | 7218 // know about and do not want to handle ones we've never seen. Otherwise |
7159 // use a generic IC. | 7219 // use a generic IC. |
7160 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { | 7220 if (ordered_functions == types->length() && FLAG_deoptimize_uncommon_cases) { |
7161 // Because the deopt may be the only path in the polymorphic call, make sure | 7221 // Because the deopt may be the only path in the polymorphic call, make sure |
7162 // that the environment stack matches the depth on deopt that it otherwise | 7222 // that the environment stack matches the depth on deopt that it otherwise |
7163 // would have had after a successful call. | 7223 // would have had after a successful call. |
7164 Drop(argument_count); | 7224 Drop(1); // Drop receiver. |
7165 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); | 7225 if (!ast_context()->IsEffect()) Push(graph()->GetConstant0()); |
7166 FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); | 7226 FinishExitWithHardDeoptimization("Unknown map in polymorphic call", join); |
7167 } else { | 7227 } else { |
7168 HInstruction* call = NewCallNamed(name, argument_count); | 7228 Property* prop = expr->expression()->AsProperty(); |
| 7229 HInstruction* function = BuildLoadNamedGeneric(receiver, name, prop); |
| 7230 AddInstruction(function); |
| 7231 Push(function); |
| 7232 AddSimulate(prop->LoadId(), REMOVABLE_SIMULATE); |
| 7233 |
| 7234 environment()->SetExpressionStackAt(1, function); |
| 7235 environment()->SetExpressionStackAt(0, receiver); |
| 7236 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 7237 |
| 7238 CallFunctionFlags flags = receiver->type().IsJSObject() |
| 7239 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; |
| 7240 HInstruction* call = New<HCallFunction>( |
| 7241 function, argument_count, flags); |
| 7242 |
7169 PushArgumentsFromEnvironment(argument_count); | 7243 PushArgumentsFromEnvironment(argument_count); |
7170 | 7244 |
| 7245 Drop(1); // Function. |
| 7246 |
7171 if (join != NULL) { | 7247 if (join != NULL) { |
7172 AddInstruction(call); | 7248 AddInstruction(call); |
7173 if (!ast_context()->IsEffect()) Push(call); | 7249 if (!ast_context()->IsEffect()) Push(call); |
7174 Goto(join); | 7250 Goto(join); |
7175 } else { | 7251 } else { |
7176 return ast_context()->ReturnInstruction(call, expr->id()); | 7252 return ast_context()->ReturnInstruction(call, expr->id()); |
7177 } | 7253 } |
7178 } | 7254 } |
7179 | 7255 |
7180 // We assume that control flow is always live after an expression. So | 7256 // We assume that control flow is always live after an expression. So |
(...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7541 function_return()->SetJoinId(ast_id); | 7617 function_return()->SetJoinId(ast_id); |
7542 set_current_block(function_return()); | 7618 set_current_block(function_return()); |
7543 } else { | 7619 } else { |
7544 set_current_block(NULL); | 7620 set_current_block(NULL); |
7545 } | 7621 } |
7546 delete target_state; | 7622 delete target_state; |
7547 return true; | 7623 return true; |
7548 } | 7624 } |
7549 | 7625 |
7550 | 7626 |
7551 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr, bool drop_extra) { | 7627 bool HOptimizedGraphBuilder::TryInlineCall(Call* expr) { |
7552 return TryInline(expr->target(), | 7628 return TryInline(expr->target(), |
7553 expr->arguments()->length(), | 7629 expr->arguments()->length(), |
7554 NULL, | 7630 NULL, |
7555 expr->id(), | 7631 expr->id(), |
7556 expr->ReturnId(), | 7632 expr->ReturnId(), |
7557 drop_extra ? DROP_EXTRA_ON_RETURN : NORMAL_RETURN); | 7633 NORMAL_RETURN); |
7558 } | 7634 } |
7559 | 7635 |
7560 | 7636 |
7561 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, | 7637 bool HOptimizedGraphBuilder::TryInlineConstruct(CallNew* expr, |
7562 HValue* implicit_return_value) { | 7638 HValue* implicit_return_value) { |
7563 return TryInline(expr->target(), | 7639 return TryInline(expr->target(), |
7564 expr->arguments()->length(), | 7640 expr->arguments()->length(), |
7565 implicit_return_value, | 7641 implicit_return_value, |
7566 expr->id(), | 7642 expr->id(), |
7567 expr->ReturnId(), | 7643 expr->ReturnId(), |
(...skipping 30 matching lines...) Expand all Loading... |
7598 int arguments_count) { | 7674 int arguments_count) { |
7599 return TryInline(function, | 7675 return TryInline(function, |
7600 arguments_count, | 7676 arguments_count, |
7601 NULL, | 7677 NULL, |
7602 expr->id(), | 7678 expr->id(), |
7603 expr->ReturnId(), | 7679 expr->ReturnId(), |
7604 NORMAL_RETURN); | 7680 NORMAL_RETURN); |
7605 } | 7681 } |
7606 | 7682 |
7607 | 7683 |
7608 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr, | 7684 bool HOptimizedGraphBuilder::TryInlineBuiltinFunctionCall(Call* expr) { |
7609 bool drop_extra) { | |
7610 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 7685 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
7611 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 7686 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
7612 switch (id) { | 7687 switch (id) { |
7613 case kMathExp: | 7688 case kMathExp: |
7614 if (!FLAG_fast_math) break; | 7689 if (!FLAG_fast_math) break; |
7615 // Fall through if FLAG_fast_math. | 7690 // Fall through if FLAG_fast_math. |
7616 case kMathRound: | 7691 case kMathRound: |
7617 case kMathFloor: | 7692 case kMathFloor: |
7618 case kMathAbs: | 7693 case kMathAbs: |
7619 case kMathSqrt: | 7694 case kMathSqrt: |
7620 case kMathLog: | 7695 case kMathLog: |
7621 if (expr->arguments()->length() == 1) { | 7696 if (expr->arguments()->length() == 1) { |
7622 HValue* argument = Pop(); | 7697 HValue* argument = Pop(); |
7623 Drop(1); // Receiver. | 7698 Drop(2); // Receiver and function. |
7624 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); | 7699 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
7625 if (drop_extra) Drop(1); // Optionally drop the function. | |
7626 ast_context()->ReturnInstruction(op, expr->id()); | 7700 ast_context()->ReturnInstruction(op, expr->id()); |
7627 return true; | 7701 return true; |
7628 } | 7702 } |
7629 break; | 7703 break; |
7630 case kMathImul: | 7704 case kMathImul: |
7631 if (expr->arguments()->length() == 2) { | 7705 if (expr->arguments()->length() == 2) { |
7632 HValue* right = Pop(); | 7706 HValue* right = Pop(); |
7633 HValue* left = Pop(); | 7707 HValue* left = Pop(); |
7634 Drop(1); // Receiver. | 7708 Drop(2); // Receiver and function. |
7635 HInstruction* op = HMul::NewImul(zone(), context(), left, right); | 7709 HInstruction* op = HMul::NewImul(zone(), context(), left, right); |
7636 if (drop_extra) Drop(1); // Optionally drop the function. | |
7637 ast_context()->ReturnInstruction(op, expr->id()); | 7710 ast_context()->ReturnInstruction(op, expr->id()); |
7638 return true; | 7711 return true; |
7639 } | 7712 } |
7640 break; | 7713 break; |
7641 default: | 7714 default: |
7642 // Not supported for inlining yet. | 7715 // Not supported for inlining yet. |
7643 break; | 7716 break; |
7644 } | 7717 } |
7645 return false; | 7718 return false; |
7646 } | 7719 } |
7647 | 7720 |
7648 | 7721 |
7649 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( | 7722 bool HOptimizedGraphBuilder::TryInlineBuiltinMethodCall( |
7650 Call* expr, | 7723 Call* expr, |
7651 HValue* receiver, | 7724 HValue* receiver, |
7652 Handle<Map> receiver_map, | 7725 Handle<Map> receiver_map) { |
7653 CheckType check_type) { | |
7654 ASSERT(check_type != RECEIVER_MAP_CHECK || !receiver_map.is_null()); | |
7655 // Try to inline calls like Math.* as operations in the calling function. | 7726 // Try to inline calls like Math.* as operations in the calling function. |
7656 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; | 7727 if (!expr->target()->shared()->HasBuiltinFunctionId()) return false; |
7657 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); | 7728 BuiltinFunctionId id = expr->target()->shared()->builtin_function_id(); |
7658 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 7729 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
7659 switch (id) { | 7730 switch (id) { |
7660 case kStringCharCodeAt: | 7731 case kStringCharCodeAt: |
7661 case kStringCharAt: | 7732 case kStringCharAt: |
7662 if (argument_count == 2 && check_type == STRING_CHECK) { | 7733 if (argument_count == 2) { |
7663 HValue* index = Pop(); | 7734 HValue* index = Pop(); |
7664 HValue* string = Pop(); | 7735 HValue* string = Pop(); |
7665 ASSERT(!expr->holder().is_null()); | 7736 Drop(1); // Function. |
7666 BuildCheckPrototypeMaps(Call::GetPrototypeForPrimitiveCheck( | |
7667 STRING_CHECK, expr->holder()->GetIsolate()), | |
7668 expr->holder()); | |
7669 HInstruction* char_code = | 7737 HInstruction* char_code = |
7670 BuildStringCharCodeAt(string, index); | 7738 BuildStringCharCodeAt(string, index); |
7671 if (id == kStringCharCodeAt) { | 7739 if (id == kStringCharCodeAt) { |
7672 ast_context()->ReturnInstruction(char_code, expr->id()); | 7740 ast_context()->ReturnInstruction(char_code, expr->id()); |
7673 return true; | 7741 return true; |
7674 } | 7742 } |
7675 AddInstruction(char_code); | 7743 AddInstruction(char_code); |
7676 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code); | 7744 HInstruction* result = NewUncasted<HStringCharFromCode>(char_code); |
7677 ast_context()->ReturnInstruction(result, expr->id()); | 7745 ast_context()->ReturnInstruction(result, expr->id()); |
7678 return true; | 7746 return true; |
7679 } | 7747 } |
7680 break; | 7748 break; |
7681 case kStringFromCharCode: | 7749 case kStringFromCharCode: |
7682 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { | 7750 if (argument_count == 2) { |
7683 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7684 HValue* argument = Pop(); | 7751 HValue* argument = Pop(); |
7685 Drop(1); // Receiver. | 7752 Drop(2); // Receiver and function. |
7686 HInstruction* result = NewUncasted<HStringCharFromCode>(argument); | 7753 HInstruction* result = NewUncasted<HStringCharFromCode>(argument); |
7687 ast_context()->ReturnInstruction(result, expr->id()); | 7754 ast_context()->ReturnInstruction(result, expr->id()); |
7688 return true; | 7755 return true; |
7689 } | 7756 } |
7690 break; | 7757 break; |
7691 case kMathExp: | 7758 case kMathExp: |
7692 if (!FLAG_fast_math) break; | 7759 if (!FLAG_fast_math) break; |
7693 // Fall through if FLAG_fast_math. | 7760 // Fall through if FLAG_fast_math. |
7694 case kMathRound: | 7761 case kMathRound: |
7695 case kMathFloor: | 7762 case kMathFloor: |
7696 case kMathAbs: | 7763 case kMathAbs: |
7697 case kMathSqrt: | 7764 case kMathSqrt: |
7698 case kMathLog: | 7765 case kMathLog: |
7699 if (argument_count == 2 && check_type == RECEIVER_MAP_CHECK) { | 7766 if (argument_count == 2) { |
7700 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7701 HValue* argument = Pop(); | 7767 HValue* argument = Pop(); |
7702 Drop(1); // Receiver. | 7768 Drop(2); // Receiver and function. |
7703 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); | 7769 HInstruction* op = NewUncasted<HUnaryMathOperation>(argument, id); |
7704 ast_context()->ReturnInstruction(op, expr->id()); | 7770 ast_context()->ReturnInstruction(op, expr->id()); |
7705 return true; | 7771 return true; |
7706 } | 7772 } |
7707 break; | 7773 break; |
7708 case kMathPow: | 7774 case kMathPow: |
7709 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { | 7775 if (argument_count == 3) { |
7710 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7711 HValue* right = Pop(); | 7776 HValue* right = Pop(); |
7712 HValue* left = Pop(); | 7777 HValue* left = Pop(); |
7713 Pop(); // Pop receiver. | 7778 Drop(2); // Receiver and function. |
7714 HInstruction* result = NULL; | 7779 HInstruction* result = NULL; |
7715 // Use sqrt() if exponent is 0.5 or -0.5. | 7780 // Use sqrt() if exponent is 0.5 or -0.5. |
7716 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { | 7781 if (right->IsConstant() && HConstant::cast(right)->HasDoubleValue()) { |
7717 double exponent = HConstant::cast(right)->DoubleValue(); | 7782 double exponent = HConstant::cast(right)->DoubleValue(); |
7718 if (exponent == 0.5) { | 7783 if (exponent == 0.5) { |
7719 result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf); | 7784 result = NewUncasted<HUnaryMathOperation>(left, kMathPowHalf); |
7720 } else if (exponent == -0.5) { | 7785 } else if (exponent == -0.5) { |
7721 HValue* one = graph()->GetConstant1(); | 7786 HValue* one = graph()->GetConstant1(); |
7722 HInstruction* sqrt = AddUncasted<HUnaryMathOperation>( | 7787 HInstruction* sqrt = AddUncasted<HUnaryMathOperation>( |
7723 left, kMathPowHalf); | 7788 left, kMathPowHalf); |
7724 // MathPowHalf doesn't have side effects so there's no need for | 7789 // MathPowHalf doesn't have side effects so there's no need for |
7725 // an environment simulation here. | 7790 // an environment simulation here. |
7726 ASSERT(!sqrt->HasObservableSideEffects()); | 7791 ASSERT(!sqrt->HasObservableSideEffects()); |
7727 result = NewUncasted<HDiv>(one, sqrt); | 7792 result = NewUncasted<HDiv>(one, sqrt); |
7728 } else if (exponent == 2.0) { | 7793 } else if (exponent == 2.0) { |
7729 result = NewUncasted<HMul>(left, left); | 7794 result = NewUncasted<HMul>(left, left); |
7730 } | 7795 } |
7731 } | 7796 } |
7732 | 7797 |
7733 if (result == NULL) { | 7798 if (result == NULL) { |
7734 result = NewUncasted<HPower>(left, right); | 7799 result = NewUncasted<HPower>(left, right); |
7735 } | 7800 } |
7736 ast_context()->ReturnInstruction(result, expr->id()); | 7801 ast_context()->ReturnInstruction(result, expr->id()); |
7737 return true; | 7802 return true; |
7738 } | 7803 } |
7739 break; | 7804 break; |
7740 case kMathMax: | 7805 case kMathMax: |
7741 case kMathMin: | 7806 case kMathMin: |
7742 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { | 7807 if (argument_count == 3) { |
7743 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7744 HValue* right = Pop(); | 7808 HValue* right = Pop(); |
7745 HValue* left = Pop(); | 7809 HValue* left = Pop(); |
7746 Drop(1); // Receiver. | 7810 Drop(2); // Receiver and function. |
7747 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin | 7811 HMathMinMax::Operation op = (id == kMathMin) ? HMathMinMax::kMathMin |
7748 : HMathMinMax::kMathMax; | 7812 : HMathMinMax::kMathMax; |
7749 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); | 7813 HInstruction* result = NewUncasted<HMathMinMax>(left, right, op); |
7750 ast_context()->ReturnInstruction(result, expr->id()); | 7814 ast_context()->ReturnInstruction(result, expr->id()); |
7751 return true; | 7815 return true; |
7752 } | 7816 } |
7753 break; | 7817 break; |
7754 case kMathImul: | 7818 case kMathImul: |
7755 if (argument_count == 3 && check_type == RECEIVER_MAP_CHECK) { | 7819 if (argument_count == 3) { |
7756 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7757 HValue* right = Pop(); | 7820 HValue* right = Pop(); |
7758 HValue* left = Pop(); | 7821 HValue* left = Pop(); |
7759 Drop(1); // Receiver. | 7822 Drop(2); // Receiver and function. |
7760 HInstruction* result = HMul::NewImul(zone(), context(), left, right); | 7823 HInstruction* result = HMul::NewImul(zone(), context(), left, right); |
7761 ast_context()->ReturnInstruction(result, expr->id()); | 7824 ast_context()->ReturnInstruction(result, expr->id()); |
7762 return true; | 7825 return true; |
7763 } | 7826 } |
7764 break; | 7827 break; |
7765 case kArrayPop: { | 7828 case kArrayPop: { |
7766 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { | 7829 if (receiver_map.is_null()) return false; |
7767 return false; | |
7768 } | |
7769 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; | 7830 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; |
7770 ElementsKind elements_kind = receiver_map->elements_kind(); | 7831 ElementsKind elements_kind = receiver_map->elements_kind(); |
7771 if (!IsFastElementsKind(elements_kind)) return false; | 7832 if (!IsFastElementsKind(elements_kind)) return false; |
7772 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7773 | 7833 |
7774 Drop(expr->arguments()->length()); | 7834 Drop(expr->arguments()->length()); |
7775 HValue* result; | 7835 HValue* result; |
7776 HValue* reduced_length; | 7836 HValue* reduced_length; |
7777 HValue* receiver = Pop(); | 7837 HValue* receiver = Pop(); |
7778 | 7838 |
7779 HValue* checked_object = AddCheckMap(receiver, receiver_map); | 7839 HValue* checked_object = AddCheckMap(receiver, receiver_map); |
7780 HValue* length = Add<HLoadNamedField>( | 7840 HValue* length = Add<HLoadNamedField>( |
7781 checked_object, static_cast<HValue*>(NULL), | 7841 checked_object, static_cast<HValue*>(NULL), |
7782 HObjectAccess::ForArrayLength(elements_kind)); | 7842 HObjectAccess::ForArrayLength(elements_kind)); |
7783 | 7843 |
| 7844 Drop(1); // Function. |
| 7845 |
7784 { NoObservableSideEffectsScope scope(this); | 7846 { NoObservableSideEffectsScope scope(this); |
7785 IfBuilder length_checker(this); | 7847 IfBuilder length_checker(this); |
7786 | 7848 |
7787 HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>( | 7849 HValue* bounds_check = length_checker.If<HCompareNumericAndBranch>( |
7788 length, graph()->GetConstant0(), Token::EQ); | 7850 length, graph()->GetConstant0(), Token::EQ); |
7789 length_checker.Then(); | 7851 length_checker.Then(); |
7790 | 7852 |
7791 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); | 7853 if (!ast_context()->IsEffect()) Push(graph()->GetConstantUndefined()); |
7792 | 7854 |
7793 length_checker.Else(); | 7855 length_checker.Else(); |
(...skipping 25 matching lines...) Expand all Loading... |
7819 length_checker.End(); | 7881 length_checker.End(); |
7820 } | 7882 } |
7821 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top(); | 7883 result = ast_context()->IsEffect() ? graph()->GetConstant0() : Top(); |
7822 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); | 7884 Add<HSimulate>(expr->id(), REMOVABLE_SIMULATE); |
7823 if (!ast_context()->IsEffect()) Drop(1); | 7885 if (!ast_context()->IsEffect()) Drop(1); |
7824 | 7886 |
7825 ast_context()->ReturnValue(result); | 7887 ast_context()->ReturnValue(result); |
7826 return true; | 7888 return true; |
7827 } | 7889 } |
7828 case kArrayPush: { | 7890 case kArrayPush: { |
7829 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { | 7891 if (receiver_map.is_null()) return false; |
7830 return false; | |
7831 } | |
7832 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; | 7892 if (receiver_map->instance_type() != JS_ARRAY_TYPE) return false; |
7833 ElementsKind elements_kind = receiver_map->elements_kind(); | 7893 ElementsKind elements_kind = receiver_map->elements_kind(); |
7834 if (!IsFastElementsKind(elements_kind)) return false; | 7894 if (!IsFastElementsKind(elements_kind)) return false; |
7835 AddCheckConstantFunction(expr->holder(), receiver, receiver_map); | |
7836 | 7895 |
7837 HValue* op_vals[] = { | 7896 HValue* op_vals[] = { |
7838 context(), | 7897 context(), |
7839 // Receiver. | 7898 // Receiver. |
7840 environment()->ExpressionStackAt(expr->arguments()->length()) | 7899 environment()->ExpressionStackAt(expr->arguments()->length()) |
7841 }; | 7900 }; |
7842 | 7901 |
7843 const int argc = expr->arguments()->length(); | 7902 const int argc = expr->arguments()->length(); |
7844 // Includes receiver. | 7903 // Includes receiver. |
7845 PushArgumentsFromEnvironment(argc + 1); | 7904 PushArgumentsFromEnvironment(argc + 1); |
7846 | 7905 |
7847 CallInterfaceDescriptor* descriptor = | 7906 CallInterfaceDescriptor* descriptor = |
7848 isolate()->call_descriptor(Isolate::CallHandler); | 7907 isolate()->call_descriptor(Isolate::CallHandler); |
7849 | 7908 |
7850 ArrayPushStub stub(receiver_map->elements_kind(), argc); | 7909 ArrayPushStub stub(receiver_map->elements_kind(), argc); |
7851 Handle<Code> code = stub.GetCode(isolate()); | 7910 Handle<Code> code = stub.GetCode(isolate()); |
7852 HConstant* code_value = Add<HConstant>(code); | 7911 HConstant* code_value = Add<HConstant>(code); |
7853 | 7912 |
7854 ASSERT((sizeof(op_vals) / kPointerSize) == | 7913 ASSERT((sizeof(op_vals) / kPointerSize) == |
7855 descriptor->environment_length()); | 7914 descriptor->environment_length()); |
7856 | 7915 |
7857 HInstruction* call = New<HCallWithDescriptor>( | 7916 HInstruction* call = New<HCallWithDescriptor>( |
7858 code_value, argc + 1, descriptor, | 7917 code_value, argc + 1, descriptor, |
7859 Vector<HValue*>(op_vals, descriptor->environment_length())); | 7918 Vector<HValue*>(op_vals, descriptor->environment_length())); |
| 7919 Drop(1); // Drop function. |
7860 ast_context()->ReturnInstruction(call, expr->id()); | 7920 ast_context()->ReturnInstruction(call, expr->id()); |
7861 return true; | 7921 return true; |
7862 } | 7922 } |
7863 default: | 7923 default: |
7864 // Not yet supported for inlining. | 7924 // Not yet supported for inlining. |
7865 break; | 7925 break; |
7866 } | 7926 } |
7867 return false; | 7927 return false; |
7868 } | 7928 } |
7869 | 7929 |
7870 | 7930 |
| 7931 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, |
| 7932 HValue* receiver) { |
| 7933 return TryInlineApiCall( |
| 7934 expr, receiver, Handle<Map>::null(), true); |
| 7935 } |
| 7936 |
| 7937 |
| 7938 bool HOptimizedGraphBuilder::TryInlineApiMethodCall(Call* expr, |
| 7939 HValue* receiver, |
| 7940 Handle<Map> receiver_map) { |
| 7941 return TryInlineApiCall(expr, receiver, receiver_map, false); |
| 7942 } |
| 7943 |
| 7944 bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr, |
| 7945 HValue* receiver, |
| 7946 Handle<Map> receiver_map, |
| 7947 bool is_function_call) { |
| 7948 if (!expr->IsMonomorphic()) return false; |
| 7949 CallOptimization optimization(expr->target()); |
| 7950 if (!optimization.is_simple_api_call()) return false; |
| 7951 Handle<Map> holder_map; |
| 7952 if (is_function_call) { |
| 7953 // Cannot embed a direct reference to the global proxy map |
| 7954 // as it maybe dropped on deserialization. |
| 7955 CHECK(!Serializer::enabled()); |
| 7956 receiver_map = Handle<Map>( |
| 7957 expr->target()->context()->global_object()->global_receiver()->map()); |
| 7958 } |
| 7959 CallOptimization::HolderLookup holder_lookup = |
| 7960 CallOptimization::kHolderNotFound; |
| 7961 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( |
| 7962 receiver_map, &holder_lookup); |
| 7963 if (holder_lookup == CallOptimization::kHolderNotFound) return false; |
| 7964 |
| 7965 if (FLAG_trace_inlining) { |
| 7966 PrintF("Inlining api function "); |
| 7967 expr->target()->ShortPrint(); |
| 7968 PrintF("\n"); |
| 7969 } |
| 7970 |
| 7971 const int argc = expr->arguments()->length(); |
| 7972 // Includes receiver. |
| 7973 PushArgumentsFromEnvironment(argc + 1); |
| 7974 |
| 7975 // Need to ensure the chain between receiver and api_holder is intact |
| 7976 AddCheckMap(receiver, receiver_map); |
| 7977 if (holder_lookup == CallOptimization::kHolderFound) { |
| 7978 AddCheckPrototypeMaps(api_holder, receiver_map); |
| 7979 } else { |
| 7980 ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); |
| 7981 } |
| 7982 |
| 7983 HValue* holder = NULL; |
| 7984 switch (holder_lookup) { |
| 7985 case CallOptimization::kHolderFound: |
| 7986 holder = Add<HConstant>(api_holder); |
| 7987 break; |
| 7988 case CallOptimization::kHolderIsReceiver: |
| 7989 holder = receiver; |
| 7990 break; |
| 7991 case CallOptimization::kHolderNotFound: |
| 7992 UNREACHABLE(); |
| 7993 break; |
| 7994 } |
| 7995 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
| 7996 Handle<Object> call_data_obj(api_call_info->data(), isolate()); |
| 7997 bool call_data_is_undefined = call_data_obj->IsUndefined(); |
| 7998 HValue* call_data = Add<HConstant>(call_data_obj); |
| 7999 ApiFunction fun(v8::ToCData<Address>(api_call_info->callback())); |
| 8000 ExternalReference ref = ExternalReference(&fun, |
| 8001 ExternalReference::DIRECT_API_CALL, |
| 8002 isolate()); |
| 8003 HValue* api_function_address = Add<HConstant>(ExternalReference(ref)); |
| 8004 |
| 8005 HValue* op_vals[] = { |
| 8006 // callee |
| 8007 Add<HConstant>(expr->target()), |
| 8008 call_data, |
| 8009 holder, |
| 8010 api_function_address, |
| 8011 context() |
| 8012 }; |
| 8013 |
| 8014 CallInterfaceDescriptor* descriptor = |
| 8015 isolate()->call_descriptor(Isolate::ApiFunctionCall); |
| 8016 |
| 8017 CallApiFunctionStub stub(true, call_data_is_undefined, argc); |
| 8018 Handle<Code> code = stub.GetCode(isolate()); |
| 8019 HConstant* code_value = Add<HConstant>(code); |
| 8020 |
| 8021 ASSERT((sizeof(op_vals) / kPointerSize) == |
| 8022 descriptor->environment_length()); |
| 8023 |
| 8024 HInstruction* call = New<HCallWithDescriptor>( |
| 8025 code_value, argc + 1, descriptor, |
| 8026 Vector<HValue*>(op_vals, descriptor->environment_length())); |
| 8027 |
| 8028 Drop(1); // Drop function. |
| 8029 ast_context()->ReturnInstruction(call, expr->id()); |
| 8030 return true; |
| 8031 } |
| 8032 |
| 8033 |
7871 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { | 8034 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
7872 Expression* callee = expr->expression(); | 8035 ASSERT(expr->expression()->IsProperty()); |
7873 Property* prop = callee->AsProperty(); | |
7874 ASSERT(prop != NULL); | |
7875 | 8036 |
7876 if (!expr->IsMonomorphic() || expr->check_type() != RECEIVER_MAP_CHECK) { | 8037 if (!expr->IsMonomorphic()) { |
7877 return false; | 8038 return false; |
7878 } | 8039 } |
7879 Handle<Map> function_map = expr->GetReceiverTypes()->first(); | 8040 Handle<Map> function_map = expr->GetReceiverTypes()->first(); |
7880 if (function_map->instance_type() != JS_FUNCTION_TYPE || | 8041 if (function_map->instance_type() != JS_FUNCTION_TYPE || |
7881 !expr->target()->shared()->HasBuiltinFunctionId() || | 8042 !expr->target()->shared()->HasBuiltinFunctionId() || |
7882 expr->target()->shared()->builtin_function_id() != kFunctionApply) { | 8043 expr->target()->shared()->builtin_function_id() != kFunctionApply) { |
7883 return false; | 8044 return false; |
7884 } | 8045 } |
7885 | 8046 |
7886 if (current_info()->scope()->arguments() == NULL) return false; | 8047 if (current_info()->scope()->arguments() == NULL) return false; |
7887 | 8048 |
7888 ZoneList<Expression*>* args = expr->arguments(); | 8049 ZoneList<Expression*>* args = expr->arguments(); |
7889 if (args->length() != 2) return false; | 8050 if (args->length() != 2) return false; |
7890 | 8051 |
7891 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); | 8052 VariableProxy* arg_two = args->at(1)->AsVariableProxy(); |
7892 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; | 8053 if (arg_two == NULL || !arg_two->var()->IsStackAllocated()) return false; |
7893 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); | 8054 HValue* arg_two_value = LookupAndMakeLive(arg_two->var()); |
7894 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; | 8055 if (!arg_two_value->CheckFlag(HValue::kIsArguments)) return false; |
7895 | 8056 |
7896 // Found pattern f.apply(receiver, arguments). | 8057 // Found pattern f.apply(receiver, arguments). |
7897 CHECK_ALIVE_OR_RETURN(VisitForValue(prop->obj()), true); | |
7898 HValue* function = Top(); | |
7899 | |
7900 AddCheckConstantFunction(expr->holder(), function, function_map); | |
7901 | |
7902 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); | 8058 CHECK_ALIVE_OR_RETURN(VisitForValue(args->at(0)), true); |
7903 HValue* receiver = Pop(); | 8059 HValue* receiver = Pop(); // receiver |
7904 | 8060 HValue* function = Pop(); // f |
7905 Drop(1); // Pop the function. | 8061 Drop(1); // apply |
7906 | 8062 |
7907 if (function_state()->outer() == NULL) { | 8063 if (function_state()->outer() == NULL) { |
7908 HInstruction* elements = Add<HArgumentsElements>(false); | 8064 HInstruction* elements = Add<HArgumentsElements>(false); |
7909 HInstruction* length = Add<HArgumentsLength>(elements); | 8065 HInstruction* length = Add<HArgumentsLength>(elements); |
7910 HValue* wrapped_receiver = BuildWrapReceiver(receiver, function); | 8066 HValue* wrapped_receiver = BuildWrapReceiver(receiver, function); |
7911 HInstruction* result = New<HApplyArguments>(function, | 8067 HInstruction* result = New<HApplyArguments>(function, |
7912 wrapped_receiver, | 8068 wrapped_receiver, |
7913 length, | 8069 length, |
7914 elements); | 8070 elements); |
7915 ast_context()->ReturnInstruction(result, expr->id()); | 8071 ast_context()->ReturnInstruction(result, expr->id()); |
7916 return true; | 8072 return true; |
7917 } else { | 8073 } else { |
7918 // We are inside inlined function and we know exactly what is inside | 8074 // We are inside inlined function and we know exactly what is inside |
7919 // arguments object. But we need to be able to materialize at deopt. | 8075 // arguments object. But we need to be able to materialize at deopt. |
7920 ASSERT_EQ(environment()->arguments_environment()->parameter_count(), | 8076 ASSERT_EQ(environment()->arguments_environment()->parameter_count(), |
7921 function_state()->entry()->arguments_object()->arguments_count()); | 8077 function_state()->entry()->arguments_object()->arguments_count()); |
7922 HArgumentsObject* args = function_state()->entry()->arguments_object(); | 8078 HArgumentsObject* args = function_state()->entry()->arguments_object(); |
7923 const ZoneList<HValue*>* arguments_values = args->arguments_values(); | 8079 const ZoneList<HValue*>* arguments_values = args->arguments_values(); |
7924 int arguments_count = arguments_values->length(); | 8080 int arguments_count = arguments_values->length(); |
| 8081 Push(function); |
7925 Push(BuildWrapReceiver(receiver, function)); | 8082 Push(BuildWrapReceiver(receiver, function)); |
7926 for (int i = 1; i < arguments_count; i++) { | 8083 for (int i = 1; i < arguments_count; i++) { |
7927 Push(arguments_values->at(i)); | 8084 Push(arguments_values->at(i)); |
7928 } | 8085 } |
7929 | 8086 |
7930 Handle<JSFunction> known_function; | 8087 Handle<JSFunction> known_function; |
7931 if (function->IsConstant() && | 8088 if (function->IsConstant() && |
7932 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { | 8089 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
7933 known_function = Handle<JSFunction>::cast( | 8090 known_function = Handle<JSFunction>::cast( |
7934 HConstant::cast(function)->handle(isolate())); | 8091 HConstant::cast(function)->handle(isolate())); |
7935 int args_count = arguments_count - 1; // Excluding receiver. | 8092 int args_count = arguments_count - 1; // Excluding receiver. |
7936 if (TryInlineApply(known_function, expr, args_count)) return true; | 8093 if (TryInlineApply(known_function, expr, args_count)) return true; |
7937 } | 8094 } |
7938 | 8095 |
7939 Drop(arguments_count - 1); | 8096 PushArgumentsFromEnvironment(arguments_count); |
7940 Push(Add<HPushArgument>(Pop())); | 8097 HInvokeFunction* call = New<HInvokeFunction>( |
7941 for (int i = 1; i < arguments_count; i++) { | 8098 function, known_function, arguments_count); |
7942 Push(Add<HPushArgument>(arguments_values->at(i))); | 8099 Drop(1); // Function. |
7943 } | |
7944 | |
7945 HInvokeFunction* call = New<HInvokeFunction>(function, | |
7946 known_function, | |
7947 arguments_count); | |
7948 Drop(arguments_count); | |
7949 ast_context()->ReturnInstruction(call, expr->id()); | 8100 ast_context()->ReturnInstruction(call, expr->id()); |
7950 return true; | 8101 return true; |
7951 } | 8102 } |
7952 } | 8103 } |
7953 | 8104 |
7954 | 8105 |
7955 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, | 8106 HValue* HOptimizedGraphBuilder::ImplicitReceiverFor(HValue* function, |
7956 Handle<JSFunction> target) { | 8107 Handle<JSFunction> target) { |
7957 SharedFunctionInfo* shared = target->shared(); | 8108 SharedFunctionInfo* shared = target->shared(); |
7958 if (shared->is_classic_mode() && !shared->native()) { | 8109 if (shared->is_classic_mode() && !shared->native()) { |
7959 HValue* context = Add<HLoadNamedField>( | 8110 // Cannot embed a direct reference to the global proxy |
7960 function, static_cast<HValue*>(NULL), | 8111 // as is it dropped on deserialization. |
7961 HObjectAccess::ForJSObjectOffset(JSFunction::kContextOffset)); | 8112 CHECK(!Serializer::enabled()); |
7962 HValue* global_object = Add<HLoadNamedField>( | 8113 Handle<JSObject> global_receiver( |
7963 context, static_cast<HValue*>(NULL), | 8114 target->context()->global_object()->global_receiver()); |
7964 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | 8115 return Add<HConstant>(global_receiver); |
7965 return Add<HLoadNamedField>( | |
7966 global_object, static_cast<HValue*>(NULL), | |
7967 HObjectAccess::ForJSObjectOffset( | |
7968 GlobalObject::kGlobalReceiverOffset)); | |
7969 } | 8116 } |
7970 return graph()->GetConstantUndefined(); | 8117 return graph()->GetConstantUndefined(); |
7971 } | 8118 } |
7972 | 8119 |
7973 | 8120 |
7974 void HOptimizedGraphBuilder::VisitCall(Call* expr) { | 8121 void HOptimizedGraphBuilder::VisitCall(Call* expr) { |
7975 ASSERT(!HasStackOverflow()); | 8122 ASSERT(!HasStackOverflow()); |
7976 ASSERT(current_block() != NULL); | 8123 ASSERT(current_block() != NULL); |
7977 ASSERT(current_block()->HasPredecessor()); | 8124 ASSERT(current_block()->HasPredecessor()); |
7978 Expression* callee = expr->expression(); | 8125 Expression* callee = expr->expression(); |
7979 int argument_count = expr->arguments()->length() + 1; // Plus receiver. | 8126 int argument_count = expr->arguments()->length() + 1; // Plus receiver. |
7980 HInstruction* call = NULL; | 8127 HInstruction* call = NULL; |
7981 | 8128 |
7982 Property* prop = callee->AsProperty(); | 8129 Property* prop = callee->AsProperty(); |
7983 if (prop != NULL) { | 8130 if (prop != NULL) { |
7984 if (!prop->key()->IsPropertyName()) { | 8131 CHECK_ALIVE(VisitForValue(prop->obj())); |
7985 // Keyed function call. | 8132 HValue* receiver = Top(); |
7986 CHECK_ALIVE(VisitForValue(prop->obj())); | |
7987 CHECK_ALIVE(VisitForValue(prop->key())); | |
7988 | 8133 |
7989 // Push receiver and key like the non-optimized code generator expects it. | 8134 SmallMapList* types; |
7990 HValue* key = Pop(); | 8135 ComputeReceiverTypes(expr, receiver, &types); |
7991 HValue* receiver = Pop(); | |
7992 Push(key); | |
7993 Push(Add<HPushArgument>(receiver)); | |
7994 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | |
7995 | 8136 |
7996 if (expr->IsMonomorphic()) { | 8137 if (prop->key()->IsPropertyName() && types->length() > 0) { |
7997 BuildCheckHeapObject(receiver); | 8138 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); |
7998 ElementsKind kind = expr->KeyedArrayCallIsHoley() | 8139 PropertyAccessInfo info(this, IC::MapToType(types->first()), name); |
7999 ? FAST_HOLEY_ELEMENTS : FAST_ELEMENTS; | 8140 if (!info.CanLoadAsMonomorphic(types)) { |
8000 | 8141 HandlePolymorphicCallNamed(expr, receiver, types, name); |
8001 Handle<Map> map(isolate()->get_initial_js_array_map(kind)); | 8142 return; |
8002 | |
8003 HValue* function = BuildMonomorphicElementAccess( | |
8004 receiver, key, NULL, NULL, map, false, STANDARD_STORE); | |
8005 | |
8006 call = New<HCallFunction>(function, argument_count); | |
8007 } else { | |
8008 call = NewCallKeyed(key, argument_count); | |
8009 } | 8143 } |
8010 Drop(argument_count + 1); // 1 is the key. | |
8011 return ast_context()->ReturnInstruction(call, expr->id()); | |
8012 } | 8144 } |
8013 | 8145 |
8014 // Named function call. | 8146 HValue* key = NULL; |
8015 if (TryCallApply(expr)) return; | 8147 if (!prop->key()->IsPropertyName()) { |
8016 | 8148 CHECK_ALIVE(VisitForValue(prop->key())); |
8017 CHECK_ALIVE(VisitForValue(prop->obj())); | 8149 key = Pop(); |
8018 CHECK_ALIVE(VisitExpressions(expr->arguments())); | |
8019 | |
8020 Handle<String> name = prop->key()->AsLiteral()->AsPropertyName(); | |
8021 HValue* receiver = | |
8022 environment()->ExpressionStackAt(expr->arguments()->length()); | |
8023 | |
8024 SmallMapList* types; | |
8025 bool was_monomorphic = expr->IsMonomorphic(); | |
8026 bool monomorphic = ComputeReceiverTypes(expr, receiver, &types); | |
8027 if (!was_monomorphic && monomorphic) { | |
8028 monomorphic = expr->ComputeTarget(types->first(), name); | |
8029 } | 8150 } |
8030 | 8151 |
8031 if (monomorphic) { | 8152 CHECK_ALIVE(PushLoad(prop, receiver, key)); |
8032 Handle<Map> map = types->first(); | 8153 HValue* function = Pop(); |
8033 if (TryInlineBuiltinMethodCall(expr, receiver, map, expr->check_type())) { | 8154 |
| 8155 // Push the function under the receiver. |
| 8156 environment()->SetExpressionStackAt(0, function); |
| 8157 |
| 8158 Push(receiver); |
| 8159 |
| 8160 if (function->IsConstant() && |
| 8161 HConstant::cast(function)->handle(isolate())->IsJSFunction()) { |
| 8162 Handle<JSFunction> known_function = Handle<JSFunction>::cast( |
| 8163 HConstant::cast(function)->handle(isolate())); |
| 8164 expr->set_target(known_function); |
| 8165 |
| 8166 if (TryCallApply(expr)) return; |
| 8167 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
| 8168 |
| 8169 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); |
| 8170 if (TryInlineBuiltinMethodCall(expr, receiver, map)) { |
8034 if (FLAG_trace_inlining) { | 8171 if (FLAG_trace_inlining) { |
8035 PrintF("Inlining builtin "); | 8172 PrintF("Inlining builtin "); |
8036 expr->target()->ShortPrint(); | 8173 known_function->ShortPrint(); |
8037 PrintF("\n"); | 8174 PrintF("\n"); |
8038 } | 8175 } |
8039 return; | 8176 return; |
8040 } | 8177 } |
| 8178 if (TryInlineApiMethodCall(expr, receiver, map)) return; |
8041 | 8179 |
8042 if (CallStubCompiler::HasCustomCallGenerator(expr->target()) || | 8180 // Wrap the receiver if necessary. |
8043 expr->check_type() != RECEIVER_MAP_CHECK) { | 8181 if (NeedsWrappingFor(IC::MapToType(types->first()), known_function)) { |
8044 // When the target has a custom call IC generator, use the IC, | 8182 // Since HWrapReceiver currently cannot actually wrap numbers and |
8045 // because it is likely to generate better code. Also use the IC | 8183 // strings, use the regular CallFunctionStub for method calls to wrap |
8046 // when a primitive receiver check is required. | 8184 // the receiver. |
8047 call = NewCallNamed(name, argument_count); | 8185 // TODO(verwaest): Support creation of value wrappers directly in |
8048 PushArgumentsFromEnvironment(argument_count); | 8186 // HWrapReceiver. |
| 8187 call = New<HCallFunction>( |
| 8188 function, argument_count, WRAP_AND_CALL); |
| 8189 } else if (TryInlineCall(expr)) { |
| 8190 return; |
8049 } else { | 8191 } else { |
8050 AddCheckConstantFunction(expr->holder(), receiver, map); | 8192 call = BuildCallConstantFunction(known_function, argument_count); |
8051 | |
8052 if (TryInlineCall(expr)) return; | |
8053 call = BuildCallConstantFunction(expr->target(), argument_count); | |
8054 PushArgumentsFromEnvironment(argument_count); | |
8055 } | 8193 } |
8056 } else if (types != NULL && types->length() > 1) { | |
8057 ASSERT(expr->check_type() == RECEIVER_MAP_CHECK); | |
8058 HandlePolymorphicCallNamed(expr, receiver, types, name); | |
8059 return; | |
8060 | 8194 |
8061 } else { | 8195 } else { |
8062 call = NewCallNamed(name, argument_count); | 8196 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
8063 PushArgumentsFromEnvironment(argument_count); | 8197 CallFunctionFlags flags = receiver->type().IsJSObject() |
| 8198 ? NO_CALL_FUNCTION_FLAGS : CALL_AS_METHOD; |
| 8199 call = New<HCallFunction>(function, argument_count, flags); |
8064 } | 8200 } |
| 8201 PushArgumentsFromEnvironment(argument_count); |
| 8202 |
8065 } else { | 8203 } else { |
8066 VariableProxy* proxy = expr->expression()->AsVariableProxy(); | 8204 VariableProxy* proxy = expr->expression()->AsVariableProxy(); |
8067 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { | 8205 if (proxy != NULL && proxy->var()->is_possibly_eval(isolate())) { |
8068 return Bailout(kPossibleDirectCallToEval); | 8206 return Bailout(kPossibleDirectCallToEval); |
8069 } | 8207 } |
8070 | 8208 |
8071 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); | 8209 bool global_call = proxy != NULL && proxy->var()->IsUnallocated(); |
8072 if (global_call) { | 8210 if (global_call) { |
8073 Variable* var = proxy->var(); | 8211 Variable* var = proxy->var(); |
8074 bool known_global_function = false; | 8212 bool known_global_function = false; |
8075 // If there is a global property cell for the name at compile time and | 8213 // If there is a global property cell for the name at compile time and |
8076 // access check is not enabled we assume that the function will not change | 8214 // access check is not enabled we assume that the function will not change |
8077 // and generate optimized code for calling the function. | 8215 // and generate optimized code for calling the function. |
8078 LookupResult lookup(isolate()); | 8216 LookupResult lookup(isolate()); |
8079 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); | 8217 GlobalPropertyAccess type = LookupGlobalProperty(var, &lookup, false); |
8080 if (type == kUseCell && | 8218 if (type == kUseCell && |
8081 !current_info()->global_object()->IsAccessCheckNeeded()) { | 8219 !current_info()->global_object()->IsAccessCheckNeeded()) { |
8082 Handle<GlobalObject> global(current_info()->global_object()); | 8220 Handle<GlobalObject> global(current_info()->global_object()); |
8083 known_global_function = expr->ComputeGlobalTarget(global, &lookup); | 8221 known_global_function = expr->ComputeGlobalTarget(global, &lookup); |
8084 } | 8222 } |
| 8223 CHECK_ALIVE(VisitForValue(expr->expression())); |
| 8224 HValue* function = Top(); |
8085 if (known_global_function) { | 8225 if (known_global_function) { |
8086 // Push the global object instead of the global receiver because | 8226 Add<HCheckValue>(function, expr->target()); |
8087 // code generated by the full code generator expects it. | |
8088 HValue* global_object = Add<HLoadNamedField>( | |
8089 context(), static_cast<HValue*>(NULL), | |
8090 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | |
8091 Push(global_object); | |
8092 | 8227 |
| 8228 // Placeholder for the receiver. |
| 8229 Push(graph()->GetConstantUndefined()); |
8093 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8230 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
8094 | 8231 |
8095 CHECK_ALIVE(VisitForValue(expr->expression())); | |
8096 HValue* function = Pop(); | |
8097 Add<HCheckValue>(function, expr->target()); | |
8098 | |
8099 // Patch the global object on the stack by the expected receiver. | 8232 // Patch the global object on the stack by the expected receiver. |
8100 HValue* receiver = ImplicitReceiverFor(function, expr->target()); | 8233 HValue* receiver = ImplicitReceiverFor(function, expr->target()); |
8101 const int receiver_index = argument_count - 1; | 8234 const int receiver_index = argument_count - 1; |
8102 environment()->SetExpressionStackAt(receiver_index, receiver); | 8235 environment()->SetExpressionStackAt(receiver_index, receiver); |
8103 | 8236 |
8104 if (TryInlineBuiltinFunctionCall(expr, false)) { // Nothing to drop. | 8237 if (TryInlineBuiltinFunctionCall(expr)) { |
8105 if (FLAG_trace_inlining) { | 8238 if (FLAG_trace_inlining) { |
8106 PrintF("Inlining builtin "); | 8239 PrintF("Inlining builtin "); |
8107 expr->target()->ShortPrint(); | 8240 expr->target()->ShortPrint(); |
8108 PrintF("\n"); | 8241 PrintF("\n"); |
8109 } | 8242 } |
8110 return; | 8243 return; |
8111 } | 8244 } |
| 8245 if (TryInlineApiFunctionCall(expr, receiver)) return; |
8112 if (TryInlineCall(expr)) return; | 8246 if (TryInlineCall(expr)) return; |
8113 | 8247 |
8114 if (expr->target().is_identical_to(current_info()->closure())) { | 8248 PushArgumentsFromEnvironment(argument_count); |
8115 graph()->MarkRecursive(); | 8249 call = BuildCallConstantFunction(expr->target(), argument_count); |
8116 } | |
8117 | |
8118 if (CallStubCompiler::HasCustomCallGenerator(expr->target())) { | |
8119 // We're about to install a contextual IC, which expects the global | |
8120 // object as receiver rather than the global proxy. | |
8121 HValue* global_object = Add<HLoadNamedField>( | |
8122 context(), static_cast<HValue*>(NULL), | |
8123 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | |
8124 const int receiver_index = argument_count - 1; | |
8125 environment()->SetExpressionStackAt(receiver_index, global_object); | |
8126 // When the target has a custom call IC generator, use the IC, | |
8127 // because it is likely to generate better code. | |
8128 call = NewCallNamed(var->name(), argument_count); | |
8129 PushArgumentsFromEnvironment(argument_count); | |
8130 } else { | |
8131 call = BuildCallConstantFunction(expr->target(), argument_count); | |
8132 PushArgumentsFromEnvironment(argument_count); | |
8133 } | |
8134 } else { | 8250 } else { |
8135 HValue* receiver = Add<HLoadNamedField>( | 8251 Push(Add<HPushArgument>(graph()->GetConstantUndefined())); |
8136 context(), static_cast<HValue*>(NULL), | |
8137 HObjectAccess::ForContextSlot(Context::GLOBAL_OBJECT_INDEX)); | |
8138 Push(Add<HPushArgument>(receiver)); | |
8139 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 8252 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
8140 | 8253 call = New<HCallFunction>(function, argument_count); |
8141 call = NewCallNamed(var->name(), argument_count); | |
8142 Drop(argument_count); | 8254 Drop(argument_count); |
8143 } | 8255 } |
8144 | 8256 |
8145 } else if (expr->IsMonomorphic()) { | 8257 } else if (expr->IsMonomorphic()) { |
8146 // The function is on the stack in the unoptimized code during | 8258 // The function is on the stack in the unoptimized code during |
8147 // evaluation of the arguments. | 8259 // evaluation of the arguments. |
8148 CHECK_ALIVE(VisitForValue(expr->expression())); | 8260 CHECK_ALIVE(VisitForValue(expr->expression())); |
8149 HValue* function = Top(); | 8261 HValue* function = Top(); |
8150 | 8262 |
8151 Add<HCheckValue>(function, expr->target()); | 8263 Add<HCheckValue>(function, expr->target()); |
8152 | 8264 |
8153 HValue* receiver = ImplicitReceiverFor(function, expr->target()); | 8265 Push(graph()->GetConstantUndefined()); |
8154 Push(receiver); | |
8155 | |
8156 CHECK_ALIVE(VisitExpressions(expr->arguments())); | 8266 CHECK_ALIVE(VisitExpressions(expr->arguments())); |
8157 | 8267 |
8158 if (TryInlineBuiltinFunctionCall(expr, true)) { // Drop the function. | 8268 HValue* receiver = ImplicitReceiverFor(function, expr->target()); |
| 8269 const int receiver_index = argument_count - 1; |
| 8270 environment()->SetExpressionStackAt(receiver_index, receiver); |
| 8271 |
| 8272 if (TryInlineBuiltinFunctionCall(expr)) { |
8159 if (FLAG_trace_inlining) { | 8273 if (FLAG_trace_inlining) { |
8160 PrintF("Inlining builtin "); | 8274 PrintF("Inlining builtin "); |
8161 expr->target()->ShortPrint(); | 8275 expr->target()->ShortPrint(); |
8162 PrintF("\n"); | 8276 PrintF("\n"); |
8163 } | 8277 } |
8164 return; | 8278 return; |
8165 } | 8279 } |
| 8280 if (TryInlineApiFunctionCall(expr, receiver)) return; |
8166 | 8281 |
8167 if (TryInlineCall(expr, true)) { // Drop function from environment. | 8282 if (TryInlineCall(expr)) return; |
8168 return; | 8283 |
8169 } else { | 8284 call = PreProcessCall(New<HInvokeFunction>( |
8170 call = PreProcessCall(New<HInvokeFunction>(function, expr->target(), | 8285 function, expr->target(), argument_count)); |
8171 argument_count)); | |
8172 Drop(1); // The function. | |
8173 } | |
8174 | 8286 |
8175 } else { | 8287 } else { |
8176 CHECK_ALIVE(VisitForValue(expr->expression())); | 8288 CHECK_ALIVE(VisitForValue(expr->expression())); |
8177 HValue* function = Top(); | 8289 HValue* function = Top(); |
8178 HValue* receiver = graph()->GetConstantUndefined(); | 8290 HValue* receiver = graph()->GetConstantUndefined(); |
8179 Push(Add<HPushArgument>(receiver)); | 8291 Push(Add<HPushArgument>(receiver)); |
8180 CHECK_ALIVE(VisitArgumentList(expr->arguments())); | 8292 CHECK_ALIVE(VisitArgumentList(expr->arguments())); |
8181 call = New<HCallFunction>( | 8293 call = New<HCallFunction>(function, argument_count); |
8182 function, argument_count, NORMAL_CONTEXTUAL_CALL); | 8294 Drop(argument_count); |
8183 Drop(argument_count + 1); | |
8184 } | 8295 } |
8185 } | 8296 } |
8186 | 8297 |
| 8298 Drop(1); // Drop the function. |
8187 return ast_context()->ReturnInstruction(call, expr->id()); | 8299 return ast_context()->ReturnInstruction(call, expr->id()); |
8188 } | 8300 } |
8189 | 8301 |
8190 | 8302 |
8191 void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { | 8303 void HOptimizedGraphBuilder::BuildInlinedCallNewArray(CallNew* expr) { |
8192 NoObservableSideEffectsScope no_effects(this); | 8304 NoObservableSideEffectsScope no_effects(this); |
8193 | 8305 |
8194 int argument_count = expr->arguments()->length(); | 8306 int argument_count = expr->arguments()->length(); |
8195 // We should at least have the constructor on the expression stack. | 8307 // We should at least have the constructor on the expression stack. |
8196 HValue* constructor = environment()->ExpressionStackAt(argument_count); | 8308 HValue* constructor = environment()->ExpressionStackAt(argument_count); |
(...skipping 2128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10325 void HOptimizedGraphBuilder::GenerateClassOf(CallRuntime* call) { | 10437 void HOptimizedGraphBuilder::GenerateClassOf(CallRuntime* call) { |
10326 // The special form detected by IsClassOfTest is detected before we get here | 10438 // The special form detected by IsClassOfTest is detected before we get here |
10327 // and does not cause a bailout. | 10439 // and does not cause a bailout. |
10328 return Bailout(kInlinedRuntimeFunctionClassOf); | 10440 return Bailout(kInlinedRuntimeFunctionClassOf); |
10329 } | 10441 } |
10330 | 10442 |
10331 | 10443 |
10332 void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) { | 10444 void HOptimizedGraphBuilder::GenerateValueOf(CallRuntime* call) { |
10333 ASSERT(call->arguments()->length() == 1); | 10445 ASSERT(call->arguments()->length() == 1); |
10334 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10446 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
10335 HValue* value = Pop(); | 10447 HValue* object = Pop(); |
10336 HValueOf* result = New<HValueOf>(value); | 10448 |
10337 return ast_context()->ReturnInstruction(result, call->id()); | 10449 IfBuilder if_objectisvalue(this); |
| 10450 HValue* objectisvalue = if_objectisvalue.If<HHasInstanceTypeAndBranch>( |
| 10451 object, JS_VALUE_TYPE); |
| 10452 if_objectisvalue.Then(); |
| 10453 { |
| 10454 // Return the actual value. |
| 10455 Push(Add<HLoadNamedField>( |
| 10456 object, objectisvalue, |
| 10457 HObjectAccess::ForJSObjectOffset(JSValue::kValueOffset))); |
| 10458 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10459 } |
| 10460 if_objectisvalue.Else(); |
| 10461 { |
| 10462 // If the object is not a value return the object. |
| 10463 Push(object); |
| 10464 Add<HSimulate>(call->id(), FIXED_SIMULATE); |
| 10465 } |
| 10466 if_objectisvalue.End(); |
| 10467 return ast_context()->ReturnValue(Pop()); |
10338 } | 10468 } |
10339 | 10469 |
10340 | 10470 |
10341 void HOptimizedGraphBuilder::GenerateDateField(CallRuntime* call) { | 10471 void HOptimizedGraphBuilder::GenerateDateField(CallRuntime* call) { |
10342 ASSERT(call->arguments()->length() == 2); | 10472 ASSERT(call->arguments()->length() == 2); |
10343 ASSERT_NE(NULL, call->arguments()->at(1)->AsLiteral()); | 10473 ASSERT_NE(NULL, call->arguments()->at(1)->AsLiteral()); |
10344 Smi* index = Smi::cast(*(call->arguments()->at(1)->AsLiteral()->value())); | 10474 Smi* index = Smi::cast(*(call->arguments()->at(1)->AsLiteral()->value())); |
10345 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10475 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
10346 HValue* date = Pop(); | 10476 HValue* date = Pop(); |
10347 HDateField* result = New<HDateField>(date, index); | 10477 HDateField* result = New<HDateField>(date, index); |
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
10600 | 10730 |
10601 void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) { | 10731 void HOptimizedGraphBuilder::GenerateMathSqrt(CallRuntime* call) { |
10602 ASSERT(call->arguments()->length() == 1); | 10732 ASSERT(call->arguments()->length() == 1); |
10603 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10733 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
10604 HValue* value = Pop(); | 10734 HValue* value = Pop(); |
10605 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt); | 10735 HInstruction* result = NewUncasted<HUnaryMathOperation>(value, kMathSqrt); |
10606 return ast_context()->ReturnInstruction(result, call->id()); | 10736 return ast_context()->ReturnInstruction(result, call->id()); |
10607 } | 10737 } |
10608 | 10738 |
10609 | 10739 |
10610 // Check whether two RegExps are equivalent | |
10611 void HOptimizedGraphBuilder::GenerateIsRegExpEquivalent(CallRuntime* call) { | |
10612 return Bailout(kInlinedRuntimeFunctionIsRegExpEquivalent); | |
10613 } | |
10614 | |
10615 | |
10616 void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { | 10740 void HOptimizedGraphBuilder::GenerateGetCachedArrayIndex(CallRuntime* call) { |
10617 ASSERT(call->arguments()->length() == 1); | 10741 ASSERT(call->arguments()->length() == 1); |
10618 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); | 10742 CHECK_ALIVE(VisitForValue(call->arguments()->at(0))); |
10619 HValue* value = Pop(); | 10743 HValue* value = Pop(); |
10620 HGetCachedArrayIndex* result = New<HGetCachedArrayIndex>(value); | 10744 HGetCachedArrayIndex* result = New<HGetCachedArrayIndex>(value); |
10621 return ast_context()->ReturnInstruction(result, call->id()); | 10745 return ast_context()->ReturnInstruction(result, call->id()); |
10622 } | 10746 } |
10623 | 10747 |
10624 | 10748 |
10625 void HOptimizedGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { | 10749 void HOptimizedGraphBuilder::GenerateFastAsciiArrayJoin(CallRuntime* call) { |
(...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11260 if (ShouldProduceTraceOutput()) { | 11384 if (ShouldProduceTraceOutput()) { |
11261 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 11385 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
11262 } | 11386 } |
11263 | 11387 |
11264 #ifdef DEBUG | 11388 #ifdef DEBUG |
11265 graph_->Verify(false); // No full verify. | 11389 graph_->Verify(false); // No full verify. |
11266 #endif | 11390 #endif |
11267 } | 11391 } |
11268 | 11392 |
11269 } } // namespace v8::internal | 11393 } } // namespace v8::internal |
OLD | NEW |