TypeOracle::UnaryTypes TypeInferenceOracle::unaryTypes(UnrootedScript 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; }
/* static */ void ArgumentsObject::MaybeForwardToCallObject(StackFrame *fp, JSObject *obj, ArgumentsData *data) { UnrootedScript script = fp->script(); if (fp->fun()->isHeavyweight() && script->argsObjAliasesFormals()) { obj->initFixedSlot(MAYBE_CALL_SLOT, ObjectValue(fp->callObj())); for (AliasedFormalIter fi(script); fi; fi++) data->args[fi.frameIndex()] = MagicValue(JS_FORWARD_TO_CALL_OBJECT); } }
static bool IsEvalCacheCandidate(UnrootedScript script) { // Make sure there are no inner objects which might use the wrong parent // and/or call scope by reusing the previous eval's script. Skip the // script's first object, which entrains the eval's scope. return script->savedCallerFun && !script->hasSingletons && script->objects()->length == 1 && !script->hasRegexps(); }
uint32_t ion::ShapeGuardFailure() { JSContext *cx = GetIonContext()->cx; UnrootedScript script = GetBailedJSScript(cx); JS_ASSERT(script->hasIonScript()); JS_ASSERT(!script->ion->invalidated()); script->failedShapeGuard = true; IonSpew(IonSpew_Invalidate, "Invalidating due to shape guard failure"); return Invalidate(cx, script); }
/* static */ bool EvalCacheHashPolicy::match(UnrootedScript script, const EvalCacheLookup &l) { JS_ASSERT(IsEvalCacheCandidate(script)); // Get the source string passed for safekeeping in the atom map // by the prior eval to frontend::CompileScript. JSAtom *keyStr = script->atoms[0]; return EqualStrings(keyStr, l.str) && script->getCallerFunction() == l.caller && script->staticLevel == l.staticLevel && script->getVersion() == l.version && script->compartment() == l.compartment; }
bool TypeInferenceOracle::arrayResultShouldHaveDoubleConversion(UnrootedScript script, jsbytecode *pc) { types::StackTypeSet::DoubleConversion conversion = script->analysis()->pushedTypes(pc, 0)->convertDoubleElements(cx); return conversion == types::StackTypeSet::AlwaysConvertToDoubles; }
bool TypeInferenceOracle::elementReadShouldAlwaysLoadDoubles(UnrootedScript 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::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::elementWriteNeedsDoubleConversion(UnrootedScript 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::elementReadIsDenseArray(UnrootedScript 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 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); }
uint32_t ion::RecompileForInlining() { AutoAssertNoGC nogc; JSContext *cx = GetIonContext()->cx; UnrootedScript script = cx->fp()->script(); IonSpew(IonSpew_Inlining, "Recompiling script to inline calls %s:%d", script->filename, script->lineno); // Invalidate the script to force a recompile. if (!Invalidate(cx, script, /* resetUses */ false)) return BAILOUT_RETURN_FATAL_ERROR; // Invalidation should not reset the use count. JS_ASSERT(script->getUseCount() >= js_IonOptions.usesBeforeInlining); return true; }
void TypeInferenceOracle::elementReadGeneric(UnrootedScript script, jsbytecode *pc, bool *cacheable, bool *monitorResult) { 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)); // 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; }
TypeOracle::BinaryTypes TypeInferenceOracle::binaryTypes(UnrootedScript 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; }
TypeOracle::Unary TypeInferenceOracle::unaryOp(UnrootedScript 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::Binary TypeInferenceOracle::binaryOp(UnrootedScript 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; }
bool TypeInferenceOracle::elementWriteHasExtraIndexedProperty(UnrootedScript 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); }
uint32_t ion::CachedShapeGuardFailure() { JSContext *cx = GetIonContext()->cx; UnrootedScript script = GetBailedJSScript(cx); JS_ASSERT(script->hasIonScript()); JS_ASSERT(!script->ion->invalidated()); script->failedShapeGuard = true; // Purge JM caches in the script and all inlined script, to avoid baking in // the same shape guard next time. for (size_t i = 0; i < script->ion->scriptEntries(); i++) mjit::PurgeCaches(script->ion->getScript(i)); IonSpew(IonSpew_Invalidate, "Invalidating due to shape guard failure"); return Invalidate(cx, script); }
bool TypeInferenceOracle::elementReadIsTypedArray(UnrootedScript 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 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; if (obj->hasObjectFlags(cx, types::OBJECT_FLAG_NON_TYPED_ARRAY)) 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; }
JS_SetTopFrameAnnotation(JSContext *cx, void *annotation) { AutoAssertNoGC nogc; StackFrame *fp = cx->fp(); JS_ASSERT_IF(fp->beginsIonActivation(), !fp->annotation()); // Note that if this frame is running in Ion, the actual calling frame // could be inlined or a callee and thus we won't have a correct |fp|. // To account for this, ion::InvalidationBailout will transfer an // annotation from the old cx->fp() to the new top frame. This works // because we will never EnterIon on a frame with an annotation. fp->setAnnotation(annotation); UnrootedScript script = fp->script(); ReleaseAllJITCode(cx->runtime->defaultFreeOp()); // Ensure that we'll never try to compile this again. JS_ASSERT(!script->hasAnyIonScript()); script->ion = ION_DISABLED_SCRIPT; script->parallelIon = ION_DISABLED_SCRIPT; }
bool TypeInferenceOracle::elementReadIsString(UnrootedScript 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; }
bool TypeInferenceOracle::elementWriteIsTypedArray(UnrootedScript 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 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; if (obj->hasObjectFlags(cx, types::OBJECT_FLAG_NON_TYPED_ARRAY)) return false; *arrayType = obj->getTypedArrayType(); if (*arrayType == TypedArray::TYPE_MAX) return false; return true; }
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::propertyReadAccessGetter(UnrootedScript script, jsbytecode *pc) { return script->analysis()->getCode(pc).accessGetter; }
bool TypeInferenceOracle::elementReadHasExtraIndexedProperty(UnrootedScript script, jsbytecode *pc) { StackTypeSet *obj = script->analysis()->poppedTypes(pc, 1); return types::TypeCanHaveExtraIndexedProperties(cx, obj); }
LazyArgumentsType TypeInferenceOracle::elementWriteMagicArguments(UnrootedScript script, jsbytecode *pc) { StackTypeSet *obj = script->analysis()->poppedTypes(pc, 2); return isArgumentObject(obj); }
bool TypeInferenceOracle::propertyWriteNeedsBarrier(UnrootedScript script, jsbytecode *pc, jsid id) { StackTypeSet *types = script->analysis()->poppedTypes(pc, 1); return types->propertyNeedsBarrier(cx, id); }
bool TypeInferenceOracle::propertyWriteCanSpecialize(UnrootedScript script, jsbytecode *pc) { return !script->analysis()->getCode(pc).monitoredTypes; }
bool TypeInferenceOracle::setElementHasWrittenHoles(UnrootedScript script, jsbytecode *pc) { return script->analysis()->getCode(pc).arrayWriteHole; }