String HeapSnapshotBuilder::descriptionForCell(JSCell *cell) const
{
    if (cell->isString())
        return emptyString(); // FIXME: get part of string.

    VM& vm = m_profiler.vm();
    Structure* structure = cell->structure(vm);

    if (structure->classInfo()->isSubClassOf(Structure::info())) {
        Structure* cellAsStructure = jsCast<Structure*>(cell);
        return cellAsStructure->classInfo()->className;
    }

    return emptyString();
}
inline Structure* getBoundFunctionStructure(VM& vm, ExecState* exec, JSGlobalObject* globalObject, JSObject* targetFunction)
{
    auto scope = DECLARE_THROW_SCOPE(vm);
    JSValue prototype = targetFunction->getPrototype(vm, exec);
    RETURN_IF_EXCEPTION(scope, nullptr);
    JSFunction* targetJSFunction = jsDynamicCast<JSFunction*>(vm, targetFunction);

    // We only cache the structure of the bound function if the bindee is a JSFunction since there
    // isn't any good place to put the structure on Internal Functions.
    if (targetJSFunction) {
        Structure* structure = targetJSFunction->rareData(vm)->getBoundFunctionStructure();
        if (structure && structure->storedPrototype() == prototype && structure->globalObject() == globalObject)
            return structure;
    }

    Structure* result = globalObject->boundFunctionStructure();

    // It would be nice if the structure map was keyed global objects in addition to the other things. Unfortunately, it is not
    // currently. Whoever works on caching structure changes for prototype transistions should consider this problem as well.
    // See: https://bugs.webkit.org/show_bug.cgi?id=152738
    if (prototype.isObject() && prototype.getObject()->globalObject() == globalObject) {
        result = vm.prototypeMap.emptyStructureForPrototypeFromBaseStructure(globalObject, prototype.getObject(), result);
        ASSERT_WITH_SECURITY_IMPLICATION(result->globalObject() == globalObject);
    } else
        result = Structure::create(vm, globalObject, prototype, result->typeInfo(), result->classInfo());

    if (targetJSFunction)
        targetJSFunction->rareData(vm)->setBoundFunctionStructure(vm, result);

    return result;
}
// In future we may want to cache this transition.
Structure* Structure::freezeTransition(VM& vm, Structure* structure)
{
    Structure* transition = preventExtensionsTransition(vm, structure);

    if (transition->propertyTable()) {
        PropertyTable::iterator iter = transition->propertyTable()->begin();
        PropertyTable::iterator end = transition->propertyTable()->end();
        if (iter != end)
            transition->setHasReadOnlyOrGetterSetterPropertiesExcludingProto(true);
        for (; iter != end; ++iter)
            iter->attributes |= iter->attributes & Accessor ? DontDelete : (DontDelete | ReadOnly);
    }

    ASSERT(transition->hasReadOnlyOrGetterSetterPropertiesExcludingProto() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties());
    ASSERT(transition->hasGetterSetterProperties() || !transition->classInfo()->hasStaticSetterOrReadonlyProperties());
    transition->checkOffsetConsistency();
    return transition;
}
Exemple #4
0
void HeapVerifier::reportObject(LiveObjectData& objData, int cycleIndex, HeapVerifier::GCCycle& cycle, LiveObjectList& list)
{
    JSObject* obj = objData.obj;

    if (objData.isConfirmedDead) {
        dataLogF("FOUND dead obj %p in GC[%d] %s list '%s'\n",
            obj, cycleIndex, cycle.collectionTypeName(), list.name);
        return;
    }

    Structure* structure = obj->structure();
    Butterfly* butterfly = obj->butterfly();
    void* butterflyBase;
    size_t butterflyCapacityInBytes;
    CopiedBlock* butterflyBlock;
    getButterflyDetails(obj, butterflyBase, butterflyCapacityInBytes, butterflyBlock);

    dataLogF("FOUND obj %p type '%s' butterfly %p (base %p size %zu block %p) in GC[%d] %s list '%s'\n",
        obj, structure->classInfo()->className,
        butterfly, butterflyBase, butterflyCapacityInBytes, butterflyBlock,
        cycleIndex, cycle.collectionTypeName(), list.name);
}
Exemple #5
0
bool HeapVerifier::verifyButterflyIsInStorageSpace(Phase phase, LiveObjectList& list)
{
    auto& liveObjects = list.liveObjects;

    CopiedSpace& storageSpace = m_heap->m_storageSpace;
    bool listNamePrinted = false;
    bool success = true;
    for (size_t i = 0; i < liveObjects.size(); i++) {
        LiveObjectData& objectData = liveObjects[i];
        if (objectData.isConfirmedDead)
            continue;

        JSObject* obj = objectData.obj;
        Butterfly* butterfly = obj->butterfly();
        if (butterfly) {
            void* butterflyBase;
            size_t butterflyCapacityInBytes;
            CopiedBlock* butterflyBlock;
            getButterflyDetails(obj, butterflyBase, butterflyCapacityInBytes, butterflyBlock);

            if (!storageSpace.contains(butterflyBlock)) {
                if (!listNamePrinted) {
                    dataLogF("Verification @ phase %s FAILED in object list '%s' (size %zu)\n",
                        phaseName(phase), list.name, liveObjects.size());
                    listNamePrinted = true;
                }

                Structure* structure = obj->structure();
                const char* structureClassName = structure->classInfo()->className;
                dataLogF("    butterfly %p (base %p size %zu block %p) NOT in StorageSpace | obj %p type '%s'\n",
                    butterfly, butterflyBase, butterflyCapacityInBytes, butterflyBlock, obj, structureClassName);
                success = false;
            }
        }
    }
    return success;
}
Exemple #6
0
Structure* InternalFunction::createSubclassStructure(ExecState* exec, JSValue newTarget, Structure* baseClass)
{

    VM& vm = exec->vm();
    // We allow newTarget == JSValue() because the API needs to be able to create classes without having a real JS frame.
    // Since we don't allow subclassing in the API we just treat newTarget == JSValue() as newTarget == exec->callee()
    ASSERT(!newTarget || newTarget.isConstructor());

    if (newTarget && newTarget != exec->callee()) {
        // newTarget may be an InternalFunction if we were called from Reflect.construct.
        JSFunction* targetFunction = jsDynamicCast<JSFunction*>(newTarget);

        if (LIKELY(targetFunction)) {
            Structure* structure = targetFunction->rareData(vm)->internalFunctionAllocationStructure();
            if (LIKELY(structure && structure->classInfo() == baseClass->classInfo()))
                return structure;

            // Note, Reflect.construct might cause the profile to churn but we don't care.
            JSValue prototypeValue = newTarget.get(exec, exec->propertyNames().prototype);
            if (UNLIKELY(vm.exception()))
                return nullptr;
            if (JSObject* prototype = jsDynamicCast<JSObject*>(prototypeValue))
                return targetFunction->rareData(vm)->createInternalFunctionAllocationStructureFromBase(vm, prototype, baseClass);
        } else {
            JSValue prototypeValue = newTarget.get(exec, exec->propertyNames().prototype);
            if (UNLIKELY(vm.exception()))
                return nullptr;
            if (JSObject* prototype = jsDynamicCast<JSObject*>(prototypeValue)) {
                // This only happens if someone Reflect.constructs our builtin constructor with another builtin constructor as the new.target.
                // Thus, we don't care about the cost of looking up the structure from our hash table every time.
                return vm.prototypeMap.emptyStructureForPrototypeFromBaseStructure(prototype, baseClass);
            }
        }
    }
    
    return baseClass;
}