Exemplo n.º 1
0
static void testStringSet()
{
	enum { numStrings = 1000 };

	HashSet<std::string> set;
	std::vector<std::string> strings;

	srand(0);

	for(Uptr i = 0;i < numStrings;++i)
	{
		while(true)
		{
			std::string randomString = generateRandomString();

			bool alreadySawString = false;
			for(const std::string& string : strings)
			{
				if(string == randomString)
				{
					alreadySawString = true;
					break;
				}
			}

			if(!alreadySawString)
			{
				strings.push_back(std::move(randomString));
				break;
			}
		};
	}

	for(Uptr i = 0;i < strings.size();++i)
	{
		errorUnless(set.add(strings[i]));
		errorUnless(!set.add(strings[i]));

		for(Uptr j = 0;j < strings.size();++j)
		{
			const bool expectedContains = j <= i;
			errorUnless(set.contains(strings[j]) == expectedContains);
		}
	}

	for(Uptr i = 0;i < strings.size();++i)
	{
		errorUnless(set.remove(strings[i]));
		errorUnless(!set.remove(strings[i]));

		for(Uptr j = 0;j < strings.size();++j)
		{
			const bool expectedContains = j > i;
			errorUnless(set.contains(strings[j]) == expectedContains);
		}
	}
}
Exemplo n.º 2
0
void RadioButtonGroup::remove(HTMLInputElement* button)
{
    ASSERT(button->isRadioButton());
    HashSet<HTMLInputElement*>::iterator it = m_members.find(button);
    if (it == m_members.end())
        return;

    bool wasValid = isValid();
    m_members.remove(it);
    if (button->isRequired()) {
        ASSERT(m_requiredCount);
        --m_requiredCount;
    }
    if (m_checkedButton) {
        button->setNeedsStyleRecalc();
        if (m_checkedButton == button) {
            m_checkedButton = nullptr;
            setNeedsStyleRecalcForAllButtons();
        }
    }

    if (m_members.isEmpty()) {
        ASSERT(!m_requiredCount);
        ASSERT(!m_checkedButton);
    } else if (wasValid != isValid())
        updateValidityForAllButtons();
    if (!wasValid) {
        // A radio button not in a group is always valid. We need to make it
        // valid only if the group was invalid.
        button->updateValidity();
    }
}
Exemplo n.º 3
0
void WebProcessTest::assertObjectIsDeletedWhenTestFinishes(GObject* object)
{
    s_watchedObjects.add(object);
    g_object_weak_ref(object, [](gpointer, GObject* finalizedObject) {
        s_watchedObjects.remove(finalizedObject);
    }, nullptr);
}
Exemplo n.º 4
0
TEST(FileSystemIterator, multipleFiles)
{
    TestDirectory rootDir(File("foobarfolder"));
    rootDir.addFile("foobar1.txt");
    rootDir.addFile("foobar2.txt");
    rootDir.addFile("foobar3.txt");
    rootDir.addFile("foobar4.txt");
    rootDir.addFile("foobar5.txt");

    HashSet<String> filenames;
    filenames.put("foobar1.txt");
    filenames.put("foobar2.txt");
    filenames.put("foobar3.txt");
    filenames.put("foobar4.txt");
    filenames.put("foobar5.txt");


    FileSystemIterator iter(rootDir.getFile());
    while (iter.isValid())
    {
        EXPECT_TRUE(filenames.hasElement(iter->getFileName()));
        filenames.remove(iter->getFileName());
        iter.next();
    }
    EXPECT_EQ(0u, filenames.count());
}
Exemplo n.º 5
0
static void testSetIterator()
{
	// Add 1..9 to a HashSet.
	HashSet<Uptr> a;
	for(Uptr i = 1;i < 10;++i)
	{
		a.add(i);
	}

	// 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 = 45
	{
		Uptr sum = 0;
		for(Uptr i : a)
		{
			sum += i;
		}
		errorUnless(sum == 45);
	}

	// Remove 5.
	a.remove(5);
	
	// 1 + 2 + 3 + 4 + 6 + 7 + 8 + 9 = 40
	{
		Uptr sum = 0;
		for(Uptr i : a)
		{
			sum += i;
		}
		errorUnless(sum == 40);
	}
}
Exemplo n.º 6
0
static void testU32Set()
{
	HashSet<U32> set;

	enum { maxI = 1024 * 1024 };

	for(Uptr i = 0;i < maxI;++i)
	{
		errorUnless(!set.contains(U32(i)));
	}

	errorUnless(set.size() == 0);
	for(Uptr i = 0;i < maxI;++i)
	{
		errorUnless(!set.contains(U32(i)));
		errorUnless(!set.get(U32(i)));
		errorUnless(set.add(U32(i)));
		errorUnless(set.contains(U32(i)));
		errorUnless(set.get(U32(i)));
		errorUnless(set.size() == i + 1);
	}

	for(Uptr i = 0;i < maxI;++i)
	{
		errorUnless(set.contains(U32(i)));
		errorUnless(set.remove(U32(i)));
		errorUnless(!set.contains(U32(i)));
		errorUnless(set.size() == maxI - i - 1);
	}

	for(Uptr i = 0;i < maxI;++i)
	{
		errorUnless(!set.contains(U32(i)));
	}
}
Exemplo n.º 7
0
void
js::gc::TraceTenuredFinalize(Cell *thing)
{
    if (!gcTraceFile)
        return;
    if (thing->tenuredGetAllocKind() == FINALIZE_OBJECT_GROUP)
        tracedGroups.remove(static_cast<const ObjectGroup *>(thing));
    TraceEvent(TraceEventTenuredFinalize, uint64_t(thing));
}
Exemplo n.º 8
0
static void webkit_web_view_container_remove(GtkContainer* container, GtkWidget* widget)
{
    //WebKitWebView* webView = WEBKIT_WEB_VIEW(container);
    ////WebKitWebViewPrivate* priv = webView->priv;

    if (children.contains(widget)) {
        gtk_widget_unparent(widget);
        children.remove(widget);
    }
}
void SharedWorkerProxy::documentDetached(Document* document)
{
    if (isClosing())
        return;
    // Remove the document from our set (if it's there) and if that was the last document in the set, mark the proxy as closed.
    MutexLocker lock(m_workerDocumentsLock);
    m_workerDocuments.remove(document);
    if (!m_workerDocuments.size())
        close();
}
Exemplo n.º 10
0
void PluginDatabase::getPluginPathsInDirectories(HashSet<String>& paths) const
{
    // FIXME: This should be a case insensitive set.
    HashSet<String> uniqueFilenames;

    HANDLE hFind = INVALID_HANDLE_VALUE;
    WIN32_FIND_DATAW findFileData;

    String oldWMPPluginPath;
    String newWMPPluginPath;

    Vector<String>::const_iterator end = m_pluginDirectories.end();
    for (Vector<String>::const_iterator it = m_pluginDirectories.begin(); it != end; ++it) {
        String pattern = *it + "\\*";

        hFind = FindFirstFileW(pattern.charactersWithNullTermination(), &findFileData);

        if (hFind == INVALID_HANDLE_VALUE)
            continue;

        do {
            if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
                continue;

            String filename = String(findFileData.cFileName, wcslen(findFileData.cFileName));
            if ((!filename.startsWith("np", false) || !filename.endsWith("dll", false)) &&
                (!equalIgnoringCase(filename, "Plugin.dll") || !it->endsWith("Shockwave 10", false)))
                continue;

            String fullPath = *it + "\\" + filename;
            if (!uniqueFilenames.add(fullPath).second)
                continue;

            paths.add(fullPath);

            if (equalIgnoringCase(filename, "npdsplay.dll"))
                oldWMPPluginPath = fullPath;
            else if (equalIgnoringCase(filename, "np-mswmp.dll"))
                newWMPPluginPath = fullPath;

        } while (FindNextFileW(hFind, &findFileData) != 0);

        FindClose(hFind);
    }

    addPluginPathsFromRegistry(HKEY_LOCAL_MACHINE, paths);
    addPluginPathsFromRegistry(HKEY_CURRENT_USER, paths);

    // If both the old and new WMP plugin are present in the plugins set, 
    // we remove the old one so we don't end up choosing the old one.
    if (!oldWMPPluginPath.isEmpty() && !newWMPPluginPath.isEmpty())
        paths.remove(oldWMPPluginPath);
}
Exemplo n.º 11
0
void JavaScriptDebugServer::removeBreakpoint(int sourceID, unsigned lineNumber)
{
    HashSet<unsigned>* lines = m_breakpoints.get(sourceID);
    if (!lines)
        return;

    lines->remove(lineNumber);

    if (!lines->isEmpty())
        return;

    m_breakpoints.remove(sourceID);
    delete lines;
}
Exemplo n.º 12
0
TEST(FileSystemIterator, defaultAcceptTest)
{
    // setup
    TestDirectory rootDir(File("foobarfolder"));
    rootDir.addFile("foobar1.txt");
    rootDir.addDirectory("foobar")->addFile("foobar2.txt");


    HashSet<String> filenames;
    filenames.put("foobar1.txt");
    filenames.put("foobar");
    filenames.put("foobar2.txt");

    FileSystemIterator iter(rootDir.getFile());

    EXPECT_TRUE(iter.isValid());
    EXPECT_TRUE(filenames.hasElement(iter->getFileName()));
    filenames.remove(iter->getFileName());

    EXPECT_TRUE(iter.next());
    EXPECT_TRUE(filenames.hasElement(iter->getFileName()));
    filenames.remove(iter->getFileName());

    EXPECT_TRUE(iter.next());
    EXPECT_TRUE(filenames.hasElement(iter->getFileName()));
    filenames.remove(iter->getFileName());

    EXPECT_EQ(0u, filenames.count());

    EXPECT_FALSE(iter.next());
    EXPECT_FALSE(iter.isValid());


    // iterate again, but don't finish
    FileSystemIterator iter2(rootDir.getFile());
}
Exemplo n.º 13
0
int _tmain(int argc, _TCHAR* argv[])
{

	HashSet myHashSet;
	for (int i=0; i<30; i++)
	{
		myHashSet.insert(i);
	}

	cout<<"The HashSet:"<<endl;
	myHashSet.printHashSet(cout);
	cout<<"The number 0 exists?"<<"\t"<<myHashSet.exists(0)<<endl;
	cout<<"The number 30 exists?"<<"\t"<<myHashSet.exists(30)<<endl;
	cout<<"insert 40:"<<myHashSet.insert(40)<<endl;
	myHashSet.printHashSet(cout);
	cout<<"insert 10:"<<myHashSet.insert(10)<<endl;
	myHashSet.printHashSet(cout);
	cout<<"delete 40:"<<myHashSet.remove(40)<<endl;
	myHashSet.printHashSet(cout);
	cout<<"delete 50:"<<myHashSet.remove(50)<<endl;
	myHashSet.printHashSet(cout);

	return 0;
}
Exemplo n.º 14
0
void DisplayRefreshMonitor::displayDidRefresh()
{
    double monotonicAnimationStartTime;
    {
        MutexLocker lock(m_mutex);
        if (!m_scheduled)
            ++m_unscheduledFireCount;
        else
            m_unscheduledFireCount = 0;

        m_scheduled = false;
        monotonicAnimationStartTime = m_monotonicAnimationStartTime;
    }

    // The call back can cause all our clients to be unregistered, so we need to protect
    // against deletion until the end of the method.
    Ref<DisplayRefreshMonitor> protect(*this);

    // Copy the hash table and remove clients from it one by one so we don't notify
    // any client twice, but can respond to removal of clients during the delivery process.
    HashSet<DisplayRefreshMonitorClient*> clientsToBeNotified = m_clients;
    m_clientsToBeNotified = &clientsToBeNotified;
    while (!clientsToBeNotified.isEmpty()) {
        // Take a random client out of the set. Ordering doesn't matter.
        // FIXME: Would read more cleanly if HashSet had a take function.
        auto it = clientsToBeNotified.begin();
        DisplayRefreshMonitorClient* client = *it;
        clientsToBeNotified.remove(it);

        client->fireDisplayRefreshIfNeeded(monotonicAnimationStartTime);

        // This checks if this function was reentered. In that case, stop iterating
        // since it's not safe to use the set any more.
        if (m_clientsToBeNotified != &clientsToBeNotified)
            break;
    }
    if (m_clientsToBeNotified == &clientsToBeNotified)
        m_clientsToBeNotified = nullptr;

    {
        MutexLocker lock(m_mutex);
        m_previousFrameDone = true;
    }
    
    DisplayRefreshMonitorManager::sharedManager()->displayDidRefresh(this);
}
Exemplo n.º 15
0
void SVGDocumentExtensions::removeAnimationElementFromTarget(SVGSMILElement* animationElement, SVGElement* targetElement)
{
    ASSERT(targetElement);
    ASSERT(animationElement);

    HashMap<SVGElement*, HashSet<SVGSMILElement*>* >::iterator it = m_animatedElements.find(targetElement);
    ASSERT(it != m_animatedElements.end());
    
    HashSet<SVGSMILElement*>* animationElementsForTarget = it->value;
    ASSERT(!animationElementsForTarget->isEmpty());

    animationElementsForTarget->remove(animationElement);
    if (animationElementsForTarget->isEmpty()) {
        m_animatedElements.remove(it);
        delete animationElementsForTarget;
    }
}
Exemplo n.º 16
0
void SVGDocumentExtensions::removeAllTargetReferencesForElement(SVGElement* referencingElement)
{
    Vector<SVGElement*> toBeRemoved;

    HashMap<SVGElement*, OwnPtr<HashSet<SVGElement*> > >::iterator end = m_elementDependencies.end();
    for (HashMap<SVGElement*, OwnPtr<HashSet<SVGElement*> > >::iterator it = m_elementDependencies.begin(); it != end; ++it) {
        SVGElement* referencedElement = it->key;
        HashSet<SVGElement*>* referencingElements = it->value.get();
        HashSet<SVGElement*>::iterator setIt = referencingElements->find(referencingElement);
        if (setIt == referencingElements->end())
            continue;

        referencingElements->remove(setIt);
        if (referencingElements->isEmpty())
            toBeRemoved.append(referencedElement);
    }

    m_elementDependencies.removeAll(toBeRemoved);
}
Exemplo n.º 17
0
TEST(WTF_HashSet, UniquePtrKey_RemoveUsingRawPointer)
{
    ConstructorDestructorCounter::TestingScope scope;

    HashSet<std::unique_ptr<ConstructorDestructorCounter>> set;

    auto uniquePtr = std::make_unique<ConstructorDestructorCounter>();
    ConstructorDestructorCounter* ptr = uniquePtr.get();
    set.add(WTF::move(uniquePtr));

    EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
    EXPECT_EQ(0u, ConstructorDestructorCounter::destructionCount);

    bool result = set.remove(ptr);
    EXPECT_EQ(true, result);

    EXPECT_EQ(1u, ConstructorDestructorCounter::constructionCount);
    EXPECT_EQ(1u, ConstructorDestructorCounter::destructionCount);
}
Exemplo n.º 18
0
void AbstractDatabase::closeDatabase()
{
    if (!m_opened)
        return;

    m_sqliteDatabase.close();
    m_opened = false;
    {
        MutexLocker locker(guidMutex());

        HashSet<AbstractDatabase*>* hashSet = guidToDatabaseMap().get(m_guid);
        ASSERT(hashSet);
        ASSERT(hashSet->contains(this));
        hashSet->remove(this);
        if (hashSet->isEmpty()) {
            guidToDatabaseMap().remove(m_guid);
            delete hashSet;
            guidToVersionMap().remove(m_guid);
        }
    }
}
Exemplo n.º 19
0
static void testSetCopy()
{
	// Add 1000..1999 to a HashSet.
	HashSet<Uptr> a;
	for(Uptr i = 0;i < 1000;++i)
	{
		a.add(i + 1000);
	}

	// Copy the set to a new HashSet.
	HashSet<Uptr> b {a};

	// Test that both the new and old HashSet contain the expected numbers.
	for(Uptr i = 0;i < 1000;++i)
	{
		errorUnless(!a.contains(i));
		errorUnless(a.contains(i + 1000));
		errorUnless(!a.contains(i + 2000));
		
		errorUnless(!b.contains(i));
		errorUnless(b.contains(i + 1000));
		errorUnless(!b.contains(i + 2000));
	}
	
	// Test copying a set from itself.
	b = b;
	
	// Test that the set wasn't changed by the copy-to-self.
	for(Uptr i = 0;i < 1000;++i)
	{
		errorUnless(!b.contains(i));
		errorUnless(b.contains(i + 1000));
		errorUnless(!b.contains(i + 2000));
	}

	// Test removing an element from the set.
	b.remove(1000);
	errorUnless(a.contains(1000));
	errorUnless(!b.contains(1000));
}
Exemplo n.º 20
0
TEST(WTF_HashSet, MoveOnly)
{
    HashSet<MoveOnly> hashSet;

    for (size_t i = 0; i < 100; ++i) {
        MoveOnly moveOnly(i + 1);
        hashSet.add(WTF::move(moveOnly));
    }

    for (size_t i = 0; i < 100; ++i)
        EXPECT_TRUE(hashSet.contains(MoveOnly(i + 1)));

    for (size_t i = 0; i < 100; ++i)
        EXPECT_TRUE(hashSet.remove(MoveOnly(i + 1)));

    EXPECT_TRUE(hashSet.isEmpty());

    for (size_t i = 0; i < 100; ++i)
        hashSet.add(MoveOnly(i + 1));

    for (size_t i = 0; i < 100; ++i)
        EXPECT_TRUE(hashSet.take(MoveOnly(i + 1)) == MoveOnly(i + 1));

    EXPECT_TRUE(hashSet.isEmpty());

    for (size_t i = 0; i < 100; ++i)
        hashSet.add(MoveOnly(i + 1));

    HashSet<MoveOnly> secondSet;

    for (size_t i = 0; i < 100; ++i)
        secondSet.add(hashSet.takeAny());

    EXPECT_TRUE(hashSet.isEmpty());

    for (size_t i = 0; i < 100; ++i)
        EXPECT_TRUE(secondSet.contains(MoveOnly(i + 1)));
}
Exemplo n.º 21
0
void DatabaseBackendBase::closeDatabase()
{
    if (!m_opened)
        return;

    m_sqliteDatabase.close();
    m_opened = false;
    // See comment at the top this file regarding calling removeOpenDatabase().
    DatabaseTracker::tracker().removeOpenDatabase(this);
    {
        MutexLocker locker(guidMutex());

        HashSet<DatabaseBackendBase*>* hashSet = guidToDatabaseMap().get(m_guid);
        ASSERT(hashSet);
        ASSERT(hashSet->contains(this));
        hashSet->remove(this);
        if (hashSet->isEmpty()) {
            guidToDatabaseMap().remove(m_guid);
            delete hashSet;
            guidToVersionMap().remove(m_guid);
        }
    }
}
Exemplo n.º 22
0
static void compileStub(
    unsigned exitID, JITCode* jitCode, OSRExit& exit, VM* vm, CodeBlock* codeBlock)
{
    StackMaps::Record* record = nullptr;
    
    for (unsigned i = jitCode->stackmaps.records.size(); i--;) {
        record = &jitCode->stackmaps.records[i];
        if (record->patchpointID == exit.m_stackmapID)
            break;
    }
    
    RELEASE_ASSERT(record->patchpointID == exit.m_stackmapID);
    
    // This code requires framePointerRegister is the same as callFrameRegister
    static_assert(MacroAssembler::framePointerRegister == GPRInfo::callFrameRegister, "MacroAssembler::framePointerRegister and GPRInfo::callFrameRegister must be the same");

    CCallHelpers jit(vm, codeBlock);
    
    // We need scratch space to save all registers, to build up the JS stack, to deal with unwind
    // fixup, pointers to all of the objects we materialize, and the elements inside those objects
    // that we materialize.
    
    // Figure out how much space we need for those object allocations.
    unsigned numMaterializations = 0;
    size_t maxMaterializationNumArguments = 0;
    for (ExitTimeObjectMaterialization* materialization : exit.m_materializations) {
        numMaterializations++;
        
        maxMaterializationNumArguments = std::max(
            maxMaterializationNumArguments,
            materialization->properties().size());
    }
    
    ScratchBuffer* scratchBuffer = vm->scratchBufferForSize(
        sizeof(EncodedJSValue) * (
            exit.m_values.size() + numMaterializations + maxMaterializationNumArguments) +
        requiredScratchMemorySizeInBytes() +
        codeBlock->calleeSaveRegisters()->size() * sizeof(uint64_t));
    EncodedJSValue* scratch = scratchBuffer ? static_cast<EncodedJSValue*>(scratchBuffer->dataBuffer()) : 0;
    EncodedJSValue* materializationPointers = scratch + exit.m_values.size();
    EncodedJSValue* materializationArguments = materializationPointers + numMaterializations;
    char* registerScratch = bitwise_cast<char*>(materializationArguments + maxMaterializationNumArguments);
    uint64_t* unwindScratch = bitwise_cast<uint64_t*>(registerScratch + requiredScratchMemorySizeInBytes());
    
    HashMap<ExitTimeObjectMaterialization*, EncodedJSValue*> materializationToPointer;
    unsigned materializationCount = 0;
    for (ExitTimeObjectMaterialization* materialization : exit.m_materializations) {
        materializationToPointer.add(
            materialization, materializationPointers + materializationCount++);
    }
    
    // Note that we come in here, the stack used to be as LLVM left it except that someone called pushToSave().
    // We don't care about the value they saved. But, we do appreciate the fact that they did it, because we use
    // that slot for saveAllRegisters().

    saveAllRegisters(jit, registerScratch);
    
    // Bring the stack back into a sane form and assert that it's sane.
    jit.popToRestore(GPRInfo::regT0);
    jit.checkStackPointerAlignment();
    
    if (vm->m_perBytecodeProfiler && codeBlock->jitCode()->dfgCommon()->compilation) {
        Profiler::Database& database = *vm->m_perBytecodeProfiler;
        Profiler::Compilation* compilation = codeBlock->jitCode()->dfgCommon()->compilation.get();
        
        Profiler::OSRExit* profilerExit = compilation->addOSRExit(
            exitID, Profiler::OriginStack(database, codeBlock, exit.m_codeOrigin),
            exit.m_kind, exit.m_kind == UncountableInvalidation);
        jit.add64(CCallHelpers::TrustedImm32(1), CCallHelpers::AbsoluteAddress(profilerExit->counterAddress()));
    }

    // The remaining code assumes that SP/FP are in the same state that they were in the FTL's
    // call frame.
    
    // Get the call frame and tag thingies.
    // Restore the exiting function's callFrame value into a regT4
    jit.move(MacroAssembler::TrustedImm64(TagTypeNumber), GPRInfo::tagTypeNumberRegister);
    jit.move(MacroAssembler::TrustedImm64(TagMask), GPRInfo::tagMaskRegister);
    
    // Do some value profiling.
    if (exit.m_profileDataFormat != DataFormatNone) {
        record->locations[0].restoreInto(jit, jitCode->stackmaps, registerScratch, GPRInfo::regT0);
        reboxAccordingToFormat(
            exit.m_profileDataFormat, jit, GPRInfo::regT0, GPRInfo::regT1, GPRInfo::regT2);
        
        if (exit.m_kind == BadCache || exit.m_kind == BadIndexingType) {
            CodeOrigin codeOrigin = exit.m_codeOriginForExitProfile;
            if (ArrayProfile* arrayProfile = jit.baselineCodeBlockFor(codeOrigin)->getArrayProfile(codeOrigin.bytecodeIndex)) {
                jit.load32(MacroAssembler::Address(GPRInfo::regT0, JSCell::structureIDOffset()), GPRInfo::regT1);
                jit.store32(GPRInfo::regT1, arrayProfile->addressOfLastSeenStructureID());
                jit.load8(MacroAssembler::Address(GPRInfo::regT0, JSCell::indexingTypeOffset()), GPRInfo::regT1);
                jit.move(MacroAssembler::TrustedImm32(1), GPRInfo::regT2);
                jit.lshift32(GPRInfo::regT1, GPRInfo::regT2);
                jit.or32(GPRInfo::regT2, MacroAssembler::AbsoluteAddress(arrayProfile->addressOfArrayModes()));
            }
        }

        if (!!exit.m_valueProfile)
            jit.store64(GPRInfo::regT0, exit.m_valueProfile.getSpecFailBucket(0));
    }

    // Materialize all objects. Don't materialize an object until all
    // of the objects it needs have been materialized. We break cycles
    // by populating objects late - we only consider an object as
    // needing another object if the later is needed for the
    // allocation of the former.

    HashSet<ExitTimeObjectMaterialization*> toMaterialize;
    for (ExitTimeObjectMaterialization* materialization : exit.m_materializations)
        toMaterialize.add(materialization);

    while (!toMaterialize.isEmpty()) {
        unsigned previousToMaterializeSize = toMaterialize.size();

        Vector<ExitTimeObjectMaterialization*> worklist;
        worklist.appendRange(toMaterialize.begin(), toMaterialize.end());
        for (ExitTimeObjectMaterialization* materialization : worklist) {
            // Check if we can do anything about this right now.
            bool allGood = true;
            for (ExitPropertyValue value : materialization->properties()) {
                if (!value.value().isObjectMaterialization())
                    continue;
                if (!value.location().neededForMaterialization())
                    continue;
                if (toMaterialize.contains(value.value().objectMaterialization())) {
                    // Gotta skip this one, since it needs a
                    // materialization that hasn't been materialized.
                    allGood = false;
                    break;
                }
            }
            if (!allGood)
                continue;

            // All systems go for materializing the object. First we
            // recover the values of all of its fields and then we
            // call a function to actually allocate the beast.
            // We only recover the fields that are needed for the allocation.
            for (unsigned propertyIndex = materialization->properties().size(); propertyIndex--;) {
                const ExitPropertyValue& property = materialization->properties()[propertyIndex];
                const ExitValue& value = property.value();
                if (!property.location().neededForMaterialization())
                    continue;

                compileRecovery(
                    jit, value, record, jitCode->stackmaps, registerScratch,
                    materializationToPointer);
                jit.storePtr(GPRInfo::regT0, materializationArguments + propertyIndex);
            }
            
            // This call assumes that we don't pass arguments on the stack.
            jit.setupArgumentsWithExecState(
                CCallHelpers::TrustedImmPtr(materialization),
                CCallHelpers::TrustedImmPtr(materializationArguments));
            jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(operationMaterializeObjectInOSR)), GPRInfo::nonArgGPR0);
            jit.call(GPRInfo::nonArgGPR0);
            jit.storePtr(GPRInfo::returnValueGPR, materializationToPointer.get(materialization));

            // Let everyone know that we're done.
            toMaterialize.remove(materialization);
        }
        
        // We expect progress! This ensures that we crash rather than looping infinitely if there
        // is something broken about this fixpoint. Or, this could happen if we ever violate the
        // "materializations form a DAG" rule.
        RELEASE_ASSERT(toMaterialize.size() < previousToMaterializeSize);
    }

    // Now that all the objects have been allocated, we populate them
    // with the correct values. This time we can recover all the
    // fields, including those that are only needed for the allocation.
    for (ExitTimeObjectMaterialization* materialization : exit.m_materializations) {
        for (unsigned propertyIndex = materialization->properties().size(); propertyIndex--;) {
            const ExitValue& value = materialization->properties()[propertyIndex].value();
            compileRecovery(
                jit, value, record, jitCode->stackmaps, registerScratch,
                materializationToPointer);
            jit.storePtr(GPRInfo::regT0, materializationArguments + propertyIndex);
        }

        // This call assumes that we don't pass arguments on the stack
        jit.setupArgumentsWithExecState(
            CCallHelpers::TrustedImmPtr(materialization),
            CCallHelpers::TrustedImmPtr(materializationToPointer.get(materialization)),
            CCallHelpers::TrustedImmPtr(materializationArguments));
        jit.move(CCallHelpers::TrustedImmPtr(bitwise_cast<void*>(operationPopulateObjectInOSR)), GPRInfo::nonArgGPR0);
        jit.call(GPRInfo::nonArgGPR0);
    }

    // Save all state from wherever the exit data tells us it was, into the appropriate place in
    // the scratch buffer. This also does the reboxing.
    
    for (unsigned index = exit.m_values.size(); index--;) {
        compileRecovery(
            jit, exit.m_values[index], record, jitCode->stackmaps, registerScratch,
            materializationToPointer);
        jit.store64(GPRInfo::regT0, scratch + index);
    }
    
    // Henceforth we make it look like the exiting function was called through a register
    // preservation wrapper. This implies that FP must be nudged down by a certain amount. Then
    // we restore the various things according to either exit.m_values or by copying from the
    // old frame, and finally we save the various callee-save registers into where the
    // restoration thunk would restore them from.
    
    // Before we start messing with the frame, we need to set aside any registers that the
    // FTL code was preserving.
    for (unsigned i = codeBlock->calleeSaveRegisters()->size(); i--;) {
        RegisterAtOffset entry = codeBlock->calleeSaveRegisters()->at(i);
        jit.load64(
            MacroAssembler::Address(MacroAssembler::framePointerRegister, entry.offset()),
            GPRInfo::regT0);
        jit.store64(GPRInfo::regT0, unwindScratch + i);
    }
    
    jit.load32(CCallHelpers::payloadFor(JSStack::ArgumentCount), GPRInfo::regT2);
    
    // Let's say that the FTL function had failed its arity check. In that case, the stack will
    // contain some extra stuff.
    //
    // We compute the padded stack space:
    //
    //     paddedStackSpace = roundUp(codeBlock->numParameters - regT2 + 1)
    //
    // The stack will have regT2 + CallFrameHeaderSize stuff.
    // We want to make the stack look like this, from higher addresses down:
    //
    //     - argument padding
    //     - actual arguments
    //     - call frame header

    // This code assumes that we're dealing with FunctionCode.
    RELEASE_ASSERT(codeBlock->codeType() == FunctionCode);
    
    jit.add32(
        MacroAssembler::TrustedImm32(-codeBlock->numParameters()), GPRInfo::regT2,
        GPRInfo::regT3);
    MacroAssembler::Jump arityIntact = jit.branch32(
        MacroAssembler::GreaterThanOrEqual, GPRInfo::regT3, MacroAssembler::TrustedImm32(0));
    jit.neg32(GPRInfo::regT3);
    jit.add32(MacroAssembler::TrustedImm32(1 + stackAlignmentRegisters() - 1), GPRInfo::regT3);
    jit.and32(MacroAssembler::TrustedImm32(-stackAlignmentRegisters()), GPRInfo::regT3);
    jit.add32(GPRInfo::regT3, GPRInfo::regT2);
    arityIntact.link(&jit);

    CodeBlock* baselineCodeBlock = jit.baselineCodeBlockFor(exit.m_codeOrigin);

    // First set up SP so that our data doesn't get clobbered by signals.
    unsigned conservativeStackDelta =
        (exit.m_values.numberOfLocals() + baselineCodeBlock->calleeSaveSpaceAsVirtualRegisters()) * sizeof(Register) +
        maxFrameExtentForSlowPathCall;
    conservativeStackDelta = WTF::roundUpToMultipleOf(
        stackAlignmentBytes(), conservativeStackDelta);
    jit.addPtr(
        MacroAssembler::TrustedImm32(-conservativeStackDelta),
        MacroAssembler::framePointerRegister, MacroAssembler::stackPointerRegister);
    jit.checkStackPointerAlignment();

    RegisterSet allFTLCalleeSaves = RegisterSet::ftlCalleeSaveRegisters();
    RegisterAtOffsetList* baselineCalleeSaves = baselineCodeBlock->calleeSaveRegisters();

    for (Reg reg = Reg::first(); reg <= Reg::last(); reg = reg.next()) {
        if (!allFTLCalleeSaves.get(reg))
            continue;
        unsigned unwindIndex = codeBlock->calleeSaveRegisters()->indexOf(reg);
        RegisterAtOffset* baselineRegisterOffset = baselineCalleeSaves->find(reg);

        if (reg.isGPR()) {
            GPRReg regToLoad = baselineRegisterOffset ? GPRInfo::regT0 : reg.gpr();

            if (unwindIndex == UINT_MAX) {
                // The FTL compilation didn't preserve this register. This means that it also
                // didn't use the register. So its value at the beginning of OSR exit should be
                // preserved by the thunk. Luckily, we saved all registers into the register
                // scratch buffer, so we can restore them from there.
                jit.load64(registerScratch + offsetOfReg(reg), regToLoad);
            } else {
                // The FTL compilation preserved the register. Its new value is therefore
                // irrelevant, but we can get the value that was preserved by using the unwind
                // data. We've already copied all unwind-able preserved registers into the unwind
                // scratch buffer, so we can get it from there.
                jit.load64(unwindScratch + unwindIndex, regToLoad);
            }

            if (baselineRegisterOffset)
                jit.store64(regToLoad, MacroAssembler::Address(MacroAssembler::framePointerRegister, baselineRegisterOffset->offset()));
        } else {
            FPRReg fpRegToLoad = baselineRegisterOffset ? FPRInfo::fpRegT0 : reg.fpr();

            if (unwindIndex == UINT_MAX)
                jit.loadDouble(MacroAssembler::TrustedImmPtr(registerScratch + offsetOfReg(reg)), fpRegToLoad);
            else
                jit.loadDouble(MacroAssembler::TrustedImmPtr(unwindScratch + unwindIndex), fpRegToLoad);

            if (baselineRegisterOffset)
                jit.storeDouble(fpRegToLoad, MacroAssembler::Address(MacroAssembler::framePointerRegister, baselineRegisterOffset->offset()));
        }
    }

    size_t baselineVirtualRegistersForCalleeSaves = baselineCodeBlock->calleeSaveSpaceAsVirtualRegisters();

    // Now get state out of the scratch buffer and place it back into the stack. The values are
    // already reboxed so we just move them.
    for (unsigned index = exit.m_values.size(); index--;) {
        VirtualRegister reg = exit.m_values.virtualRegisterForIndex(index);

        if (reg.isLocal() && reg.toLocal() < static_cast<int>(baselineVirtualRegistersForCalleeSaves))
            continue;

        jit.load64(scratch + index, GPRInfo::regT0);
        jit.store64(GPRInfo::regT0, AssemblyHelpers::addressFor(reg));
    }
    
    handleExitCounts(jit, exit);
    reifyInlinedCallFrames(jit, exit);
    adjustAndJumpToTarget(jit, exit, false);
    
    LinkBuffer patchBuffer(*vm, jit, codeBlock);
    exit.m_code = FINALIZE_CODE_IF(
        shouldDumpDisassembly() || Options::verboseOSR() || Options::verboseFTLOSRExit(),
        patchBuffer,
        ("FTL OSR exit #%u (%s, %s) from %s, with operands = %s, and record = %s",
            exitID, toCString(exit.m_codeOrigin).data(),
            exitKindToString(exit.m_kind), toCString(*codeBlock).data(),
            toCString(ignoringContext<DumpContext>(exit.m_values)).data(),
            toCString(*record).data()));
}
Exemplo n.º 23
0
int hashset_testmain(int argc, const char *argv[]) {
	/* 0: Test Data/Result Initialization; Test Environment peekup */
	testlog = fopen("hashsettest_log.txt", "a");
	testresult = fopen("hashsettest_result.txt", "a");

	char *string0 = "tester0";
	char *string1 = "tester1";
	char *string2 = "tester2";
    	char *string3 = "tester3";
	char *string4 = "tester4";
	char *string5 = "tester5";
	char *string6 = "tester6";
	char *string7 = "tester7";
	char *string8 = "tester8";
	char *string9 = "tester9";

	/* 1: No Data Structure Memory Test */
	stage_log(1, "START");

	HashSet *set = hashset_create(DATATYPE_STRING, POOLTYPE_LOCAL, 10);

	if(set != NULL) stage_result(1, "create", true, set);
	else stage_result(1, "create", false, set);

	stage_log(1, "END");

	/* 2: No Node Memory Test */
	stage_log(2, "START");

	/* Test Data peekup */
	set = hashset_create(DATATYPE_STRING, POOLTYPE_LOCAL, 10);

	bool stage2_result = set->add(set, string0);
	if(stage2_result == true) stage_result(2, "get", true, set);
	else stage_result(2, "get", false, set);

	hashset_destroy(set);
	stage_log(2, "END");

	/* 3: Between Node Memory: NULL Data */
	stage_log(3, "START");

	/* Test Data peekup */
	set = hashset_create(DATATYPE_STRING, POOLTYPE_LOCAL, 10);

	/* Test Procedure */

	void* stage31_result = set->get(set, (void *)NULL);
	if(stage31_result != NULL) stage_result(3, "get", true, set);
	else stage_result(3, "get", false, set);

	bool stage32_result = set->add(set, (void *)NULL);
	if(stage32_result == true) stage_result(3, "add", true, set);
	else stage_result(3, "add", false, set);

	bool stage33_result = set->remove(set, (void*)NULL);
	if(stage33_result == true) stage_result(3, "remove", true, set);
	else stage_result(3, "remove", false, set);

	bool stage34_result = set->contains(set, (void *)NULL);
	if(stage34_result == true) stage_result(3, "contains", true, set);
	else stage_result(3, "contains", false, set);

	hashset_destroy(set);
	stage_log(3, "END");

	/* 4: Between Node Memory: No Duplicated Data */
	stage_log(4, "START");

	/* Test Data removeup */
	set = hashset_create(DATATYPE_STRING, POOLTYPE_LOCAL, 10);
	set->add(set, string0);
	set->add(set, string1);
	set->add(set, string2);
	set->add(set, string3);
	set->add(set, string4);

	/* Test Procedure */
	void* stage41_result = set->get(set, string5);
	if(stage41_result != NULL) stage_result(4, "get", true, set);
	else stage_result(4, "get", false, set);

	bool stage42_result = set->add(set, string5 );
	if(stage42_result == true) stage_result(4, "add", true, set);
	else stage_result(4, "add", false, set);

	bool stage43_result = set->remove(set, string5);
	if(stage43_result == true) stage_result(4, "remove", true, set);
	else stage_result(4, "remove", false, set);

	bool stage44_result = set->contains(set, string1);
	if(stage44_result == true) stage_result(4, "contains", true, set);
	else stage_result(4, "contains", false, set);

	/* abnormal case */
	void* stage45_result = set->get(set, string9);
	if(stage45_result != NULL) stage_result(4, "abnormal get", true, set);
	else stage_result(4, "abnormal get", false, set);

        bool stage46_result = set->remove(set, string8);
	if(stage46_result == true) stage_result(4, "abnormal remove", true, set);
	else stage_result(4, "abnormal remove", false, set);

	bool stage47_result = set->contains(set, string8);
	if(stage47_result == true) stage_result(4, "abnormal contains", true, set);
	else stage_result(4, "abnormal contains", false, set);

	hashset_destroy(set);
	stage_log(4, "END");

	/* 5: Between Node Memory: Duplicated Data */
	stage_log(5, "START");

	/* Test Data removeup */
	set = hashset_create(DATATYPE_STRING, POOLTYPE_LOCAL, 10);
	set->add(set, string0);
	set->add(set, string1);
	set->add(set, string2);
	set->add(set, string3);
	set->add(set, string4);

	/* Test Procedure */
	void* stage51_result = set->get(set, string0);
	if(stage51_result != NULL) stage_result(5, "get", true, set);
	else stage_result(5, "get", false, set);

	bool stage52_result = set->add(set, string1);
	if(stage52_result == true) stage_result(5, "add", true, set);
	else stage_result(5, "add", false, set);

	bool stage53_result = set->remove(set, string1);
	if(stage53_result == true) stage_result(5, "remove", true, set);
	else stage_result(5, "remove", false, set);

	bool stage54_result = set->contains(set, string1);
	if(stage54_result == true) stage_result(5, "contains", true, set);
	else stage_result(5, "contains", false, set);

	hashset_destroy(set);
	stage_log(5, "END");

	/* 6: Max Node Memory: NULL Data */
	stage_log(6, "START");

	/* Test Data removeup */
	set = hashset_create(DATATYPE_STRING, POOLTYPE_LOCAL, 10);
	set->add(set, string0);
	set->add(set, string1);
	set->add(set, string2);
	set->add(set, string3);
	set->add(set, string4);
	set->add(set, string5);
	set->add(set, string6);
	set->add(set, string7);
	set->add(set, string8);
	set->add(set, string9);

	/* Test Procedure */

	void* stage61_result = set->get(set, (void *)NULL);
	if(stage61_result != NULL) stage_result(6, "get", true, set);
	else stage_result(6, "get", false, set);

	bool stage62_result = set->add(set, (void *)NULL);
	if(stage62_result == true) stage_result(6, "add", true, set);
	else stage_result(6, "add", false, set);

	bool stage63_result = set->remove(set, (void *)NULL);
	if(stage63_result == true) stage_result(6, "remove", true, set);
	else stage_result(6, "remove", false, set);

	bool stage64_result = set->contains(set, (void *)NULL);
	if(stage64_result == true) stage_result(6, "contains", true, set);
	else stage_result(6, "contains", false, set);

	hashset_destroy(set);
	stage_log(6, "END");

	/* 7: Max Node Memory: No Duplicated Data */
	stage_log(7, "START");

	/* Test Data removeup */
	set = hashset_create(DATATYPE_STRING, POOLTYPE_LOCAL, 10);
	set->add(set, string0);
	set->add(set, string1);
	set->add(set, string2);
	set->add(set, string3);
	set->add(set, string4);
	set->add(set, string5);
	set->add(set, string6);
	set->add(set, string7);
	set->add(set, string8);
	set->add(set, string9);

	/* Test Procedure */
	void* stage71_result = set->get(set, string1);
	if(stage71_result != NULL) stage_result(7, "get", true, set);
	else stage_result(7, "get", false, set);

	bool stage72_result = set->add(set, string1);
	if(stage72_result == true) stage_result(7, "add", true, set);
	else stage_result(7, "add", false, set);

	bool stage73_result = set->remove(set, string1);
	if(stage73_result == true) stage_result(7, "remove", true, set);
	else stage_result(7, "remove", false, set);

	bool stage74_result = set->contains(set, string1);
	if(stage74_result == true) stage_result(7, "contains", true, set);
	else stage_result(7, "contains", false, set);

	hashset_destroy(set);
	stage_log(7, "END");

	/* 8: Max Node Memory: Duplicated Data */
	stage_log(8, "START");

	/* Test Data removeup */
	set = hashset_create(DATATYPE_STRING, POOLTYPE_LOCAL, 10);
	set->add(set, string0);
	set->add(set, string1);
	set->add(set, string2);
	set->add(set, string3);
	set->add(set, string4);
	set->add(set, string0);
	set->add(set, string1);
	set->add(set, string2);
	set->add(set, string3);
	set->add(set, string4);

	/* Test Procedure */
	void* stage81_result = set->get(set, string1);
	if(stage81_result != NULL) stage_result(8, "get", true, set);
	else stage_result(8, "get", false, set);

	bool stage82_result = set->add(set, string1);
	if(stage82_result == true) stage_result(8, "add", true, set);
	else stage_result(8, "add", false, set);

	bool stage83_result = set->remove(set, string1);
	if(stage83_result == true) stage_result(8, "remove", true, set);
	else stage_result(8, "remove", false, set);

	bool stage84_result = set->contains(set, string1);
	if(stage84_result == true) stage_result(8, "contains", true, set);
	else stage_result(8, "contains", false, set);

	hashset_destroy(set);
	stage_log(8, "END");

	/* 9: Test Result Store */
	fclose(testlog);
	fclose(testresult);

	return 0;
}
// ECMA 15.4.4
JSValue* ArrayProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
{
  unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);

  JSValue *result = 0; // work around gcc 4.0 bug in uninitialized variable warning
  
  switch (id) {
  case ToLocaleString:
  case ToString:

    if (!thisObj->inherits(&ArrayInstance::info))
      return throwError(exec, TypeError);

    // fall through
  case Join: {
    static HashSet<JSObject*> visitedElems;
    if (visitedElems.contains(thisObj))
        return jsString("");
    UString separator = ",";
    UString str = "";

    visitedElems.add(thisObj);
    if (id == Join && !args[0]->isUndefined())
        separator = args[0]->toString(exec);
    for (unsigned int k = 0; k < length; k++) {
        if (k >= 1)
            str += separator;
        if (str.isNull()) {
            JSObject *error = Error::create(exec, GeneralError, "Out of memory");
            exec->setException(error);
            break;
        }

        JSValue* element = thisObj->get(exec, k);
        if (element->isUndefinedOrNull())
            continue;

        bool fallback = false;
        if (id == ToLocaleString) {
            JSObject* o = element->toObject(exec);
            JSValue* conversionFunction = o->get(exec, exec->propertyNames().toLocaleString);
            if (conversionFunction->isObject() && static_cast<JSObject*>(conversionFunction)->implementsCall())
                str += static_cast<JSObject*>(conversionFunction)->call(exec, o, List())->toString(exec);
            else
                // try toString() fallback
                fallback = true;
        }

        if (id == ToString || id == Join || fallback)
            str += element->toString(exec);

        if (str.isNull()) {
            JSObject *error = Error::create(exec, GeneralError, "Out of memory");
            exec->setException(error);
        }

        if (exec->hadException())
            break;
    }
    visitedElems.remove(thisObj);
    result = jsString(str);
    break;
  }
  case Concat: {
    JSObject *arr = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec,List::empty()));
    int n = 0;
    JSValue *curArg = thisObj;
    JSObject *curObj = static_cast<JSObject *>(thisObj);
    ListIterator it = args.begin();
    for (;;) {
      if (curArg->isObject() &&
          curObj->inherits(&ArrayInstance::info)) {
        unsigned int k = 0;
        // Older versions tried to optimize out getting the length of thisObj
        // by checking for n != 0, but that doesn't work if thisObj is an empty array.
        length = curObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
        while (k < length) {
          if (JSValue *v = getProperty(exec, curObj, k))
            arr->put(exec, n, v);
          n++;
          k++;
        }
      } else {
        arr->put(exec, n, curArg);
        n++;
      }
      if (it == args.end())
        break;
      curArg = *it;
      curObj = static_cast<JSObject *>(it++); // may be 0
    }
    arr->put(exec, exec->propertyNames().length, jsNumber(n), DontEnum | DontDelete);

    result = arr;
    break;
  }
  case Pop:{
    if (length == 0) {
      thisObj->put(exec, exec->propertyNames().length, jsNumber(length), DontEnum | DontDelete);
      result = jsUndefined();
    } else {
      result = thisObj->get(exec, length - 1);
      thisObj->put(exec, exec->propertyNames().length, jsNumber(length - 1), DontEnum | DontDelete);
    }
    break;
  }
  case Push: {
    for (int n = 0; n < args.size(); n++)
      thisObj->put(exec, length + n, args[n]);
    length += args.size();
    thisObj->put(exec, exec->propertyNames().length, jsNumber(length), DontEnum | DontDelete);
    result = jsNumber(length);
    break;
  }
  case Reverse: {

    unsigned int middle = length / 2;

    for (unsigned int k = 0; k < middle; k++) {
      unsigned lk1 = length - k - 1;
      JSValue *obj2 = getProperty(exec, thisObj, lk1);
      JSValue *obj = getProperty(exec, thisObj, k);

      if (obj2) 
        thisObj->put(exec, k, obj2);
      else
        thisObj->deleteProperty(exec, k);

      if (obj)
        thisObj->put(exec, lk1, obj);
      else
        thisObj->deleteProperty(exec, lk1);
    }
    result = thisObj;
    break;
  }
  case Shift: {
    if (length == 0) {
      thisObj->put(exec, exec->propertyNames().length, jsNumber(length), DontEnum | DontDelete);
      result = jsUndefined();
    } else {
      result = thisObj->get(exec, 0);
      for(unsigned int k = 1; k < length; k++) {
        if (JSValue *obj = getProperty(exec, thisObj, k))
          thisObj->put(exec, k-1, obj);
        else
          thisObj->deleteProperty(exec, k-1);
      }
      thisObj->deleteProperty(exec, length - 1);
      thisObj->put(exec, exec->propertyNames().length, jsNumber(length - 1), DontEnum | DontDelete);
    }
    break;
  }
  case Slice: {
    // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10

    // We return a new array
    JSObject *resObj = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec,List::empty()));
    result = resObj;
    double begin = 0;
    if (!args[0]->isUndefined()) {
        begin = args[0]->toInteger(exec);
        if (begin >= 0) { // false for NaN
            if (begin > length)
                begin = length;
        } else {
            begin += length;
            if (!(begin >= 0)) // true for NaN
                begin = 0;
        }
    }
    double end = length;
    if (!args[1]->isUndefined()) {
      end = args[1]->toInteger(exec);
      if (end < 0) { // false for NaN
        end += length;
        if (end < 0)
          end = 0;
      } else {
        if (!(end <= length)) // true for NaN
          end = length;
      }
    }

    //printf( "Slicing from %d to %d \n", begin, end );
    int n = 0;
    int b = static_cast<int>(begin);
    int e = static_cast<int>(end);
    for(int k = b; k < e; k++, n++) {
      if (JSValue *v = getProperty(exec, thisObj, k))
        resObj->put(exec, n, v);
    }
    resObj->put(exec, exec->propertyNames().length, jsNumber(n), DontEnum | DontDelete);
    break;
  }
  case Sort:{
#if 0
    printf("KJS Array::Sort length=%d\n", length);
    for ( unsigned int i = 0 ; i<length ; ++i )
      printf("KJS Array::Sort: %d: %s\n", i, thisObj->get(exec, i)->toString(exec).ascii() );
#endif
    JSObject *sortFunction = NULL;
    if (!args[0]->isUndefined())
      {
        sortFunction = args[0]->toObject(exec);
        if (!sortFunction->implementsCall())
          sortFunction = NULL;
      }
    
    if (thisObj->classInfo() == &ArrayInstance::info) {
      if (sortFunction)
        ((ArrayInstance *)thisObj)->sort(exec, sortFunction);
      else
        ((ArrayInstance *)thisObj)->sort(exec);
      result = thisObj;
      break;
    }

    if (length == 0) {
      thisObj->put(exec, exec->propertyNames().length, jsNumber(0), DontEnum | DontDelete);
      result = thisObj;
      break;
    }

    // "Min" sort. Not the fastest, but definitely less code than heapsort
    // or quicksort, and much less swapping than bubblesort/insertionsort.
    for ( unsigned int i = 0 ; i<length-1 ; ++i )
      {
        JSValue *iObj = thisObj->get(exec,i);
        unsigned int themin = i;
        JSValue *minObj = iObj;
        for ( unsigned int j = i+1 ; j<length ; ++j )
          {
            JSValue *jObj = thisObj->get(exec,j);
            double cmp;
            if (jObj->isUndefined()) {
              cmp = 1; // don't check minObj because there's no need to differentiate == (0) from > (1)
            } else if (minObj->isUndefined()) {
              cmp = -1;
            } else if (sortFunction) {
                List l;
                l.append(jObj);
                l.append(minObj);
                cmp = sortFunction->call(exec, exec->dynamicInterpreter()->globalObject(), l)->toNumber(exec);
            } else {
              cmp = (jObj->toString(exec) < minObj->toString(exec)) ? -1 : 1;
            }
            if ( cmp < 0 )
              {
                themin = j;
                minObj = jObj;
              }
          }
        // Swap themin and i
        if ( themin > i )
          {
            //printf("KJS Array::Sort: swapping %d and %d\n", i, themin );
            thisObj->put( exec, i, minObj );
            thisObj->put( exec, themin, iObj );
          }
      }
#if 0
    printf("KJS Array::Sort -- Resulting array:\n");
    for ( unsigned int i = 0 ; i<length ; ++i )
      printf("KJS Array::Sort: %d: %s\n", i, thisObj->get(exec, i)->toString(exec).ascii() );
#endif
    result = thisObj;
    break;
  }
  case Splice: {
    // 15.4.4.12 - oh boy this is huge
    JSObject *resObj = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec,List::empty()));
    result = resObj;
    int begin = args[0]->toUInt32(exec);
    if ( begin < 0 )
      begin = maxInt( begin + length, 0 );
    else
      begin = minInt( begin, length );
    unsigned int deleteCount = minInt( maxInt( args[1]->toUInt32(exec), 0 ), length - begin );

    //printf( "Splicing from %d, deleteCount=%d \n", begin, deleteCount );
    for(unsigned int k = 0; k < deleteCount; k++) {
      if (JSValue *v = getProperty(exec, thisObj, k+begin))
        resObj->put(exec, k, v);
    }
    resObj->put(exec, exec->propertyNames().length, jsNumber(deleteCount), DontEnum | DontDelete);

    unsigned int additionalArgs = maxInt( args.size() - 2, 0 );
    if ( additionalArgs != deleteCount )
    {
      if ( additionalArgs < deleteCount )
      {
        for ( unsigned int k = begin; k < length - deleteCount; ++k )
        {
          if (JSValue *v = getProperty(exec, thisObj, k+deleteCount))
            thisObj->put(exec, k+additionalArgs, v);
          else
            thisObj->deleteProperty(exec, k+additionalArgs);
        }
        for ( unsigned int k = length ; k > length - deleteCount + additionalArgs; --k )
          thisObj->deleteProperty(exec, k-1);
      }
      else
      {
        for ( unsigned int k = length - deleteCount; (int)k > begin; --k )
        {
          if (JSValue *obj = getProperty(exec, thisObj, k + deleteCount - 1))
            thisObj->put(exec, k + additionalArgs - 1, obj);
          else
            thisObj->deleteProperty(exec, k+additionalArgs-1);
        }
      }
    }
    for ( unsigned int k = 0; k < additionalArgs; ++k )
    {
      thisObj->put(exec, k+begin, args[k+2]);
    }
    thisObj->put(exec, exec->propertyNames().length, jsNumber(length - deleteCount + additionalArgs), DontEnum | DontDelete);
    break;
  }
  case UnShift: { // 15.4.4.13
    unsigned int nrArgs = args.size();
    for ( unsigned int k = length; k > 0; --k )
    {
      if (JSValue *v = getProperty(exec, thisObj, k - 1))
        thisObj->put(exec, k+nrArgs-1, v);
      else
        thisObj->deleteProperty(exec, k+nrArgs-1);
    }
    for ( unsigned int k = 0; k < nrArgs; ++k )
      thisObj->put(exec, k, args[k]);
    result = jsNumber(length + nrArgs);
    thisObj->put(exec, exec->propertyNames().length, result, DontEnum | DontDelete);
    break;
  }
  case Filter:
  case Map: {
    JSObject *eachFunction = args[0]->toObject(exec);
    
    if (!eachFunction->implementsCall())
      return throwError(exec, TypeError);
    
    JSObject *applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicInterpreter()->globalObject() :  args[1]->toObject(exec);
    JSObject *resultArray;
    
    if (id == Filter) 
      resultArray = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec, List::empty()));
    else {
      List args;
      args.append(jsNumber(length));
      resultArray = static_cast<JSObject *>(exec->lexicalInterpreter()->builtinArray()->construct(exec, args));
    }
    
    unsigned filterIndex = 0;
    for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
      PropertySlot slot;

      if (!thisObj->getPropertySlot(exec, k, slot))
         continue;
        
      JSValue *v = slot.getValue(exec, thisObj, k);
      
      List eachArguments;
      
      eachArguments.append(v);
      eachArguments.append(jsNumber(k));
      eachArguments.append(thisObj);
      
      JSValue *result = eachFunction->call(exec, applyThis, eachArguments);
      
      if (id == Map)
        resultArray->put(exec, k, result);
      else if (result->toBoolean(exec)) 
        resultArray->put(exec, filterIndex++, v);
    }
    
    return resultArray;
  }
  case Every:
  case ForEach:
  case Some: {
    //Documentation for these three is available at:
    //http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:every
    //http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEach
    //http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:some
    
    JSObject *eachFunction = args[0]->toObject(exec);
    
    if (!eachFunction->implementsCall())
      return throwError(exec, TypeError);
    
    JSObject *applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicInterpreter()->globalObject() :  args[1]->toObject(exec);
    
    if (id == Some || id == Every)
      result = jsBoolean(id == Every);
    else
      result = jsUndefined();
    
    for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
      PropertySlot slot;
        
      if (!thisObj->getPropertySlot(exec, k, slot))
        continue;
      
      List eachArguments;
      
      eachArguments.append(slot.getValue(exec, thisObj, k));
      eachArguments.append(jsNumber(k));
      eachArguments.append(thisObj);
      
      bool predicateResult = eachFunction->call(exec, applyThis, eachArguments)->toBoolean(exec);
      
      if (id == Every && !predicateResult) {
        result = jsBoolean(false);
        break;
      }
      if (id == Some && predicateResult) {
        result = jsBoolean(true);
        break;
      }
    }
    break;
  }

  case IndexOf: {
    // JavaScript 1.5 Extension by Mozilla
    // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf

    unsigned index = 0;
    double d = args[1]->toInteger(exec);
    if (d < 0)
        d += length;
    if (d > 0) {
        if (d > length)
            index = length;
        else
            index = static_cast<unsigned>(d);
    }

    JSValue* searchElement = args[0];
    for (; index < length; ++index) {
        JSValue* e = getProperty(exec, thisObj, index);
        if (!e)
            continue;
        if (strictEqual(exec, searchElement, e))
            return jsNumber(index);
    }

    return jsNumber(-1);
  }
  case LastIndexOf: {
       // JavaScript 1.6 Extension by Mozilla
      // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf 

    int index = length - 1;
    double d = args[1]->toInteger(exec);

    if (d < 0) {
        d += length;
        if (d < 0) 
            return jsNumber(-1);
    }
    if (d < length)
        index = static_cast<int>(d);
          
    JSValue* searchElement = args[0];
    for (; index >= 0; --index) {
        JSValue* e = getProperty(exec, thisObj, index);
        if (!e)
            continue;
        if (strictEqual(exec, searchElement, e))
            return jsNumber(index);
    }
          
    return jsNumber(-1);
}
  default:
    assert(0);
    result = 0;
    break;
  }
  return result;
}
void AXObjectCacheImpl::updateAriaOwns(const AXObject* owner, const Vector<String>& idVector, HeapVector<Member<AXObject>>& ownedChildren)
{
    //
    // Update the map from the AXID of this element to the ids of the owned children,
    // and the reverse map from ids to possible AXID owners.
    //

    HashSet<String> currentIds = m_ariaOwnerToIdsMapping.get(owner->axObjectID());
    HashSet<String> newIds;
    bool idsChanged = false;
    for (const String& id : idVector) {
        newIds.add(id);
        if (!currentIds.contains(id)) {
            idsChanged = true;
            HashSet<AXID>* owners = m_idToAriaOwnersMapping.get(id);
            if (!owners) {
                owners = new HashSet<AXID>();
                m_idToAriaOwnersMapping.set(id, adoptPtr(owners));
            }
            owners->add(owner->axObjectID());
        }
    }
    for (const String& id : currentIds) {
        if (!newIds.contains(id)) {
            idsChanged = true;
            HashSet<AXID>* owners = m_idToAriaOwnersMapping.get(id);
            if (owners) {
                owners->remove(owner->axObjectID());
                if (owners->isEmpty())
                    m_idToAriaOwnersMapping.remove(id);
            }
        }
    }
    if (idsChanged)
        m_ariaOwnerToIdsMapping.set(owner->axObjectID(), newIds);

    //
    // Now figure out the ids that actually correspond to children that exist and
    // that we can legally own (not cyclical, not already owned, etc.) and update
    // the maps and |ownedChildren| based on that.
    //

    // Figure out the children that are owned by this object and are in the tree.
    TreeScope& scope = owner->node()->treeScope();
    Vector<AXID> newChildAXIDs;
    for (const String& idName : idVector) {
        Element* element = scope.getElementById(AtomicString(idName));
        if (!element)
            continue;

        AXObject* child = getOrCreate(element);
        if (!child)
            continue;

        // If this child is already aria-owned by a different owner, continue.
        // It's an author error if this happens and we don't worry about which of the
        // two owners wins ownership of the child, as long as only one of them does.
        if (isAriaOwned(child) && getAriaOwnedParent(child) != owner)
            continue;

        // You can't own yourself!
        if (child == owner)
            continue;

        // Walk up the parents of the owner object, make sure that this child doesn't appear
        // there, as that would create a cycle.
        bool foundCycle = false;
        for (AXObject* parent = owner->parentObject(); parent && !foundCycle; parent = parent->parentObject()) {
            if (parent == child)
                foundCycle = true;
        }
        if (foundCycle)
            continue;

        newChildAXIDs.append(child->axObjectID());
        ownedChildren.append(child);
    }

    // Compare this to the current list of owned children, and exit early if there are no changes.
    Vector<AXID> currentChildAXIDs = m_ariaOwnerToChildrenMapping.get(owner->axObjectID());
    bool same = true;
    if (currentChildAXIDs.size() != newChildAXIDs.size()) {
        same = false;
    } else {
        for (size_t i = 0; i < currentChildAXIDs.size() && same; ++i) {
            if (currentChildAXIDs[i] != newChildAXIDs[i])
                same = false;
        }
    }
    if (same)
        return;

    // The list of owned children has changed. Even if they were just reordered, to be safe
    // and handle all cases we remove all of the current owned children and add the new list
    // of owned children.
    for (size_t i = 0; i < currentChildAXIDs.size(); ++i) {
        // Find the AXObject for the child that this owner no longer owns.
        AXID removedChildID = currentChildAXIDs[i];
        AXObject* removedChild = objectFromAXID(removedChildID);

        // It's possible that this child has already been owned by some other owner,
        // in which case we don't need to do anything.
        if (removedChild && getAriaOwnedParent(removedChild) != owner)
            continue;

        // Remove it from the child -> owner mapping so it's not owned by this owner anymore.
        m_ariaOwnedChildToOwnerMapping.remove(removedChildID);

        if (removedChild) {
            // If the child still exists, find its "real" parent, and reparent it back to
            // its real parent in the tree by detaching it from its current parent and
            // calling childrenChanged on its real parent.
            removedChild->detachFromParent();
            AXID realParentID = m_ariaOwnedChildToRealParentMapping.get(removedChildID);
            AXObject* realParent = objectFromAXID(realParentID);
            childrenChanged(realParent);
        }

        // Remove the child -> original parent mapping too since this object has now been
        // reparented back to its original parent.
        m_ariaOwnedChildToRealParentMapping.remove(removedChildID);
    }

    for (size_t i = 0; i < newChildAXIDs.size(); ++i) {
        // Find the AXObject for the child that will now be a child of this owner.
        AXID addedChildID = newChildAXIDs[i];
        AXObject* addedChild = objectFromAXID(addedChildID);

        // Add this child to the mapping from child to owner.
        m_ariaOwnedChildToOwnerMapping.set(addedChildID, owner->axObjectID());

        // Add its parent object to a mapping from child to real parent. If later this owner
        // doesn't own this child anymore, we need to return it to its original parent.
        AXObject* originalParent = addedChild->parentObject();
        m_ariaOwnedChildToRealParentMapping.set(addedChildID, originalParent->axObjectID());

        // Now detach the object from its original parent and call childrenChanged on the
        // original parent so that it can recompute its list of children.
        addedChild->detachFromParent();
        childrenChanged(originalParent);
    }

    // Finally, update the mapping from the owner to the list of child IDs.
    m_ariaOwnerToChildrenMapping.set(owner->axObjectID(), newChildAXIDs);
}
Exemplo n.º 26
0
TEST(FileSystemIterator, subSubDirs)
{
    TestDirectory rootDir(File("foobarfolder"));
    TestDirectoryPtr subDir1 = rootDir.addDirectory("subdir1");
    TestDirectoryPtr subDir2 = rootDir.addDirectory("subdir2");
    TestDirectoryPtr subDir3 = rootDir.addDirectory("subdir3");

    subDir1->addDirectory("sub1subdir1")->addFile("sub1subdir1file1")->addFile("sub1subdir1file2");
    subDir1->addDirectory("sub1subdir2")->addFile("sub1subdir2file1")->addFile("sub1subdir2file2");
    subDir1->addDirectory("sub1subdir3")->addFile("sub1subdir3file1")->addFile("sub1subdir3file2");

    subDir2->addDirectory("sub2subdir1")->addFile("sub2subdir1file1")->addFile("sub2subdir1file2");
    subDir2->addDirectory("sub2subdir2")->addFile("sub2subdir2file1")->addFile("sub2subdir2file2");
    subDir2->addDirectory("sub2subdir3")->addFile("sub2subdir3file1")->addFile("sub2subdir3file2");

    subDir3->addDirectory("sub3subdir1")->addFile("sub3subdir1file1")->addFile("sub3subdir1file2");
    subDir3->addDirectory("sub3subdir2")->addFile("sub3subdir2file1")->addFile("sub3subdir2file2");
    subDir3->addDirectory("sub3subdir3")->addFile("sub3subdir3file1")->addFile("sub3subdir3file2");


    HashSet<String> filenames;
    filenames.put("subdir1");
    filenames.put("subdir2");
    filenames.put("subdir3");
    filenames.put("sub1subdir1");
    filenames.put("sub1subdir2");
    filenames.put("sub1subdir3");
    filenames.put("sub2subdir1");
    filenames.put("sub2subdir2");
    filenames.put("sub2subdir3");
    filenames.put("sub3subdir1");
    filenames.put("sub3subdir2");
    filenames.put("sub3subdir3");
    filenames.put("sub1subdir1file1");
    filenames.put("sub1subdir2file1");
    filenames.put("sub1subdir3file1");
    filenames.put("sub2subdir1file1");
    filenames.put("sub2subdir2file1");
    filenames.put("sub2subdir3file1");
    filenames.put("sub3subdir1file1");
    filenames.put("sub3subdir2file1");
    filenames.put("sub3subdir3file1");
    filenames.put("sub1subdir1file2");
    filenames.put("sub1subdir2file2");
    filenames.put("sub1subdir3file2");
    filenames.put("sub2subdir1file2");
    filenames.put("sub2subdir2file2");
    filenames.put("sub2subdir3file2");
    filenames.put("sub3subdir1file2");
    filenames.put("sub3subdir2file2");
    filenames.put("sub3subdir3file2");

    FileSystemIterator iter(rootDir.getFile());
    while (iter.isValid())
    {
        EXPECT_TRUE(filenames.hasElement(iter->getFileName()));
        EXPECT_EQ(CAPU_OK, filenames.remove(iter->getFileName()));
        iter.next();
    }
    EXPECT_EQ(0u, filenames.count());

}
Exemplo n.º 27
0
static void sortBlock(unsigned from, unsigned to, Vector<Vector<Node*> >& parentMatrix, bool mayContainAttributeNodes)
{
    ASSERT(from + 1 < to); // Should not call this function with less that two nodes to sort.
    unsigned minDepth = UINT_MAX;
    for (unsigned i = from; i < to; ++i) {
        unsigned depth = parentMatrix[i].size() - 1;
        if (minDepth > depth)
            minDepth = depth;
    }

    // Find the common ancestor.
    unsigned commonAncestorDepth = minDepth;
    Node* commonAncestor;
    while (true) {
        commonAncestor = parentWithDepth(commonAncestorDepth, parentMatrix[from]);
        if (commonAncestorDepth == 0)
            break;

        bool allEqual = true;
        for (unsigned i = from + 1; i < to; ++i) {
            if (commonAncestor != parentWithDepth(commonAncestorDepth, parentMatrix[i])) {
                allEqual = false;
                break;
            }
        }
        if (allEqual)
            break;

        --commonAncestorDepth;
    }

    if (commonAncestorDepth == minDepth) {
        // One of the nodes is the common ancestor => it is the first in document order.
        // Find it and move it to the beginning.
        for (unsigned i = from; i < to; ++i)
            if (commonAncestor == parentMatrix[i][0]) {
                parentMatrix[i].swap(parentMatrix[from]);
                if (from + 2 < to)
                    sortBlock(from + 1, to, parentMatrix, mayContainAttributeNodes);
                return;
            }
    }

    if (mayContainAttributeNodes && commonAncestor->isElementNode()) {
        // The attribute nodes and namespace nodes of an element occur before the children of the element.
        // The namespace nodes are defined to occur before the attribute nodes.
        // The relative order of namespace nodes is implementation-dependent.
        // The relative order of attribute nodes is implementation-dependent.
        unsigned sortedEnd = from;
        // FIXME: namespace nodes are not implemented.
        for (unsigned i = sortedEnd; i < to; ++i) {
            Node* n = parentMatrix[i][0];
            if (n->isAttributeNode() && static_cast<Attr*>(n)->ownerElement() == commonAncestor)
                parentMatrix[i].swap(parentMatrix[sortedEnd++]);
        }
        if (sortedEnd != from) {
            if (to - sortedEnd > 1)
                sortBlock(sortedEnd, to, parentMatrix, mayContainAttributeNodes);
            return;
        }
    }

    // Children nodes of the common ancestor induce a subdivision of our node-set.
    // Sort it according to this subdivision, and recursively sort each group.
    HashSet<Node*> parentNodes;
    for (unsigned i = from; i < to; ++i)
        parentNodes.add(parentWithDepth(commonAncestorDepth + 1, parentMatrix[i]));

    unsigned previousGroupEnd = from;
    unsigned groupEnd = from;
    for (Node* n = commonAncestor->firstChild(); n; n = n->nextSibling()) {
        // If parentNodes contains the node, perform a linear search to move its children in the node-set to the beginning.
        if (parentNodes.contains(n)) {
            for (unsigned i = groupEnd; i < to; ++i)
                if (parentWithDepth(commonAncestorDepth + 1, parentMatrix[i]) == n)
                    parentMatrix[i].swap(parentMatrix[groupEnd++]);

            if (groupEnd - previousGroupEnd > 1)
                sortBlock(previousGroupEnd, groupEnd, parentMatrix, mayContainAttributeNodes);

            ASSERT(previousGroupEnd != groupEnd);
            previousGroupEnd = groupEnd;
#ifndef NDEBUG
            parentNodes.remove(n);
#endif
        }
    }

    ASSERT(parentNodes.isEmpty());
}
Exemplo n.º 28
0
void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate& update, const Element* animatingElement, Element& element, const ComputedStyle& style, ComputedStyle* parentStyle, StyleResolver* resolver)
{
    const ElementAnimations* elementAnimations = animatingElement ? animatingElement->elementAnimations() : nullptr;

    bool isAnimationStyleChange = elementAnimations && elementAnimations->isAnimationStyleChange();

#if !ENABLE(ASSERT)
    // If we're in an animation style change, no animations can have started, been cancelled or changed play state.
    // When ASSERT is enabled, we verify this optimization.
    if (isAnimationStyleChange)
        return;
#endif

    const CSSAnimationData* animationData = style.animations();
    const CSSAnimations* cssAnimations = elementAnimations ? &elementAnimations->cssAnimations() : nullptr;
    const Element* elementForScoping = animatingElement ? animatingElement : &element;

    HashSet<AtomicString> inactive;
    if (cssAnimations) {
        for (const auto& entry : cssAnimations->m_animations)
            inactive.add(entry.key);
    }

    if (style.display() != NONE) {
        for (size_t i = 0; animationData && i < animationData->nameList().size(); ++i) {
            AtomicString animationName(animationData->nameList()[i]);
            if (animationName == CSSAnimationData::initialName())
                continue;

            const bool isPaused = CSSTimingData::getRepeated(animationData->playStateList(), i) == AnimPlayStatePaused;

            Timing timing = animationData->convertToTiming(i);
            Timing specifiedTiming = timing;
            RefPtr<TimingFunction> keyframeTimingFunction = timing.timingFunction;
            timing.timingFunction = Timing::defaults().timingFunction;

            RefPtrWillBeRawPtr<StyleRuleKeyframes> keyframesRule = resolver->findKeyframesRule(elementForScoping, animationName);
            if (!keyframesRule)
                continue; // Cancel the animation if there's no style rule for it.

            if (cssAnimations) {
                AnimationMap::const_iterator existing(cssAnimations->m_animations.find(animationName));
                if (existing != cssAnimations->m_animations.end()) {
                    inactive.remove(animationName);

                    const RunningAnimation* runningAnimation = existing->value.get();
                    Animation* animation = runningAnimation->animation.get();

                    if (keyframesRule != runningAnimation->styleRule || keyframesRule->version() != runningAnimation->styleRuleVersion || runningAnimation->specifiedTiming != specifiedTiming) {
                        ASSERT(!isAnimationStyleChange);
                        update.updateAnimation(animationName, animation, InertEffect::create(
                            createKeyframeEffectModel(resolver, animatingElement, element, &style, parentStyle, animationName, keyframeTimingFunction.get(), i),
                            timing, isPaused, animation->unlimitedCurrentTimeInternal()), specifiedTiming, keyframesRule);
                    }

                    if (isPaused != animation->paused()) {
                        ASSERT(!isAnimationStyleChange);
                        update.toggleAnimationPaused(animationName);
                    }

                    continue;
                }
            }

            ASSERT(!isAnimationStyleChange);
            update.startAnimation(animationName, InertEffect::create(
                createKeyframeEffectModel(resolver, animatingElement, element, &style, parentStyle, animationName, keyframeTimingFunction.get(), i),
                timing, isPaused, 0), specifiedTiming, keyframesRule);
        }
    }

    ASSERT(inactive.isEmpty() || cssAnimations);
    for (const AtomicString& animationName : inactive) {
        ASSERT(!isAnimationStyleChange);
        update.cancelAnimation(animationName, *cssAnimations->m_animations.get(animationName)->animation);
    }
}
Exemplo n.º 29
0
void CSSAnimations::calculateAnimationUpdate(CSSAnimationUpdate* update, const Element* animatingElement, Element& element, const RenderStyle& style, RenderStyle* parentStyle, StyleResolver* resolver)
{
    const ActiveAnimations* activeAnimations = animatingElement ? animatingElement->activeAnimations() : nullptr;

#if !ENABLE(ASSERT)
    // If we're in an animation style change, no animations can have started, been cancelled or changed play state.
    // When ASSERT is enabled, we verify this optimization.
    if (activeAnimations && activeAnimations->isAnimationStyleChange())
        return;
#endif

    const CSSAnimationData* animationData = style.animations();
    const CSSAnimations* cssAnimations = activeAnimations ? &activeAnimations->cssAnimations() : nullptr;

    HashSet<AtomicString> inactive;
    if (cssAnimations) {
        for (const auto& entry : cssAnimations->m_animations)
            inactive.add(entry.key);
    }

    if (style.display() != NONE) {
        for (size_t i = 0; animationData && i < animationData->nameList().size(); ++i) {
            AtomicString animationName(animationData->nameList()[i]);
            if (animationName == CSSAnimationData::initialName())
                continue;

            bool isPaused = CSSTimingData::getRepeated(animationData->playStateList(), i) == AnimPlayStatePaused;

            // Keyframes and animation properties are snapshotted when the
            // animation starts, so we don't need to track changes to these,
            // with the exception of play-state.
            if (cssAnimations) {
                AnimationMap::const_iterator existing(cssAnimations->m_animations.find(animationName));
                if (existing != cssAnimations->m_animations.end()) {
                    inactive.remove(animationName);
                    AnimationPlayer* player = existing->value.get();
                    if (isPaused != player->paused()) {
                        ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange());
                        update->toggleAnimationPaused(animationName);
                    }
                    continue;
                }
            }

            Timing timing = animationData->convertToTiming(i);
            RefPtr<TimingFunction> keyframeTimingFunction = timing.timingFunction;
            timing.timingFunction = Timing::defaults().timingFunction;
            AnimatableValueKeyframeVector resolvedKeyframes;
            resolveKeyframes(resolver, animatingElement, element, style, parentStyle, animationName, keyframeTimingFunction.get(), resolvedKeyframes);
            if (!resolvedKeyframes.isEmpty()) {
                ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange());
                update->startAnimation(animationName, InertAnimation::create(AnimatableValueKeyframeEffectModel::create(resolvedKeyframes), timing, isPaused));
            }
        }
    }

    ASSERT(inactive.isEmpty() || cssAnimations);
    for (const AtomicString& animationName : inactive) {
        ASSERT(!activeAnimations || !activeAnimations->isAnimationStyleChange());
        update->cancelAnimation(animationName, *cssAnimations->m_animations.get(animationName));
    }
}