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 5343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5354 if (!lookup_.IsFound()) { | 5354 if (!lookup_.IsFound()) { |
5355 return (!info->lookup_.IsFound() || info->has_holder()) && | 5355 return (!info->lookup_.IsFound() || info->has_holder()) && |
5356 map()->prototype() == info->map()->prototype(); | 5356 map()->prototype() == info->map()->prototype(); |
5357 } | 5357 } |
5358 | 5358 |
5359 // Mismatch if the other access info found the property in the prototype | 5359 // Mismatch if the other access info found the property in the prototype |
5360 // chain. | 5360 // chain. |
5361 if (info->has_holder()) return false; | 5361 if (info->has_holder()) return false; |
5362 | 5362 |
5363 if (lookup_.IsPropertyCallbacks()) { | 5363 if (lookup_.IsPropertyCallbacks()) { |
5364 return accessor_.is_identical_to(info->accessor_); | 5364 return accessor_.is_identical_to(info->accessor_) && |
| 5365 api_holder_.is_identical_to(info->api_holder_); |
5365 } | 5366 } |
5366 | 5367 |
5367 if (lookup_.IsConstant()) { | 5368 if (lookup_.IsConstant()) { |
5368 return constant_.is_identical_to(info->constant_); | 5369 return constant_.is_identical_to(info->constant_); |
5369 } | 5370 } |
5370 | 5371 |
5371 ASSERT(lookup_.IsField()); | 5372 ASSERT(lookup_.IsField()); |
5372 if (!info->lookup_.IsField()) return false; | 5373 if (!info->lookup_.IsField()) return false; |
5373 | 5374 |
5374 Representation r = access_.representation(); | 5375 Representation r = access_.representation(); |
(...skipping 25 matching lines...) Expand all Loading... |
5400 if (lookup_.IsField()) { | 5401 if (lookup_.IsField()) { |
5401 access_ = HObjectAccess::ForField(map, &lookup_, name_); | 5402 access_ = HObjectAccess::ForField(map, &lookup_, name_); |
5402 } else if (lookup_.IsPropertyCallbacks()) { | 5403 } else if (lookup_.IsPropertyCallbacks()) { |
5403 Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate()); | 5404 Handle<Object> callback(lookup_.GetValueFromMap(*map), isolate()); |
5404 if (!callback->IsAccessorPair()) return false; | 5405 if (!callback->IsAccessorPair()) return false; |
5405 Object* raw_accessor = IsLoad() | 5406 Object* raw_accessor = IsLoad() |
5406 ? Handle<AccessorPair>::cast(callback)->getter() | 5407 ? Handle<AccessorPair>::cast(callback)->getter() |
5407 : Handle<AccessorPair>::cast(callback)->setter(); | 5408 : Handle<AccessorPair>::cast(callback)->setter(); |
5408 if (!raw_accessor->IsJSFunction()) return false; | 5409 if (!raw_accessor->IsJSFunction()) return false; |
5409 Handle<JSFunction> accessor = handle(JSFunction::cast(raw_accessor)); | 5410 Handle<JSFunction> accessor = handle(JSFunction::cast(raw_accessor)); |
5410 CallOptimization call_optimization(accessor); | 5411 if (accessor->shared()->IsApiFunction()) { |
5411 // TODO(dcarney): temporary hack unless crankshaft can handle api calls. | 5412 CallOptimization call_optimization(accessor); |
5412 if (call_optimization.is_simple_api_call()) return false; | 5413 if (!call_optimization.is_simple_api_call()) return false; |
| 5414 CallOptimization::HolderLookup holder_lookup; |
| 5415 api_holder_ = call_optimization.LookupHolderOfExpectedType( |
| 5416 map, &holder_lookup); |
| 5417 switch (holder_lookup) { |
| 5418 case CallOptimization::kHolderNotFound: |
| 5419 return false; |
| 5420 case CallOptimization::kHolderIsReceiver: |
| 5421 case CallOptimization::kHolderFound: |
| 5422 break; |
| 5423 } |
| 5424 } |
5413 accessor_ = accessor; | 5425 accessor_ = accessor; |
5414 } else if (lookup_.IsConstant()) { | 5426 } else if (lookup_.IsConstant()) { |
5415 constant_ = handle(lookup_.GetConstantFromMap(*map), isolate()); | 5427 constant_ = handle(lookup_.GetConstantFromMap(*map), isolate()); |
5416 } | 5428 } |
5417 | 5429 |
5418 return true; | 5430 return true; |
5419 } | 5431 } |
5420 | 5432 |
5421 | 5433 |
5422 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { | 5434 bool HOptimizedGraphBuilder::PropertyAccessInfo::LookupInPrototypes() { |
(...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
5565 argument_count = 2; | 5577 argument_count = 2; |
5566 Push(value); | 5578 Push(value); |
5567 } | 5579 } |
5568 | 5580 |
5569 if (NeedsWrappingFor(info->type(), info->accessor())) { | 5581 if (NeedsWrappingFor(info->type(), info->accessor())) { |
5570 HValue* function = Add<HConstant>(info->accessor()); | 5582 HValue* function = Add<HConstant>(info->accessor()); |
5571 PushArgumentsFromEnvironment(argument_count); | 5583 PushArgumentsFromEnvironment(argument_count); |
5572 return New<HCallFunction>(function, argument_count, WRAP_AND_CALL); | 5584 return New<HCallFunction>(function, argument_count, WRAP_AND_CALL); |
5573 } else if (FLAG_inline_accessors && can_inline_accessor) { | 5585 } else if (FLAG_inline_accessors && can_inline_accessor) { |
5574 bool success = info->IsLoad() | 5586 bool success = info->IsLoad() |
5575 ? TryInlineGetter(info->accessor(), ast_id, return_id) | 5587 ? TryInlineGetter(info->accessor(), info->map(), ast_id, return_id) |
5576 : TryInlineSetter(info->accessor(), ast_id, return_id, value); | 5588 : TryInlineSetter(info->accessor(), ast_id, return_id, value); |
5577 if (success) return NULL; | 5589 if (success) return NULL; |
5578 } | 5590 } |
5579 | 5591 |
5580 PushArgumentsFromEnvironment(argument_count); | 5592 PushArgumentsFromEnvironment(argument_count); |
5581 return BuildCallConstantFunction(info->accessor(), argument_count); | 5593 return BuildCallConstantFunction(info->accessor(), argument_count); |
5582 } | 5594 } |
5583 | 5595 |
5584 ASSERT(info->lookup()->IsConstant()); | 5596 ASSERT(info->lookup()->IsConstant()); |
5585 if (info->IsLoad()) { | 5597 if (info->IsLoad()) { |
(...skipping 1801 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7387 return TryInline(expr->target(), | 7399 return TryInline(expr->target(), |
7388 expr->arguments()->length(), | 7400 expr->arguments()->length(), |
7389 implicit_return_value, | 7401 implicit_return_value, |
7390 expr->id(), | 7402 expr->id(), |
7391 expr->ReturnId(), | 7403 expr->ReturnId(), |
7392 CONSTRUCT_CALL_RETURN); | 7404 CONSTRUCT_CALL_RETURN); |
7393 } | 7405 } |
7394 | 7406 |
7395 | 7407 |
7396 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, | 7408 bool HOptimizedGraphBuilder::TryInlineGetter(Handle<JSFunction> getter, |
| 7409 Handle<Map> receiver_map, |
7397 BailoutId ast_id, | 7410 BailoutId ast_id, |
7398 BailoutId return_id) { | 7411 BailoutId return_id) { |
| 7412 if (TryInlineApiGetter(getter, receiver_map, ast_id)) return true; |
7399 return TryInline(getter, | 7413 return TryInline(getter, |
7400 0, | 7414 0, |
7401 NULL, | 7415 NULL, |
7402 ast_id, | 7416 ast_id, |
7403 return_id, | 7417 return_id, |
7404 GETTER_CALL_RETURN); | 7418 GETTER_CALL_RETURN); |
7405 } | 7419 } |
7406 | 7420 |
7407 | 7421 |
7408 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, | 7422 bool HOptimizedGraphBuilder::TryInlineSetter(Handle<JSFunction> setter, |
(...skipping 262 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7671 default: | 7685 default: |
7672 // Not yet supported for inlining. | 7686 // Not yet supported for inlining. |
7673 break; | 7687 break; |
7674 } | 7688 } |
7675 return false; | 7689 return false; |
7676 } | 7690 } |
7677 | 7691 |
7678 | 7692 |
7679 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, | 7693 bool HOptimizedGraphBuilder::TryInlineApiFunctionCall(Call* expr, |
7680 HValue* receiver) { | 7694 HValue* receiver) { |
7681 return TryInlineApiCall( | 7695 Handle<JSFunction> function = expr->target(); |
7682 expr, receiver, Handle<Map>::null(), true); | 7696 int argc = expr->arguments()->length(); |
| 7697 SmallMapList receiver_maps; |
| 7698 return TryInlineApiCall(function, |
| 7699 receiver, |
| 7700 &receiver_maps, |
| 7701 argc, |
| 7702 expr->id(), |
| 7703 kCallApiFunction); |
7683 } | 7704 } |
7684 | 7705 |
7685 | 7706 |
7686 bool HOptimizedGraphBuilder::TryInlineApiMethodCall(Call* expr, | 7707 bool HOptimizedGraphBuilder::TryInlineApiMethodCall( |
7687 HValue* receiver, | 7708 Call* expr, |
7688 Handle<Map> receiver_map) { | 7709 HValue* receiver, |
7689 return TryInlineApiCall(expr, receiver, receiver_map, false); | 7710 SmallMapList* receiver_maps) { |
| 7711 Handle<JSFunction> function = expr->target(); |
| 7712 int argc = expr->arguments()->length(); |
| 7713 return TryInlineApiCall(function, |
| 7714 receiver, |
| 7715 receiver_maps, |
| 7716 argc, |
| 7717 expr->id(), |
| 7718 kCallApiMethod); |
7690 } | 7719 } |
7691 | 7720 |
7692 bool HOptimizedGraphBuilder::TryInlineApiCall(Call* expr, | 7721 |
7693 HValue* receiver, | 7722 bool HOptimizedGraphBuilder::TryInlineApiGetter(Handle<JSFunction> function, |
7694 Handle<Map> receiver_map, | 7723 Handle<Map> receiver_map, |
7695 bool is_function_call) { | 7724 BailoutId ast_id) { |
7696 if (!expr->IsMonomorphic()) return false; | 7725 SmallMapList receiver_maps(1, zone()); |
7697 CallOptimization optimization(expr->target()); | 7726 receiver_maps.Add(receiver_map, zone()); |
| 7727 return TryInlineApiCall(function, |
| 7728 NULL, // Receiver is on expression stack. |
| 7729 &receiver_maps, |
| 7730 0, |
| 7731 ast_id, |
| 7732 kCallApiGetter); |
| 7733 } |
| 7734 |
| 7735 |
| 7736 bool HOptimizedGraphBuilder::TryInlineApiCall(Handle<JSFunction> function, |
| 7737 HValue* receiver, |
| 7738 SmallMapList* receiver_maps, |
| 7739 int argc, |
| 7740 BailoutId ast_id, |
| 7741 ApiCallType call_type) { |
| 7742 CallOptimization optimization(function); |
7698 if (!optimization.is_simple_api_call()) return false; | 7743 if (!optimization.is_simple_api_call()) return false; |
7699 Handle<Map> holder_map; | 7744 Handle<Map> holder_map; |
7700 if (is_function_call) { | 7745 if (call_type == kCallApiFunction) { |
7701 // Cannot embed a direct reference to the global proxy map | 7746 // Cannot embed a direct reference to the global proxy map |
7702 // as it maybe dropped on deserialization. | 7747 // as it maybe dropped on deserialization. |
7703 CHECK(!Serializer::enabled()); | 7748 CHECK(!Serializer::enabled()); |
7704 receiver_map = Handle<Map>( | 7749 ASSERT_EQ(0, receiver_maps->length()); |
7705 expr->target()->context()->global_object()->global_receiver()->map()); | 7750 receiver_maps->Add(handle( |
| 7751 function->context()->global_object()->global_receiver()->map()), |
| 7752 zone()); |
7706 } | 7753 } |
7707 CallOptimization::HolderLookup holder_lookup = | 7754 CallOptimization::HolderLookup holder_lookup = |
7708 CallOptimization::kHolderNotFound; | 7755 CallOptimization::kHolderNotFound; |
7709 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( | 7756 Handle<JSObject> api_holder = optimization.LookupHolderOfExpectedType( |
7710 receiver_map, &holder_lookup); | 7757 receiver_maps->first(), &holder_lookup); |
7711 if (holder_lookup == CallOptimization::kHolderNotFound) return false; | 7758 if (holder_lookup == CallOptimization::kHolderNotFound) return false; |
7712 | 7759 |
7713 if (FLAG_trace_inlining) { | 7760 if (FLAG_trace_inlining) { |
7714 PrintF("Inlining api function "); | 7761 PrintF("Inlining api function "); |
7715 expr->target()->ShortPrint(); | 7762 function->ShortPrint(); |
7716 PrintF("\n"); | 7763 PrintF("\n"); |
7717 } | 7764 } |
7718 | 7765 |
7719 const int argc = expr->arguments()->length(); | 7766 bool drop_extra = false; |
7720 // Includes receiver. | 7767 switch (call_type) { |
7721 PushArgumentsFromEnvironment(argc + 1); | 7768 case kCallApiFunction: |
7722 | 7769 case kCallApiMethod: |
7723 // Need to ensure the chain between receiver and api_holder is intact | 7770 // Need to check that none of the receiver maps could have changed. |
7724 AddCheckMap(receiver, receiver_map); | 7771 Add<HCheckMaps>(receiver, receiver_maps); |
7725 if (holder_lookup == CallOptimization::kHolderFound) { | 7772 // Need to ensure the chain between receiver and api_holder is intact. |
7726 AddCheckPrototypeMaps(api_holder, receiver_map); | 7773 if (holder_lookup == CallOptimization::kHolderFound) { |
7727 } else { | 7774 AddCheckPrototypeMaps(api_holder, receiver_maps->first()); |
7728 ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); | 7775 } else { |
| 7776 ASSERT_EQ(holder_lookup, CallOptimization::kHolderIsReceiver); |
| 7777 } |
| 7778 // Includes receiver. |
| 7779 PushArgumentsFromEnvironment(argc + 1); |
| 7780 // Drop function after call. |
| 7781 drop_extra = true; |
| 7782 break; |
| 7783 case kCallApiGetter: |
| 7784 // Receiver and prototype chain cannot have changed. |
| 7785 ASSERT_EQ(0, argc); |
| 7786 ASSERT_EQ(NULL, receiver); |
| 7787 // Receiver is on expression stack. |
| 7788 receiver = Pop(); |
| 7789 Add<HPushArgument>(receiver); |
| 7790 break; |
7729 } | 7791 } |
7730 | 7792 |
7731 HValue* holder = NULL; | 7793 HValue* holder = NULL; |
7732 switch (holder_lookup) { | 7794 switch (holder_lookup) { |
7733 case CallOptimization::kHolderFound: | 7795 case CallOptimization::kHolderFound: |
7734 holder = Add<HConstant>(api_holder); | 7796 holder = Add<HConstant>(api_holder); |
7735 break; | 7797 break; |
7736 case CallOptimization::kHolderIsReceiver: | 7798 case CallOptimization::kHolderIsReceiver: |
7737 holder = receiver; | 7799 holder = receiver; |
7738 break; | 7800 break; |
7739 case CallOptimization::kHolderNotFound: | 7801 case CallOptimization::kHolderNotFound: |
7740 UNREACHABLE(); | 7802 UNREACHABLE(); |
7741 break; | 7803 break; |
7742 } | 7804 } |
7743 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); | 7805 Handle<CallHandlerInfo> api_call_info = optimization.api_call_info(); |
7744 Handle<Object> call_data_obj(api_call_info->data(), isolate()); | 7806 Handle<Object> call_data_obj(api_call_info->data(), isolate()); |
7745 bool call_data_is_undefined = call_data_obj->IsUndefined(); | 7807 bool call_data_is_undefined = call_data_obj->IsUndefined(); |
7746 HValue* call_data = Add<HConstant>(call_data_obj); | 7808 HValue* call_data = Add<HConstant>(call_data_obj); |
7747 ApiFunction fun(v8::ToCData<Address>(api_call_info->callback())); | 7809 ApiFunction fun(v8::ToCData<Address>(api_call_info->callback())); |
7748 ExternalReference ref = ExternalReference(&fun, | 7810 ExternalReference ref = ExternalReference(&fun, |
7749 ExternalReference::DIRECT_API_CALL, | 7811 ExternalReference::DIRECT_API_CALL, |
7750 isolate()); | 7812 isolate()); |
7751 HValue* api_function_address = Add<HConstant>(ExternalReference(ref)); | 7813 HValue* api_function_address = Add<HConstant>(ExternalReference(ref)); |
7752 | 7814 |
7753 HValue* op_vals[] = { | 7815 HValue* op_vals[] = { |
7754 // callee | 7816 Add<HConstant>(function), |
7755 Add<HConstant>(expr->target()), | |
7756 call_data, | 7817 call_data, |
7757 holder, | 7818 holder, |
7758 api_function_address, | 7819 api_function_address, |
7759 context() | 7820 context() |
7760 }; | 7821 }; |
7761 | 7822 |
7762 CallInterfaceDescriptor* descriptor = | 7823 CallInterfaceDescriptor* descriptor = |
7763 isolate()->call_descriptor(Isolate::ApiFunctionCall); | 7824 isolate()->call_descriptor(Isolate::ApiFunctionCall); |
7764 | 7825 |
7765 CallApiFunctionStub stub(true, call_data_is_undefined, argc); | 7826 CallApiFunctionStub stub(true, call_data_is_undefined, argc); |
7766 Handle<Code> code = stub.GetCode(isolate()); | 7827 Handle<Code> code = stub.GetCode(isolate()); |
7767 HConstant* code_value = Add<HConstant>(code); | 7828 HConstant* code_value = Add<HConstant>(code); |
7768 | 7829 |
7769 ASSERT((sizeof(op_vals) / kPointerSize) == | 7830 ASSERT((sizeof(op_vals) / kPointerSize) == |
7770 descriptor->environment_length()); | 7831 descriptor->environment_length()); |
7771 | 7832 |
7772 HInstruction* call = New<HCallWithDescriptor>( | 7833 HInstruction* call = New<HCallWithDescriptor>( |
7773 code_value, argc + 1, descriptor, | 7834 code_value, argc + 1, descriptor, |
7774 Vector<HValue*>(op_vals, descriptor->environment_length())); | 7835 Vector<HValue*>(op_vals, descriptor->environment_length())); |
7775 | 7836 |
7776 Drop(1); // Drop function. | 7837 if (drop_extra) Drop(1); // Drop function. |
7777 ast_context()->ReturnInstruction(call, expr->id()); | 7838 ast_context()->ReturnInstruction(call, ast_id); |
7778 return true; | 7839 return true; |
7779 } | 7840 } |
7780 | 7841 |
7781 | 7842 |
7782 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { | 7843 bool HOptimizedGraphBuilder::TryCallApply(Call* expr) { |
7783 ASSERT(expr->expression()->IsProperty()); | 7844 ASSERT(expr->expression()->IsProperty()); |
7784 | 7845 |
7785 if (!expr->IsMonomorphic()) { | 7846 if (!expr->IsMonomorphic()) { |
7786 return false; | 7847 return false; |
7787 } | 7848 } |
(...skipping 128 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
7916 | 7977 |
7917 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); | 7978 Handle<Map> map = types->length() == 1 ? types->first() : Handle<Map>(); |
7918 if (TryInlineBuiltinMethodCall(expr, receiver, map)) { | 7979 if (TryInlineBuiltinMethodCall(expr, receiver, map)) { |
7919 if (FLAG_trace_inlining) { | 7980 if (FLAG_trace_inlining) { |
7920 PrintF("Inlining builtin "); | 7981 PrintF("Inlining builtin "); |
7921 known_function->ShortPrint(); | 7982 known_function->ShortPrint(); |
7922 PrintF("\n"); | 7983 PrintF("\n"); |
7923 } | 7984 } |
7924 return; | 7985 return; |
7925 } | 7986 } |
7926 if (TryInlineApiMethodCall(expr, receiver, map)) return; | 7987 if (TryInlineApiMethodCall(expr, receiver, types)) return; |
7927 | 7988 |
7928 // Wrap the receiver if necessary. | 7989 // Wrap the receiver if necessary. |
7929 if (NeedsWrappingFor(ToType(types->first()), known_function)) { | 7990 if (NeedsWrappingFor(ToType(types->first()), known_function)) { |
7930 // Since HWrapReceiver currently cannot actually wrap numbers and | 7991 // Since HWrapReceiver currently cannot actually wrap numbers and |
7931 // strings, use the regular CallFunctionStub for method calls to wrap | 7992 // strings, use the regular CallFunctionStub for method calls to wrap |
7932 // the receiver. | 7993 // the receiver. |
7933 // TODO(verwaest): Support creation of value wrappers directly in | 7994 // TODO(verwaest): Support creation of value wrappers directly in |
7934 // HWrapReceiver. | 7995 // HWrapReceiver. |
7935 call = New<HCallFunction>( | 7996 call = New<HCallFunction>( |
7936 function, argument_count, WRAP_AND_CALL); | 7997 function, argument_count, WRAP_AND_CALL); |
(...skipping 3206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
11143 if (ShouldProduceTraceOutput()) { | 11204 if (ShouldProduceTraceOutput()) { |
11144 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); | 11205 isolate()->GetHTracer()->TraceHydrogen(name(), graph_); |
11145 } | 11206 } |
11146 | 11207 |
11147 #ifdef DEBUG | 11208 #ifdef DEBUG |
11148 graph_->Verify(false); // No full verify. | 11209 graph_->Verify(false); // No full verify. |
11149 #endif | 11210 #endif |
11150 } | 11211 } |
11151 | 11212 |
11152 } } // namespace v8::internal | 11213 } } // namespace v8::internal |
OLD | NEW |