IndexingType leastUpperBoundOfIndexingTypeAndType(IndexingType indexingType, SpeculatedType type) { if (!type) return indexingType; switch (indexingType) { case ALL_BLANK_INDEXING_TYPES: case ALL_UNDECIDED_INDEXING_TYPES: case ALL_INT32_INDEXING_TYPES: if (isInt32Speculation(type)) return (indexingType & ~IndexingShapeMask) | Int32Shape; // FIXME: Should this really say that it wants a double for NaNs. if (isFullNumberSpeculation(type)) return (indexingType & ~IndexingShapeMask) | DoubleShape; return (indexingType & ~IndexingShapeMask) | ContiguousShape; case ALL_DOUBLE_INDEXING_TYPES: // FIXME: Should this really say that it wants a double for NaNs. if (isFullNumberSpeculation(type)) return indexingType; return (indexingType & ~IndexingShapeMask) | ContiguousShape; case ALL_CONTIGUOUS_INDEXING_TYPES: case ALL_ARRAY_STORAGE_INDEXING_TYPES: return indexingType; default: CRASH(); return 0; } }
bool VariableAccessData::shouldUseDoubleFormatAccordingToVote() { // We don't support this facility for arguments, yet. // FIXME: make this work for arguments. if (local().isArgument()) return false; // If the variable is not a number prediction, then this doesn't // make any sense. if (!isFullNumberSpeculation(prediction())) { // FIXME: we may end up forcing a local in inlined argument position to be a double even // if it is sometimes not even numeric, since this never signals the fact that it doesn't // want doubles. https://bugs.webkit.org/show_bug.cgi?id=109511 return false; } // If the variable is predicted to hold only doubles, then it's a // no-brainer: it should be formatted as a double. if (isDoubleSpeculation(prediction())) return true; // If the variable is known to be used as an integer, then be safe - // don't force it to be a double. if (flags() & NodeBytecodeUsesAsInt) return false; // If the variable has been voted to become a double, then make it a // double. if (voteRatio() >= Options::doubleVoteRatioForDoubleFormat()) return true; return false; }
// We don't expose this because we don't want anyone relying on the fact that this method currently // just returns string constants. static const char* speculationToAbbreviatedString(SpeculatedType prediction) { if (isFinalObjectSpeculation(prediction)) return "<Final>"; if (isArraySpeculation(prediction)) return "<Array>"; if (isStringIdentSpeculation(prediction)) return "<StringIdent>"; if (isStringSpeculation(prediction)) return "<String>"; if (isFunctionSpeculation(prediction)) return "<Function>"; if (isInt8ArraySpeculation(prediction)) return "<Int8array>"; if (isInt16ArraySpeculation(prediction)) return "<Int16array>"; if (isInt32ArraySpeculation(prediction)) return "<Int32array>"; if (isUint8ArraySpeculation(prediction)) return "<Uint8array>"; if (isUint16ArraySpeculation(prediction)) return "<Uint16array>"; if (isUint32ArraySpeculation(prediction)) return "<Uint32array>"; if (isFloat32ArraySpeculation(prediction)) return "<Float32array>"; if (isFloat64ArraySpeculation(prediction)) return "<Float64array>"; if (isDirectArgumentsSpeculation(prediction)) return "<DirectArguments>"; if (isScopedArgumentsSpeculation(prediction)) return "<ScopedArguments>"; if (isStringObjectSpeculation(prediction)) return "<StringObject>"; if (isStringOrStringObjectSpeculation(prediction)) return "<StringOrStringObject>"; if (isObjectSpeculation(prediction)) return "<Object>"; if (isCellSpeculation(prediction)) return "<Cell>"; if (isInt32Speculation(prediction)) return "<Int32>"; if (isInt52AsDoubleSpeculation(prediction)) return "<Int52AsDouble>"; if (isInt52Speculation(prediction)) return "<Int52>"; if (isMachineIntSpeculation(prediction)) return "<MachineInt>"; if (isDoubleSpeculation(prediction)) return "<Double>"; if (isFullNumberSpeculation(prediction)) return "<Number>"; if (isBooleanSpeculation(prediction)) return "<Boolean>"; if (isOtherSpeculation(prediction)) return "<Other>"; if (isMiscSpeculation(prediction)) return "<Misc>"; return ""; }
ArrayMode ArrayMode::refine( Graph& graph, CodeOrigin codeOrigin, SpeculatedType base, SpeculatedType index, SpeculatedType value, NodeFlags flags) const { if (!base || !index) { // It can be that we had a legitimate arrayMode but no incoming predictions. That'll // happen if we inlined code based on, say, a global variable watchpoint, but later // realized that the callsite could not have possibly executed. It may be worthwhile // to fix that, but for now I'm leaving it as-is. return ArrayMode(Array::ForceExit); } if (!isInt32Speculation(index)) return ArrayMode(Array::Generic); // Note: our profiling currently doesn't give us good information in case we have // an unlikely control flow path that sets the base to a non-cell value. Value // profiling and prediction propagation will probably tell us that the value is // either a cell or not, but that doesn't tell us which is more likely: that this // is an array access on a cell (what we want and can optimize) or that the user is // doing a crazy by-val access on a primitive (we can't easily optimize this and // don't want to). So, for now, we assume that if the base is not a cell according // to value profiling, but the array profile tells us something else, then we // should just trust the array profile. switch (type()) { case Array::Unprofiled: return ArrayMode(Array::ForceExit); case Array::Undecided: if (!value) return withType(Array::ForceExit); if (isInt32Speculation(value)) return withTypeAndConversion(Array::Int32, Array::Convert); if (isFullNumberSpeculation(value)) return withTypeAndConversion(Array::Double, Array::Convert); return withTypeAndConversion(Array::Contiguous, Array::Convert); case Array::Int32: if (!value || isInt32Speculation(value)) return *this; if (isFullNumberSpeculation(value)) return withTypeAndConversion(Array::Double, Array::Convert); return withTypeAndConversion(Array::Contiguous, Array::Convert); case Array::Double: if (flags & NodeBytecodeUsesAsInt) return withTypeAndConversion(Array::Contiguous, Array::RageConvert); if (!value || isFullNumberSpeculation(value)) return *this; return withTypeAndConversion(Array::Contiguous, Array::Convert); case Array::Contiguous: if (doesConversion() && (flags & NodeBytecodeUsesAsInt)) return withConversion(Array::RageConvert); return *this; case Array::SelectUsingPredictions: { base &= ~SpecOther; if (isStringSpeculation(base)) return withType(Array::String); if (isArgumentsSpeculation(base)) return withType(Array::Arguments); ArrayMode result; if (graph.hasExitSite(codeOrigin, OutOfBounds) || !isInBounds()) result = withSpeculation(Array::OutOfBounds); else result = withSpeculation(Array::InBounds); if (isInt8ArraySpeculation(base)) return result.withType(Array::Int8Array); if (isInt16ArraySpeculation(base)) return result.withType(Array::Int16Array); if (isInt32ArraySpeculation(base)) return result.withType(Array::Int32Array); if (isUint8ArraySpeculation(base)) return result.withType(Array::Uint8Array); if (isUint8ClampedArraySpeculation(base)) return result.withType(Array::Uint8ClampedArray); if (isUint16ArraySpeculation(base)) return result.withType(Array::Uint16Array); if (isUint32ArraySpeculation(base)) return result.withType(Array::Uint32Array); if (isFloat32ArraySpeculation(base)) return result.withType(Array::Float32Array); if (isFloat64ArraySpeculation(base)) return result.withType(Array::Float64Array); return ArrayMode(Array::Generic); } default: return *this; } }