| Index: src/ic.cc
|
| diff --git a/src/ic.cc b/src/ic.cc
|
| index fd86f1e460b661562f48a38cd136bf7d46cc14b3..c79ea2c7cf09e9b194a27b7c18e36f9164588884 100644
|
| --- a/src/ic.cc
|
| +++ b/src/ic.cc
|
| @@ -424,8 +424,6 @@ void IC::Clear(Isolate* isolate, Address address) {
|
| case Code::STORE_IC: return StoreIC::Clear(isolate, address, target);
|
| case Code::KEYED_STORE_IC:
|
| return KeyedStoreIC::Clear(isolate, address, target);
|
| - case Code::CALL_IC: return CallIC::Clear(address, target);
|
| - case Code::KEYED_CALL_IC: return KeyedCallIC::Clear(address, target);
|
| case Code::COMPARE_IC: return CompareIC::Clear(isolate, address, target);
|
| case Code::COMPARE_NIL_IC: return CompareNilIC::Clear(address, target);
|
| case Code::BINARY_OP_IC:
|
| @@ -438,14 +436,6 @@ void IC::Clear(Isolate* isolate, Address address) {
|
| }
|
|
|
|
|
| -void CallICBase::Clear(Address address, Code* target) {
|
| - if (IsCleared(target)) return;
|
| - Code* code = target->GetIsolate()->stub_cache()->FindCallInitialize(
|
| - target->arguments_count(), target->kind());
|
| - SetTargetAtAddress(address, code);
|
| -}
|
| -
|
| -
|
| void KeyedLoadIC::Clear(Isolate* isolate, Address address, Code* target) {
|
| if (IsCleared(target)) return;
|
| // Make sure to also clear the map used in inline fast cases. If we
|
| @@ -492,50 +482,6 @@ void CompareIC::Clear(Isolate* isolate, Address address, Code* target) {
|
| }
|
|
|
|
|
| -Handle<Object> CallICBase::TryCallAsFunction(Handle<Object> object) {
|
| - Handle<Object> delegate = Execution::GetFunctionDelegate(isolate(), object);
|
| -
|
| - if (delegate->IsJSFunction() && !object->IsJSFunctionProxy()) {
|
| - // Patch the receiver and use the delegate as the function to
|
| - // invoke. This is used for invoking objects as if they were functions.
|
| - const int argc = target()->arguments_count();
|
| - StackFrameLocator locator(isolate());
|
| - JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
|
| - int index = frame->ComputeExpressionsCount() - (argc + 1);
|
| - frame->SetExpression(index, *object);
|
| - }
|
| -
|
| - return delegate;
|
| -}
|
| -
|
| -
|
| -void CallICBase::ReceiverToObjectIfRequired(Handle<Object> callee,
|
| - Handle<Object> object) {
|
| - while (callee->IsJSFunctionProxy()) {
|
| - callee = Handle<Object>(JSFunctionProxy::cast(*callee)->call_trap(),
|
| - isolate());
|
| - }
|
| -
|
| - if (callee->IsJSFunction()) {
|
| - Handle<JSFunction> function = Handle<JSFunction>::cast(callee);
|
| - if (!function->shared()->is_classic_mode() || function->IsBuiltin()) {
|
| - // Do not wrap receiver for strict mode functions or for builtins.
|
| - return;
|
| - }
|
| - }
|
| -
|
| - // And only wrap string, number or boolean.
|
| - if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
|
| - // Change the receiver to the result of calling ToObject on it.
|
| - const int argc = this->target()->arguments_count();
|
| - StackFrameLocator locator(isolate());
|
| - JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
|
| - int index = frame->ComputeExpressionsCount() - (argc + 1);
|
| - frame->SetExpression(index, *isolate()->factory()->ToObject(object));
|
| - }
|
| -}
|
| -
|
| -
|
| static bool MigrateDeprecated(Handle<Object> object) {
|
| if (!object->IsJSObject()) return false;
|
| Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| @@ -545,248 +491,6 @@ static bool MigrateDeprecated(Handle<Object> object) {
|
| }
|
|
|
|
|
| -MaybeObject* CallICBase::LoadFunction(Handle<Object> object,
|
| - Handle<String> name) {
|
| - bool use_ic = MigrateDeprecated(object) ? false : FLAG_use_ic;
|
| -
|
| - // If the object is undefined or null it's illegal to try to get any
|
| - // of its properties; throw a TypeError in that case.
|
| - if (object->IsUndefined() || object->IsNull()) {
|
| - return TypeError("non_object_property_call", object, name);
|
| - }
|
| -
|
| - // Check if the name is trivially convertible to an index and get
|
| - // the element if so.
|
| - uint32_t index;
|
| - if (name->AsArrayIndex(&index)) {
|
| - Handle<Object> result = Object::GetElement(isolate(), object, index);
|
| - RETURN_IF_EMPTY_HANDLE(isolate(), result);
|
| - if (result->IsJSFunction()) return *result;
|
| -
|
| - // Try to find a suitable function delegate for the object at hand.
|
| - result = TryCallAsFunction(result);
|
| - if (result->IsJSFunction()) return *result;
|
| -
|
| - // Otherwise, it will fail in the lookup step.
|
| - }
|
| -
|
| - // Lookup the property in the object.
|
| - LookupResult lookup(isolate());
|
| - LookupForRead(object, name, &lookup);
|
| -
|
| - if (!lookup.IsFound()) {
|
| - // If the object does not have the requested property, check which
|
| - // exception we need to throw.
|
| - return object->IsGlobalObject()
|
| - ? ReferenceError("not_defined", name)
|
| - : TypeError("undefined_method", object, name);
|
| - }
|
| -
|
| - // Lookup is valid: Update inline cache and stub cache.
|
| - if (use_ic) UpdateCaches(&lookup, object, name);
|
| -
|
| - // Get the property.
|
| - PropertyAttributes attr;
|
| - Handle<Object> result =
|
| - Object::GetProperty(object, object, &lookup, name, &attr);
|
| - RETURN_IF_EMPTY_HANDLE(isolate(), result);
|
| -
|
| - if (lookup.IsInterceptor() && attr == ABSENT) {
|
| - // If the object does not have the requested property, check which
|
| - // exception we need to throw.
|
| - return object->IsGlobalObject()
|
| - ? ReferenceError("not_defined", name)
|
| - : TypeError("undefined_method", object, name);
|
| - }
|
| -
|
| - ASSERT(!result->IsTheHole());
|
| -
|
| - // Make receiver an object if the callee requires it. Strict mode or builtin
|
| - // functions do not wrap the receiver, non-strict functions and objects
|
| - // called as functions do.
|
| - ReceiverToObjectIfRequired(result, object);
|
| -
|
| - if (result->IsJSFunction()) {
|
| - Handle<JSFunction> function = Handle<JSFunction>::cast(result);
|
| -#ifdef ENABLE_DEBUGGER_SUPPORT
|
| - // Handle stepping into a function if step into is active.
|
| - Debug* debug = isolate()->debug();
|
| - if (debug->StepInActive()) {
|
| - // Protect the result in a handle as the debugger can allocate and might
|
| - // cause GC.
|
| - debug->HandleStepIn(function, object, fp(), false);
|
| - }
|
| -#endif
|
| - return *function;
|
| - }
|
| -
|
| - // Try to find a suitable function delegate for the object at hand.
|
| - result = TryCallAsFunction(result);
|
| - if (result->IsJSFunction()) return *result;
|
| -
|
| - return TypeError("property_not_function", object, name);
|
| -}
|
| -
|
| -
|
| -Handle<Code> CallICBase::ComputeMonomorphicStub(LookupResult* lookup,
|
| - Handle<Object> object,
|
| - Handle<String> name) {
|
| - int argc = target()->arguments_count();
|
| - Handle<JSObject> holder(lookup->holder(), isolate());
|
| - switch (lookup->type()) {
|
| - case FIELD: {
|
| - PropertyIndex index = lookup->GetFieldIndex();
|
| - return isolate()->stub_cache()->ComputeCallField(
|
| - argc, kind_, extra_ic_state(), name, object, holder, index);
|
| - }
|
| - case CONSTANT: {
|
| - if (!lookup->IsConstantFunction()) return Handle<Code>::null();
|
| - // Get the constant function and compute the code stub for this
|
| - // call; used for rewriting to monomorphic state and making sure
|
| - // that the code stub is in the stub cache.
|
| - Handle<JSFunction> function(lookup->GetConstantFunction(), isolate());
|
| - return isolate()->stub_cache()->ComputeCallConstant(
|
| - argc, kind_, extra_ic_state(), name, object, holder, function);
|
| - }
|
| - case NORMAL: {
|
| - // If we return a null handle, the IC will not be patched.
|
| - if (!object->IsJSObject()) return Handle<Code>::null();
|
| - Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| -
|
| - if (holder->IsGlobalObject()) {
|
| - Handle<GlobalObject> global = Handle<GlobalObject>::cast(holder);
|
| - Handle<PropertyCell> cell(
|
| - global->GetPropertyCell(lookup), isolate());
|
| - if (!cell->value()->IsJSFunction()) return Handle<Code>::null();
|
| - Handle<JSFunction> function(JSFunction::cast(cell->value()));
|
| - return isolate()->stub_cache()->ComputeCallGlobal(
|
| - argc, kind_, extra_ic_state(), name,
|
| - receiver, global, cell, function);
|
| - } else {
|
| - // There is only one shared stub for calling normalized
|
| - // properties. It does not traverse the prototype chain, so the
|
| - // property must be found in the receiver for the stub to be
|
| - // applicable.
|
| - if (!holder.is_identical_to(receiver)) return Handle<Code>::null();
|
| - return isolate()->stub_cache()->ComputeCallNormal(
|
| - argc, kind_, extra_ic_state());
|
| - }
|
| - break;
|
| - }
|
| - case INTERCEPTOR:
|
| - ASSERT(HasInterceptorGetter(*holder));
|
| - return isolate()->stub_cache()->ComputeCallInterceptor(
|
| - argc, kind_, extra_ic_state(), name, object, holder);
|
| - default:
|
| - return Handle<Code>::null();
|
| - }
|
| -}
|
| -
|
| -
|
| -Handle<Code> CallICBase::megamorphic_stub() {
|
| - return isolate()->stub_cache()->ComputeCallMegamorphic(
|
| - target()->arguments_count(), kind_, extra_ic_state());
|
| -}
|
| -
|
| -
|
| -Handle<Code> CallICBase::pre_monomorphic_stub() {
|
| - return isolate()->stub_cache()->ComputeCallPreMonomorphic(
|
| - target()->arguments_count(), kind_, extra_ic_state());
|
| -}
|
| -
|
| -
|
| -void CallICBase::UpdateCaches(LookupResult* lookup,
|
| - Handle<Object> object,
|
| - Handle<String> name) {
|
| - // Bail out if we didn't find a result.
|
| - if (!lookup->IsProperty() || !lookup->IsCacheable()) return;
|
| -
|
| - if (state() == UNINITIALIZED) {
|
| - set_target(*pre_monomorphic_stub());
|
| - TRACE_IC("CallIC", name);
|
| - return;
|
| - }
|
| -
|
| - Handle<Code> code = ComputeMonomorphicStub(lookup, object, name);
|
| - // If there's no appropriate stub we simply avoid updating the caches.
|
| - // TODO(verwaest): Install a slow fallback in this case to avoid not learning,
|
| - // and deopting Crankshaft code.
|
| - if (code.is_null()) return;
|
| -
|
| - Handle<JSObject> cache_object = object->IsJSObject()
|
| - ? Handle<JSObject>::cast(object)
|
| - : Handle<JSObject>(JSObject::cast(object->GetPrototype(isolate())),
|
| - isolate());
|
| -
|
| - PatchCache(CurrentTypeOf(cache_object, isolate()), name, code);
|
| - TRACE_IC("CallIC", name);
|
| -}
|
| -
|
| -
|
| -MaybeObject* KeyedCallIC::LoadFunction(Handle<Object> object,
|
| - Handle<Object> key) {
|
| - if (key->IsInternalizedString()) {
|
| - return CallICBase::LoadFunction(object, Handle<String>::cast(key));
|
| - }
|
| -
|
| - if (object->IsUndefined() || object->IsNull()) {
|
| - return TypeError("non_object_property_call", object, key);
|
| - }
|
| -
|
| - bool use_ic = MigrateDeprecated(object)
|
| - ? false : FLAG_use_ic && !object->IsAccessCheckNeeded();
|
| -
|
| - if (use_ic && state() != MEGAMORPHIC) {
|
| - ASSERT(!object->IsJSGlobalProxy());
|
| - int argc = target()->arguments_count();
|
| - Handle<Code> stub;
|
| -
|
| - // Use the KeyedArrayCallStub if the call is of the form array[smi](...),
|
| - // where array is an instance of one of the initial array maps (without
|
| - // extra named properties).
|
| - // TODO(verwaest): Also support keyed calls on instances of other maps.
|
| - if (object->IsJSArray() && key->IsSmi()) {
|
| - Handle<JSArray> array = Handle<JSArray>::cast(object);
|
| - ElementsKind kind = array->map()->elements_kind();
|
| - if (IsFastObjectElementsKind(kind) &&
|
| - array->map() == isolate()->get_initial_js_array_map(kind)) {
|
| - KeyedArrayCallStub stub_gen(IsHoleyElementsKind(kind), argc);
|
| - stub = stub_gen.GetCode(isolate());
|
| - }
|
| - }
|
| -
|
| - if (stub.is_null()) {
|
| - stub = isolate()->stub_cache()->ComputeCallMegamorphic(
|
| - argc, Code::KEYED_CALL_IC, kNoExtraICState);
|
| - if (object->IsJSObject()) {
|
| - Handle<JSObject> receiver = Handle<JSObject>::cast(object);
|
| - if (receiver->elements()->map() ==
|
| - isolate()->heap()->non_strict_arguments_elements_map()) {
|
| - stub = isolate()->stub_cache()->ComputeCallArguments(argc);
|
| - }
|
| - }
|
| - ASSERT(!stub.is_null());
|
| - }
|
| - set_target(*stub);
|
| - TRACE_IC("CallIC", key);
|
| - }
|
| -
|
| - Handle<Object> result = GetProperty(isolate(), object, key);
|
| - RETURN_IF_EMPTY_HANDLE(isolate(), result);
|
| -
|
| - // Make receiver an object if the callee requires it. Strict mode or builtin
|
| - // functions do not wrap the receiver, non-strict functions and objects
|
| - // called as functions do.
|
| - ReceiverToObjectIfRequired(result, object);
|
| - if (result->IsJSFunction()) return *result;
|
| -
|
| - result = TryCallAsFunction(result);
|
| - if (result->IsJSFunction()) return *result;
|
| -
|
| - return TypeError("property_not_function", object, key);
|
| -}
|
| -
|
| -
|
| MaybeObject* LoadIC::Load(Handle<Object> object,
|
| Handle<String> name) {
|
| // If the object is undefined or null it's illegal to try to get any
|
| @@ -880,6 +584,7 @@ MaybeObject* LoadIC::Load(Handle<Object> object,
|
| attr == ABSENT && IsUndeclaredGlobal(object)) {
|
| return ReferenceError("not_defined", name);
|
| }
|
| +
|
| return *result;
|
| }
|
|
|
| @@ -1027,9 +732,7 @@ void IC::PatchCache(Handle<HeapType> type,
|
| case MONOMORPHIC: {
|
| // For now, call stubs are allowed to rewrite to the same stub. This
|
| // happens e.g., when the field does not contain a function.
|
| - ASSERT(target()->is_call_stub() ||
|
| - target()->is_keyed_call_stub() ||
|
| - !target().is_identical_to(code));
|
| + ASSERT(!target().is_identical_to(code));
|
| Code* old_handler = target()->FindFirstHandler();
|
| if (old_handler == *code && IsTransitionOfMonomorphicTarget(type)) {
|
| UpdateMonomorphicIC(type, code, name);
|
| @@ -1056,23 +759,20 @@ void IC::PatchCache(Handle<HeapType> type,
|
| }
|
|
|
|
|
| -Handle<Code> LoadIC::initialize_stub(Isolate* isolate, ContextualMode mode) {
|
| - Handle<Code> ic = isolate->stub_cache()->ComputeLoad(
|
| - UNINITIALIZED, ComputeExtraICState(mode));
|
| - return ic;
|
| +Handle<Code> LoadIC::initialize_stub(Isolate* isolate,
|
| + ExtraICState extra_state) {
|
| + return isolate->stub_cache()->ComputeLoad(UNINITIALIZED, extra_state);
|
| }
|
|
|
|
|
| Handle<Code> LoadIC::pre_monomorphic_stub(Isolate* isolate,
|
| - ContextualMode mode) {
|
| - return isolate->stub_cache()->ComputeLoad(
|
| - PREMONOMORPHIC, ComputeExtraICState(mode));
|
| + ExtraICState extra_state) {
|
| + return isolate->stub_cache()->ComputeLoad(PREMONOMORPHIC, extra_state);
|
| }
|
|
|
|
|
| Handle<Code> LoadIC::megamorphic_stub() {
|
| - return isolate()->stub_cache()->ComputeLoad(
|
| - MEGAMORPHIC, extra_ic_state());
|
| + return isolate()->stub_cache()->ComputeLoad(MEGAMORPHIC, extra_ic_state());
|
| }
|
|
|
|
|
| @@ -2025,51 +1725,6 @@ MaybeObject* KeyedStoreIC::Store(Handle<Object> object,
|
| //
|
|
|
| // Used from ic-<arch>.cc.
|
| -RUNTIME_FUNCTION(MaybeObject*, CallIC_Miss) {
|
| - HandleScope scope(isolate);
|
| - ASSERT(args.length() == 2);
|
| - CallIC ic(isolate);
|
| - Handle<Object> receiver = args.at<Object>(0);
|
| - Handle<String> key = args.at<String>(1);
|
| - ic.UpdateState(receiver, key);
|
| - MaybeObject* maybe_result = ic.LoadFunction(receiver, key);
|
| - JSFunction* raw_function;
|
| - if (!maybe_result->To(&raw_function)) return maybe_result;
|
| -
|
| - // The first time the inline cache is updated may be the first time the
|
| - // function it references gets called. If the function is lazily compiled
|
| - // then the first call will trigger a compilation. We check for this case
|
| - // and we do the compilation immediately, instead of waiting for the stub
|
| - // currently attached to the JSFunction object to trigger compilation.
|
| - if (raw_function->is_compiled()) return raw_function;
|
| -
|
| - Handle<JSFunction> function(raw_function);
|
| - Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
|
| - return *function;
|
| -}
|
| -
|
| -
|
| -// Used from ic-<arch>.cc.
|
| -RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_Miss) {
|
| - HandleScope scope(isolate);
|
| - ASSERT(args.length() == 2);
|
| - KeyedCallIC ic(isolate);
|
| - Handle<Object> receiver = args.at<Object>(0);
|
| - Handle<Object> key = args.at<Object>(1);
|
| - ic.UpdateState(receiver, key);
|
| - MaybeObject* maybe_result = ic.LoadFunction(receiver, key);
|
| - // Result could be a function or a failure.
|
| - JSFunction* raw_function = NULL;
|
| - if (!maybe_result->To(&raw_function)) return maybe_result;
|
| -
|
| - if (raw_function->is_compiled()) return raw_function;
|
| -
|
| - Handle<JSFunction> function(raw_function, isolate);
|
| - Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
|
| - return *function;
|
| -}
|
| -
|
| -
|
| // Used from ic-<arch>.cc.
|
| RUNTIME_FUNCTION(MaybeObject*, LoadIC_Miss) {
|
| HandleScope scope(isolate);
|
| @@ -2128,28 +1783,6 @@ RUNTIME_FUNCTION(MaybeObject*, StoreIC_MissFromStubFailure) {
|
| }
|
|
|
|
|
| -RUNTIME_FUNCTION(MaybeObject*, KeyedCallIC_MissFromStubFailure) {
|
| - HandleScope scope(isolate);
|
| - ASSERT(args.length() == 2);
|
| - KeyedCallIC ic(isolate);
|
| - Arguments* caller_args = reinterpret_cast<Arguments*>(args[0]);
|
| - Handle<Object> key = args.at<Object>(1);
|
| - Handle<Object> receiver((*caller_args)[0], isolate);
|
| -
|
| - ic.UpdateState(receiver, key);
|
| - MaybeObject* maybe_result = ic.LoadFunction(receiver, key);
|
| - // Result could be a function or a failure.
|
| - JSFunction* raw_function = NULL;
|
| - if (!maybe_result->To(&raw_function)) return maybe_result;
|
| -
|
| - if (raw_function->is_compiled()) return raw_function;
|
| -
|
| - Handle<JSFunction> function(raw_function, isolate);
|
| - Compiler::EnsureCompiled(function, CLEAR_EXCEPTION);
|
| - return *function;
|
| -}
|
| -
|
| -
|
| RUNTIME_FUNCTION(MaybeObject*, StoreIC_ArrayLength) {
|
| SealHandleScope shs(isolate);
|
|
|
|
|