| Index: src/ic.cc
|
| diff --git a/src/ic.cc b/src/ic.cc
|
| index 8a25504564640c17e7a8f5f067889a2b6aececa8..a642230a2885e99653f5190e9f0f555943abe121 100644
|
| --- a/src/ic.cc
|
| +++ b/src/ic.cc
|
| @@ -35,6 +35,7 @@
|
| #include "ic-inl.h"
|
| #include "runtime.h"
|
| #include "stub-cache.h"
|
| +#include "v8conversions.h"
|
|
|
| namespace v8 {
|
| namespace internal {
|
| @@ -440,9 +441,6 @@ static int ComputeTypeInfoCountDelta(IC::State old_state, IC::State new_state) {
|
|
|
|
|
| void IC::PostPatching(Address address, Code* target, Code* old_target) {
|
| - if (FLAG_type_info_threshold == 0 && !FLAG_watch_ic_patching) {
|
| - return;
|
| - }
|
| Isolate* isolate = target->GetHeap()->isolate();
|
| Code* host = isolate->
|
| inner_pointer_to_code_cache()->GetCacheEntry(address)->code;
|
| @@ -465,10 +463,8 @@ void IC::PostPatching(Address address, Code* target, Code* old_target) {
|
| TypeFeedbackInfo::cast(host->type_feedback_info());
|
| info->change_own_type_change_checksum();
|
| }
|
| - if (FLAG_watch_ic_patching) {
|
| - host->set_profiler_ticks(0);
|
| - isolate->runtime_profiler()->NotifyICChanged();
|
| - }
|
| + host->set_profiler_ticks(0);
|
| + isolate->runtime_profiler()->NotifyICChanged();
|
| // TODO(2029): When an optimized function is patched, it would
|
| // be nice to propagate the corresponding type information to its
|
| // unoptimized version for the benefit of later inlining.
|
| @@ -2058,7 +2054,7 @@ RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
|
| if (raw_function->is_compiled()) return raw_function;
|
|
|
| Handle<JSFunction> function(raw_function);
|
| - JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
|
| + Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
|
| return *function;
|
| }
|
|
|
| @@ -2079,7 +2075,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) {
|
| if (raw_function->is_compiled()) return raw_function;
|
|
|
| Handle<JSFunction> function(raw_function, isolate);
|
| - JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
|
| + Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
|
| return *function;
|
| }
|
|
|
| @@ -2159,7 +2155,7 @@ RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_MissFromStubFailure) {
|
| if (raw_function->is_compiled()) return raw_function;
|
|
|
| Handle<JSFunction> function(raw_function, isolate);
|
| - JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
|
| + Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
|
| return *function;
|
| }
|
|
|
| @@ -2601,6 +2597,7 @@ void BinaryOpIC::State::Print(StringStream* stream) const {
|
| stream->Add("(%s", Token::Name(op_));
|
| if (mode_ == OVERWRITE_LEFT) stream->Add("_ReuseLeft");
|
| else if (mode_ == OVERWRITE_RIGHT) stream->Add("_ReuseRight");
|
| + if (CouldCreateAllocationMementos()) stream->Add("_CreateAllocationMementos");
|
| stream->Add(":%s*", KindToString(left_kind_));
|
| if (fixed_right_arg_.has_value) {
|
| stream->Add("%d", fixed_right_arg_.value);
|
| @@ -2640,6 +2637,18 @@ void BinaryOpIC::State::Update(Handle<Object> left,
|
| }
|
| }
|
|
|
| + // We don't want to distinguish INT32 and NUMBER for string add (because
|
| + // NumberToString can't make use of this anyway).
|
| + if (left_kind_ == STRING && right_kind_ == INT32) {
|
| + ASSERT_EQ(STRING, result_kind_);
|
| + ASSERT_EQ(Token::ADD, op_);
|
| + right_kind_ = NUMBER;
|
| + } else if (right_kind_ == STRING && left_kind_ == INT32) {
|
| + ASSERT_EQ(STRING, result_kind_);
|
| + ASSERT_EQ(Token::ADD, op_);
|
| + left_kind_ = NUMBER;
|
| + }
|
| +
|
| // Reset overwrite mode unless we can actually make use of it, or may be able
|
| // to make use of it at some point in the future.
|
| if ((mode_ == OVERWRITE_LEFT && left_kind_ > NUMBER) ||
|
| @@ -2679,7 +2688,7 @@ BinaryOpIC::State::Kind BinaryOpIC::State::UpdateKind(Handle<Object> object,
|
| new_kind = SMI;
|
| } else if (object->IsHeapNumber()) {
|
| double value = Handle<HeapNumber>::cast(object)->value();
|
| - new_kind = TypeInfo::IsInt32Double(value) ? INT32 : NUMBER;
|
| + new_kind = IsInt32Double(value) ? INT32 : NUMBER;
|
| } else if (object->IsString() && op() == Token::ADD) {
|
| new_kind = STRING;
|
| }
|
| @@ -2725,7 +2734,9 @@ Handle<Type> BinaryOpIC::State::KindToType(Kind kind, Isolate* isolate) {
|
| }
|
|
|
|
|
| -MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) {
|
| +MaybeObject* BinaryOpIC::Transition(Handle<AllocationSite> allocation_site,
|
| + Handle<Object> left,
|
| + Handle<Object> right) {
|
| State state(target()->extended_extra_ic_state());
|
|
|
| // Compute the actual result using the builtin for the binary operation.
|
| @@ -2741,9 +2752,29 @@ MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) {
|
| State old_state = state;
|
| state.Update(left, right, result);
|
|
|
| - // Install the new stub.
|
| - BinaryOpICStub stub(state);
|
| - set_target(*stub.GetCode(isolate()));
|
| + // Check if we have a string operation here.
|
| + Handle<Code> target;
|
| + if (!allocation_site.is_null() || state.ShouldCreateAllocationMementos()) {
|
| + // Setup the allocation site on-demand.
|
| + if (allocation_site.is_null()) {
|
| + allocation_site = isolate()->factory()->NewAllocationSite();
|
| + }
|
| +
|
| + // Install the stub with an allocation site.
|
| + BinaryOpICWithAllocationSiteStub stub(state);
|
| + target = stub.GetCodeCopyFromTemplate(isolate(), allocation_site);
|
| +
|
| + // Sanity check the trampoline stub.
|
| + ASSERT_EQ(*allocation_site, target->FindFirstAllocationSite());
|
| + } else {
|
| + // Install the generic stub.
|
| + BinaryOpICStub stub(state);
|
| + target = stub.GetCode(isolate());
|
| +
|
| + // Sanity check the generic stub.
|
| + ASSERT_EQ(NULL, target->FindFirstAllocationSite());
|
| + }
|
| + set_target(*target);
|
|
|
| if (FLAG_trace_ic) {
|
| char buffer[150];
|
| @@ -2754,9 +2785,12 @@ MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) {
|
| old_state.Print(&stream);
|
| stream.Add(" => ");
|
| state.Print(&stream);
|
| - stream.Add(" @ %p <- ", static_cast<void*>(*target()));
|
| + stream.Add(" @ %p <- ", static_cast<void*>(*target));
|
| stream.OutputToStdOut();
|
| JavaScriptFrame::PrintTop(isolate(), stdout, false, true);
|
| + if (!allocation_site.is_null()) {
|
| + PrintF(" using allocation site %p", static_cast<void*>(*allocation_site));
|
| + }
|
| PrintF("]\n");
|
| }
|
|
|
| @@ -2773,10 +2807,25 @@ MaybeObject* BinaryOpIC::Transition(Handle<Object> left, Handle<Object> right) {
|
|
|
| RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_Miss) {
|
| HandleScope scope(isolate);
|
| + ASSERT_EQ(2, args.length());
|
| Handle<Object> left = args.at<Object>(BinaryOpICStub::kLeft);
|
| Handle<Object> right = args.at<Object>(BinaryOpICStub::kRight);
|
| BinaryOpIC ic(isolate);
|
| - return ic.Transition(left, right);
|
| + return ic.Transition(Handle<AllocationSite>::null(), left, right);
|
| +}
|
| +
|
| +
|
| +RUNTIME_FUNCTION(MaybeObject*, BinaryOpIC_MissWithAllocationSite) {
|
| + HandleScope scope(isolate);
|
| + ASSERT_EQ(3, args.length());
|
| + Handle<AllocationSite> allocation_site = args.at<AllocationSite>(
|
| + BinaryOpWithAllocationSiteStub::kAllocationSite);
|
| + Handle<Object> left = args.at<Object>(
|
| + BinaryOpWithAllocationSiteStub::kLeft);
|
| + Handle<Object> right = args.at<Object>(
|
| + BinaryOpWithAllocationSiteStub::kRight);
|
| + BinaryOpIC ic(isolate);
|
| + return ic.Transition(allocation_site, left, right);
|
| }
|
|
|
|
|
|
|