void SlotVisitor::append(JSValue value) { if (!value || !value.isCell()) return; if (UNLIKELY(m_heapSnapshotBuilder)) m_heapSnapshotBuilder->appendEdge(m_currentCell, value.asCell()); setMarkedAndAppendToMarkStack(value.asCell()); }
SpeculatedType speculationFromValue(JSValue value) { if (value.isEmpty()) return SpecEmpty; if (value.isInt32()) return SpecInt32; if (value.isDouble()) { double number = value.asNumber(); if (number == number) { int64_t asInt64 = static_cast<int64_t>(number); if (asInt64 == number && (asInt64 || !std::signbit(number)) && asInt64 < (static_cast<int64_t>(1) << 47) && asInt64 >= -(static_cast<int64_t>(1) << 47)) { return SpecInt48AsDouble; } return SpecNonIntAsDouble; } return SpecDoubleNaN; } if (value.isCell()) return speculationFromCell(value.asCell()); if (value.isBoolean()) return SpecBoolean; ASSERT(value.isUndefinedOrNull()); return SpecOther; }
EncodedJSValue DFG_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) { JSGlobalData* globalData = &exec->globalData(); NativeCallFrameTracer tracer(globalData, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); if (LIKELY(baseValue.isCell())) { JSCell* base = baseValue.asCell(); if (property.isUInt32()) { return getByVal(exec, base, property.asUInt32()); } else if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); if (propertyAsUInt32 == propertyAsDouble) return getByVal(exec, base, propertyAsUInt32); } else if (property.isString()) { if (JSValue result = base->fastGetOwnProperty(exec, asString(property)->value(exec))) return JSValue::encode(result); } } Identifier ident(exec, property.toString(exec)->value(exec)); return JSValue::encode(baseValue.get(exec, ident)); }
bool AbstractValue::mergeOSREntryValue(Graph& graph, JSValue value) { AbstractValue oldMe = *this; if (isClear()) { FrozenValue* frozenValue = graph.freeze(value); if (frozenValue->pointsToHeap()) { m_structure = frozenValue->structure(); m_arrayModes = asArrayModes(frozenValue->structure()->indexingType()); } else { m_structure.clear(); m_arrayModes = 0; } m_type = speculationFromValue(value); m_value = value; } else { mergeSpeculation(m_type, speculationFromValue(value)); if (!!value && value.isCell()) { Structure* structure = value.asCell()->structure(); graph.registerStructure(structure); mergeArrayModes(m_arrayModes, asArrayModes(structure->indexingType())); m_structure.merge(StructureSet(structure)); } if (m_value != value) m_value = JSValue(); } checkConsistency(); assertIsRegistered(graph); return oldMe != *this; }
static CodeBlock* codeBlockFromArg(ExecState* exec) { VM& vm = exec->vm(); if (exec->argumentCount() < 1) return nullptr; JSValue value = exec->uncheckedArgument(0); CodeBlock* candidateCodeBlock = nullptr; if (value.isCell()) { JSFunction* func = jsDynamicCast<JSFunction*>(vm, value.asCell()); if (func) { if (func->isHostFunction()) candidateCodeBlock = nullptr; else candidateCodeBlock = func->jsExecutable()->eitherCodeBlock(); } } else if (value.isDouble()) { // If the value is a double, it may be an encoded CodeBlock* that came from // $vm.codeBlockForFrame(). We'll treat it as a candidate codeBlock and check if it's // valid below before using. candidateCodeBlock = reinterpret_cast<CodeBlock*>(bitwise_cast<uint64_t>(value.asDouble())); } if (candidateCodeBlock && JSDollarVMPrototype::isValidCodeBlock(exec, candidateCodeBlock)) return candidateCodeBlock; if (candidateCodeBlock) dataLog("Invalid codeBlock: ", RawPointer(candidateCodeBlock), " ", value, "\n"); else dataLog("Invalid codeBlock: ", value, "\n"); return nullptr; }
EncodedJSValue JIT_OPERATION operationGetByVal(ExecState* exec, EncodedJSValue encodedBase, EncodedJSValue encodedProperty) { VM& vm = exec->vm(); NativeCallFrameTracer tracer(&vm, exec); JSValue baseValue = JSValue::decode(encodedBase); JSValue property = JSValue::decode(encodedProperty); if (LIKELY(baseValue.isCell())) { JSCell* base = baseValue.asCell(); if (property.isUInt32()) { return getByVal(exec, base, property.asUInt32()); } else if (property.isDouble()) { double propertyAsDouble = property.asDouble(); uint32_t propertyAsUInt32 = static_cast<uint32_t>(propertyAsDouble); if (propertyAsUInt32 == propertyAsDouble) return getByVal(exec, base, propertyAsUInt32); } else if (property.isString()) { Structure& structure = *base->structure(vm); if (JSCell::canUseFastGetOwnProperty(structure)) { if (AtomicStringImpl* existingAtomicString = asString(property)->toExistingAtomicString(exec)) { if (JSValue result = base->fastGetOwnProperty(vm, structure, existingAtomicString)) return JSValue::encode(result); } } } } PropertyName propertyName = property.toPropertyKey(exec); return JSValue::encode(baseValue.get(exec, propertyName)); }
void SlotVisitor::appendHidden(JSValue value) { if (!value || !value.isCell()) return; setMarkedAndAppendToMarkStack(value.asCell()); }
JSValue JSInjectedScriptHost::functionDetails(ExecState* exec) { if (exec->argumentCount() < 1) return jsUndefined(); JSValue value = exec->argument(0); if (!value.asCell()->inherits(&JSFunction::s_info)) return jsUndefined(); JSFunction* function = jsCast<JSFunction*>(value); const SourceCode* sourceCode = function->sourceCode(); if (!sourceCode) return jsUndefined(); int lineNumber = sourceCode->firstLine(); if (lineNumber) lineNumber -= 1; // In the inspector protocol all positions are 0-based while in SourceCode they are 1-based UString scriptId = UString::number(sourceCode->provider()->asID()); JSObject* location = constructEmptyObject(exec); location->putDirect(exec->globalData(), Identifier(exec, "lineNumber"), jsNumber(lineNumber)); location->putDirect(exec->globalData(), Identifier(exec, "scriptId"), jsString(exec, scriptId)); JSObject* result = constructEmptyObject(exec); result->putDirect(exec->globalData(), Identifier(exec, "location"), location); UString name = function->name(exec); if (!name.isEmpty()) result->putDirect(exec->globalData(), Identifier(exec, "name"), jsString(exec, name)); UString displayName = function->displayName(exec); if (!displayName.isEmpty()) result->putDirect(exec->globalData(), Identifier(exec, "displayName"), jsString(exec, displayName)); // FIXME: provide function scope data in "scopesRaw" property when JSC supports it. // https://bugs.webkit.org/show_bug.cgi?id=87192 return result; }
bool Structure::prototypeChainMayInterceptStoreTo(JSGlobalData& globalData, PropertyName propertyName) { unsigned i = propertyName.asIndex(); if (i != PropertyName::NotAnIndex) return anyObjectInChainMayInterceptIndexedAccesses(); for (Structure* current = this; ;) { JSValue prototype = current->storedPrototype(); if (prototype.isNull()) return false; current = prototype.asCell()->structure(); unsigned attributes; JSCell* specificValue; PropertyOffset offset = current->get(globalData, propertyName, attributes, specificValue); if (!JSC::isValidOffset(offset)) continue; if (attributes & (ReadOnly | Accessor)) return true; return false; } }
CallLinkStatus::CallLinkStatus(JSValue value) : m_callTarget(value) , m_executable(0) , m_structure(0) , m_couldTakeSlowPath(false) , m_isProved(false) { if (!value || !value.isCell()) return; m_structure = value.asCell()->structure(); if (!value.asCell()->inherits(&JSFunction::s_info)) return; m_executable = jsCast<JSFunction*>(value.asCell())->executable(); }
void SamplingProfiler::processUnverifiedStackTraces() { // This function needs to be called from the JSC execution thread. RELEASE_ASSERT(m_lock.isLocked()); TinyBloomFilter filter = m_vm.heap.objectSpace().blocks().filter(); MarkedBlockSet& markedBlockSet = m_vm.heap.objectSpace().blocks(); for (unsigned i = m_indexOfNextStackTraceToVerify; i < m_stackTraces.size(); i++) { StackTrace& stackTrace = m_stackTraces[i]; if (!stackTrace.needsVerification) continue; stackTrace.needsVerification = false; for (StackFrame& stackFrame : stackTrace.frames) { if (stackFrame.frameType != FrameType::UnverifiedCallee) { RELEASE_ASSERT(stackFrame.frameType == FrameType::VerifiedExecutable); continue; } JSValue callee = JSValue::decode(stackFrame.u.unverifiedCallee); if (!Heap::isValueGCObject(filter, markedBlockSet, callee)) { stackFrame.frameType = FrameType::Unknown; continue; } JSCell* calleeCell = callee.asCell(); auto frameTypeFromCallData = [&] () -> FrameType { FrameType result = FrameType::Unknown; CallData callData; CallType callType; callType = getCallData(calleeCell, callData); if (callType == CallTypeHost) result = FrameType::Host; return result; }; if (calleeCell->type() != JSFunctionType) { stackFrame.frameType = frameTypeFromCallData(); continue; } ExecutableBase* executable = static_cast<JSFunction*>(calleeCell)->executable(); if (!executable) { stackFrame.frameType = frameTypeFromCallData(); continue; } RELEASE_ASSERT(Heap::isPointerGCObject(filter, markedBlockSet, executable)); stackFrame.frameType = FrameType::VerifiedExecutable; stackFrame.u.verifiedExecutable = executable; m_seenExecutables.add(executable); } } m_indexOfNextStackTraceToVerify = m_stackTraces.size(); }
void RegisterFile::gatherConservativeRoots(ConservativeRoots& conservativeRoots) { for (Register* it = start(); it != end(); ++it) { JSValue v = it->jsValue(); if (!v.isCell()) continue; conservativeRoots.add(v.asCell()); } }
void HandleHeap::protectedObjectTypeCounts(TypeCounter& typeCounter) { Node* end = m_strongList.end(); for (Node* node = m_strongList.begin(); node != end; node = node->next()) { JSValue value = *node->slot(); if (value && value.isCell()) typeCounter(value.asCell()); } }
EncodedJSValue JSC_HOST_CALL constructJSDataCue(ExecState* exec) { DOMConstructorObject* castedThis = jsCast<DOMConstructorObject*>(exec->callee()); if (exec->argumentCount() < 3) return throwVMError(exec, createNotEnoughArgumentsError(exec)); ExceptionCode ec = 0; double startTime(exec->argument(0).toNumber(exec)); if (UNLIKELY(exec->hadException())) return JSValue::encode(jsUndefined()); double endTime(exec->argument(1).toNumber(exec)); if (UNLIKELY(exec->hadException())) return JSValue::encode(jsUndefined()); ScriptExecutionContext* context = castedThis->scriptExecutionContext(); if (!context) return throwConstructorDocumentUnavailableError(*exec, "DataCue"); String type; #if ENABLE(DATACUE_VALUE) if (exec->argumentCount() > 3) { if (!exec->argument(3).isString()) return throwVMError(exec, createTypeError(exec, "Second argument of the constructor is not of type String")); type = exec->argument(3).getString(exec); } #endif JSValue valueArgument = exec->argument(2); if (valueArgument.isUndefinedOrNull()) { setDOMException(exec, TypeError); return JSValue::encode(JSValue()); } RefPtr<DataCue> object; if (valueArgument.isCell() && valueArgument.asCell()->inherits(std::remove_pointer<JSArrayBuffer*>::type::info())) { ArrayBuffer* data(toArrayBuffer(valueArgument)); if (UNLIKELY(exec->hadException())) return JSValue::encode(jsUndefined()); object = DataCue::create(*context, startTime, endTime, data, type, ec); if (ec) { setDOMException(exec, ec); return JSValue::encode(JSValue()); } return JSValue::encode(asObject(toJS(exec, castedThis->globalObject(), object.get()))); } #if !ENABLE(DATACUE_VALUE) return JSValue::encode(jsUndefined()); #else object = DataCue::create(*context, startTime, endTime, valueArgument, type); return JSValue::encode(asObject(toJS(exec, castedThis->globalObject(), object.get()))); #endif }
void Heap::protect(JSValue k) { ASSERT(k); ASSERT(m_vm->currentThreadIsHoldingAPILock()); if (!k.isCell()) return; m_protectedValues.add(k.asCell()); }
bool Heap::unprotect(JSValue k) { ASSERT(k); ASSERT(m_globalData->apiLock().currentThreadIsHoldingLock()); if (!k.isCell()) return false; return m_protectedValues.remove(k.asCell()); }
bool Heap::unprotect(JSValue k) { ASSERT(k); ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance()); if (!k.isCell()) return false; return m_protectedValues.remove(k.asCell()); }
static ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double& x) { if (thisValue.isInt32()) { x = thisValue.asInt32(); return true; } if (thisValue.isDouble()) { x = thisValue.asDouble(); return true; } if (thisValue.isCell() && thisValue.asCell()->type() == NumberObjectType) { x = static_cast<const NumberObject*>(thisValue.asCell())->internalValue().asNumber(); return true; } return false; }
void Heap::protect(JSValue k) { ASSERT(k); ASSERT(m_globalData->apiLock().currentThreadIsHoldingLock()); if (!k.isCell()) return; m_protectedValues.add(k.asCell()); }
static JSObject* callRuntimeConstructor(ExecState* exec, JSObject* constructor, const ArgList& args) { RefPtr<Instance> instance(static_cast<RuntimeObject*>(constructor)->getInternalInstance()); instance->begin(); JSValue result = instance->invokeConstruct(exec, args); instance->end(); ASSERT(result); return result.isObject() ? static_cast<JSObject*>(result.asCell()) : constructor; }
void Heap::protect(JSValue k) { ASSERT(k); ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance()); if (!k.isCell()) return; m_protectedValues.add(k.asCell()); }
bool Heap::unprotect(JSValue k) { ASSERT(k); ASSERT(m_vm->currentThreadIsHoldingAPILock()); if (!k.isCell()) return false; return m_protectedValues.remove(k.asCell()); }
CallLinkStatus::CallLinkStatus(JSValue value) : m_couldTakeSlowPath(false) , m_isProved(false) { if (!value || !value.isCell()) { m_couldTakeSlowPath = true; return; } m_variants.append(CallVariant(value.asCell())); }
unsigned HandleHeap::protectedGlobalObjectCount() { unsigned count = 0; Node* end = m_strongList.end(); for (Node* node = m_strongList.begin(); node != end; node = node->next()) { JSValue value = *node->slot(); if (value.isObject() && asObject(value.asCell())->isGlobalObject()) count++; } return count; }
PredictedType predictionFromValue(JSValue value) { if (value.isInt32()) return PredictInt32; if (value.isDouble()) return PredictDouble; if (value.isCell()) return predictionFromCell(value.asCell()); if (value.isBoolean()) return PredictBoolean; ASSERT(value.isUndefinedOrNull()); return PredictOther; }
ALWAYS_INLINE void SlotVisitor::internalAppend(JSValue* slot) { // This internalAppend is only intended for visits to object and array backing stores. // as it can change the JSValue pointed to be the argument when the original JSValue // is a string that contains the same contents as another string. StackStats::probe(); ASSERT(slot); JSValue value = *slot; ASSERT(value); if (!value.isCell()) return; JSCell* cell = value.asCell(); if (!cell) return; validate(cell); if (m_shouldHashCons && cell->isString()) { JSString* string = jsCast<JSString*>(cell); if (string->shouldTryHashCons() && string->tryHashConsLock()) { UniqueStringMap::AddResult addResult = m_uniqueStrings.add(string->string().impl(), value); if (addResult.isNewEntry) string->setHashConsSingleton(); else { JSValue existingJSValue = addResult.iterator->value; if (value != existingJSValue) jsCast<JSString*>(existingJSValue.asCell())->clearHashConsSingleton(); *slot = existingJSValue; string->releaseHashConsLock(); return; } string->releaseHashConsLock(); } } internalAppend(cell); }
static EncodedJSValue JSC_HOST_CALL callRuntimeConstructor(ExecState* exec) { JSObject* constructor = exec->callee(); ASSERT(constructor->inherits(RuntimeObject::info())); RefPtr<Instance> instance(static_cast<RuntimeObject*>(exec->callee())->getInternalInstance()); instance->begin(); ArgList args(exec); JSValue result = instance->invokeConstruct(exec, args); instance->end(); ASSERT(result); return JSValue::encode(result.isObject() ? jsCast<JSObject*>(result.asCell()) : constructor); }
void MarkStack::drain() { #if !ASSERT_DISABLED ASSERT(!m_isDraining); m_isDraining = true; #endif while (!m_markSets.isEmpty() || !m_values.isEmpty()) { while (!m_markSets.isEmpty() && m_values.size() < 50) { ASSERT(!m_markSets.isEmpty()); MarkSet& current = m_markSets.last(); ASSERT(current.m_values); JSValue* end = current.m_end; ASSERT(current.m_values); ASSERT(current.m_values != end); findNextUnmarkedNullValue: ASSERT(current.m_values != end); JSValue value = *current.m_values; current.m_values++; JSCell* cell; if (!value || !value.isCell() || Heap::testAndSetMarked(cell = value.asCell())) { if (current.m_values == end) { m_markSets.removeLast(); continue; } goto findNextUnmarkedNullValue; } if (cell->structure()->typeInfo().type() < CompoundType) { cell->JSCell::visitChildren(*this); if (current.m_values == end) { m_markSets.removeLast(); continue; } goto findNextUnmarkedNullValue; } if (current.m_values == end) m_markSets.removeLast(); visitChildren(cell); } while (!m_values.isEmpty()) visitChildren(m_values.removeLast()); } #if !ASSERT_DISABLED m_isDraining = false; #endif }
void HighFidelityLog::recordTypeInformationForLocation(JSValue v, TypeLocation* location) { ASSERT(m_logStartPtr); ASSERT(m_currentOffset < m_highFidelityLogSize); LogEntry* entry = m_logStartPtr + m_currentOffset; entry->location = location; entry->value = v; entry->structure = (v.isCell() ? v.asCell()->structure() : nullptr); m_currentOffset += 1; if (m_currentOffset == m_highFidelityLogSize) processHighFidelityLog(true, "Log Full"); }
EncodedJSValue JSC_HOST_CALL typedArrayViewPrivateFuncLength(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSValue argument = exec->argument(0); if (!argument.isCell() || !isTypedView(argument.asCell()->classInfo()->typedArrayStorageType)) return throwVMTypeError(exec, scope, ASCIILiteral("Receiver should be a typed array view")); JSArrayBufferView* thisObject = jsCast<JSArrayBufferView*>(argument); if (thisObject->isNeutered()) return throwVMTypeError(exec, scope, ASCIILiteral("Underlying ArrayBuffer has been detached from the view")); return JSValue::encode(jsNumber(thisObject->length())); }