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(); }
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; }