bool TypeInferenceOracle::elementReadIsTypedArray(RawScript script, jsbytecode *pc, int *arrayType) { // Check whether the object is a typed array and index is int32 or double. StackTypeSet *obj = script->analysis()->poppedTypes(pc, 1); StackTypeSet *id = script->analysis()->poppedTypes(pc, 0); JSValueType idType = id->getKnownTypeTag(); if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE) return false; if (obj->hasType(types::Type::StringType())) return false; *arrayType = obj->getTypedArrayType(); if (*arrayType == TypedArray::TYPE_MAX) return false; JS_ASSERT(*arrayType >= 0 && *arrayType < TypedArray::TYPE_MAX); // Unlike dense arrays, the types of elements in typed arrays are not // guaranteed to be present in the object's type, and we need to use // knowledge about the possible contents of the array vs. the types // that have been read out of it to figure out how to do the load. types::TypeSet *result = propertyRead(script, pc); if (*arrayType == TypedArray::TYPE_FLOAT32 || *arrayType == TypedArray::TYPE_FLOAT64) { if (!result->hasType(types::Type::DoubleType())) return false; } else { if (!result->hasType(types::Type::Int32Type())) return false; } return true; }
bool TypeInferenceOracle::elementReadShouldAlwaysLoadDoubles(RawScript script, jsbytecode *pc) { StackTypeSet *types = script->analysis()->poppedTypes(pc, 1); types::StackTypeSet::DoubleConversion conversion = types->convertDoubleElements(cx); return conversion == StackTypeSet::AlwaysConvertToDoubles; }
MIRType TypeInferenceOracle::elementWrite(UnrootedScript script, jsbytecode *pc) { StackTypeSet *objTypes = script->analysis()->poppedTypes(pc, 2); MIRType elementType = MIRType_None; unsigned count = objTypes->getObjectCount(); for (unsigned i = 0; i < count; i++) { if (objTypes->getSingleObject(i)) return MIRType_None; if (TypeObject *object = objTypes->getTypeObject(i)) { types::HeapTypeSet *elementTypes = object->getProperty(cx, JSID_VOID, false); if (!elementTypes) return MIRType_None; MIRType type = getMIRType(elementTypes); if (type == MIRType_None) return MIRType_None; if (elementType == MIRType_None) elementType = type; else if (elementType != type) return MIRType_None; } } return elementType; }
bool TypeInferenceOracle::propertyReadIdempotent(HandleScript script, jsbytecode *pc, HandleId id) { if (script->analysis()->getCode(pc).notIdempotent) return false; if (id != MakeTypeId(cx, id)) return false; StackTypeSet *types = script->analysis()->poppedTypes(pc, 0); if (!types || types->unknownObject()) return false; for (unsigned i = 0; i < types->getObjectCount(); i++) { if (types->getSingleObject(i)) return false; if (TypeObject *obj = types->getTypeObject(i)) { if (obj->unknownProperties()) return false; // Check if the property has been reconfigured or is a getter. HeapTypeSet *propertyTypes = obj->getProperty(cx, id, false); if (!propertyTypes || propertyTypes->isOwnProperty(cx, obj, true)) return false; } } return true; }
bool TypeInferenceOracle::elementWriteNeedsDoubleConversion(RawScript script, jsbytecode *pc) { StackTypeSet *types = script->analysis()->poppedTypes(pc, 2); types::StackTypeSet::DoubleConversion conversion = types->convertDoubleElements(cx); return conversion == StackTypeSet::AlwaysConvertToDoubles || conversion == StackTypeSet::MaybeConvertToDoubles; }
bool TypeInferenceOracle::elementWriteNeedsBarrier(UnrootedScript script, jsbytecode *pc) { // Return true if SETELEM-like instructions need a write barrier before modifying // a property. The object is the third value popped by SETELEM. StackTypeSet *types = script->analysis()->poppedTypes(pc, 2); return types->propertyNeedsBarrier(cx, JSID_VOID); }
bool TypeInferenceOracle::elementWriteHasExtraIndexedProperty(RawScript script, jsbytecode *pc) { StackTypeSet *obj = script->analysis()->poppedTypes(pc, 2); if (obj->hasObjectFlags(cx, types::OBJECT_FLAG_LENGTH_OVERFLOW)) return true; return types::TypeCanHaveExtraIndexedProperties(cx, obj); }
bool TypeInferenceOracle::elementReadIsDenseNative(RawScript script, jsbytecode *pc) { // Check whether the object is a dense array and index is int32 or double. StackTypeSet *obj = script->analysis()->poppedTypes(pc, 1); StackTypeSet *id = script->analysis()->poppedTypes(pc, 0); JSValueType idType = id->getKnownTypeTag(); if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE) return false; Class *clasp = obj->getKnownClass(); return clasp && clasp->isNative(); }
bool TypeInferenceOracle::elementWriteIsDenseArray(HandleScript script, jsbytecode *pc) { // Check whether the object is a dense array and index is int32 or double. StackTypeSet *obj = script->analysis()->poppedTypes(pc, 2); StackTypeSet *id = script->analysis()->poppedTypes(pc, 1); JSValueType objType = obj->getKnownTypeTag(); if (objType != JSVAL_TYPE_OBJECT) return false; JSValueType idType = id->getKnownTypeTag(); if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE) return false; return !obj->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY); }
bool TypeInferenceOracle::inObjectIsDenseNativeWithoutExtraIndexedProperties(HandleScript script, jsbytecode *pc) { // Check whether the object is a native and index is int32 or double. StackTypeSet *id = script->analysis()->poppedTypes(pc, 1); StackTypeSet *obj = script->analysis()->poppedTypes(pc, 0); JSValueType idType = id->getKnownTypeTag(); if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE) return false; Class *clasp = obj->getKnownClass(); if (!clasp || !clasp->isNative()) return false; return !types::TypeCanHaveExtraIndexedProperties(cx, obj); }
bool TypeInferenceOracle::elementWriteIsTypedArray(RawScript script, jsbytecode *pc, int *arrayType) { // Check whether the object is a dense array and index is int32 or double. StackTypeSet *obj = script->analysis()->poppedTypes(pc, 2); StackTypeSet *id = script->analysis()->poppedTypes(pc, 1); JSValueType idType = id->getKnownTypeTag(); if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE) return false; *arrayType = obj->getTypedArrayType(); if (*arrayType == TypedArray::TYPE_MAX) return false; return true; }
bool TypeInferenceOracle::elementWriteIsDenseNative(HandleScript script, jsbytecode *pc) { // Check whether the object is a dense array and index is int32 or double. StackTypeSet *obj = script->analysis()->poppedTypes(pc, 2); StackTypeSet *id = script->analysis()->poppedTypes(pc, 1); JSValueType idType = id->getKnownTypeTag(); if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE) return false; Class *clasp = obj->getKnownClass(); if (!clasp || !clasp->isNative()) return false; return obj->convertDoubleElements(cx) != StackTypeSet::AmbiguousDoubleConversion; }
bool TypeInferenceOracle::elementReadIsString(JSScript *script, jsbytecode *pc) { // Check for string[int32]. StackTypeSet *value = script->analysis()->poppedTypes(pc, 1); StackTypeSet *id = script->analysis()->poppedTypes(pc, 0); if (value->getKnownTypeTag() != JSVAL_TYPE_STRING) return false; if (id->getKnownTypeTag() != JSVAL_TYPE_INT32) return false; types::TypeSet *pushed = script->analysis()->pushedTypes(pc, 0); if (!pushed->hasType(types::Type::StringType())) return false; return true; }
bool TypeInferenceOracle::elementReadIsString(JSScript *script, jsbytecode *pc) { // Check for string[int32]. StackTypeSet *value = script->analysis()->poppedTypes(pc, 1); StackTypeSet *id = script->analysis()->poppedTypes(pc, 0); if (value->getKnownTypeTag() != JSVAL_TYPE_STRING) return false; if (id->getKnownTypeTag() != JSVAL_TYPE_INT32) return false; // This function is used for jsop_getelem_string which should return // undefined if this is out-side the string bounds. Currently we just // fallback to a CallGetElement. StackTypeSet *pushed = script->analysis()->pushedTypes(pc, 0); if (pushed->getKnownTypeTag() != JSVAL_TYPE_STRING) return false; return true; }
bool TypeInferenceOracle::elementReadIsPacked(RawScript script, jsbytecode *pc) { StackTypeSet *types = script->analysis()->poppedTypes(pc, 1); return !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED); }
bool TypeInferenceOracle::propertyWriteNeedsBarrier(UnrootedScript script, jsbytecode *pc, jsid id) { StackTypeSet *types = script->analysis()->poppedTypes(pc, 1); return types->propertyNeedsBarrier(cx, id); }
bool TypeInferenceOracle::elementWriteIsPacked(UnrootedScript script, jsbytecode *pc) { StackTypeSet *types = script->analysis()->poppedTypes(pc, 2); return !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY); }
bool TypeInferenceOracle::inArrayIsPacked(JSScript *script, jsbytecode *pc) { StackTypeSet *types = script->analysis()->poppedTypes(pc, 0); return !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY); }