Exemple #1
0
void SlotVisitor::append(JSValue value)
{
    if (!value || !value.isCell())
        return;

    if (UNLIKELY(m_heapSnapshotBuilder))
        m_heapSnapshotBuilder->appendEdge(m_currentCell, value.asCell());

    setMarkedAndAppendToMarkStack(value.asCell());
}
Exemple #2
0
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;
}
Exemple #3
0
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;
}
Exemple #6
0
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));
}
Exemple #7
0
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;
}
Exemple #9
0
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;
    }
}
Exemple #10
0
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();
}
Exemple #11
0
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());
    }
}
Exemple #14
0
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
}
Exemple #15
0
void Heap::protect(JSValue k)
{
    ASSERT(k);
    ASSERT(m_vm->currentThreadIsHoldingAPILock());

    if (!k.isCell())
        return;

    m_protectedValues.add(k.asCell());
}
Exemple #16
0
bool Heap::unprotect(JSValue k)
{
    ASSERT(k);
    ASSERT(m_globalData->apiLock().currentThreadIsHoldingLock());

    if (!k.isCell())
        return false;

    return m_protectedValues.remove(k.asCell());
}
Exemple #17
0
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;
}
Exemple #19
0
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;
}
Exemple #21
0
void Heap::protect(JSValue k)
{
    ASSERT(k);
    ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance());

    if (!k.isCell())
        return;

    m_protectedValues.add(k.asCell());
}
Exemple #22
0
bool Heap::unprotect(JSValue k)
{
    ASSERT(k);
    ASSERT(m_vm->currentThreadIsHoldingAPILock());

    if (!k.isCell())
        return false;

    return m_protectedValues.remove(k.asCell());
}
Exemple #23
0
CallLinkStatus::CallLinkStatus(JSValue value)
    : m_couldTakeSlowPath(false)
    , m_isProved(false)
{
    if (!value || !value.isCell()) {
        m_couldTakeSlowPath = true;
        return;
    }
    
    m_variants.append(CallVariant(value.asCell()));
}
Exemple #24
0
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;
}
Exemple #25
0
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;
}
Exemple #26
0
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);
}
Exemple #27
0
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);
}
Exemple #28
0
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
}
Exemple #29
0
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()));
}