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; }
TypeOracle::UnaryTypes TypeInferenceOracle::unaryTypes(RawScript script, jsbytecode *pc) { JS_ASSERT(script == this->script()); UnaryTypes res; res.inTypes = script->analysis()->poppedTypes(pc, 0); res.outTypes = script->analysis()->pushedTypes(pc, 0); return res; }
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::elementWriteIsTypedArray(RawScript script, jsbytecode *pc, int *arrayType) { return elementWriteIsTypedArray(script->analysis()->poppedTypes(pc, 2), script->analysis()->poppedTypes(pc, 1), arrayType); }
MIRType TypeInferenceOracle::elementWrite(RawScript 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)) { if (object->unknownProperties()) return MIRType_None; 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::arrayResultShouldHaveDoubleConversion(RawScript script, jsbytecode *pc) { types::StackTypeSet::DoubleConversion conversion = script->analysis()->pushedTypes(pc, 0)->convertDoubleElements(cx); return conversion == types::StackTypeSet::AlwaysConvertToDoubles; }
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; }
bool TypeInferenceOracle::elementWriteNeedsBarrier(RawScript 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. return elementWriteNeedsBarrier(script->analysis()->poppedTypes(pc, 2)); }
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::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; }
TypeOracle::Binary TypeInferenceOracle::binaryOp(RawScript script, jsbytecode *pc) { JS_ASSERT(script == this->script()); JSOp op = (JSOp)*pc; Binary res; if (op == JSOP_NEG || op == JSOP_POS) { res.lhs = getMIRType(script->analysis()->poppedTypes(pc, 0)); res.rhs = MIRType_Int32; res.rval = getMIRType(script->analysis()->pushedTypes(pc, 0)); } else { res.lhs = getMIRType(script->analysis()->poppedTypes(pc, 1)); res.rhs = getMIRType(script->analysis()->poppedTypes(pc, 0)); res.rval = getMIRType(script->analysis()->pushedTypes(pc, 0)); } return res; }
TypeOracle::Unary TypeInferenceOracle::unaryOp(RawScript script, jsbytecode *pc) { JS_ASSERT(script == this->script()); Unary res; res.ival = getMIRType(script->analysis()->poppedTypes(pc, 0)); res.rval = getMIRType(script->analysis()->pushedTypes(pc, 0)); return res; }
TypeOracle::BinaryTypes TypeInferenceOracle::binaryTypes(RawScript script, jsbytecode *pc) { JS_ASSERT(script == this->script()); JSOp op = (JSOp)*pc; BinaryTypes res; if (op == JSOP_NEG || op == JSOP_POS) { res.lhsTypes = script->analysis()->poppedTypes(pc, 0); res.rhsTypes = NULL; res.outTypes = script->analysis()->pushedTypes(pc, 0); } else { res.lhsTypes = script->analysis()->poppedTypes(pc, 1); res.rhsTypes = script->analysis()->poppedTypes(pc, 0); res.outTypes = script->analysis()->pushedTypes(pc, 0); } return res; }
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); }
void TypeInferenceOracle::elementReadGeneric(RawScript script, jsbytecode *pc, bool *cacheable, bool *monitorResult, bool *intIndex) { MIRType obj = getMIRType(script->analysis()->poppedTypes(pc, 1)); MIRType id = getMIRType(script->analysis()->poppedTypes(pc, 0)); *cacheable = (obj == MIRType_Object && (id == MIRType_Value || id == MIRType_Int32 || id == MIRType_String)); *intIndex = id == MIRType_Int32; // Turn off cacheing if the element is int32 and we've seen non-native objects as the target // of this getelem. if (*cacheable && id == MIRType_Int32 && script->analysis()->getCode(pc).nonNativeGetElement) *cacheable = false; if (*cacheable) *monitorResult = (id == MIRType_String || script->analysis()->getCode(pc).getStringElement); else *monitorResult = true; }
bool TypeInferenceOracle::elementReadIsString(RawScript script, jsbytecode *pc) { // Check for string[index]. StackTypeSet *value = script->analysis()->poppedTypes(pc, 1); StackTypeSet *id = script->analysis()->poppedTypes(pc, 0); if (value->getKnownTypeTag() != JSVAL_TYPE_STRING) return false; JSValueType idType = id->getKnownTypeTag(); if (idType != JSVAL_TYPE_INT32 && idType != JSVAL_TYPE_DOUBLE) 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; }
LazyArgumentsType TypeInferenceOracle::elementWriteMagicArguments(RawScript script, jsbytecode *pc) { StackTypeSet *obj = script->analysis()->poppedTypes(pc, 2); return isArgumentObject(obj); }
bool TypeInferenceOracle::propertyReadAccessGetter(RawScript script, jsbytecode *pc) { return script->analysis()->getCode(pc).accessGetter; }
bool TypeInferenceOracle::propertyWriteNeedsBarrier(RawScript script, jsbytecode *pc, RawId id) { StackTypeSet *types = script->analysis()->poppedTypes(pc, 1); return types->propertyNeedsBarrier(cx, id); }
bool TypeInferenceOracle::propertyWriteCanSpecialize(RawScript script, jsbytecode *pc) { return !script->analysis()->getCode(pc).monitoredTypes; }
bool TypeInferenceOracle::elementReadHasExtraIndexedProperty(RawScript script, jsbytecode *pc) { StackTypeSet *obj = script->analysis()->poppedTypes(pc, 1); return types::TypeCanHaveExtraIndexedProperties(cx, obj); }
bool TypeInferenceOracle::setElementHasWrittenHoles(RawScript script, jsbytecode *pc) { return script->analysis()->getCode(pc).arrayWriteHole; }
bool TypeInferenceOracle::elementWriteIsPacked(RawScript script, jsbytecode *pc) { StackTypeSet *types = script->analysis()->poppedTypes(pc, 2); return !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED); }