bool
GetPropIRGenerator::tryAttachWindowProxy(HandleObject obj, ObjOperandId objId, HandleId id)
{
    // Attach a stub when the receiver is a WindowProxy and we are calling some
    // kinds of JSNative getters on the Window object (the global object).

    if (!IsWindowProxy(obj))
        return false;

    // This must be a WindowProxy for the current Window/global. Else it would
    // be a cross-compartment wrapper and IsWindowProxy returns false for
    // those.
    MOZ_ASSERT(obj->getClass() == cx_->maybeWindowProxyClass());
    MOZ_ASSERT(ToWindowIfWindowProxy(obj) == cx_->global());

    // Now try to do the lookup on the Window (the current global) and see if
    // it's a native getter.
    HandleObject windowObj = cx_->global();
    RootedShape shape(cx_);
    RootedNativeObject holder(cx_);
    NativeGetPropCacheability type = CanAttachNativeGetProp(cx_, windowObj, id, &holder, &shape, pc_,
                                                            engine_, isTemporarilyUnoptimizable_);
    if (type != CanAttachCallGetter ||
        !IsCacheableGetPropCallNative(windowObj, holder, shape))
    {
        return false;
    }

    // Make sure the native getter is okay with the IC passing the Window
    // instead of the WindowProxy as |this| value.
    JSFunction* callee = &shape->getterObject()->as<JSFunction>();
    MOZ_ASSERT(callee->isNative());
    if (!callee->jitInfo() || callee->jitInfo()->needsOuterizedThisObject())
        return false;

    // Guard the incoming object is a WindowProxy and inline a getter call based
    // on the Window object.
    maybeEmitIdGuard(id);
    writer.guardClass(objId, GuardClassKind::WindowProxy);
    ObjOperandId windowObjId = writer.loadObject(windowObj);
    EmitCallGetterResult(writer, windowObj, holder, shape, windowObjId);
    return true;
}
static void
EmitCallGetterResultNoGuards(CacheIRWriter& writer, JSObject* obj, JSObject* holder,
                             Shape* shape, ObjOperandId objId)
{
    if (IsCacheableGetPropCallNative(obj, holder, shape)) {
        JSFunction* target = &shape->getterValue().toObject().as<JSFunction>();
        MOZ_ASSERT(target->isNative());
        writer.callNativeGetterResult(objId, target);
        writer.typeMonitorResult();
        return;
    }

    MOZ_ASSERT(IsCacheableGetPropCallScripted(obj, holder, shape));

    JSFunction* target = &shape->getterValue().toObject().as<JSFunction>();
    MOZ_ASSERT(target->hasJITCode());
    writer.callScriptedGetterResult(objId, target);
    writer.typeMonitorResult();
}
Beispiel #3
0
static bool
AddCacheIRGetPropFunction(ICCacheIR_Monitored* stub, bool innerized,
                          JSObject** holder, Shape** holderShape,
                          JSFunction** commonGetter, Shape** globalShape, bool* isOwnProperty,
                          BaselineInspector::ReceiverVector& receivers,
                          BaselineInspector::ObjectGroupVector& convertUnboxedGroups,
                          JSScript* script)
{
    // We match either an own getter:
    //
    //   GuardIsObject objId
    //   [..WindowProxy innerization..]
    //   <GuardReceiver objId>
    //   Call(Scripted|Native)GetterResult objId
    //
    // Or a getter on the prototype:
    //
    //   GuardIsObject objId
    //   [..WindowProxy innerization..]
    //   <GuardReceiver objId>
    //   LoadObject holderId
    //   GuardShape holderId
    //   Call(Scripted|Native)GetterResult objId
    //
    // If |innerized| is true, we replaced a WindowProxy with the Window
    // object and we're only interested in Baseline getter stubs that performed
    // the same optimization. This means we expect the following ops for the
    // [..WindowProxy innerization..] above:
    //
    //   GuardClass objId WindowProxy
    //   objId = LoadObject <global>

    CacheIRReader reader(stub->stubInfo());

    ObjOperandId objId = ObjOperandId(0);
    if (!reader.matchOp(CacheOp::GuardIsObject, objId)) {
        return AddCacheIRGlobalGetter(stub, innerized, holder, holderShape, commonGetter,
                                      globalShape, isOwnProperty, receivers, convertUnboxedGroups,
                                      script);
    }

    if (innerized) {
        if (!reader.matchOp(CacheOp::GuardClass, objId) ||
            reader.guardClassKind() != GuardClassKind::WindowProxy)
        {
            return false;
        }
        if (!reader.matchOp(CacheOp::LoadObject))
            return false;
        objId = reader.objOperandId();
        DebugOnly<JSObject*> obj =
            stub->stubInfo()->getStubField<JSObject*>(stub, reader.stubOffset()).get();
        MOZ_ASSERT(obj->is<GlobalObject>());
    }

    ReceiverGuard receiver;
    if (!MatchCacheIRReceiverGuard(reader, stub, stub->stubInfo(), objId, &receiver))
        return false;

    if (reader.matchOp(CacheOp::CallScriptedGetterResult, objId) ||
        reader.matchOp(CacheOp::CallNativeGetterResult, objId))
    {
        // This is an own property getter, the first case.
        MOZ_ASSERT(receiver.shape);
        MOZ_ASSERT(!receiver.group);

        size_t offset = reader.stubOffset();
        JSFunction* getter =
            &stub->stubInfo()->getStubField<JSObject*>(stub, offset)->as<JSFunction>();

        if (*commonGetter && (!*isOwnProperty || *globalShape || *holderShape != receiver.shape))
            return false;

        MOZ_ASSERT_IF(*commonGetter, *commonGetter == getter);
        *holder = nullptr;
        *holderShape = receiver.shape;
        *commonGetter = getter;
        *isOwnProperty = true;
        return true;
    }

    if (!reader.matchOp(CacheOp::LoadObject))
        return false;
    ObjOperandId holderId = reader.objOperandId();
    JSObject* obj = stub->stubInfo()->getStubField<JSObject*>(stub, reader.stubOffset());

    if (!reader.matchOp(CacheOp::GuardShape, holderId))
        return false;
    Shape* objShape = stub->stubInfo()->getStubField<Shape*>(stub, reader.stubOffset());

    if (!reader.matchOp(CacheOp::CallScriptedGetterResult, objId) &&
        !reader.matchOp(CacheOp::CallNativeGetterResult, objId))
    {
        return false;
    }

    // A getter on the prototype.
    size_t offset = reader.stubOffset();
    JSFunction* getter =
        &stub->stubInfo()->getStubField<JSObject*>(stub, offset)->as<JSFunction>();

    Shape* thisGlobalShape = nullptr;
    if (getter->isNative() && receiver.shape &&
        (receiver.shape->getObjectClass()->flags & JSCLASS_IS_GLOBAL))
    {
        thisGlobalShape = receiver.shape;
    }

    if (*commonGetter &&
        (*isOwnProperty || *globalShape != thisGlobalShape || *holderShape != objShape))
    {
        return false;
    }

    MOZ_ASSERT_IF(*commonGetter, *commonGetter == getter);

    if (obj->as<NativeObject>().lastProperty() != objShape) {
        // Skip this stub as the shape is no longer correct.
        return true;
    }

    if (!AddReceiver(receiver, receivers, convertUnboxedGroups))
        return false;

    *holder = obj;
    *holderShape = objShape;
    *commonGetter = getter;
    *isOwnProperty = false;
    return true;
}