| 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 |